Docker Composeで複数コンテナからなるサービスを動かしている最中に、一部コンテナをアップデートしたいことがあります1。
そこで、本記事ではその方法を紹介します(もし、さらに良い方法がありましたらぜひ伺いたいです)。
前提
例えば下図のサービス構成で、service_1~3を動的に更新することを考えます。
この構成では、apiコンテナがコンテナ外部とのインタフェースになっています。コンテナ更新用のAPIにリクエストがあると、core_controllコンテナを介してservice_*用imageコンテナを都度ビルド、新規コンテナをアタッチする想定です。
<network> api internal
|--------------| |---------------|
<=> [service_1]
[api] <=> [core_controll] <=> [service_2]
<=> [service_3]
新たにコンテナをビルドをするにはDockerデーモンにアクセスする必要があるのですが、デフォルト設定ではコンテナ内からアクセスできません。
そこで、DooD(Docker outside of Docker)を使用します2。DooDの説明にいては割愛します。
環境構築
ファイル構成を準備する
以下の通りファイルを配置します3。
some_service/
- docker-compose.yml
- api/
- Dockerfile
- ...(APIサーバ用コード)...
- core_controll/
- Dockerfile
- docker-compose.yml
- ...(core_controll用コード)...
service1/
- Dockerfile
- ...(service1用コード)...
service2/
- Dockerfile
- ...(service1用コード)...
service3/
- Dockerfile
- ...(service1用コード)...
この構成において、some_service直下でdocker-compose up
を実行することによりapiコンテナ、core_controllコンテナを作成するようにしています。
DooDを使えるようにする
some_service/docker-compose.ymlについて、volumesで/var/run/docker.sock:/var/run/docker.sock
と指定します。
この設定がホスト環境のDockerのsockをcore_controllコンテナに共有する設定になります。これにより、コンテナ側からホスト側のDockerを操作できるようになります。
some_service/docker-compose.yml
version: '3.4'
services:
vision:
container_name: "api"
build:
context: ./api
dockerfile: Dockerfile
restart: always
tty: true
ports:
- "8000:8000"
networks:
- api
core_controll:
container_name: "core_controll"
build:
context: ./core_controll
dockerfile: Dockerfile
depends_on:
- service1
- service2
- service3
volumes:
- /var/run/docker.sock:/var/run/docker.sock
networks:
- api
- internal
networks:
api:
internal:
コンテナ内部でdocker-composeコマンドを使えるようにする
core_controllコンテナ内でdocker-composeコマンドを使えるようインストールに加えます。
(Alpine Linux環境のためapkを使っていますが、ベースOSに応じてyumやapt-get等に読み替えてください)
FROM node:14-alpine
RUN apk add --update docker-compose
コンテナ内部でservice_*用コードを取得、ビルドする機構を作る
コード上で、以下2処理を記載します。
- service1~3のコードをsome_service/下にフェッチします(サンプルコードではシェルスクリプトによりコピーしているので、割愛しています)。
- サブプロセスで
docker-compose up -d
を実行します。pythonの場合、subprocess.run
、Node.jsの場合child_process.exec
などが該当します。
service1~3構成用Docker Compose設定を記載する
some_service/core_controll/docker-compose.ymlにservice1~3の構成を記載します。
version: '3.4'
services:
service1:
container_name: "service1"
build:
context: ./service2
dockerfile: Dockerfile
networks:
- internal
service2:
container_name: "service2"
build:
context: ./service2
dockerfile: Dockerfile
networks:
- internal
service3:
container_name: "service3"
build:
context: ./service3
dockerfile: Dockerfile
networks:
- internal
networks:
internal:
external:
name: some_service_internal
このうち、networksでinternalネットワークと、some_service_internalネットワークを接続しています。このsome_service_internalネットワークは、some_service/docker-compose.ymlで設定したinternalネットワークに対応します。
以上で設定は完了です。
service1~3コンテナを動的に更新する
※ 具体的な実装例、および動作をテストしてみたい場合はサンプルコードをご覧ください。
(事前処理) some_service/下でdocker-compose up -d
を実行し、apiコンテナとcore_controllコンテナを立ち上げておきます。
コンテナ更新用のAPIを呼び出し、core_controll下でdocker-composeコマンドによるビルドを行います。ビルドが成功していれば、service1~3コンテナが自動的にアタッチされます。
これによりサービス全体を動かしつつ、service1~3を動的に更新することができます。
サンプルコード
以下URLを参照ください。
https://github.com/pirika-inc/docker_compose_hot_container_update_sample
以上になります。ご覧いただきありがとうございます!