LoginSignup
102
88

More than 3 years have passed since last update.

Dockerのまとめ - コンテナとボリューム編

Last updated at Posted at 2018-09-09

この記事で伝えたいこと

  • Docker for Mac が使う Dockerの実行環境 moby vm と LinuxKit
  • Docker は Mac 上ではなく hyperkitという 仮想マシン上で動いている(Docker for Mac の場合)
    • Linux で Dockerを使うときは同じカーネルを使うのでMac環境とかなり異なる
  • volume は仮想マシン上の /var/lib/docker/volumes 配下においている

前回のおさらい

前回はコンテナとイメージ周りのデータ構造を見てきました。イメージは複数の読み取り専用のレイヤで構成され、コンテナはイメージのレイヤをベースに起動し、レイヤとしてcommitするまで永続化されないことを見てきました。では、MySQLのデータのような、コンテナを破棄しても残しておきたいデータはどうしておくとよいでしょうか?

今回は永続化したいデータを保持するためのボリュームと、コンテナが動作している moby vm について見ていきます。

この記事で解説する docker の概念

  • コンテナ
  • ボリューム
  • moby vm と Linuxkit

ボリュームの作り方

ボリュームは、例えて言うなら拡張データ領域です。早速作成してみましょう。

$ docker volume create test_volume
test_volume
 $ docker volume ls
DRIVER              VOLUME NAME
local               test_volume

volumeのサブコマンドはこんな感じ

docker command 意味
docker volume create [volume] 指定した volume を作成
docker volume inspect [volume] 指定した volume の設定を見る
docker volume ls 存在する volume を一覧する
docker volume prune 使われていない volume を削除する
docker volume rm [volume] 指定した volume を削除する

コンテナからボリュームをマウントして起動する

では、コンテナからマウントして起動してみましょう。

$ docker container run --rm --name test -v test_volume:/home -it alpine:latest sh

ここで指定しているオプションも簡単に解説します。

オプション 意味
--rm 終了時にコンテナを破棄する
--name [NAME] コンテナに指定した名前をつける。未指定の場合は適当な名がつく。
-v [volume名]:[path] pathに volume を割り当てる
-i 対話シェルを開く
-t 仮想ttyを割り当てる
sh コンテナで起動するコマンド

containerサブコマンド、imageサブコマンドは別途補足でよく使うものを解説します。

ボリュームにファイルを保存し、永続化できていることを見てみる

先程起動したコンテナの中でファイルを保存し、再度起動して永続化できているのを確認しましょう。

/ # cd /home
/home # ls
/home # echo 'Hello volume' > test.txt
/home # ls
test.txt
/home # echo 'Not save on /root' > /root/not_saved.txt
/home # exit
$ docker container run --rm --name test -v test_volume:/home -it alpine:latest sh
/ # ls /root
/ # ls /home
test.txt

/root に保存したファイルは消えてますが、 /home に保存したファイルが残っています。

ボリュームがどこに保存されているか見ていこう

では、この test_volume はどこにあるでしょう? inspect サブコマンドを使って見ていきます。

$ docker volume inspect test_volume
[
    {
        "CreatedAt": "2018-07-01T15:21:33Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/test_volume/_data",
        "Name": "test_volume",
        "Options": {},
        "Scope": "local"
    }
]

なるほど、 /var/lib/docker/volumes/test_volume/_data ですか。と思っておもむろに ls してみましょう。

$ ls /var/lib/docker/volumes/test_volume/_data
ls: /var/lib/docker/volumes/test_volume/_data: No such file or directory

見つかりません。なぜなら docker は VM で動いているからです。

screen を使ってmoby vmの仮想ターミナルを開く

下記コマンドを叩いてみましょう。

$ screen ~/Library/Containers/com.docker.docker/Data/vms/0/
linuxkit-025000000001:~#

というような文字列が表示されたはずです。おもむろに ctrlを押したままD を叩いてみましょう。

