プログラムを中心とした個人的なメモ用のブログです。 タイトルは迷走中。
内容の保証はできませんのであしからずご了承ください。

2022/06/27

Portainer API を使って Docker Engine API を叩いてみる

event_note2022/06/27 4:38

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()

ここまでやれば、後は大体のことができるんじゃないかと思います。