LoginSignup
33
30

More than 5 years have passed since last update.

Docker container コマンドのメモ(コマンドフロー図付き)

Last updated at Posted at 2018-09-09

これは何?

  • docker container コマンドについて書いたメモです。
    • 操作対象が明確になるよう container は省略しない。
    • 例えば docker container rundocker run でもよい。
    • 各コマンド毎に、Docker公式のドキュメント(英語)、及び Docker-docs-ja(日本語) へのリンクも付けておきます。
  • 気になった部分は、[補足] として詳しく書きました。
  • なお、環境は Vagrant Ubuntu18.04(ubuntu/bionic64)、Docker version 18.06.1-ce, build e68fc7a を使用しました。

要約

コンテナのライフサイクル

  • 主なものに「実行中 -> 停止 -> 破棄」がある。
  • 実行中
    • 指定されたイメージをもとにコンテナが作成され、DockerfileのCMDやENTRYPOINTで定義されているアプリが実行される。
    • ここで起動されたアプリが実行中なら、コンテナの状態としても 実行中 となる。
  • 停止
    • Webアプリなど、HTTPリクエストを受けるコンテナは、実行中 の状態が継続するので、起動している限り勝手に 停止 にはならない。
    • コマンドラインツールなど、一度の実行で終了し 停止 になる。
  • 破棄
    • 停止 してもコンテナの内部データは保持されており、勝手に 破棄 はされない。
    • 従って、頻繁にコンテナの開始、停止を繰り返すと、ディスクをどんどん消費するので注意
    • なお、コンテナ開始時に --rm オプションを付けておけば、停止 と同時に 破棄 することも可能

docker container コマンドフロー

docker-container-command-flow.png

docker container run IMAGE

# 指定イメージからコンテナを生成実行&
# 指定コマンド(/bin/bash)を実行(CMDの上書き実行)
# 指定コマンド終了と伴にコンテナを自動的に破棄(--rm)
$ docker container run -it --rm --name ubuntu ubuntu /bin/bash

# バックグラウンドで起動
$ docker container run -d -p 8080:80 nginx

# ホストの9000を、コンテナの8080へポートフォワードする。
#   `curl http://localhost:9000/` で コンテナの8080へつながる。
$ docker container run -d -p 9000:8080 --name echo example/echo:latest`
  • -d(--detach) : バックグラウンドで実行
  • -t(--tty) : ホストのシェルの入出力を実行するコンテナの PID=1 につなぐ
  • -i(--interactive) : ホストの入力をコンテナにつなぎ続ける
    • ctrl+p ctrl+q : コンテナ終了せずホストに戻る
    • 再度コンテナにつなぐ場合、docker container attach する。
  • --rm : コンテナが停止したときに、自動でコンテナを削除する
  • --name : 任意のコンテナ名を付ける(これが無いと適当な名前が付けられる)

[補足] コンテナは停止しても、削除はされません。

  • 通常、コンテナが正常であれ異常であれ停止(exited)しても、コンテナは自動で削除されない。
  • コンテナを削除するときは、明示的に docker container rm または docker container prune コマンドを実行しないと、削除されることはない。
  • ただし、自動削除したい場合、docker container run--rm を付与すれば、コンテナ停止(exited)と同時に削除することもできる。

docker container attach CONTAINER

docker container exec CONTAINER

$ docker container exec -it ubuntu /bin/bash  # コンテナ内で新しいbashを起動する。
$ docker container exec ubuntu ls -al /
  • running コンテナ内で任意のコマンドを実行する。
  • PIDは新たに採番される(つまり、docker container attach のように PID=1 にはつながらない)
  • -it : ホストのシェルの入出力を実行するコマンドにつなぐ
    • ctrl+p ctrl+q : 実行コマンドを終了せずホストに戻る

docker container logs CONTAINER

docker container stop CONTAINER

[補足] docker container stop ですぐに停止しない理由

  • コンテナが停止するまで。

    • 1) docker container stop は 、コンテナ内の PID=1 に SIGTERM を送信する。
    • 2) SIGTERM を受けた PID=1 のプロセスが終了処理を行い停止する。
  • ところが、PID=1 で実行されたプロセスは特殊で、デフォルトで全てのシグナルを無視する。

  • Docker run リファレンス — Docker-docs-ja 17.06.Beta ドキュメント
    http://docs.docker.jp/engine/reference/run.html

    コンテナ内で PID 1 として実行しているプロセスは、Linux が特別に扱います。
    デフォルトの操作では、あらゆるシグナルを無視します。
    そのため、プロセスは SIGINT か SIGTERM で停止するようにコードを書かない限り、停止できません。

  • つまり、SIGINT、SIGTERM を適切に処理するコードを書いたプログラムを PID=1 で実行させないと docker container stop してもすぐには停止しない。

  • --init で解決するようだ。おそらく表面上は・・・

[補足] --init について

  • 恐らく『コンテナがすぐに停止しない問題を、安易に --init で解決してしまう』と、実害として『kubernetes などで、オートスケーリングの都度、正体不明のアプリ不具合が生じる可能性』がある。
  • なぜなら、--init はシグナルを受信できるプロセスを PID=1 で動かすだけで、これの子として実行するアプリレベルで見れば、適切な終了になっている保証は無い。
  • 本来なら、アプリに応じた適切な終了処理をシグナル受信時に行うべき。行っていない場合、シグナルを受けると即終了してしまう為、負荷の急増/急減で大量のコンテナが停止すると、まさに処理中(通信中、ファイルアクセス中など)にシグナル受信し、強制終了するケースが頻発するはず。

docker container kill CONTAINER

docker container rm CONTAINER

# 指定イメージで起動されたコンテナを全て強制削除
$ docker container rm -f $(docker container list --filter "ancestor=<イメージ名>" -q)`
  • コンテナを削除する。
    • 誤って削除しても二度と復活しないので注意
    • 操作を誤って running コンテナ を削除しようとしても、できない安心設計になっている。
  • '-f'(--force) : running コンテナも強制削除したいとき

