イメージが変更された後にDockerコンテナーをアップグレードする方法


518

公式のmysql:5.6.21イメージをプルしたとしましょう。

いくつかのDockerコンテナーを作成して、このイメージをデプロイしました。

これらのコンテナは、MySQL 5.6.22がリリースされるまでしばらく実行されていました。mysql:5.6の公式イメージは新しいリリースで更新されますが、私のコンテナーはまだ5.6.21を実行しています。

イメージの変更をすべての既存のコンテナーに伝播するには(つまり、MySQLディストリビューションをアップグレードします)。これを行う適切なDockerの方法は何ですか?

回答:


579

回答を評価してトピックを検討した後、まとめたいと思います。

コンテナーをアップグレードするDockerの方法は次のようです。

アプリケーションコンテナには、アプリケーションデータを格納しないでください。このように、次のようなものを実行することで、いつでもアプリコンテナーを新しいバージョンに置き換えることができます。

docker pull mysql
docker stop my-mysql-container
docker rm my-mysql-container
docker run --name=my-mysql-container --restart=always \
  -e MYSQL_ROOT_PASSWORD=mypwd -v /my/data/dir:/var/lib/mysql -d mysql

ホスト(ボリュームとしてマウントされたディレクトリ内)または特別なデータ専用コンテナーにデータを保存できます。それについてもっと読む

コンテナー内でのアプリケーションのアップグレード(yum / apt-getアップグレードなど)は、アンチパターンと見なされます。アプリケーションコンテナは不変であることが想定されており、再現可能な動作が保証されます。一部の公式アプリケーションイメージ(特にmysql:5.6)は、自己更新するように設計されていません(apt-getアップグレードは機能しません)。

答えを出してくださった皆さんに感謝します。そうすれば、さまざまなアプローチをすべて見ることができます。


31
データの移行が必要な場合はどうなりますか?新しいサーバーは古い形式であるため、データをマウントできません。移行が行われていることを認識し、データ表現を変更する必要があります。
Dor Rotman、2015年

12
私は、イメージの設計者はそれを考慮に入れ、コンテナーの最初の実行中にカスタム(たとえば、データ移行)コマンドを起動できるようにする必要があると思います。
Yaroslav Stavnichiy 2015年


4
@static_rtti docker rename my-mysql-container trash-container新しいものを作成する前にどうですか?
フランクリンYu

4
(プルされた新しいイメージに基づいて)手動で停止、削除、再作成する必要なしにコンテナーを更新するオールインワンコマンドはありますか?
マイケル・ペラン

83

ボリュームをホストディレクトリへのリンクとしてマウントするのは好きではないので、Dockerコンテナーを完全にDockerで管理されたコンテナーにアップグレードするパターンを思いつきました。で新しいdockerコンテナーを作成する--volumes-from <container>と、更新されたイメージを含む新しいコンテナーにdocker管理ボリュームの所有権が共有されます。

docker pull mysql
docker create --volumes-from my_mysql_container [...] --name my_mysql_container_tmp mysql

my_mysql_container元のコンテナをすぐに削除しないことにより、アップグレードされたコンテナに適切なデータがない場合、または正常性テストに失敗した場合に、既知の正常なコンテナに戻すことができます。

この時点で、私は通常、何か問題が発生した場合に備えて自分自身にセーフティネットを提供するために、コンテナ用のバックアップスクリプトを実行します。

docker stop my_mysql_container
docker start my_mysql_container_tmp

これで、新しいコンテナーにあると予想されるデータが存在することを確認し、健全性チェックを実行する機会が得られました。

docker rm my_mysql_container
docker rename my_mysql_container_tmp my_mysql_container

コンテナーがそれらを使用している限り、Dockerボリュームは残りますので、元のコンテナーを安全に削除できます。元のコンテナが削除されると、新しいコンテナは元のコンテナの名前を引き継ぎ、すべてを開始時と同じようにきれいにできます。

このパターンを使用してDockerコンテナーをアップグレードすることには、2つの大きな利点があります。まず、ボリュームをアップグレードされたコンテナに直接転送できるようにすることで、ボリュームをホストディレクトリにマウントする必要がなくなります。第2に、Dockerコンテナーが機能していない位置にいることはありません。そのため、アップグレードが失敗した場合は、元のDockerコンテナーを再度スピンアップすることで、以前の状態に簡単に戻すことができます。


