これは、なにをしたくて書いたもの?
リモートホストで動作しているDockerデーモンを扱ったことがなかったので、1度試してみようかな、と。
環境
今回の環境は、こちらです。
$ uname -srvmpio Linux 4.15.0-108-generic #109-Ubuntu SMP Fri Jun 19 11:33:10 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux $ docker version Client: Docker Engine - Community Version: 19.03.12 API version: 1.40 Go version: go1.13.10 Git commit: 48a66213fe Built: Mon Jun 22 15:45:36 2020 OS/Arch: linux/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.12 API version: 1.40 (minimum version 1.12) Go version: go1.13.10 Git commit: 48a66213fe Built: Mon Jun 22 15:44:07 2020 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.2.13 GitCommit: 7ad184331fa3e55e52b890ea95e65ba581ae3429 runc: Version: 1.0.0-rc10 GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd docker-init: Version: 0.18.0 GitCommit: fec3683
Dockerをインストールしたサーバーは、2つ用意します。
- 192.168.33.10 … host1
- 192.168.33.11 … host2
このうち、host1をクライアント側、host2をサーバー側とします。コマンドの記載も、コメントでhost1とhost2を書いて見分ける
ようにしていきます。
他のDockerデーモンを使うには?
DOCKER_HOST環境変数を使うか、コンテキストの切り替えを行うみたいです。
Use the Docker command line | Docker Documentation
Docker Context | Docker Documentation
それぞれ試してみましょう。
DOCKER_HOST環境変数を使う
最初は、DOCKER_HOST環境変数を試してみます。この環境変数を使うことで、接続先のDockerデーモンを指定できます。
Use the Docker command line | Docker Documentation
ちなみに、コマンド都度で書くことになりますが、「-H」オプションで指定することも可能です。
今回は、クライアント側からTCP接続できるようにします。
サーバー側の設定としては、Dockerデーモンのソケット指定を行います。
dockerd / Daemon socket option
dockerコマンドに対して、「-H」でどのような方法で接続を待つのかを指定します。パッケージインストールした場合は、
systemdのUnitファイルでの指定になります。
デフォルトの状態を確認してみます。
/etc/systemd/system/multi-user.target.wants/docker.service
# host2 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
「fd://」のみですね。この状態だと、「/var/run/docker.sock」というUnixドメインソケットが使用されます。
ここで、TCP接続可能にしてみましょう。今回は「0.0.0.0」で全インターフェースにバインド、2375ポートでリッスンします。
# host2 ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H fd:// --containerd=/run/containerd/containerd.sock
Dockerデーモンを再起動。
# host2 $ sudo systemctl daemon-reload $ sudo systemctl restart docker
TCPポートをリッスンするようになりました。
# host2 $ ss -tnl | grep 2375 LISTEN 0 128 *:2375 *:*
ここで、クライアント側でDOCKER_HOST環境変数の指定を行ってみます。
# host1 $ export DOCKER_HOST=tcp://192.168.33.11:2375
nginxのイメージをPullしてみましょう。
# host1 $ docker image pull nginx:latest
確認。
# host1 $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 2622e6cca7eb 2 weeks ago 132MB
ここで、サーバー側でも確認してみます。同じイメージが取得できています。
# host2 $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 2622e6cca7eb 2 weeks ago 132MB
クライアント側に戻って、コンテナを起動してみましょう。この時に、ポート80をローカルにもバインドさせてみます。
# host1 $ docker container run -d -p 80:80 nginx:latest
どこでコンテナが動作しているか、確認してみます。ポート80は、クライアント側ではバインドされません。
# host1 $ ss -tnl | grep 80
この状態なので、当然、接続もできません。
# host1 $ curl -I localhost curl: (7) Failed to connect to localhost port 80: Connection refused
サーバー側のIPアドレスを指定すると、接続できます。
# host1 $ curl -I 192.168.33.11 HTTP/1.1 200 OK Server: nginx/1.19.0 Date: Tue, 30 Jun 2020 12:50:43 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Tue, 26 May 2020 15:00:20 GMT Connection: keep-alive ETag: "5ecd2f04-264" Accept-Ranges: bytes
「docker container ps」で、実行中のコンテナを確認してみます。
# host1 $ docker container ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e70a043d60c0 nginx:latest "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:80->80/tcp sweet_sutherland
サーバー側でも、同じように見えます。
# host2 $ docker container ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e70a043d60c0 nginx:latest "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:80->80/tcp sweet_sutherland
つまり、この状態でDockerコンテナが動作するのは、サーバー側(Dockerデーモンが動作している側)となります。
# host2 $ ss -tnl | grep 80 LISTEN 0 128 *:80 *:*
この動きをちゃんと確認したのは、初めてだったりします。
確認できたので、コンテナの停止と削除。
# host1 $ docker container stop sweet_sutherland $ docker container rm sweet_sutherland
なお、最初にも記載しましたが、DOCKER_HOST環境変数の代わりに、「-H」オプションで接続先のDockerデーモンを指定しても
同じ動作になります。
# host1 $ docker -H tcp://192.168.33.11:2375 container run -it --rm nginx:latest
コマンド都度の指定になるので、面倒といえば面倒ですが…。
コンテキストを使う
次に、コンテキストの切り替えを行ってみます。
Docker Context | Docker Documentation
現在のコンテキストは、「docker context ls」で確認できます。
※DOCKER_HOST環境変数は、今回は未設定です
# host1 $ docker context ls NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm
docker context ls | Docker Documentation
ここで、新しくコンテキストを作成します。名前は「remote」にしました。
# host1 $ docker context create remote --docker host=tcp://192.168.33.11:2375 remote Successfully created context "remote"
docker context create | Docker Documentation
確認。
# host1 $ docker context ls NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm remote tcp://192.168.33.11:2375
「docker context use」で、指定のコンテキストに切り替えることができます。
# host1 $ docker context use remote remote Current context is now "remote"
docker context use | Docker Documentation
あとは、DOCKER_HOST環境変数で指定したように、接続先のDockerデーモンを切り替えた状態で操作することができます。
# host1 $ docker image pull httpd:latest
コンテナの起動。
# host1 $ docker container run -d -p 80:80 httpd:latest
確認。
# host1 $ curl -I 192.168.33.11 HTTP/1.1 200 OK Date: Tue, 30 Jun 2020 13:01:40 GMT Server: Apache/2.4.43 (Unix) Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT ETag: "2d-432a5e4a73a80" Accept-Ranges: bytes Content-Length: 45 Content-Type: text/html
また、コンテキストの作成後であれば、「docker context use」ではなく、DOCKER_CONTEXT環境変数でコンテキスト名を
指定することで切り替えることもできます。
# host1 $ export DOCKER_CONTEXT=remote $ docker context ls NAME DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR default Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm remote * tcp://192.168.33.11:2375
確認したいことはできたので、OKとしましょう。