人生100年!生涯エンジニア人生!

楽しいエンジニア人生!

PythonからDockerコンテナを起動する。

docker-compose.ymlでも良いのですが・・・

Scrapyの技術同人誌を書いたとき、Dockerの起動はdocker-compose.ymlを書いて起動するようにしました。
kawahara-ci.hatenablog.com

これをPythonのDockerモジュールを使って起動する方法もあるよねと思いました。
pip install dockerをやってから早速やってみました。

コンテナの状態

プログラムからDockerのコンテナを起動するとき、コンテナは3つの状態が考えられます。

  1. 該当のコンテナが起動済み。
  2. 該当のコンテナがあるが起動してない。
  3. 該当コンテナが存在しない。

この3つの状態を理解して作っていきましょう。

コンテナが起動済み

docker.from_env()でDockerのオブジェクトを取得しておき、そのオブジェクトから、コンテナリスト(containers.list())を調べて、コンテナ名と一致していたら、コンテナが起動しているので、何もしないで終わります。

コンテナがあるが起動してない

コンテナリスト(containers.list())のデフォルトは起動しているコンテナを取得しますが、パラメータにall=Trueを追加するとすべての状態のコンテナリストを取得します。

最初に起動しているかを確認しているので、このときに取得できたコンテナリストとコンテナ名が一致したら、起動していないコンテナがあることになります。

そのときはcontainer.restart()でコンテナを再起動します。

コンテナが存在しない

最後は、コンテナが存在しない状態なのでcontainers.runでDockerイメージをpullしてコンテナを起動してしまいます。
なお、Dockerイメージが既にpull済みのときは、コンテナの起動だけをします。

containers.run('scrapinghub/splash', name='splash', ports={'8050/tcp': 8050}, detach=True)このような感じでコンテナを起動します。

ここで重要なのはnameパラメータです。
コンテナを起動するとき名前を設定しないと、Dockerは良きに計らえということで適当な名前を付けてしまいます。
そうなると、コンテナの存在を確認しにくいので、コンテナの名前を付けて起動するようにします。

完成形

以上のことを踏まえて作ると、以下のようになります。
3つの状態を判別してコンテナが起動できるようになりました。

import sys
import docker

container_name = 'splash'
client = docker.from_env()

container_exists = False
for container in client.containers.list():
    if container_name == container.name:
        container_exists = True
        print('Container is up.')

if container_exists == False:
    for container in client.containers.list(all=True):
        if container_name == container.name:
            container.restart()
            print('Container restartup.')
            sys.exit()

    container = client.containers.run('scrapinghub/splash', name=container_name, ports={'8050/tcp': 8050}, detach=True)
    print('Container startup.')