docker container start CONTAINER

docker container pause CONTAINER

docker container unpause CONTAINER

docker container prune

docker container ls

$ docker container ls

# コンテナの状態でフィルタ status=(created|restarting|removing|running|paused|exited)
$ docker container ls -a --filter 'status=running'

# コンテナ名でフィルタ name=<コンテナ名> 
$ docker container ls -a --filter 'name=ubuntu'
  • コンテナの一覧を表示する。
  • lslist ps でもいい
  • -a(--all) : 全状態のコンテナの一覧(default runningコンテナのみ)
  • -f(--filter) : フィルタ条件
$ man docker-container-ls
:
       Filter output based on these conditions:
          - ancestor=(<image-name>[:tag]|<image-id>| ⟨image@digest⟩)
            containers created from an image or a descendant.
          - before=(<container-name>|<container-id>)
          - expose=(<port>[/<proto>]|<startport-endport>/[<proto>])
          - exited=<int> an exit code of <int>
          - health=(starting|healthy|unhealthy|none)
          - id=<ID> a container's ID
          - isolation=(default|process|hyperv) (Windows daemon only)
          - is-task=(true|false)
          - label=<key> or label=<key>=<value>
          - name=<string> a container's name
          - network=(<network-id>|<network-name>)
          - publish=(<port>[/<proto>]|<startport-endport>/[<proto>])
          - since=(<container-name>|<container-id>)
          - status=(created|restarting|removing|running|paused|exited)
          - volume=(<volume name>|<mount point destination>)

[補足] コンテナの状態(created|restarting|removing|running|paused|exited)を取得する方法は?

  • コンテナの状態には、(created|restarting|removing|running|paused|exited) があるらしいが、docker container ls で表示される STATUS(ex. "Up 25 minutes") は加工されているので、加工されていないものが見たい。

  • docker container ls--format でやってみる → 失敗

$ FMT="table {{.ID}}\t{{.Image}}\t{{.Names}}\t{{.Command}}\t{{.Status}}\t{{.Size}}\t{{.CreatedAt}}\t{{.RunningFor}}\t{{.Ports}}\t{{.Networks}}\t{{.Labels}}"
$ docker container ls -a --format "$FMT"
CONTAINER ID        IMAGE               NAMES                COMMAND                  STATUS              SIZE                  CREATED AT                      CREATED             PORTS                  NETWORKS            LABELS
1816cfc302a8        nginx               tender_nobel         "nginx -g 'daemon of…"   Up About a minute   2B (virtual 109MB)    2018-09-09 17:55:17 +0900 JST   3 minutes ago       0.0.0.0:8080->80/tcp   bridge              maintainer=NGINX Docker Maintainers <docker-maint@nginx.com>
e234e67b68d0        ubuntu              boring_stonebraker   "--name ubuntu"          Created             0B (virtual 84.1MB)   2018-09-09 17:26:02 +0900 JST   33 minutes ago                             bridge
  • Docker API でやってみる → 成功
$ # API経由で全コンテナのリストを得る
$ curl -s --unix-socket /var/run/docker.sock http:/v1.37/containers/json?all=true \
  | python3 -mjson.tool \
  | head -25
