Dockerコンテナの基本的な起動、操作

今の職場がkubernetesでproduction環境を構築していて、アプリケーション開発の基盤をこれから触るにあたってDockerの周辺知識が必須なので、基本的なことからまとめながら理解していく。

コンテナの起動

以下のコマンドではDebianのコンテナを起動してHello Worldを出力している。

$ docker run debian echo "Hello World"
Unable to find image 'debian:latest' locally
latest: Pulling from library/debian
376057ac6fa1: Pull complete 
Digest: sha256:4ab3309ba955211d1db92f405be609942b595a720de789286376f030502ffd6f
Status: Downloaded newer image for debian:latest
Hello World

ここで起きたことを追っていく。 docker runは指定したイメージのコンテナを起動し、指定されたコマンドを実行するコマンド。

docker run [オプション] イメージ [コマンド] [引数...]

ここで指定しているイメージは最新バージョンのDebianイメージ、コマンドはecho、引数は"Hello World"となる。

Unable to find image 'debian:latest' locally
latest: Pulling from library/debian
376057ac6fa1: Pull complete 
Digest: sha256:4ab3309ba955211d1db92f405be609942b595a720de789286376f030502ffd6f
Status: Downloaded newer image for debian:latest

最新バージョンのDebianイメージのローカルコピーがないため、DockerはDocker Hubをオンラインでチェックし最新バージョンのDebianイメージをダウンロードする。

Hello World

ダウンロードが完了すると、コンテナを起動しその中で指定されたechoコマンドを実行する。

再度同じコマンドを実行すると、今度はイメージのダウンロードなしですぐにコンテナが起動される。

$ docker run debian echo "Hello World"
Hello World

コンテナの一覧・削除

先ほど作ったコンテナを一覧で見てみる。

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                CREATED              STATUS                          PORTS               NAMES
91f05417bc1b        debian              "echo 'Hello World'"   About a minute ago   Exited (0) About a minute ago                       angry_leakey
e711e9698233        debian              "echo 'Hello World'"   15 minutes ago       Exited (0) 15 minutes ago                           sad_hermann

同じイメージだが、コマンドを打った分コンテナが作られていて、statusがexitedとありコンテナは停止している。

今度はコンテナ内でシェルを使えるように起動してみる。

$ docker run -it debian /bin/bash
root@ead650c481f3:/# echo "Hello World"
Hello World
root@ead650c481f3:/# 

-itオプションでコンテナのSTDINにアタッチして擬似ターミナルを割り当てている。 /bin/bash コマンドでbashシェルが立ち上がる。 シェルを終了すると、コンテナも停止する。コンテナが動作するのは、そのコンテナのメインプロセスが動作している間だけ。

ここまでで作ったコンテナは不要なので削除する。

docker rm [オプション] コンテナ [コンテナ...]

コンテナ名もしくはコンテナIDを指定して削除できる

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                       PORTS               NAMES
ead650c481f3        debian              "/bin/bash"            14 minutes ago      Exited (130) 2 seconds ago                       mystifying_elbakyan
9ff7a951dfdc        debian              "echo 'Hello World'"   22 minutes ago      Exited (0) 22 minutes ago                        quirky_tesla
91f05417bc1b        debian              "echo 'Hello World'"   24 minutes ago      Exited (0) 24 minutes ago                        angry_leakey
e711e9698233        debian              "echo 'Hello World'"   38 minutes ago      Exited (0) 38 minutes ago                        sad_hermann
$ docker rm mystifying_elbakyan
mystifying_elbakyan
$ docker rm 9ff7a951dfdc
9ff7a951dfdc

また、以下コマンドで停止した全てのコンテナを削除できる。

$ docker rm -v $(docker ps -aq -f status=exited)
91f05417bc1b
e711e9698233
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

コンテナの詳細情報

今度はコンテナにホスト名・コンテナ名をつけて起動する。

$ docker run -h test-host --name="test-name" -it debian /bin/bash
root@test-host:/# 

新しいターミナルを開いてこのコンテナの情報をdocker inspectで確認する。

docker inspect [オプション] コンテナ|イメージ|タスク [コンテナ|イメージ|タスク...]

$ docker inspect test-name
[
    {
        "Id": "a56167ee8d64950c793ded1950362a7f815e82fcbd23ae2004985a3629deb016",
        "Created": "2020-05-23T07:24:13.3995891Z",
        "Path": "/bin/bash",
        "Args": [],
        "State": {
            "Status": "running",
[省略]

詳細な情報がJSON配列で表示されるが情報量が多すぎるのでgrep か formatオプションで必要な情報をフィルタリングする。

$ docker inspect --format {{.Config.Hostname}} test-name
test-host

$ docker inspect --format {{.NetworkSettings.IPAddress}} test-name
172.17.0.2

コンテナのログ

先ほど起動したコンテナの中をいじってみる。

/# mv /bin /basket
root@test-host:/# ls -al
bash: /bin/ls: No such file or directory

いじるというか壊しているが、コンテナ内で操作をした記録を確認することができる。 コンテナで実行したコマンドとその出力をdocker logsで見れる。

$ docker logs test-name
# mv /bin /basket
root@test-host:/# ls -al
bash: /bin/ls: No such file or directory

また、docker diff でコンテナのファイルシステム上で、変更したファイルやディレクトリの一覧を見れる。

$ docker diff test-name
A /basket
A /basket/date
A /basket/mknod
[中略]
D /bin

mvコマンドによって /bin が削除され、/basket ディレクトリに追加されていることが分かる。 これらのコマンドでコンテナで起きたことを後から確認することができる。

イメージのファイルシステムはリードオンリーのレイヤとしてマウントされており、実行中のコンテナへの全ての変更は、その上にマウントされている読み書き可能なレイヤに対して行われる。 そのため、Dockerは最上位の読み書き可能なレイヤだけ見れば、実行中のファイルシステムに対して行われた変更を見つけることができる。