CLOVER🍀

That was when it all began.

リモートホストで動作しているDockerデーモンを使用する

これは、なにをしたくて書いたもの?

リモートホストで動作している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

デフォルトのUnixドメインソケットが使われています。

ここで、新しくコンテキストを作成します。名前は「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としましょう。