なんとなくのDockerを卒業するために

こんにちは。データ戦略室の小宮です。

みなさん、突然ですが「Docker」使ってますか? 私はここ1年くらいで触り始めた若輩者で日々勉強中です。

先日開催された「なんとなくを卒業するためのDocker入門」に参加してきたのですが、 今まで理解したつもりでいた基本的なことを改めて学んできました。

studyco.connpass.com

ただそこで疑問に思ったことがありました。 Dockerは必ずLinux上で動く。という話。

Linux上で必ず動く...

なぜ私のPCはMacなのに動いている??

というとてもピュアな疑問が湧いてしまったので、調べてみました。

結論:HyperKitという仮想マシン上でLinuxが動いている

Docker for Macをインストールした際に、Dockerを動かすための仮想のLinux環境が同時に構築されるみたいです。 なるほど。だがもうちょっと調べてみたい。

Dockerの実態

DockerHubからイメージをpullする場合の図です。

※あくまでイメージ図であり、厳密なものではありません。

f:id:so-technologies:20220310181223p:plain

こんな感じになっているとのこと。ふむふむ。該当イメージを起動すると同じようなディレクトリ構成のコンテナが出来上がると。 この図を見ると、必ずLinux上で動いていることや、Host OSのカーネルを共有していること。Guest OSが必要なく軽量なことなどが分かりやすいですね。

というわけで更に理解を深めるべく、実際にこのLinuxの中に入ってみてDockerの実態を解き明かしてみようと思います。

Linux(Hyperkit VM)に入ってみる

HyperKitとやらに入ってみます。 いくつかやり方があるみたいですが、今回は特権コンテナを使う方法を試してみます。

こちらを参考にしました。 uzimihsr.github.io

% docker run -it --rm --privileged --pid=host justincormack/nsenter1
/ # hostname
docker-desktop
/ # uname -a
Linux docker-desktop 5.10.47-linuxkit #1 SMP Sat Jul 3 21:51:47 UTC 2021 x86_64 Linux

どうやら入れたっぽいですね。

lsコマンドで中を確認してみます。

/ # ls
bin          containers   etc          home         lib          mnt          proc         run          srv          tmp          var
boot         dev          grpcfuse.ko  init         media        opt          root         sbin         sys          usr

Linuxを触ったことがあれば、この辺は困らなさそうですね。

実際にdockerのイメージやコンテナがありそうな場所探してみます。

/ # cd /var/lib/docker/
buildkit/    image/       overlay2/    runtimes/    tmp/         volumes/
containers/  network/     plugins/     swarm/       trust/

見つけました。 ここにDockerに関する情報がありそうです。

実際にイメージを見てみます。

/var/lib/docker/image/overlay2/imagedb/content/sha256 # ls
2b011a947b19f22001624bce3d2fdb3cb6dccb8de2f8efb623db0f52da32cbe9  c81481184b1b001f225769d1482b360b4be18fe7dd53fa93cdbd45d568e905a7
44bae28e3bfe6de59a7fb7cb996d1eb906c8a333a86b4cb8fd658583cb738274  d2689e7d3df97b10e8cb34fedc6b9430ba1a761a119b3c151e56f60e12572765
4666c4437e7a05434b7ee4648fea099ed8488efe84a44c5f27adc5fffa479cdf  f659c7f011403edffbdc4e1d549280ea42b3d19ad2cedc060c2fa904102ab27b
6d2c35ea975326b83955434e7c69c3bef758b40b9bb0f22c13cf82b90b109ae2  f78b71bc463d7242a85f99c2a2b42b42167688e3fb02a204474051175b9ad3de
a971aeeb4d8fe07d75ab73b6e9ca22a4e098ffeaa3178fd7705ea753f85a4831

ハッシュ化されていますが、 私がローカルで作成したイメージが並んでいます。

中身を見てみると、 EntrypointやWorkingDirなどの情報がありますね。 その他履歴やレイヤ情報などもこちらのイメージファイルの中にありました。

