1. 概要

このチュートリアルでは、Docker Engine APIを使用して、コンテナー内からDockerコンテナー情報にアクセスする方法を説明します。

2. 設定

Dockerエンジンには複数の方法で接続できます。 Linuxで最も役立つものについて説明しますが、他のオペレーティングシステムでも機能します。

ただし、リモートアクセスを有効にするとセキュリティリスクが発生するため、非常に注意する必要があります。 コンテナがエンジンにアクセスできる場合、ホストオペレーティングシステムからの分離が解除されます。

セットアップの部分では、ホストを完全に制御できると見なします。

2.1. デフォルトのUnixソケットの転送

デフォルトでは、Dockerエンジンは、ホストOSの/var/run/docker.sockの下にマウントされたUnixソケットを使用します。

$ ss -xan | grep var

u_str LISTEN 0      4096              /var/run/docker/libnetwork/dd677ae5f81a.sock 56352            * 0           
u_dgr UNCONN 0      0                                 /var/run/chrony/chronyd.sock 24398            * 0           
u_str LISTEN 0      4096                                      /var/run/nscd/socket 23131            * 0           
u_str LISTEN 0      4096                              /var/run/docker/metrics.sock 42876            * 0           
u_str LISTEN 0      4096                                      /var/run/docker.sock 53704            * 0    
...       

このアプローチでは、どのコンテナがAPIにアクセスできるかを厳密に制御できます。 これは、DockerCLIが舞台裏でどのように機能するかです。

alpine Dockerコンテナを起動し、-vフラグを使用してこのパスをマウントしましょう。

$ docker run -it -v /var/run/docker.sock:/var/run/docker.sock alpine

(alpine) $

次に、コンテナにいくつかのユーティリティをインストールしましょう。

(alpine) $ apk add curl && apk add jq

fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/community/x86_64/APKINDEX.tar.gz
(1/4) Installing ca-certificates (20191127-r2)
(2/4) Installing nghttp2-libs (1.40.0-r1)
...

次に、を–unix-socketフラグおよび Jq とともにcurlを使用して、いくつかのコンテナーデータをフェッチおよびフィルター処理してみましょう。

(alpine) $ curl -s --unix-socket /var/run/docker.sock http://dummy/containers/json | jq '.'

