こんにちは、ロジカル・アーツの福島です。先日、ある環境上に動いているDockerコンテナを調査し、移行のためローカルで同じコンテナを動かし動作確認をするという業務を行いました。その際の大まかな流れを紹介しようと思います。また動作していたDockerコンテナのイメージのタグがlatestとなっており、ミスや事故が起こりやすい状況でしたのでその点についても注目しようと思います。
Dockerについて
Linux上でOSから上の領域の仮想化を行い動作させるための技術です。Dockerの特徴として、仮想化を行っているため環境差異によっての不具合が起きにくいことが挙げられます。またOSの領域の仮想化を行っていないため、従来の仮想化技術(VM Ware等)と比較し軽量である点もメリットとして挙げられます。Docker上で動く仮想化された部分をコンテナと呼びます。Dockerのコンテナを起動する際は、起動するコンテナの情報が保存されているイメージを使用します。
公式のドキュメント(日本語化したもの)では、より詳細な概念・特徴の説明がされていますので詳しくはそちらをご覧ください。
イメージの取得・タグについて
Dockerイメージはdocker pull リポジトリ名:タグ名
で取得します。取得は通常、DockerHub(イメージを保存できる標準レジストリ)から行われます、その際にタグを指定しなければlatestタグになります。イメージをプッシュする際に、独自のタグを付けて上述のDockerHubに保存しておけば、異なるバージョンを混同することなく管理することができます。
latestタグを使用する問題点
移行前の環境で動いているDockerコンテナがあり、Dockerコンテナのイメージのタグが(おそらく何も指定しなかったため)latestとなっていました。10か月ほど前に登録されたイメージを使用していました。※例としてApache(httpd)のイメージを使用しています。
fukushima:~/environment $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE httpd latest ccbcea8a6757 10 months ago 166MB
移行後の環境で同じイメージ名・同じlatestタグのイメージを取得してきた場合下記のようになります。
fukushima:~/environment $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE httpd latest 0b932df43057 2 weeks ago 138MB
移行後の環境では2週間前に登録されたイメージを使用しています。イメージ名タグ名は同じですが、移行前の10か月前に登録されたイメージと内容が異なっており、混同しやすくまた複数環境で動作させる場合は取得時期により中身が異なり不具合が生じる可能性があります。
上記のような問題があるためイメージのVersionを固定し、latestタグを使用しない方が良いとされています。公式ホームページのベストプラクティスに下記のような記述があります。
イメージをビルドする場合には、常にわかりやすいタグをつけるようにします。 このタグを用いて、バージョン情報をコード化したり、目的とする用途(たとえば prod や test など)や安定性など、いろいろな情報を付与したりします。 こうしておけば、アプリケーションをさまざまな環境にデプロイする際にわかりやすくなります。 自動的に生成される latest タグには頼らないようにします。
今回の場合、前回のイメージを取得した際に管理しているDockerHubのアカウントに適切なタグを付与しイメージをプッシュしている状態にしておけば、同一のイメージを取得することが容易であったと思います。
今回の対処法
元々のイメージと同じものを取得するためdigest値を使用しました。digest値の特徴として、イメージごとに中身が異なれば異なるdigest値になることが保証されます。またdigest値を用いてイメージを取得することも可能です。digest値を指定することによって、移行前のイメージと同じイメージであることを保証できます。
また起動しているコンテナは、データ・ボリュームとしてホスト上のディレクトリをマウントする設定が行われていました。そのためDockerコンテナがマウントしているボリュームも併せて移行しました。マウントされているボリュームはdocker inspect
コマンドで確認できます。
実際にDockerコンテナが起動している状態で下記のコマンドを実行します。 ※例としてpostgresを起動させています。
fukushima:~/environment $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e343ea2bfccb postgres "docker-entrypoint.s…" 11 seconds ago Up 10 seconds 5432/tcp some-postgres
CONTAINER ID
に該当する値(上記の場合e343ea2bfccb
)を用いて下記コマンドを実行します。
fukushima:~/environment $ docker inspect e343ea2bfccb [ { "Id": "e343ea2bfccb42c1dfe04809aef7f4dadef9534e6137bca2f43fa300ed160f66", ・ ・ ・ "Mounts": [ { "Type": "volume", "Name": "33e41193ef92ea2dbd8c9799bad2f3f32bb5d85bded126e314a1f3617d379a21", "Source": "/var/lib/docker/volumes/33e41193ef92ea2dbd8c9799bad2f3f32bb5d85bded126e314a1f3617d379a21/_data", "Destination": "/var/lib/postgresql/data", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ・ ・ ・
上記の"Source"の値がマウントされているボリュームのホストのPATH、"Destination"がマウントされているボリュームのコンテナのPATHです。ホストのPATHに指定されているディレクトリを新しい環境に移行します。
新たに移行先でイメージからコンテナを起動する際に、ボリュームのPATHを指定しなければ自動でマウント用のディレクトリが割り当てられるので、移行してきたボリュームをマウントするため-v
オプションでDockerコンテナを起動します。
※今回はpostgresのパスワードを指定するため環境変数を指定する-e POSTGRES_PASSWORD=mysecretpassword
も必要となっています。
fukushima:~/environment $ docker run -v /var/lib/docker/volumes/33e41193ef92ea2dbd8c9799bad2f3f32bb5d85bded126e314a1f3617d379a21/_data:/var/lib/postgresql/data -e POSTGRES_PASSWORD=mysecretpassword postgres
まとめ
今回はDockerコンテナについて、移行作業の流れとlatestタグを使用すべきでないことについての記事でした。Dockerに限らず何かの技術を使用する際に、ベストプラクティスに沿った形で安全に作業していけるよう学習していきたいです。