「Dockerが何かは知っている・動かしてみたことはある」ぐらいの方以上を想定して
-
Dockerfileでimageを自作 -
docker-composeで複数コンテナを立ち上げ - サイドカーパターン
をつまみ食いしながらまとめていきます。

__サイドカーパターンの図__をこちらのブログより転載させていただきました。
冒頭記載の対象読者層を超えてしまいますが、良い論文紹介記事です!
データを他のコンテナが共用で使っている様子が、まるでサイドカーみたいですね(棒)
今回はこの共用データを持つ役割もコンテナに担当してもらいます(データコンテナ)。
いきなり余談(?)
この記事を書くに至った経緯ですので飛ばしてもらっても構いません。
Composeファイルのフォーマットには2020年1月現在1.0、2.x、3.xと複数のバージョンがあります。
docker-compose.yamlファイルの最初に
version: '3'
みたいに指定します。
インターンでデータコンテナを含む設計を触ることになったのでDockerの勉強から始め、docker-composeを3.x系で何の疑いもなく作ろうとしました。
しかし他のコンテナ名を指定して特定のボリュームを参照できるvolumes_fromが、3.xでは無くなっていました。
ここで悩んだ挙句に代替案が分からなかったので、一旦のまとめとしてこの記事を書いています。
2つ以上のコンテナでデータを共用したい場合
- データ用のコンテナを1つ作り、特定のディレクトリを他のコンテナからも覗けるようにする
- ホスト側にデータを保存しみんなで参照する永続化ボリュームを確保する
のいずれかの構成にすることが多いかと思います。
業務ではKubernetesでサイドカーパターンのPodをスケーリングさせる予定だったので、2つめの永続化ボリュームを使う設計では新しいボリュームがどんどこ作られてつらい事態に陥りそうと考え1つめのデザインパターンを試しました。
なおKubernetesでは各Podに専用の空ディレクトリを作成すればよさそうなので、結局はDockerのおべんきょうができただけでした。
apiVersion: v1
kind: Pod
metadata:
name: test-pod-1
spec:
containers:
- image: centos:latest
name: test1
volumeMounts:
- mountPath: /test
name: test-volume
command: ["tail", "-f", "/dev/null"]
- image: centos:latest
name: test2
volumeMounts:
- mountPath: /test
name: test-volume
command: ["tail", "-f", "/dev/null"]
volumes:
- name: sample-volume
emptyDir: {}
ハンズオン!
それでは
-
centosコンテナ -
Dockerfileでつくってみるオリジナルcentos-volumeコンテナ -
docker-composeでまとめて立ち上げ - 確認・お片づけ
の順でさくさくと試していきましょう。
DockerfileでオリジナルのDocker imageを作る
ざっっっくり言うと、Dockerコンテナを作る型抜きの原型がDocker imageです。
Docker Hubに公開されているものだけでなく、元となるファイル(名前をDockerfileにしておく)を自分で記述し新しいimageを作ることもできます。
今回は共有したいデータを持つ方のデータコンテナを自作で定義してみます。
FROM centos
WORKDIR /mount-test
RUN echo "volume mount test" > mount_test.txt
なんとなくこういうルールなのかな、みたいなのは察していただけるかと思いますが
FROM:CentOSのimageであるcentosを元にして
WORKDIR:作業ディレクトリを移って
RUN:指定したコマンドを実行
のように順番に操作を書くのがDockerfileです。
既存のimageをベースに敷き、各コマンドの層を積み重ねていく感じで作られていきます。
今回はデータコンテナとしての役割を確かめるため、/mount-testディレクトリとその中にmount_test.txtファイルを作成しています。
このFROMやRUNなどの命令は全部で20種類くらいあります。詳しくは公式のドキュメントなどをまた適宜ご覧ください。
こうして書いたDockerfileをbuildすることで、Docker imageとして使えるようになります。
$ docker build ./ -t centos-volume
ここで./はDockerfileが今のディレクトリ階層にあり、-tはbuildするimageに名前をつけることをそれぞれ指示しています。
以下のように表示されていれば成功です。
Sending build context to Docker daemon 42.5kB
Step 1/3 : FROM centos
---> <適当なハッシュ値1>
Step 2/3 : WORKDIR /mount-test
---> Running in <適当なハッシュ値2>
Removing intermediate container <適当なハッシュ値2>
---> <適当なハッシュ値3>
Step 3/3 : RUN echo "volume mount test" > mount_test.txt
---> Running in <適当なハッシュ値4>
Removing intermediate container <適当なハッシュ値4>
---> <適当なハッシュ値5>
Successfully built <適当なハッシュ値5>
Successfully tagged centos-volume:latest
これが最新バージョンだよ、と最後にはlatestタグまでつけてimage化してくれていますね。
タグとは例えば
$ docker pull centos:centos7
のように、Docker imageをバージョンなどの情報つきで指定する時に併記するために使います。
数字は中のミドルウェア・ソフトウェアのバージョンに対応してることが多いと思います。
ここでタグを指定しない時には、latestタグがついたimageを表します。
latestタグはそのimageを使いたい人みんなにとっていい感じの塩梅になるようなバージョンを選んでつけてくれている(?)とは思いますが、特定のバージョンを指定する必要がある場合も多いかと思います。
また今回は行いませんが、buildしたオリジナルのimageは$ docker pushを行うことでDocker Hubに登録することでオープンに共有ができます。
逆に自分だけが使えるようにしておきたい、あるいは業務などで特定の人にだけ限定公開したい場合は
- Docker Hubにプライベートリポジトリを作成(2つ目以降は有料プラン)
- クラウドのマネージドサービス(AWSならECR、GCPならGCRなど)を利用
のどちらかを選びます。
そして上記のbuildプロセスを見てお気づきかもしれませんが、Dockerfileから「コマンドを一行ずつ実行してはimage化」を繰り返して行われます。
そのため同じ命令がたくさんある場合には、中間生成されるimageが少なくて済むように\や&&で繋いでひとまとめの命令にしておきましょう。
以下の例のようにRUN命令などが特に当てはまります。
RUN apt-get update && apt-get install -y \
bzr \
cvs \
git \
mercurial \
subversion
参考・参照
Dockerfileを書くベストプラクティス
Docker Composeで複数コンテナをまとめて立ち上げる
Docker Composeは複数のコンテナをまとめて扱いたい時に便利です。
ファイル名をdocker-compose.yamlとしてComposeファイルのバージョンと各コンテナの定義を書いていきます。
version: '2'
services:
data-container:
image: centos-volume
container_name: data-container
tty: true
volumes:
- /mount-test
centos1:
image: centos
container_name: centos1
tty: true
volumes_from:
- data-container:ro
なんとなくimageやcontainer_nameは分かりやすいかと思います。
versionはDockerではなくComposeファイルのバージョンです。
またtty: trueでポート待ち受けなど特に何もしないコンテナも立ち上げ後に起動させ続けることができます。
これが無いとコンテナがすぐに終了してしまいます。
そしてvolumes_fromではマウント元となるボリュームを読み取り専用でマウントするため、後ろに:ro(read only)とつけています。
マウント元のコンテナ名だけを書くか:rwと付けると読み書きできる権限が付与されます。
なおこのComposeファイルで指定できる項目はめちゃくちゃたくさんあるので、またドキュメントなどを適宜参照してください。
参考
Composeファイル バージョン2リファレンス
Composeファイル バージョン3リファレンス
あとはdocker-compose.yamlがあるディレクトリで
$ docker-compose up -d
とすれば、docker-compose.yamlと名前がつけられたファイルを探して読み込んでコンテナを立ち上げてくれます。
-dはバックグラウンド実行を指定しています。
Creating data-container ... done
Creating centos1 ... done
と表示されていればコンテナ作成は成功。
$ docker ps
で2つとも表示されていればちゃんと動いています。
続いて各コンテナが定義通り作られているかを確認してみましょう。
まずはデータコンテナの方に入り、Dockerfile内で作ったはずのmount_test.txtがあるかを見てみます。
$ docker exec -it data-container bash
[root@<皆さんのコンテナID> mount-test]# cat mount_test.txt
volume mount test
ファイルはちゃんと作成されており、作業(カレント)ディレクトリがDockerfileの通り/mount-testになっていますね。
またこのディレクトリではvimなどでmount_test.txtを編集したり、新しいファイルを作ったりといった読み書き作業もできるかと思います。
次にexitコマンドでデータコンテナから抜け、データを覗く側のコンテナに入ります。
$ docker exec -it centos1 bash
[root@<皆さんのコンテナID> /]# cat mount-test/mount_test.txt
volume mount test
データコンテナ(data-container)のディレクトリとその中身がちゃんと見えていますね。
今回はdocker-compose.yamlにてread onlyを指定しているので、マウントされたこの/mount-testディレクトリの中では既存ファイルの編集や新規ファイルの作成をしようとするとちゃんと怒られます。
最後に立ち上げたコンテナたちを停止、削除しましょう。
片付けるまでがハンズオンです。
$ docker-compose stop
でdocker-compose upしたコンテナ群をまとめて停止、
$ docker-compose rm
で削除できます。便利...。
さいごに
まだDocker始めて2週間ぐらいしか触ってないので、修正・追記すべき箇所などあるかと思います。
Compose3.x系ではこうすればいいよなどのアドバイスも含めありましたらよろしくお願いします^^