[
    {
        "Id": "1816cfc302a8149a94cb60eb13bf0570262ac61ca951deb898835440fe517597",
        "Names": [
            "/tender_nobel"
        ],
        "Image": "nginx",
        "ImageID": "sha256:06144b2878448774e55577ae7d66b5f43a87c2e44322b3884e4e6c70d070b262",
        "Command": "nginx -g 'daemon off;'",
        "Created": 1536483317,
        "Ports": [
            {
                "IP": "0.0.0.0",
                "PrivatePort": 80,
                "PublicPort": 8080,
                "Type": "tcp"
            }
        ],
        "Labels": {
            "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
        },
        "State": "running", # <------------------------- 状態
        "Status": "Up 3 minutes",
        "HostConfig": {
            "NetworkMode": "default"
$
$ # jqを使って、コンテナ名と状態のみ抽出
$ curl -s --unix-socket /var/run/docker.sock http:/v1.37/containers/json?all=true \
    | jq -r '[ .[] | { Name: .Names[0], State: .State } ]' \
    | jq -r '["Name","State"], (.[] | [.Name,.State]) | @csv' \
    | column -t -s ,
"Name"                 "State"
"/tender_nobel"        "running"
"/boring_stonebraker"  "created"
"/ubuntu"              "exited"

docker container top CONTAINER

[補足] コンテナ内部で実行したプロセスがどのように見えるか?

  • ubuntuコンテナ内部で、sleep を2つをバックグラウンドで動かして、docker container top や 普通に ps してみる。

  • まず、コンテナから

$ # コンテナを起動し、コンテナ内部で、sleep を動かしておく
$ docker container run -it --name ubuntu ubuntu /bin/bash
root@fc659b390b7f:/# sleep 1000000 &
[1] 10
root@fc659b390b7f:/# sleep 1000000 &
[2] 11
root@fc659b390b7f:/# ps -alxf
F   UID   PID  PPID PRI  NI    VSZ   RSS WCHAN  STAT TTY        TIME COMMAND
4     0     1     0  20   0  18508  3448 wait   Ss   pts/0      0:00 /bin/bash
4     0    10     1  20   0   4532   780 hrtime S    pts/0      0:00 sleep 1000000
0     0    11     1  20   0   4532   776 hrtime S    pts/0      0:00 sleep 1000000
4     0    12     1  20   0  25944  1412 -      R+   pts/0      0:00 ps -alxf
root@fc659b390b7f:/# read escape sequence ---- ### ctrl+p ctrl+q でコンテナを抜けホストに戻る
  • 次に、ホストから
$ # docker container top してみる → コンテナから見たPID、PPIDとは違って見えている(プロセス空間が隔離されている為)
$ docker container top ubuntu
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                20808               20775               0                   01:10               pts/0               00:00:00            /bin/bash
root                21200               20808               0                   01:16               pts/0               00:00:00            sleep 1000000
root                21203               20808               0                   01:16               pts/0               00:00:00            sleep 1000000
$
$ # docker container top で、オプション指定して、詳細を見る
$ docker container top ubuntu -alxf
F                   UID                 PID                 PPID                PRI                 NI                  VSZ                 RSS                 WCHAN               STAT                TTY                 TIME                COMMAND
4                   0                   20808               20775               20                  0                   18508               3444                poll_s              Ss+                 pts/0               0:00                | \_ /bin/bash
4                   0                   21200               20808               20                  0                   4532                780                 hrtime              S                   pts/0               0:00                | \_ sleep 1000000
0                   0                   21203               20808               20                  0                   4532                776                 hrtime              S                   pts/0               0:00                | \_ sleep 1000000
$
$ # ホストで普通に ps してみる → コンテナ内部のプロセスも見えている(コンテナはホストのkernelを使っている為)
$ ps -alxf
F   UID   PID  PPID PRI  NI    VSZ   RSS WCHAN  STAT TTY        TIME COMMAND
:
4     0  1286     1  20   0 1113408 54580 -     Ssl  ?         10:40 /usr/bin/dockerd -H fd://
4     0  1435  1286  20   0 1024084 23248 -     Ssl  ?          8:22  \_ docker-containerd --config /var/run/docker/containerd/containerd.toml
4     0 20775  1435  20   0   8908  4412 -      Sl   ?          0:00      \_ docker-containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/fc659b390b7f525d6be7e69d0f2610887fffc05f75
4     0 20808 20775  20   0  18508  3444 -      Ss+  pts/0      0:00          \_ /bin/bash
4     0 21200 20808  20   0   4532   780 -      S    pts/0      0:00              \_ sleep 1000000
0     0 21203 20808  20   0   4532   776 -      S    pts/0      0:00              \_ sleep 1000000
$

docker container stats

  • top コマンドのようなもの
$ docker container stats
CONTAINER ID    NAME     CPU %     MEM USAGE / LIMIT     MEM %     NET I/O          BLOCK I/O      PIDS
c4fd37367595    echo     0.00%     6.887MiB / 1.947GiB   0.35%     6.71kB / 890B    149MB / 0B     14
33
30
1

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
33
30