3
Dockerコンテナー内にホストボリュームをマウントしたくないのですか?(私はそれを正確に行っているので、それに対する反対の引数に興味があります./postgres-data/:/var/lib/postgres/data./postgres-data/
:-)

4
@KajMagnus私はdocker swarmsを頻繁に使用しており、swarmでうまく機能するようにコンテナーを作成するのが好きです。スウォーム内のコンテナーを起動するとき、コンテナーがどのスウォームノードに住むかわからないので、必要なデータを含むホストパスに依存できません。Docker 1.9(私は思う)のボリュームはホスト間で共有できるため、私が説明した方法を使用すると、コンテナーのアップグレードと移行が簡単になります。別の方法として、すべてのスウォームノードにネットワークボリュームがマウントされていることを確認することもできますが、これは維持するのが非常に困難に思えます。
kMaiSmith 2016年

ありがとう!さて、ホストボリュームのマウントは、今は避けたいようです。アプリが人気になり、複数のサーバーにスケーリングする必要がある場合、少なくとも少し後で
KajMagnus

32

より一般的な(mysql固有ではない)回答を提供するためだけに...

  1. 要するに

サービスイメージレジストリと同期する(https://docs.docker.com/compose/compose-file/#image):

docker-compose pull 

docker-composeファイルまたはイメージが変更された場合は、コンテナーを再作成します。

docker-compose up -d
  1. バックグラウンド

コンテナーイメージ管理は、docker-composeを使用する理由の1つです(https://docs.docker.com/compose/reference/up/を参照)。

サービス用の既存のコンテナーがあり、コンテナーの作成後にサービスの構成またはイメージが変更された場合、docker-composeはコンテナーを停止して再作成することで変更を取得します(マウントされたボリュームを保持)。Composeが変更を取得しないようにするには、-no-recreateフラグを使用します。

データ管理の側面は、マウントされた外部「ボリューム」(https://docs.docker.com/compose/compose-file/#volumesを参照)またはデータコンテナーを介したdocker-composeでもカバーされます

これにより、潜在的な下位互換性とデータ移行の問題はそのまま残りますが、これらはDocker固有ではなく、「適用可能な」問題であり、リリースノートとテストに対してチェックする必要があります...


バージョン管理でこれをどのように行いますか?たとえば、新しい画像はfoo / image:2で、docker-compose.ymlには画像があります:foo / image:1?
dman

ありがとうございました。ベストアンサー!
ミック

これは確かに進むべき道ですが、コンテナが再作成されると、コンテナで行われた変更はすべて失われることに注意してください。そのため、コンテナの変更をマウントされたボリューム内に維持することが依然として必要です。
PetrBodnár

23

このプロセスを自動的に実行したい場合(@Yaroslavで説明されているのと同じ設定で新しいコンテナーをダウンロード、停止、再起動)したい場合は、WatchTowerを使用できることを付け加えておきます。コンテナーが変更されたときにコンテナーを自動更新するプログラムhttps://github.com/v2tec/watchtower


20

この回答を検討してください:

  • データベース名は app_schema
  • コンテナ名は app_db
  • rootパスワードは root123

コンテナー内にアプリケーションデータを保存するときにMySQLを更新する方法

コンテナーを失うとデータが失われるため、これは悪い習慣と見なされます。これは悪い習慣ですが、次の方法で行うことができます。

1)SQLとしてデータベースダンプを実行します。

docker exec app_db sh -c 'exec mysqldump app_schema -uroot -proot123' > database_dump.sql

2)画像を更新します。

docker pull mysql:5.6

3)コンテナーを更新します。

docker rm -f app_db
docker run --name app_db --restart unless-stopped \
-e MYSQL_ROOT_PASSWORD=root123 \
-d mysql:5.6

4)データベースダンプを復元します。

docker exec app_db sh -c 'exec mysql -uroot -proot123' < database_dump.sql

外部ボリュームを使用してMySQLコンテナーを更新する方法

外部ボリュームを使用する方がデータを管理する優れた方法であり、MySQLの更新が容易になります。コンテナを失ってもデータは失われません。docker-composeを使用すると、単一のホストで複数コンテナのDockerアプリケーションを簡単に管理できます。

1)docker-compose.ymlアプリケーションを管理するためにファイルを作成します。

version: '2'
services:
  app_db:
    image: mysql:5.6
    restart: unless-stopped
    volumes_from: app_db_data
  app_db_data:
    volumes: /my/data/dir:/var/lib/mysql