Welcome to LinuxKit

                        ##         .
                  ## ## ##        ==
               ## ## ## ## ##    ===
           /"""""""""""""""""___/ ===
          {                       /  ===-
           ______ O           __/
                          __/
              ___________/

linuxkit-025000000001 login: root (automatic login)

Welcome to LinuxKit!

NOTE: This system is namespaced.
The namespace you are currently in may not be the root.
login[2738]: root login on 'ttyS0'
linuxkit-025000000001:~#

ハロー、クジラさん。ということで LinuxKitが動くVMの中に入れました。先に終了方法を書いておくと ctrlを押したままA のあとに ctrlを押したままK のあとに yes を押してください。

先程のvolumeを確認する

試しに先程のパスを見てみましょう。

# ls /var/lib/docker/volumes/test_volume/_data
test.txt
linuxkit-025000000001:~# cat /var/lib/docker/volumes/test_volume/_data/test.txt
Hello volume

先程書き込んだファイルが見えたはずです。このまま別のセッションを開き、コンテナを起動して test_volume の内容を書き換えると、 moby vm の中のボリュームも更新されます。このように、 volume はコンテナと別の領域にファイルが保存されるため、コンテナの破棄に影響されません。

コンテナの方はどうなってるの?

では container の方はどうなっているんでしょうか? inspect サブコマンドで確認しましょう。

$ docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
470a088200f6        alpine:latest       "sh"                4 seconds ago       Up 2 seconds                            test
$ docker container inspect test
[
    {
        "Id": "470a088200f693a8b60efe74b59431f99d30cadb9df2b4ebd0d151d24ccd12fe",
        "Created": "2018-07-01T15:59:08.60750946Z",
        "Path": "sh",
        "Args": [],
        ...
        "GraphDriver": {
            "Data": {
                ...
                "MergedDir": "/var/lib/docker/overlay2/13808d33031c2e5b79ca99c346b4a5d0e1c84c2bc82c25a26572b6cdfd7f313e/merged",
                ...
            },
            "Name": "overlay2"
        },
        "Mounts": [
            {
                "Type": "volume",
                "Name": "test_volume",
                "Source": "/var/lib/docker/volumes/test_volume/_data",
                "Destination": "/home",
                "Driver": "local",
                "Mode": "z",
                "RW": true,
                "Propagation": ""
            }
        ],    }
]

細かいことはおいておいて、JSONが返ってきて、先程マウントしたボリュームについての情報も表示されているはずです。

コンテナ側の設定を見てみる

コンテナ側の設定を見てみるのも面白いです。試しに GraphDriver/Data/MergedDir にあるパスをmoby vm上で覗いてみましょう。

linuxkit-025000000001:~# ls /var/lib/docker/overlay2/13808d33031c2e5b79ca99c346b
4a5d0e1c84c2bc82c25a26572b6cdfd7f313e/merged
bin    etc    lib    mnt    root   sbin   sys    usr
dev    home   media  proc   run    srv    tmp    var

起動している test コンテナのルートディレクトリが見えます。試しに root ディレクトリの中を見てみましょう。

linuxkit-025000000001:~# ls /var/lib/docker/overlay2/13808d33031c2e5b79ca99c346b
4a5d0e1c84c2bc82c25a26572b6cdfd7f313e/merged/root
not_saved.txt

最初に起動したコンテナを終了していなければ、追加した not_saved.txt ファイルがあるはずです。

結局のところコンテナとは何なのか?

Linuxには chroot というコマンドがあります。このコマンドは実行したプロセス、及びその子プロセスのルートディレクトリを変える、というものです。 docker は chroot や カーネルの機能である namespace 、 cgroup なんかを使って環境を独立させたものがコンテナです。
ちなみに Windows Server にも類似の機能があり、 Windows 用のコンテナもあります。

(補足) ローカルのファイルシステムをマウントする bind マウント

(Docker for Windows を使ったことがないので Docker for Mac に限った話かもしれません。)

docker volume のマウント方式にはローカルのファイルシステムをマウントする bind マウントという方式があります。この方式は確かにローカルのファイルシステムをマウントできますが、LinuxKitからMacのファイルを参照できるよう、LinuxKitへ転送しています。このプロセス com.docker.osxfs がMac上のプロセスとしてメモリ食いであり、重いです。

bind マウントが遅いため、それを回避する docker-syncというツールもあります。しかし、このツールは、直接 docker container がbindしているvolumeを参照しないことでコンテナ自体を高速化するためのもので、Mac->LinuxKitへの転送自体が早くなるものではありません。

まとめ

ボリュームとコンテナについての機能解説と、moby vm と LinuxKit の中身まで見てきました。docker が Linux の機能を積み重ねて出来ているところもざっくり見ました。

Mac上でdockerコマンドを叩くと moby vm に通信するあたりとかも面白かったりするんですが、それは別の機会で。

よく使う conteiner のサブコマンド

docker command 意味
docker container run [image] 指定した イメージ を元に起動
docker container ls (-a) 存在する コンテナ を一覧する。-a を着けると停止した コンテナ も表示する
docker container stop [container_ID] 指定した コンテナ を停止する
docker container prune 使われていない コンテナ を削除する
docker container commit [container] 指定したコンテナからイメージを作成する

よく使う image のサブコマンド

docker command 意味
docker image build PATH 指定した Dockerfile を使ってイメージを作成する
docker image ls 存在するイメージを一覧する
docker image history [image_ID] 指定したイメージの作成履歴を表示する
docker image prune 使われていないイメージを削除する
docker image rm [image_ID] 使われていないイメージを削除する
docker image commit [container] 指定したコンテナからイメージを作成する
docker image pull [image_ID] 指定したイメージを取得する
docker image push [image_ID] 指定したイメージをpushする
docker image tag [image_ID] [target] 指定したイメージにタグをつける

参考文献

102
88
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
102
88