dockerの公式チュートリアル兼Hands on labがあったので、やってみた。
※途中でlabのセッション切れたりで、実行ログに矛盾があるかもです。
URL
Play with Docker Classroom
Docker for IT Pros and System Administrators Stage 1
Your First Linux Containers
※利用にはDockerアカウント登録が必要な模様。
メールアドレスのみでサクッと作れます。
lab環境の確認
$ uname -a
Linux node1 4.4.0-169-generic #198-Ubuntu SMP Tue Nov 12 10:38:00 UTC 2019 x86_64 Linux
うぶんちゅでーす。
コンテナを起動してみる。
$ docker container run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:4fe721ccc2e8dc7362278a29dc660d833570ec2682f4e4194f4ee23e415e1064
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent
it to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
何が起きたか
Docker engineちゃんが下記の流れで動くご様子。
- "hello-world"というイメージを探す。
- ローカルに該当イメージがなかたので、デフォルトのDocker registryであるDocker Storeに
該当イメージを探しに行く。 - 見つけたら落としてきて、コンテナの中で該当イメージを起動する。
VMと何が違う?
VMはハードウェアの抽象化、コンテナはアプリケーションの抽象化。
VMの中でコンテナを動かすことが可能。
イメージ
以降のlabはAlpine Linuxコンテナを使用するらしい。理由は、めっちゃ軽いから。
$ docker image pull alpine
Using default tag: latest
latest: Pulling from library/alpine
e6b0cf9c0882: Pull complete
Digest: sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78
Status: Downloaded newer image for alpine:latest
docker.io/library/alpine:latest
早い…!
今回もデフォルトのDocker registryであるDocker Storeからpullしてきたが、
Docker registryは変更可能。ただし、このlabだとできないらしい。
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest cc0abc535e36 7 days ago 5.59MB
hello-world latest fce289e99eb9 12 months ago 1.84kB
先ほどpullしてきた"hello-world"と合わせ、2つのイメージが確認できる。
alpineコンテナをいじってみる
$ docker container run alpine ls -l
total 8
drwxr-xr-x 2 root root 4096 Dec 24 15:04 bin
drwxr-xr-x 5 root root 340 Jan 1 15:45 dev
drwxr-xr-x 1 root root 66 Jan 1 15:45 etc
drwxr-xr-x 2 root root 6 Dec 24 15:04 home
drwxr-xr-x 5 root root 185 Dec 24 15:04 lib
drwxr-xr-x 5 root root 44 Dec 24 15:04 media
drwxr-xr-x 2 root root 6 Dec 24 15:04 mnt
drwxr-xr-x 2 root root 6 Dec 24 15:04 opt
dr-xr-xr-x 532 root root 0 Jan 1 15:45 proc
drwx------ 2 root root 6 Dec 24 15:04 root
drwxr-xr-x 2 root root 6 Dec 24 15:04 run
drwxr-xr-x 2 root root 4096 Dec 24 15:04 sbin
drwxr-xr-x 2 root root 6 Dec 24 15:04 srv
dr-xr-xr-x 13 root root 0 Dec 4 04:54 sys
drwxrwxrwt 2 root root 6 Dec 24 15:04 tmp
drwxr-xr-x 7 root root 66 Dec 24 15:04 usr
drwxr-xr-x 12 root root 137 Dec 24 15:04 var
見慣れたlsコマンドの結果が返ってきたが、dockerを通すと裏では下記の流れで処理されている。
- Docker clientがalpineイメージを見つけて、コンテナを建てる。
- 建てたalpineコンテナ上で
ls -l
を実行する。 -
ls -l
が終了したら、コンテナをシャットダウンする。
コンテナに渡したコマンドが終了したらコンテナがシャットダウンするというのがミソ。
OSをVMとしてではなく、アプリケーションとして扱うからこその動作と思われる。
先ほどのls -l
と同じ流れで、alpineコンテナ上で‘echo‘を実行しつつ、time
で実行時間を計測してみる。
$ time docker container run alpine echo "hello from alpine"
hello from alpine
real 0m1.163s
user 0m0.036s
sys 0m0.012s
仮にVMで同じ操作(VM起動→コマンド実行→VM停止)をする場合を考えると、
比較にならないほど早い。これは、VMと違ってハードウェアのエミュレーションが
不要であるところが大きい。
今度は、alpineコンテナ上で/bin/sh
を実行してみる。
$ docker container run alpine /bin/sh
Docker client上でプロンプトが返るだけ。
意図したとおりに/bin/sh
が実行されたは良いが、そのままshellを閉じて返ってきてしまった。
shellを対話形式で実行したい場合は、下記のように記述する。
$ docker container run -it alpine /bin/sh
参考までにオプションのヘルプ抜粋。
$ docker run --help
オプション | 意味 |
---|---|
-i, --interactive | Keep STDIN open even if not attached |
-t, --tty | Allocate a pseudo-TTY |
コンテナ上の標準入力に擬似端末を割り当てる、的な意味だと思う。
alpineコンテナのshell上でreleaseを確認してみる。
# cat /etc/alpine-release
3.11.2
alpineであることが確認できる。
uname -a
を打つと…。
# uname -a
Linux dd6e08781c56 4.4.0-169-generic #198-Ubuntu SMP Tue Nov 12 10:38:00 UTC 2019 x86_64 Linux
うぶんちゅでーす。
コンテナはDocker hostのカーネルで動作する。こういった点も、コンテナが軽量である理由の1つ。
満足したのでalpineコンテナから抜けておく。
exit
Docker clientに戻ったところで、下記コマンドで実行中のコンテナを確認してみる。
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
表示なし。
今まで実行したコマンドは、コンテナ内でプログラムを実行して、プログラム終了後にコンテナを
シャットダウンしてしまうので、コンテナは残っていない。
-a
オプションを追記することで、コンテナの実行履歴が確認できる。
STATUS
の時間が短いのは、ターミナルのセッション切れてやり直したからです。
$ docker container ls -a
$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b552d69dbb21 alpine "/bin/sh" 6 minutes ago Exited (0) 6 minutes ago distracted_moser
f1bf62c070a3 alpine "/bin/sh" 6 minutes ago Exited (0) 6 minutes ago keen_solomon
a512e55a5320 alpine "echo 'hello from al…" 6 minutes ago Exited (0) 6 minutes ago quirky_payne
7a34aab5edca alpine "ls -l" 6 minutes ago Exited (0) 6 minutes ago goofy_booth
164107ad610a hello-world "/hello" 6 minutes ago Exited (0) 6 minutes ago magical_volhard
リソースの分離
docker container ls -a
で参照したコンテナは、全て分離されていた。
これは、各コンテナが異なる名前空間上で、ファイルシステムを実行しているから。
ここで言う名前空間(namespaces)は、Linuxが提供するシステムリソースのwrap機能を指す。
プロセス(今回の場合はコンテナ)が使用するシステムリソースをLinuxの機能で他のプロセスから
分離しているので、各コンテナが使用するシステムリソースがセキュアに分離できている、というお話。
分離させるシステムリソースは、ファイルシステム、ネットワーク、PID、UID等々。
これが何を意味するかというと、新しくalpineコンテナを作成して…。
$ docker container run -it alpine /bin/ash
# echo "hello world" > hello.txt
# ls
bin hello.txt media proc sbin tmp
dev home mnt root srv usr
etc lib opt run sys var
hello.txt
を作る。その後、hello.txt
を作成したalpineコンテナから抜けて、
Docker clientからls
。
$ docker container run alpine ls
bin
dev
etc
home
lib
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
hello.txt
が存在しない。
これは、同じalpine imageから作成していても、hello.txt
を作成したコンテナと、
ls
を実行したコンテナが、違うシステムリソースを参照している(別の名前空間上で動作している)から。
hello.txt
を作成したコンテナを再度起動するには、対象コンテナのCONTAINER IDを特定する必要がある。
$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6863c5d371eb alpine "ls" 11 minutes ago Exited (0) 11 minutes ago flamboyant_hertz
e1d7ef17948e alpine "/bin/ash" 20 minutes ago Exited (127) 11 minutes ago cool_leakey
b552d69dbb21 alpine "/bin/sh" About an hour ago Exited (0) About an hour ago distracted_moser
f1bf62c070a3 alpine "/bin/sh" About an hour ago Exited (0) About an hour ago keen_solomon
a512e55a5320 alpine "echo 'hello from al…" About an hour ago Exited (0) About an hour ago quirky_payne
7a34aab5edca alpine "ls -l" About an hour ago Exited (0) About an hour ago goofy_booth
164107ad610a hello-world "/hello" About an hour ago Exited (0) About an hour ago magical_volhard
先ほど/bin/ash
でログインしてコンテナを起動したので、hello.txt
を作成したコンテナの
CONTAINER IDはe1d7ef17948e
であることがわかる。
docker container start <container ID>
で対象コンテナを起動する。
$ docker container start e1d7ef17948e
起動したか確認。
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e1d7ef17948e alpine "/bin/ash" 24 minutes ago Up 35 seconds cool_leakey
今は、先ほどhello.txt
を作成したコンテナ上で、/bin/ash
がコマンド待ちしている状態。
このコンテナに、docker container exec
を使用して、ls
を渡してあげると…。
$ docker container exec e1d7ef17948e ls
bin
dev
etc
hello.txt
home
lib
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
hello.txt
が確認できた。
まとめ
-
docker image pull <IMAGE>
でDocker registryからイメージをダウンロードする。 -
docker image ls
でイメージを確認する。 -
docker container run <IMAGE>
で新規コンテナを起動する。
起動したコンテナはプログラム実行後にシャットダウンする。 - 起動したコンテナはDockerホストのカーネルに依存する。
-
docker container ls
で起動中のコンテナを確認する。
-a
をつけると、シャットダウン済みのコンテナも確認できる。 - 各コンテナは、同じイメージから起動しても、別の名前空間を使用するため、異なるシステムリソースを
参照する。 - 一度シャットダウンしたコンテナを再度起動するには、
docker container ls -a
でCONTAINER IDを
特定して、docker container start <CONTAINER ID>
を実行する。