$shibayu36->blog;

株式会社はてなでエンジニアをしています。プログラミングや読書のことなどについて書いています。

docker inspectでDockerコンテナの情報を取得する

dockerコマンドにはinspectコマンドというのがあって、コンテナやイメージの様々な情報を取得できる。今回はこのコマンドについていろいろ触ったので、メモを書いておく。

簡単な使い方

基本的には

$ docker inspect (コンテナID)

と使う

$ docker inspect 2a5624c52119
[{
    "ID": "2a5624c5211981af1ddc1b43916176778f92665ec13f64346456ab24ddfef9b2",
    "Created": "2013-12-28T05:03:32.821608786Z",
    "Path": "/bin/sh",
    "Args": [
        "-c",
        "while true; do echo hello world; sleep 1; done"
    ],
    "Config": {
        "Hostname": "2a5624c52119",
# ...

format

さらに-formatでformat指定して取得もできる。あるコンテナのIPを取得してみる。

$ docker inspect -format="{{ .NetworkSettings.IPAddress }}" 2a5624c52119
172.17.0.24

このformatはtemplate - The Go Programming Languageの構文が使えるみたい。

いろいろやってみた

いろいろ構文あったので、試しにやってみた。

IPアドレス取得

変数には.を使ってアクセスできるっぽい。上にも書いたけどもう一回。

$ docker inspect -format="{{ .NetworkSettings.IPAddress }}" 2a5624c52119
172.17.0.24

あるコンテナに設定されている環境変数取得

range使えばfor文みたいなのできる。

$ docker inspect -format='{{range .Config.Env}}{{println .}}{{end}}' c3fa3ce1622b
HOME=/
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

22番portの空いているコンテナのforwardingされたport一覧取得

とたんに難しくなりますが、現在立ち上がっているコンテナの中で22番portが空いている場合の、port forwarding先port番号の表示です。

$ docker ps -q | xargs docker inspect -format='{{ if index .NetworkSettings.Ports "22/tcp" }}{{(index (index .NetworkSettings.Ports "22/tcp") 0).HostPort}}{{ end }}' | sed '/^$/d'
49156
49155
49154
49153
  • docker ps -qでCONTAINER ID取得
  • if endで条件分岐
    • indexで.NetworkSettings.Ports['22/tcp']を取得
    • 存在したら分岐に入る
  • xargsでしたので、空行をsedで削除

特定のイメージ名で動いているIP一覧を表示

ubuntuで動いているイメージのIP一覧を取ってみます。

$ docker ps -q | xargs docker inspect -format='{{ if eq .Config.Image "ubuntu" }}{{ .NetworkSettings.IPAddress }}{{ end }}' | sed  '/^$/d'
172.17.0.24
172.17.0.23

注意点はif .Config.Image == "ubuntu"と書けないところですね...

まとめ

とりあえずdocker inspectを使って色々やってみました。これを使うとコンテナを立ちあげて、その情報を取得して、それに対して何かを実行するというのをシェルスクリプトでも結構簡単に出来ます。とはいえsyntaxが結構難しいので、やり過ぎ注意というイメージを受けました。

docker commitでCMDやENVなどを指定する

 現状Dockerfileに書けるCMDやENVなどはdocker commitしてしまうと消えてしまいます(https://github.com/dotcloud/docker/issues/1141)。本当は前のオプションのまま残しておいて欲しいのですが出来ないので、今回はdocker commitの時のこのようなオプションを指定する方法について書きます。

 docker commitには-runオプションがあり、それによってCMDやENVやEXPOSEなどを指定できるようでした。例えば以下の様な使い方が出来ます。http://docs.docker.io/en/latest/commandline/cli/#change-the-command-that-a-container-runs も参考に。

docker commit -run '
{
    "Cmd": [
        "/usr/bin/supervisord",
        "-c",
        "/opt/Sample-App/current/supervisor/supervisord.conf"
    ],
    "Env": [
        "HOME=/",
        "PATH=/opt/ruby/bin:/opt/perl/bin:/usr/sbin:/sbin:/usr/bin:/bin",
        "DEBIAN_FRONTEND=noninteractive"
    ],
    "ExposedPorts": {
        "22/tcp": {},
        "8000/tcp": {}
    }
}' 7dd9480063c8 sample-app

 ちゃんと調べてないですが、ここで指定できるJSONはdocker inspectの時に出てくるConfigというところに保存しているものっぽいですね。

$ sudo docker inspect 7dd9480063c8
[{
    // ...
    "Args": [
        "-c",
        "cd /docker-registry \u0026\u0026 ./setup-configs.sh \u0026\u0026 ./run.sh"
    ],
    "Config": {
        "Hostname": "7dd9480063c8",
        "Domainname": "",
        "User": "",
        "Memory": 0,
        "MemorySwap": 0,
        "CpuShares": 0,
        "AttachStdin": false,
        "AttachStdout": false,
        "AttachStderr": false,
        "PortSpecs": null,
        "ExposedPorts": {
            "5000/tcp": {}
        },
        "Tty": false,
        "OpenStdin": false,
        "StdinOnce": false,
        "Env": [
            "HOME=/",
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
        ],
        "Cmd": [
            "/bin/sh",
            "-c",
            "cd /docker-registry \u0026\u0026 ./setup-configs.sh \u0026\u0026 ./run.sh"
        ],
        "Dns": null,
        "Image": "stackbrew/registry",
        "Volumes": {
            "/tmp/registry": {}
        },
        "VolumesFrom": "",
        "WorkingDir": "",
        "Entrypoint": null,
        "NetworkDisabled": false
    },
    "State": {
        "Running": true,
        "Pid": 4793,
        "ExitCode": 0,
        "StartedAt": "2013-12-19T08:56:29.577405721Z",
        "FinishedAt": "0001-01-01T00:00:00Z",
        "Ghost": false
    },
    // ...
}]

社内用Docker Registryを立てる

 Dockerにはimageを登録しておくためのregistryが用意されていて、https://index.docker.io/ にPublicなイメージを登録しておくことが出来ます。また、社内用など、Publicには出したくない時も自分でregistryを立てることが出来ます。そこで、今回は社内用Docker Registryの立て方について書こうと思います。

 https://github.com/dotcloud/docker-registry を参考にします。

Docker Registryを立ち上げる

 立てるのはすごく簡単で、docker runするだけでした。

$ docker run -p 5000:5000 -d stackbrew/registry

 これで実行したhostの5000番portにDocker Registryを立てることができます。

 ここに対して、pushやpullをしたい場合は、host名を含めたtagを付ける必要があります。例えばこのhostの名前が private-docker-registry.com だったとすると

$ docker build -t private-docker-registry.com:5000/sample-app .
$ docker push private-docker-registry.com:5000/sample-app

のようにします。簡単ですね。

データのディレクトリをマウントする

 ただ、このままではDockerコンテナをstopしたらデータが消えてしまいます。そこでhostのディレクトリを、Docker Registryのデータディレクトリにmountして、データを永続化できるようにします。

 これも立ちあげ方を変えるだけです。これでDockerを立ちあげているhostの/var/registryが、Dockerコンテナ内の/tmp/registryにmountされ、Dockerコンテナがstopしても/var/registryに残り続けてくれます。

docker run -d -p 5000:5000 -v /var/registry:/tmp/registry stackbrew/registry

その他の立ちあげ方

https://github.com/dotcloud/docker-registry を見ると分かる通り、config.ymlをうまくいじることによって、S3にデータを保存するなどの事もできるようです。

S3-backed Private Docker Registry | blog.hansode.org この辺りも参考に

まとめ

 今回は簡単なDocker Registryの立て方について書きました。とりあえず試すくらいならこの程度で十分だと思います。