1. 序章

私たちのプロジェクトでは、私たちはよく使用します docker-compose コンテナ化されたアプリケーションをデプロイします。 CIとCDでは、コードの変更と展開が最近非常に頻繁に行われています。 したがって、docker-composeが常にアプリケーションの最新のイメージを使用するようにすることが重要です。.

このチュートリアルでは、同じことを実現するためのいくつかのオプションを確認します。

2. 画像を明示的にプルする

docker-composeファイルの簡単な例を見てみましょう。

version: '2.4'
services:
  db:
    image: postgres
  my_app:
    image: "eugen/test-app:latest"
    ports:
      - "8080:8080"

ここでは、2つのサービスを使用しました。1つはPostgreSQLデータベースで、もう1つはテストアプリケーションです。 次のコマンドを使用してアプリケーションをデプロイします。

$ docker-compose up -d

これにより、両方のイメージがリモートリポジトリ(たとえば、 dockerhub )からプルされ、対応するコンテナが作成されます。

同じコマンドを使用してアプリケーションを再デプロイすると、問題が発生します。 イメージはローカルリポジトリにすでに存在するため、リモートリポジトリでこれらのイメージに変更があるかどうかはチェックされません。したがって、事前にdocker-composeファイル内のすべてのイメージをプルするオプションがあります。

$ docker-compose pull
Pulling db     ... done
Pulling my_app ... done

このコマンドは、最初にdockerhubの両方のイメージで利用可能な更新があるかどうかを確認します。 次に、リモートで画像を最新の状態に保つために必要なレイヤーのみをダウンロードします。

ただし、Postgresのイメージをプルすることを常に好むとは限りません。 データベースの安定バージョンを使用する場合、イメージに変更はありません。 したがって、展開ごとにダウンロードするのは意味がありません。 場合によっては、既存のデータファイルが新しいバージョンと互換性がないことがあります。 これにより、展開が中断される可能性があります。 その場合、プルコマンドで特定のサービスの名前のみを使用できます:

$ docker-compose pull my_app
Pulling my_app ... done

ここで、upコマンドを実行すると、最新のイメージでコンテナーが再作成されます。

$ docker-compose up -d
Starting docker-test_db_1     ... done
Starting docker-test_my_app_1 ... done

もちろん、両方のコマンドを組み合わせて単一のライナーを作成することもできます。

$ docker-compose pull && docker-compose up -d

3. ローカル画像の削除

同じ例をもう一度考えてみましょう。 主な問題はローカル画像の存在であることはすでにわかっています。 したがって、ここでの2番目のオプションは、すべてのコンテナーを停止し、ローカルリポジトリからそれらのイメージを削除することです

$ docker-compose down --rmi all
Stopping docker-test_my_app_1 ... done
Removing docker-test_db_1     ... done
Removing docker-test_my_app_1 ... done
Removing network docker-test_default
Removing image postgres
Removing image eugen/test-app:latest

down コマンドは、コンテナーを停止して削除します。 –rmi オプションは、ローカルリポジトリから画像を削除します。 rmiタイプlocalは、ローカルでビルドされたイメージのみを削除します。 したがって、rmiタイプallを使用して、現在の構成で使用されているすべてのイメージが確実に削除されるようにすることをお勧めします。

ここで、upコマンドを使用してコンテナーを再起動します。

$ docker-compose up -d
Creating network "docker-test_default" with the default driver
Pulling db (postgres:)...
latest: Pulling from library/postgres
7d63c13d9b9b: Pull complete
cad0f9d5f5fe: Pull complete
...
Digest: sha256:eb83331cc518946d8ee1b52e6d9e97d0cdef6195b7bf25323004f2968e91a825
Status: Downloaded newer image for postgres:latest
Pulling my_app (eugen/test-app:latest)...
latest: Pulling from eugen/test-app
df5590a8898b: Already exists
705bb4cb554e: Already exists
...
Digest: sha256:31c05c8245192b32b8b359fc58b5e45d8397674ccf41f5f17a7d3109772ab5c1
Status: Downloaded newer image for eugen/test-app:latest
Creating docker-test_db_1     ... done
Creating docker-test_my_app_1 ... done

