1. ホーム
  2. git

[解決済み] ファイル変更時のDockerコンテナの再構築

2022-07-27 02:06:49

質問

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 また、コンテナの停止/削除 の前に の前にコンテナを停止または削除します。ここで何が間違っているのかよくわかりません。docker は正しくイメージを更新しているようです。 COPY src src を呼び出すと、レイヤー ID とキャッシュの呼び出しが発生しないため、Docker は正しくイメージを更新しているようです。

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

コンテナを更新するために推奨される方法は何ですか?

私の典型的なシナリオは次のようなものです。アプリケーションは Docker コンテナ内のサーバーで実行されています。現在、アプリケーションの一部が、たとえば、ファイルを修正することによって更新されています。今、コンテナは新しいバージョンを実行する必要があります。Dockerは、既存のコンテナを修正する代わりに、新しいイメージを構築することを推奨しているようです。

どのように解決するのか?

いくつかの調査とテストの後、私はDockerコンテナの寿命についていくつかの誤解をしていることに気づきました。単にコンテナを再起動しただけでは、その間にイメージが再構築された場合、Docker は新しいイメージを使用しません。その代わり、Dockerはイメージの取得にのみ の前に その代わり、Dockerはコンテナを作成する前にのみイメージを取得します。そのため、コンテナを実行した後の状態は永続的です。

削除が必要な理由

そのため、再構築や再起動だけでは十分ではありません。コンテナはサービスのように動作すると思っていました。サービスを停止して、変更を行い、再起動すれば、それが適用されると思っていました。これが私の最大の間違いでした。

コンテナは永久的なものなので、削除するには docker rm <ContainerName> を使用して削除する必要があります。コンテナが削除された後、単純にコンテナを起動するには docker start . を使って行わなければなりません。 docker run を使用する必要があります。この画像は新しいコンテナインスタンスを作成するために最新の画像を使用します。

コンテナは可能な限り独立であるべき

このような知識があれば、なぜコンテナにデータを格納することが がバッドプラクティスと認定された理由も理解できます。 であり、Docker が推奨する データボリューム/マウントホストディレクトリ を推奨しています。アプリケーションを更新するためにはコンテナを破壊しなければならないので、内部の保存データも失われることになります。これは、サービスのシャットダウン、データのバックアップなど、余分な作業の原因となります。

そこで、これらのデータをコンテナから完全に除外するのが賢い解決策です。データはホスト上に安全に保存され、コンテナはアプリケーションのみを保持するため、私たちはデータの心配をする必要がないのです。

なぜ -rf は本当にあなたを助けていないかもしれません

docker run コマンドでは クリーンアップ というスイッチがあります。 -rf . これは、dockerコンテナを永続的に保持する動作を停止させるものです。使用方法 -rf を使用すると、Dockerはコンテナが終了した後にコンテナを破棄します。しかし、このスイッチには2つの問題があります。

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

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

コンテナーを削除する方法

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

docker rm --force <ContainerName>

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

docker stop <ContainerName>
docker rm <ContainerName>

どちらも同じです。 docker stop はまた シグマ . しかし --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

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