[
  {
    "Id": "483c5d4aa0280ca35f0dbca59b5d2381ad1aa455ebe0cf0ca604900b47210490",
    "Names": [
      "/wizardly_chatelet"
    ],
    "Image": "alpine",
    "ImageID": "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
    "Command": "/bin/sh",
    "Created": 1595882408,
    "Ports": [],
...

ここでは、 / containers / json エンドポイントでGETを発行し、現在実行中のコンテナーを取得します。 次に、jqを使用して出力をプリティファイします。

エンジンAPIの詳細については後で説明します。

2.2. TCPリモートアクセスの有効化

TCPソケットを使用してリモートアクセスを有効にすることもできます。

systemd に付属するLinuxディストリビューションの場合、Dockerサービスユニットをカスタマイズする必要があります。 他のLinuxディストリビューションの場合、通常 / etc /dockerにあるdaemon.jsonをカスタマイズする必要があります。

ほとんどの手順は類似しているため、最初の種類のセットアップについてのみ説明します。

デフォルトのDockerセットアップには、ブリッジネットワークが含まれています。 これはで、特に指定がない限り、すべてのコンテナが接続されます

コンテナだけがエンジンAPIにアクセスできるようにしたいので、最初にそれらのネットワークを識別しましょう。

$ docker network ls

a3b64ea758e1        bridge              bridge              local
dfad5fbfc671        host                host                local
1ee855939a2a        none                null                local

その詳細を見てみましょう:

$ docker network inspect a3b64ea758e1

[
    {
        "Name": "bridge",
        "Id": "a3b64ea758e1f02f4692fd5105d638c05c75d573301fd4c025f38d075ed2a158",
...
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
...

次に、Dockerサービスユニットが配置されている場所を確認しましょう。

$ systemctl status docker.service

docker.service - Docker Application Container Engine
     Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
...
     CGroup: /system.slice/docker.service
             ├─6425 /usr/bin/dockerd --add-runtime oci=/usr/sbin/docker-runc
             └─6452 docker-containerd --config /var/run/docker/containerd/containerd.toml --log-level warn

次に、サービスユニットの定義を見てみましょう。

$ cat /usr/lib/systemd/system/docker.service

[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.com
After=network.target lvm2-monitor.service SuSEfirewall2.service

[Service]
EnvironmentFile=/etc/sysconfig/docker
...
Type=notify
ExecStart=/usr/bin/dockerd --add-runtime oci=/usr/sbin/docker-runc $DOCKER_NETWORK_OPTIONS $DOCKER_OPTS
ExecReload=/bin/kill -s HUP $MAINPID
...

ExecStart プロパティは、 systemd dockerd 実行可能ファイル)によって実行されるコマンドを定義します。 -Hフラグを渡し、対応するネットワークとポートを指定してをリッスンします。

このサービスユニットを直接変更することもできますが(非推奨)、 $ DOCKER_OPTS 変数( EnvironmentFile = / etc / sysconfig / docker で定義)を使用しましょう。

$ cat /etc/sysconfig/docker 

## Path           : System/Management
## Description    : Extra cli switches for docker daemon
## Type           : string
## Default        : ""
## ServiceRestart : docker
#
DOCKER_OPTS="-H unix:///var/run/docker.sock -H tcp://172.17.0.1:2375"

ここでは、ブリッジネットワークのゲートウェイアドレスをバインドアドレスとして使用します。 これはホストのdocker0インターフェースに対応します

$ ip address show dev docker0

3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:6c:7d:9c:8d brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:6cff:fe7d:9c8d/64 scope link 
       valid_lft forever preferred_lft forever

また、ローカルUnixソケットを有効にして、DockerCLIがホスト上で引き続き機能するようにします。

もう1つのステップが必要です。 コンテナパケットがホストに到達できるようにします。

$ iptables -I INPUT -i docker0 -j ACCEPT

ここでは、docker0インターフェースを経由するすべてのパッケージを受け入れるようにLinuxファイアウォールを設定します。

それでは、Dockerサービスを再起動しましょう。

$ systemctl restart docker.service
$ systemctl status docker.service
 docker.service - Docker Application Container Engine
     Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
...
     CGroup: /system.slice/docker.service
             ├─8110 /usr/bin/dockerd --add-runtime oci=/usr/sbin/docker-runc -H unix:///var/run/docker.sock -H tcp://172.17.0.1:2375
             └─8137 docker-containerd --config /var/run/docker/containerd/containerd.toml --log-level wa

高山コンテナをもう一度実行してみましょう。

(alpine) $ curl -s http://172.17.0.1:2375/containers/json | jq '.'

[
  {
    "Id": "45f13902b710f7a5f324a7d4ec7f9b934057da4887650dc8fb4391c1d98f051c",
    "Names": [
      "/unruffled_cray"
    ],
    "Image": "alpine",
    "ImageID": "sha256:a24bb4013296f61e89ba57005a7b3e52274d8edd3ae2077d04395f806b63d83e",
    "Command": "/bin/sh",
    "Created": 1596046207,
    "Ports": [],
...

ブリッジネットワークに接続されているすべてのコンテナがデーモンAPIにアクセスできることに注意する必要があります。

さらに、TCP接続は暗号化されていません

3. Docker Engine API

リモートアクセスを設定したので、APIを見てみましょう。

いくつかの興味深いオプションについて説明しますが、完全なドキュメントで詳細を確認できます。

コンテナに関する情報を取得しましょう

(alpine) $ curl -s http://172.17.0.1:2375/containers/"$(hostname)"/json | jq '.'

{
  "Id": "45f13902b710f7a5f324a7d4ec7f9b934057da4887650dc8fb4391c1d98f051c",
  "Created": "2020-07-29T18:10:07.261589135Z",
  "Path": "/bin/sh",
  "Args": [],
  "State": {
    "Status": "running",
...

ここで/container / {container-id} / json URLを使用して、コンテナーの詳細を取得します。

この場合、 hostname コマンドを実行して、container-idを取得します。

次に、Dockerデーモンのイベントをリッスンしましょう。

(alpine) $ curl -s http://172.17.0.1:2375/events | jq '.'

別の端末で、 hello-worldcontainerを起動しましょう。

$ docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.
...

高山コンテナに戻ると、次のようなイベントが発生します。

{
  "status": "create",
  "id": "abf881cbecfc0b022a3c1a6908559bb27406d0338a917fc91a77200d52a2553c",
  "from": "hello-world",
  "Type": "container",
  "Action": "create",
...
}
{
  "status": "attach",
  "id": "abf881cbecfc0b022a3c1a6908559bb27406d0338a917fc91a77200d52a2553c",
  "from": "hello-world",
  "Type": "container",
  "Action": "attach",
...

これまで、邪魔にならないことを行ってきました。 物事を少し振る時間。

コンテナを作成して開始しましょう。 まず、マニフェストを定義します。

(alpine) $ cat > create.json << EOF
{
  "Image": "hello-world",
  "Cmd": ["/hello"]
}
EOF

次に、マニフェストを使用して/ containers/createエンドポイントを呼び出しましょう。

(alpine) $ curl -X POST -H "Content-Type: application/json" -d @create.json http://172.17.0.1:2375/containers/create

{"Id":"f96a6360ad8e36271cc75a3cff05348761569cf2f089bbb30d826bd1e2d52f59","Warnings":[]}

次に、idを使用してコンテナーを開始します。

(alpine) $ curl -X POST http://172.17.0.1:2375/containers/f96a6360ad8e36271cc75a3cff05348761569cf2f089bbb30d826bd1e2d52f59/start

最後に、ログを調べることができます。

(alpine) $ curl http://172.17.0.1:2375/containers/f96a6360ad8e36271cc75a3cff05348761569cf2f089bbb30d826bd1e2d52f59/logs?stdout=true --output -

Hello from Docker!
KThis message shows that your installation appears to be working correctly.

;To generate this message, Docker took the following steps:
3 1. The Docker client contacted the Docker daemon.
...

各行の先頭に奇妙な文字が表示されていることに注意してください。 これは、ログが送信されるストリームが多重化され、stderrstdoutを区別するために発生します。

その結果、出力はさらに処理する必要があります。

これを回避するには、コンテナを作成するときにTTYオプションを有効にするだけです。

(alpine) $ cat create.json

{
  "Tty":true,	
  "Image": "hello-world",
  "Cmd": ["/hello"]
}

4. 結論

このチュートリアルでは、Docker EngineRemoteAPIの使用方法を学びました。

UNIXソケットまたはTCPのいずれかからリモートアクセスを設定することから始め、リモートAPIの使用方法をさらに示しました。