web-dev-qa-db-ja.com

ファイルの変更時にDockerコンテナーを再構築する

ASP.NET Coreアプリケーションを実行するために、アプリケーションをビルドし、コンテナ内のソースコードをコピーするdockerfileを生成しました。これは、Jenkinsを使用してGitによって取得されます。したがって、私のワークスペースでは、dockerfileで次のことを行います。

WORKDIR /app
COPY src src

Jenkinsはホスト上のファイルをGitで正しく更新しますが、Dockerはこれを画像に適用しません。

構築のための私の基本的なスクリプト:

#!/bin/bash
imageName=xx:my-image
containerName=my-container

docker build -t $imageName -f Dockerfile  .

containerRunning=$(docker inspect --format="{{ .State.Running }}" $containerName 2> /dev/null)

if [ "$containerRunning" == "true" ]; then
        docker stop $containerName
        docker start $containerName
else
        docker run -d -p 5000:5000 --name $containerName $imageName
fi

--rm--no-cacheおよびdocker runパラメーターなどのさまざまなことを試してみました。また、コンテナーを停止/削除しますbefore新しいものがビルドされます。ここで何が間違っているのかわかりません。 COPY src srcを呼び出すとレイヤーIDが発生し、キャッシュは呼び出されないため、dockerはイメージを正しく更新しているようです。

Step 6 : COPY src src
 ---> 382ef210d8fd

コンテナを更新する推奨方法は何ですか?

私の典型的なシナリオは次のとおりです。アプリケーションはサーバー上でDockerコンテナーで実行されています。これで、アプリの一部が更新されました。ファイルを変更します。これで、コンテナは新しいバージョンを実行するはずです。 Dockerは、既存のコンテナーを変更するのではなく、新しいイメージを構築することを推奨しているようです。そのため、私のように再構築する一般的な方法は正しいと思いますが、実装の詳細を改善する必要があります。

51
Lion

いくつかの調査とテストを行った結果、Dockerコンテナの寿命について誤解していることがわかりました。コンテナを再起動するだけでは、その間にイメージが再構築されたときに、Dockerが新しいイメージを使用することはありません。代わりに、Dockerはコンテナーを実行する前にイメージのみをフェッチしています。したがって、コンテナを実行した後の状態は永続的です。

削除が必要な理由

したがって、再構築と再起動だけでは不十分です。コンテナはサービスのように機能すると考えました。サービスを停止し、変更を加え、再起動すると適用されます。それが私の最大の間違いでした。

コンテナは永続的であるため、最初にdocker rm <ContainerName>を使用してコンテナを削除する必要があります。コンテナが削除された後、docker startで単純に起動することはできません。これは、docker runを使用して実行する必要があります。_SOMECODE自体は、新しいコンテナインスタンスを作成するために最新のイメージを使用します。

コンテナはできるだけ独立している必要があります

この知識があれば、なぜコンテナにデータを保存するのが 悪い習慣として認定 であり、代わりにDockerが データボリューム/ホストディレクトリのマウント を推奨するのかを理解できます:コンテナを更新するには破棄する必要があるためアプリケーションでは、内部に保存されたデータも失われます。これにより、サービスのシャットダウン、データのバックアップなどに余分な作業が発生します。

したがって、これらのデータをコンテナから完全に除外するのは賢明なソリューションです。ホストに安全に保存され、コンテナがアプリケーション自体のみを保持している場合、データを心配する必要はありません。

-rfが本当に役に立たない理由

docker runコマンドには、-rfと呼ばれるClean upスイッチがあります。 Dockerコンテナを永続的に保持する動作を停止します。 -rfを使用すると、Dockerは終了後にコンテナを破棄します。ただし、このスイッチには2つの問題があります。

  1. Dockerは、コンテナに関連付けられた名前のないボリュームも削除します。これにより、データが削除される可能性があります
  2. このオプションを使用すると、-dスイッチを使用してバックグラウンドでコンテナーを実行することはできません

-rfスイッチは、クイックテストのために開発中の作業を節約するのに適したオプションですが、実稼働環境ではあまり適していません。特に、バックグラウンドでコンテナを実行するオプションがないため、ほとんどの場合これが必要になります。

コンテナを削除する方法

コンテナを削除するだけで、これらの制限を回避できます。

docker rm --force <ContainerName>

実行中のコンテナでSIGKILLを使用する--force(または-f)スイッチ。代わりに、次の前にコンテナを停止することもできます。

docker stop <ContainerName>
docker rm <ContainerName>

両方とも同等です。 docker stopSIGTERM を使用しています。ただし、--forceスイッチを使用すると、特にCIサーバーを使用する場合、スクリプトが短縮されます。コンテナが実行されていない場合、docker stopはエラーをスローします。これにより、Jenkinsおよび他の多くのCIサーバーは、ビルドが失敗したと誤って判断します。これを修正するには、質問で行ったようにコンテナが実行されているかどうかを最初に確認する必要があります(containerRunning変数を参照)。

Dockerコンテナを再構築するための完全なスクリプト

この新しい知識によると、スクリプトを次のように修正しました。

#!/bin/bash
imageName=xx:my-image
containerName=my-container

docker build -t $imageName -f Dockerfile  .

echo Delete old container...
docker rm -f $containerName

echo Run new container...
docker run -d -p 5000:5000 --name $containerName $imageName

これは完璧に動作します:)

96
Lion

Dockerfile、compose、requirementsに変更が加えられるたびに、docker-compose up --buildを使用して再実行します。画像が再構築および更新されるように

16
yunus