{
    "architecture": "amd64",
    "config": {
        "Env": [
            "PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
            "LANG=C.UTF-8",
            "PYTHON_VERSION=3.9.10",
            "PYTHON_PIP_VERSION=21.2.4",
            "PYTHON_SETUPTOOLS_VERSION=58.1.0",
            "PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/2caf84b14febcda8077e59e9b8a6ef9a680aa392/public/get-pip.py",
            "PYTHON_GET_PIP_SHA256=7c5239cea323cadae36083079a5ee6b2b3d56f25762a0c060d2867b89e5e06c5"
        ],
        "Entrypoint": [
            "python3",
            "/home/test/app.py"
        ],
        "WorkingDir": "/home/test",
        "OnBuild": null
    },
〜省略〜

コンテナのログも確認できました。

/var/lib/docker/containers # cat 2ac90ecd1eec0573ee660f0d910d0d7655498b1a7af23963020f003094fe443e/2ac90ecd1eec0573ee660f0d910d0d7655498b1a
7af23963020f003094fe443e-json.log

{"log":"/ # \u001b[6n\r/ # \u001b[Jhostname\r\n","stream":"stdout","time":"2022-02-25T03:32:12.6508739Z"}
{"log":"docker-desktop\r\n","stream":"stdout","time":"2022-02-25T03:32:12.6517307Z"}
{"log":"/ # \u001b[6nuname -a\r\n","stream":"stdout","time":"2022-02-25T03:32:39.2869949Z"}
{"log":"Linux docker-desktop 5.10.47-linuxkit #1 SMP Sat Jul 3 21:51:47 UTC 2021 x86_64 Linux\r\n","stream":"stdout","time":"2022-02-25T03:32:39.2875769Z"}
{"log":"/ # \u001b[6nls\r\n","stream":"stdout","time":"2022-02-25T03:34:34.0292413Z"}
{"log":"\u001b[1;34mbin\u001b[m          \u001b[1;34mcontainers\u001b[m   \u001b[1;34metc\u001b[m          \u001b[1;34mhome\u001b[m         \u001b[1;34mlib\u001b[m          \u001b[1;34mmnt\u001b[m          \u001b[1;34mproc\u001b[m         \u001b[1;34mrun\u001b[m          \u001b[1;34msrv\u001b[m          \u001b[1;34mtmp\u001b[m          \u001b[1;34mvar\u001b[m\r\n","stream":"stdout","time":"2022-02-25T03:34:34.0300374Z"}
{"log":"\u001b[1;34mboot\u001b[m         \u001b[1;34mdev\u001b[m          \u001b[0;0mgrpcfuse.ko\u001b[m  \u001b[1;32minit\u001b[m         \u001b[1;34mmedia\u001b[m        \u001b[1;34mopt\u001b[m          \u001b[1;34mroot\u001b[m         \u001b[1;34msbin\u001b[m         \u001b[1;34msys\u001b[m          \u001b[1;34musr\u001b[m\r\n","stream":"stdout","time":"2022-02-25T03:34:34.0300743Z"}
{"log":"/ # \u001b[6n\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # \u001b[J\r/ # ls\u001b[J\r/ # uname -a\u001b[J\r/ # hostname\u001b[J\u0007\u0007\u0007\u0007\u0007\u0007\r/ # uname -a\u001b[J\r/ # ls\u001b[J\r/ # \u001b[J\u0007\u0007cd /v\r/ # cd /var/\u001b[J\u0007\r\n","stream":"stdout","time":"2022-02-25T03:35:36.7396036Z"}
{"log":"cache/   empty/   lib/     local/   lock/    log/     opt/     run/     spool/   tmp/     vpnkit/\r\n","stream":"stdout","time":"2022-02-25T03:35:36.7397056Z"}
{"log":"\r/ # cd /var/\u001b[J\r\n","stream":"stdout","time":"2022-02-25T03:35:36.9162215Z"}
{"log":"cache/   empty/   lib/     local/   lock/    log/     opt/     run/     spool/   tmp/     vpnkit/\r\n","stream":"stdout","time":"2022-02-25T03:35:36.9162668Z"}
{"log":"\r/ # cd /var/\u001b[Jli\r/ # cd /var/lib/\u001b[J\u0007\r\n","stream":"stdout","time":"2022-02-25T03:35:43.1135367Z"}

おわりに

いかがでしたでしょうか。

ご存知の方からすると当たり前な話かもしれませんが、改めて学んでみると知らないことがたくさんありました。実際は特にここまで知っていなくても使えてしまいますが、内部を知ることで何か問題が起きた時に特定しやすくなるのかなと思います。座学だけじゃなくて、実際に触ってみるとより理解が深まりますね。

それではまたいつか。