Docker を WebUI で操作できる Portainer には API が用意されており、これを使えば Portainer の UI でできることを全て自動化できます。また、Portainer API を介して Docker Engine API も叩くことができるので試してみました。
Portainer の API のドキュメントは以下です。
Docker Engine API のドキュメントは以下です。
Python + aiohttp で実装してみました。
環境
- Docker 20.10.12
- Portainer 2.13.1
- Python 3.8.10
- aiohttp 3.8.1
サンプルコード
細かい解説は後にして、先にコード全体を載せます。
import asyncio
import aiohttp
PORTAINER_URL="http://portainer_url"
async def main():
async with aiohttp.ClientSession() as session:
# トークンを取得
r = await session.post(f'{PORTAINER_URL}/api/auth', json={ 'Username': 'Admin', 'Password': 'AdminPassword' })
data = await r.json()
jwt = data['jwt']
# ヘッダー
headers={ 'Authorization': f'Bearer {jwt}' }
#headers={ 'X-API-Key': 'token' }
# EnvironmentID を取得
r = await session.get(f'{PORTAINER_URL}/api/endpoint_groups', headers=headers)
environments = await r.json()
id = environments[0]['Id']
# コンテナ一覧の取得
r = await session.get(f'{PORTAINER_URL}/api/endpoints/{id}/docker/containers/json', json={ 'all': 'true' }, headers=headers)
containers = await r.json()
print(containers)
if __name__ == '__main__':
asyncio.run(main())
トークンの取得
Portainer のアカウントを使って JWT トークンを取得します。
r = await session.post(f'{PORTAINER_URL}/api/auth', json={ 'Username': 'Admin', 'Password': 'AdminPassword' })
data = await r.json()
jwt = data['jwt']
このトークンは8時間の間だけ有効だそうです。
または、Portainer の myaccount 画面からでも API トークンを発行できます。
それぞれヘッダーの書き方が少し異なります。
前者の場合は
headers={ 'Authorization': f'Bearer {jwt}' }
後者の場合は
headers={ 'X-API-Key': 'token' }
のように記述します。
Environment(endpoint) ID の取得
Portainer は複数の Docker ホストを管理できるので、Docker Engine API を叩く際にはどのホストの Docker に対する操作かを指定する必要があります。 なので、Docker Engine API を叩く前に Environment の一覧を取得します。
r = await session.get(f'{PORTAINER_URL}/api/endpoint_groups', headers=headers)
environments = await r.json()
id = environments[0]['Id']
コンテナの一覧を取得
コンテナの一覧を取得してみます。
API の仕様は以下を参照してください。
Portainer のエンドポイント /api/endpoints/{id}/docker
より後ろが docker のエンドポイントと同じになるみたいですね。
r = await session.get(f'{PORTAINER_URL}/api/endpoints/{id}/docker/containers/json', json={ 'all': 'true' }, headers=headers)
containers = await r.json()
ここまでやれば、後は大体のことができるんじゃないかと思います。