2)MySQLを更新します(docker-compose.ymlファイルと同じフォルダーから):

docker-compose pull
docker-compose up -d

注:上記の最後のコマンドはMySQLイメージを更新し、新しいイメージでコンテナを再作成して起動します。


巨大なデータベース(数GB)があるとしましょう。データベース全体がインポートされるまでデータにアクセスできませんか?それは巨大な「ダウンタイム」になる可能性があります
hellimac 2017年

あなたが言及したのでdocker-compose、これはうまくいきますか?stackoverflow.com/a/31485685/65313
sivabudh 2017年

1
volumes_fromキーは非推奨になり(バージョン3の構成ファイルで削除された場合でも)、新しいvolumesキーが採用されました。
フランクリンYu

docker pull image_uri:tag && docker restart container_running_that_image私のために働いた。必要はありませんdocker-compose pull && docker-compose up -d
Yuriy Pozniak

16

上記と同様の答え

docker images | awk '{print $1}' | grep -v 'none' | grep -iv 'repo' | xargs -n1 docker pull

1
鮮やかさ!それ以上の票を獲得しなかったのにはかなり驚いた。欠けているのは、更新されたすべてのコンテナの再起動をトリガーすることだけです。
ソリン2017年

7
残念ながら、これは既存のコンテナを更新しません。これはプルされたイメージを更新するだけですが、既存のコンテナは不変であり、それを作成するために使用された元のイメージをまだ使用しています。これは、イメージから新しいコンテナーを作成する場合にのみ機能しますが、既存のコンテナーは依然として元のイメージに基づいています。
エリック

すごい。コンテナーの特定のバージョンをプルする必要がある場合は、次のようにします。awk '{print $ 1 ":" $ 2}' | grep -v 'none' | grep -iv 'repo' | xargs -n1 docker pull
rogervila

11

docker-composeカスタムを構築するときに使用する方法は次のとおりDockerfileです。

  1. 最初にカスタムDockerfileを作成し、区別するために次のバージョン番号を追加します。例:docker build -t imagename:version . 新しいバージョンをローカルに保存します。
  2. 走る docker-compose down
  3. docker-compose.yml手順1で設定した新しいイメージ名を反映するようにファイルを編集します。
  4. を実行しますdocker-compose up -d。ローカルでイメージを探し、アップグレードしたイメージを使用します。

-編集-

上記の私の手順は、必要以上に冗長です。build: .docker-composeファイルにパラメーターを含めることでワークフローを最適化しました。手順は次のようになります。

  1. 私のDockerfileが、私がそれをどのように見せたいかを確認してください。
  2. docker-composeファイルでイメージ名のバージョン番号を設定します。
  3. イメージがまだビルドされていない場合:実行 docker-compose build
  4. 走る docker-compose up -d

当時は気づきませんでしたが、docker-composeは、最初にコンテナーをダウンさせる必要がなく、コマンドを1つ実行するだけでコンテナーを新しいイメージに更新するだけの十分な機能を備えています。


実際の状況では、自分の手を使ってそれらの変更を行うことはできません。ソリューションは、問題を解決する自動方法をサポートしていません。
CarlosVázquezLosada 2017年

7
私のソリューションは自動化されていないため、有効ではないということですか?それはOPからの要件ですか?そして、他の答えは自動化を意味していますか?本当に混乱しています。そして、私は反対投票がここに来る他の人々に害を及ぼしていると思います。質問は100%有効です。
gdbj 2017年

この回答に感謝しますdocker-compose up -d。最初にすべてを停止する必要なしに、単純に実行できることも知りませんでした。
radicand

4

Docker Composeを使用したくない場合は、portainerをお勧めします。最新のイメージを取得しながらコンテナを再作成できる再作成機能があります。


2

すべてのイメージを再構築してすべてのコンテナーを再起動するか、どういうわけかソフトウェアを更新してデータベースを再起動する必要があります。アップグレードパスはありませんが、自分で設計する必要があります。


コンテナを再起動するとはどういう意味ですか?docker restartコマンドはありますが、画像の変更が反映されるかどうかはわかりません。コンテナ内のデータはどうなりますか?
Yaroslav Stavnichiy 2014年

1
申し訳ありませんが、Dockerを再起動するつもりはありませんでした。docker rm -f CONTANER; docker run NEW_IMAGE。SQLコンテナー内のデータが消えます。そのため、一般的にボリュームを使用してデータを保存します。
seanmcl 2014年

