はじめに
1年くらい前にDockerに入門した初心者です。いくつか自分でDockerfileを書いてみて、ある程度知識が得られてきたので、ここらでちょっとまとめてみます。
数回に分けて公開するつもりです。
dockerの主な概念
- レイヤ
- イメージ
- コンテナ
今日はこのあたりの話をコマンドとともに解説します。
この記事を読むと
- docker image周りの構造がわかります。
- データ領域を別途ボリュームに指定する理由がわかります。
git と docker の類似性
docker には git と似たコマンドがあります。
- git commit / docker commit
- git tag / docker tag
- git pull / docker pull
- git push / docker push
- git log / docker history
これらはどれもレイヤを操作するコマンドです。
これらのレイヤを操作するコマンドの意味は・・
- commit : コンテナで操作中のレイヤをread-onlyなレイヤとしてimage化
- tag : 特定のレイヤにタグ(別名)をつける
- pull : 特定のイメージを手元に持ってくる
- push : 特定のタグをサーバーに送信する
- history : 特定のイメージのレイヤを操作コマンドとともに表示する
例: docker pull alpine:latest
docker pull は指定した image を手元に持ってくるコマンドです。
$ docker pull alpine:latest
latest: Pulling from library/alpine
ff3a5c916c92: Already exists
Digest: sha256:e1871801d30885a610511c867de0d6baca7ed4e6a2573d506bbec7fd3b03873f
Status: Downloaded newer image for alpine:latest
手元に alpine のイメージを持ってきました。
docker history alpine:latest
docker history は image の履歴(レイヤ)を見るコマンドです。
$ docker history alpine:latest
IMAGE CREATED CREATED BY SIZE COMMENT
3fd9065eaf02 5 months ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 5 months ago /bin/sh -c #(nop) ADD file:093f0723fa46f6cdb… 4.15MB
小さい小さいと言われる alpine ですが 4.15MB しかないですね。
CREATED BY 列を見るとどういうコマンドで作成されたかわかります。
レイヤを作成する - docker commit をやってみる(1)
alpineのコンテナを起動し、ファイルを書き込んでみます。
$ docker run --name kompiro_test -it alpine:latest
/ # mkdir -p /home/kompiro
/ # echo 'Hello Docker' > /home/kompiro/hello.txt
/ # exit
レイヤを作成する - docker commit をやってみる(2)
終了しているコンテナから今名前をつけて起動したコンテナを選び、コミットします。
$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0757c3c1e365 alpine:latest "/bin/sh" About a minute ago Exited (0) 39 seconds ago kompiro_test
2bf0c11c23b1 alpine:latest "--name kompiro_exam…" About a minute ago Created determined_sammet
$ docker commit kompiro_test kompiro/alpine:hello_world
sha256:80efa78a627ee1ff861bdba27445b18ff77f996aeec1e6477a581b74be5818f4
レイヤを作成する - docker commit をやってみる(3)
コミットしたイメージを使ってコンテナを起動してみます。
$ docker run -it kompiro/alpine:hello_world
/ # ls /home/kompiro
hello.txt
/ # cat /home/kompiro/hello.txt
Hello Docker
/ #
先程コミットしたイメージを元にコンテナが起動できています。
レイヤとコンテナとイメージ
- イメージは読み込み専用の複数のレイヤを重ねたもの
- コンテナは読み書き可能なレイヤを追加して起動したもの
docker の image は、複数のレイヤを重ねてできたものです。
git の commit もファイルツリーを重ねてできたものです。とても似ていますね。
レイヤの中身をのぞいてみる(1)
docker のレイヤの中身をのぞいてみましょう。docker save
コマンドを使うと指定したimageをtar形式で取得できます。
$ docker save kompiro/alpine:hello_world > hello_world.tar
$ tar -tvf hello_world.tar
drwxr-xr-x 0 0 0 0 6 25 01:04 22446ff33a4b67a4278adcb0d33b0972adb33c7cb209180e547a1cf60568783c/
-rw-r--r-- 0 0 0 3 6 25 01:04 22446ff33a4b67a4278adcb0d33b0972adb33c7cb209180e547a1cf60568783c/VERSION
-rw-r--r-- 0 0 0 1107 6 25 01:04 22446ff33a4b67a4278adcb0d33b0972adb33c7cb209180e547a1cf60568783c/json
-rw-r--r-- 0 0 0 4608 6 25 01:04 22446ff33a4b67a4278adcb0d33b0972adb33c7cb209180e547a1cf60568783c/layer.tar
drwxr-xr-x 0 0 0 0 6 25 01:04 498654318d0999ce36c7b90901ed8bd8cb63d86837cb101ea1ec9bb092f44e59/
-rw-r--r-- 0 0 0 3 6 25 01:04 498654318d0999ce36c7b90901ed8bd8cb63d86837cb101ea1ec9bb092f44e59/VERSION
-rw-r--r-- 0 0 0 401 6 25 01:04 498654318d0999ce36c7b90901ed8bd8cb63d86837cb101ea1ec9bb092f44e59/json
-rw-r--r-- 0 0 0 4403200 6 25 01:04 498654318d0999ce36c7b90901ed8bd8cb63d86837cb101ea1ec9bb092f44e59/layer.tar
-rw-r--r-- 0 0 0 1501 6 25 01:04 80efa78a627ee1ff861bdba27445b18ff77f996aeec1e6477a581b74be5818f4.json
-rw-r--r-- 0 0 0 292 1 1 1970 manifest.json
-rw-r--r-- 0 0 0 102 1 1 1970 repositories
いくつか layer.tar と呼ばれるファイルとバージョン情報のjsonが含まれているようですね。この 22446ff
等で始まるのが sha256 でハッシュ化されたレイヤです。
レイヤの中身をのぞいてみる(2)
では tar -xvf
で解凍して、見てみましょう。まず repositories から見てみます。
$ cat repositories
{"kompiro/alpine":{"hello_world":"22446ff33a4b67a4278adcb0d33b0972adb33c7cb209180e547a1cf60568783c"}}
レイヤの中身をのぞいてみる(3) - jsonファイルを開いてみる
repositories は image の最新のレイヤを指し示しているようです。jsonファイルはなんでしょうか?
$ cat 22446ff33a4b67a4278adcb0d33b0972adb33c7cb209180e547a1cf60568783c/json | jq
{
"id": "22446ff33a4b67a4278adcb0d33b0972adb33c7cb209180e547a1cf60568783c",
"parent": "498654318d0999ce36c7b90901ed8bd8cb63d86837cb101ea1ec9bb092f44e59",
"created": "2018-06-24T16:04:43.795799189Z",
...
"architecture": "amd64",
"os": "linux"
}
レイヤ情報を管理しているファイルのようです。
レイヤの中身をのぞいてみる(4) - layer.tarファイルを開いてみる
layer.tar はなんでしょうか。
$ tar -tvf 22446ff33a4b67a4278adcb0d33b0972adb33c7cb209180e547a1cf60568783c/layer.tar
drwxr-xr-x 0 0 0 0 6 25 01:03 home/
drwxr-xr-x 0 0 0 0 6 25 01:03 home/kompiro/
-rw-r--r-- 0 0 0 13 6 25 01:03 home/kompiro/hello.txt
drwx------ 0 0 0 0 6 25 01:03 root/
-rw------- 0 0 0 74 6 25 01:03 root/.ash_history
先程 commit したファイルレイヤで変更があったファイルがそのまま入っています。
docker commit コマンドで「レイヤを作成する」と書きました。docker は レイヤを tar に固めて保持しています。
docker はコンテナを立ち上げる際、イメージを元に起動します。
イメージに固められたtarを順番に解凍して指定されたプロセスを起動します。
もう一方の layer.tar ものぞいてみると面白いです。なぜ busybox と呼ばれるのかがよくわかります。
FYI: docker commit の --change オプション
docker commit のヘルプを見ていて面白いことに気が付きました。
--changeオプションは指定したイメージにDockerfileと同じコマンドで操作ができます。 サポートしているDockerfileのコマンド: CMD|ENTRYPOINT|ENV|EXPOSE|LABEL|ONBUILD|USER|VOLUME|WORKDIR
だそうです。 Dockerfile を直接こねこねしないでも良さそうですね。
docker push と docker tag
docker push
コマンドは指定したイメージをリポジトリにpushするコマンドです。何も指定しないと公式リポジトリであるdocker hubに push します。プライベートリポジトリに push するには、 docker tag
コマンドでURLを指定しなければなりません。
$ docker tag example.com/kompiro/alpine:latest
$ docker push example.com/kompiro/alpine:latest
みたいな感じです。
まとめ
docker はプロセスを確実に起動できるよう、余計なファイル変更を削ぎ落とすアーキテクチャになっています。必要であれば commit するようにして docker image として使えるようにしておきましょう。