これにより、ローカルリポジトリで画像が見つからなくなったことがわかります。 そのため、リモートリポジトリから最新のイメージをプルして、コンテナを再作成します。

このアプローチの欠点は、削除する特定の画像を選択できないことです。 そのため、常に postgres イメージを削除し、同じイメージを再度ダウンロードしますが、これは不要です。 これを解決するには、 dockerrmiを使用して特定のイメージを削除します。

$ docker rmi -f eugen/test-app:latest
Untagged: eugen/test-app:latest
Untagged: eugen/test-app@sha256:31c05c8245192b32b8b359fc58b5e45d8397674ccf41f5f17a7d3109772ab5c1
Deleted: sha256:7bc07b4eb1c23f7a91afeb7133f107e0a8318fb77655d7d5f2f395a035a13eb7

4. 画像の再構築

別のフレーバーを持つdocker-composeファイルの同じ例を見てみましょう。

version: '2.4'
services:
  db:
    image: postgres
  my_app:
    build: ./test-app
    ports:
      - "8080:8080"

ここでは、Postgresで同じdbサービスを使用しました。 ただし、サービス my_app には、既製のイメージを使用する代わりに、ビルドセクションを指定しました。 このセクションには、test-appのビルドコンテキストが含まれています。 test-appディレクトリにあるdockerファイルは次のようになります。

FROM openjdk:11
COPY target/test-app-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

このシナリオでは、 up コマンドを使用して再デプロイすると、docker-composeはローカルイメージが存在する場合はそれを再利用します。 したがって、デプロイメントをトリガーするたびにdocker-composeがイメージを再構築することを確認する必要があります。 オプション–build:を使用してこれを行うことができます

$ docker-compose up -d --build
Building my_app
[+] Building 2.5s (8/8) FINISHED                                                                                            
 => [internal] load build definition from Dockerfile                                                                    0.0s
 => => transferring dockerfile: 41B                                                                                     0.0s
 => [internal] load .dockerignore                                                                                       0.0s
 => => transferring context: 2B                                                                                         0.0s
 => [internal] load metadata for docker.io/library/openjdk:11                                                           2.3s
 => [auth] library/openjdk:pull token for registry-1.docker.io                                                          0.0s
 => [1/2] FROM docker.io/library/openjdk:11@sha256:1b04b1958a4a61900feec994e3938a2a5d8f88db8ec9515f46a25cbe561b65d9     0.0s
 => [internal] load build context                                                                                       0.0s
 => => transferring context: 84B                                                                                        0.0s
 => CACHED [2/2] COPY target/test-app-0.0.1-SNAPSHOT.jar app.jar                                                        0.0s
 => exporting to image                                                                                                  0.0s
 => => exporting layers                                                                                                 0.0s
 => => writing image sha256:4867a3f0b0a043cd54e16086e2d3c81dbf4c418806399f60fc7d7ffc094c7159                            0.0s
 => => naming to docker.io/library/docker-test_my_app                                                                   0.0s

Starting docker-test_db_1 ... 
Starting docker-test_db_1 ... done

別のアプローチは、upコマンドを実行する前にbuildコマンドを使用することです。

$ docker-compose build --pull --no-cache
db uses an image, skipping
Building my_app
...                                                                                                           0.0s
 => => naming to docker.io/library/docker-test_my_app 

このコマンドには、さらに2つのオプションがあります。 –pull オプションは、イメージの構築中にDockerfileのベースイメージをリモートリポジトリからプルするように要求します。 –no-cache オプションは、ローカルキャッシュがスキップされることを示します。 ただし、ここでは直接イメージを使用しているため、dbサービスの構築はスキップされます。

ここで、作成構成を再起動すると、コンテナーは最新のイメージを使用します。

$ docker-compose up -d
Starting docker-test_db_1       ... done
Recreating docker-test_my_app_1 ... done

5. 結論

この記事では、docker-composeがデプロイ時に最新のイメージを使用しない理由を説明しました。 また、docker-composeが常に最新のイメージを使用して、そのイメージでコンテナーを再作成する方法をいくつか学びました。 また、アプローチの落とし穴と、それらを軽減する方法についても説明しました。

この記事に関連するコードは、GitHubから入手できます。