すべてのデータを別々のコンテナーまたはホストマシンのボリュームにマウントしている場合、nas @seanmclは、同じデータに接続された新しいmysqlで新しいコンテナーを作成するだけだと言っています。そうしなかった場合は(必要があります)、Docker 1.3で利用可能なdocker execコマンドを使用してmysqlを更新し、コンテナー内で再起動できます。
Usman Ismail

2

http://blog.stefanxo.com/2014/08/update-all-docker-images-at-once/から取得

次のコマンドパイプラインを使用して、既存のすべてのイメージを更新できます。

docker images | awk '/^REPOSITORY|\<none\>/ {next} {print $1}' | xargs -n 1 docker pull

6
これにより画像は更新されますが、コンテナは更新されません。コンテナは不変であり、更新されたイメージから新しいコンテナを作成しない限り、そのベースイメージは変更できません。
エリックB.

2

コンテナー内にあるプロセスの状態に関連するコンテナーに格納するすべての永続データ(構成、ログ、またはアプリケーションデータ)にボリュームを使用していることを確認してください。Dockerfileを更新し、必要な変更を加えてイメージを再構築し、適切な場所にボリュームをマウントしてコンテナーを再起動します。


1

これは私自身のイメージのためにも苦労してきました。Dockerイメージを作成するサーバー環境があります。サーバーを更新するとき、Dockerイメージに基づいてコンテナーを実行しているすべてのユーザーが最新のサーバーにアップグレードできるようにしたいと考えています。

理想的には、新しいバージョンのDockerイメージを生成し、そのイメージの以前のバージョンに基づくすべてのコンテナーを自動的に新しいイメージに自動的に更新することをお勧めします。しかし、このメカニズムは存在しないようです。

したがって、これまでに思いついた次善の設計は、コンテナ自体を更新する方法を提供することです。これは、デスクトップアプリケーションが更新をチェックしてからそれ自体をアップグレードする方法と同様です。私の場合、これはおそらく、よく知られているタグからのGitプルを含むスクリプトを作成することを意味します。

画像/コンテナは実際には変更されませんが、そのコンテナの「内部」が変更されます。apt-get、yum、または環境に適したものを使用して同じことを想像できます。これに加えて、レジストリのmyserver:latestイメージを更新して、新しいコンテナが最新のイメージに基づくようにします。

このシナリオに対処する先行技術があるかどうかを聞いてみたいと思います。


7
これは、不変インフラストラクチャの概念とその利点の一部に反します。アプリケーション/環境をテストして、動作することを確認できます。内部のコンポーネントを更新しても保証されません。構成からのデータからコンテナーコードを分割すると、更新してテストし、現在動作していることをテストして本番環境にデプロイできます。テストしたイメージと本番のイメージに異なるコード行はないことがわかります。とにかく、あなたが言うように、システムはあなたにそれを管理させ、あなたの選択です。
gmuslera 2014年

非常に良い点gmuslera。既存のDockerコンテナーの「内部」を更新することはアンチパターンであることに同意しました。
bjlevine 2014年

では、Dockerイメージの更新に基づいてDockerコンテナーを自動更新して、すべてのコンテナーに簡単に更新を配信するための最良のソリューションは何ですか?
tarek salem

1

更新

これは主に、イメージの構築が実行される方法であるため、更新しないようにコンテナをクエリすることです

同じ問題が発生したため、Docker-runを作成しました。これは、Dockerコンテナー内で実行して、実行中の他のコンテナーのパッケージを更新する非常にシンプルなコマンドラインツールです。

これは、使用していますドッカ-PYをドッキングウィンドウコンテナおよびアップデートパッケージを実行していると通信したり、任意の単一のコマンドを実行します

例:

docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run exec

デフォルトでは、実行date中のすべてのコンテナでコマンドが実行され、結果が返されますが、次のようなコマンドを発行できます。docker-run exec "uname -a"

パッケージを更新するには(現在はapt-getのみを使用):

docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run update

エイリアスを作成して、通常のコマンドラインとして使用できます。

alias docker-run='docker run --rm -v /var/run/docker.sock:/tmp/docker.sock itech/docker-run'


これは良い考えですか?(apt update; apt upgrade
そうすると

@yaroslavのイメージは、この問題のより良い解決策です。上記は実際にDockerで行う方法ではありません。
Joost van der Laan 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.