これは、なにをしたくて書いたもの?
Docker Composeを使って起動するコンテナの初期処理をするには、どうしたらいいのかな?ということで。
ちょっと考えてみました。
環境
今回の環境は、こちら。
$ docker version Client: Docker Engine - Community Version: 23.0.1 API version: 1.42 Go version: go1.19.5 Git commit: a5ee5b1 Built: Thu Feb 9 19:47:01 2023 OS/Arch: linux/amd64 Context: default Server: Docker Engine - Community Engine: Version: 23.0.1 API version: 1.42 (minimum version 1.12) Go version: go1.19.5 Git commit: bc3805a Built: Thu Feb 9 19:47:01 2023 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.6.18 GitCommit: 2456e983eb9e37e47538f59ea18f2043c9a73640 runc: Version: 1.1.4 GitCommit: v1.1.4-0-g5fd4c4d docker-init: Version: 0.19.0 GitCommit: de40ad0 $ docker compose version Docker Compose version v2.16.0
コンテナの初期処理をしたい
Dockerfile
でビルドする時になんとかすればいいのでは、という話もありますが、すでに作成済みのコンテナイメージを使いたい場合、
その他いろんな理由でコンテナの初期処理を行いたい場合があるような気がします。
今回はDocker Composeの範囲でなんとかするように考えてみます。
Compose specification | Docker Documentation
Docker Composeの構成ファイルには、初期処理用の定義などはないですからね。ではどうしましょうか?という話です。
お題として、MinIOのDockerイメージを使ってみましょう。
entrypointを再定義する
最初に思いつくのは、entrypoint
を定義することですね。
Compose file specification / Services top-level element / entrypoint
たとえば、MinIOのDockerイメージに含まれるmc
コマンドを使えるようにgunzip
する初期処理を行ってみましょう。
compose.yaml
services: minio: image: minio/minio:RELEASE.2023-02-17T17-52-43Z ports: - 9000:9000 - 9001:9001 environment: MINIO_ROOT_USER: myminioadmin MINIO_ROOT_PASSWORD: myminioadmin entrypoint: >- bash -c 'gunzip /opt/bin/mc.gz \ && chmod a+x /opt/bin/mc \ && /usr/bin/docker-entrypoint.sh minio server /data --console-address ":9001" '
こんな感じで、entrypoint
を再定義します。
entrypoint: >- bash -c 'gunzip /opt/bin/mc.gz \ && chmod a+x /opt/bin/mc \ && /usr/bin/docker-entrypoint.sh minio server /data --console-address ":9001" '
これで、コンテナの主となるプロセス(今回はMinIOサーバー)の起動前に処理を追加したりできます。
初期処理を行う前の状態は、こうでした。
$ docker compose exec -it minio ls -l /opt/bin total 106684 -rw-r--r-- 1 root root 9246981 Feb 17 19:11 mc.gz -rwxr-xr-x 1 root root 99983360 Feb 17 19:11 minio -rw-r--r-- 1 root root 329 Feb 17 19:11 minio.minisig -rw-r--r-- 1 root root 100 Feb 17 19:11 minio.sha256sum
先述のcompose.yaml
の内容で起動すると
$ docker compose up
mc.gz
ファイルが展開できていることが確認できます。
$ docker compose exec -it minio ls -l /opt/bin total 122784 -rwxr-xr-x 1 root root 25735168 Feb 17 19:11 mc -rwxr-xr-x 1 root root 99983360 Feb 17 19:11 minio -rw-r--r-- 1 root root 329 Feb 17 19:11 minio.minisig -rw-r--r-- 1 root root 100 Feb 17 19:11 minio.sha256sum
この方法の欠点は、カスタマイズ元のDockerイメージの起動コマンドがわかっていないと差し替えができないこと、適用できるのが
コンテナ内で主となるプロセスの起動前にできる内容に限られること、ですね。
使用するコンテナイメージの内部にちょっと踏み込んでいる感じがします。
今回のMinIOのコンテナイメージだとcommand
で起動引数を追加できるようになっているはずなのですが、それも潰してしまって
いますし。
初期処理用のコンテナを使う
次の方法としては、初期処理用のコンテナを追加することを考えてみたいと思います。
たとえば今回のMinIOを使った例だと、MinIOサーバーが起動した後にバケットの作成を行うといった感じですね。
compose.yaml
services: minio: image: minio/minio:RELEASE.2023-02-17T17-52-43Z ports: - 9000:9000 - 9001:9001 environment: MINIO_ROOT_USER: myminioadmin MINIO_ROOT_PASSWORD: myminioadmin command: server /data --console-address ":9001" minio-setup: image: minio/mc:RELEASE.2023-02-16T19-20-11Z restart: "no" depends_on: - minio entrypoint: [] command: >- bash -c 'sleep 3 \ && mc alias set myminio http://minio:9000 myminioadmin myminioadmin \ && mc mb myminio/my-bucket \ && echo "minio setup complete"'
初期処理をしたら、終了するコンテナを追加しています。初期処理が目的なので、MinIOクライアントのコンテナイメージを使っています。
depends_on
で、対象のコンテナの後に起動するようにして
depends_on: - minio
再起動も行わないようにします。これはデフォルトですが。
restart: "no"
あとは、entrypoint
の内容を書き換えて、command
で初期処理を実行。
entrypoint: [] command: >- bash -c 'sleep 3 \ && mc alias set myminio http://minio:9000 myminioadmin myminioadmin \ && mc mb myminio/my-bucket \ && echo "minio setup complete"'
entrypoint
にそのまま書いてしまってもいいと思いますけど。
entrypoint: >- bash -c 'sleep 3 \ && mc alias set myminio http://minio:9000 myminioadmin myminioadmin \ && mc mb myminio/my-bucket \ && echo "minio setup complete"'
sleep
を入れているのは、depends_on
はあくまでコンテナの起動順をコントロールするだけなので、MinIOサーバーが立ち上がるのを
待つようにするためです。
これで起動すると
$ docker compose up
バケットが作成できていることが確認できます。
$ aws s3 ls --endpoint-url http://localhost:9000 2023-02-19 03:27:01 my-bucket
初期処理用のコンテナの様子は、こんな感じですね。
xxxxx-minio-setup-1 | Added `myminio` successfully. xxxxx-minio-setup-1 | Bucket created successfully `myminio/my-bucket`. xxxxx-minio-setup-1 | minio setup complete xxxxx-minio-setup-1 exited with code 0
処理が終わったら終了しています。
この方法だと初期処理を行いたい対象のコンテナ自体はそのままでよいのですが、初期処理のためだけのコンテナ定義ができてしまうことと、
初期処理を適用したい対象のコンテナを--scale
で複数インタンスにしてしまうとまた事情が変わってしまうことだと思います。
複数のインスタンスがあっても、クラスタリングなどで解決できればいいんですけどね。
まとめ
Docker Composeを使って、コンテナの起動時に初期処理を行う方法を考えてみました。
だいぶムリヤリな感じはしますが、Docker Composeだけでなんとかしようとする場合はこんな感じではないでしょうか。