LoginSignup
0
1

More than 1 year has passed since last update.

リモートのDocker Swarmをラップトップから操作する

Posted at

今更ながらDocker Swarmに入門することとなりました。普段K8sに慣れていたのでK8sと同じようにラップトップ側でクラスタの操作をしたいと思いました。調べたらDockerのAPIを外部に公開することで可能なようです。ただ、おもむろに公開するのはセキュリティ的にもよろしくないのでTLSを設定して安全にしたいと思います。

基本的に公式ドキュメントのここを参考にして進めていきます。

環境説明

AWS上のEC2にDockerをインストールしています。ホストは全部で5台ありSwarmクラスタを組んでいます。5台中3台がmanagerで残り2台がworkerです。各ホストのスペックは以下の通りです。各ホストはパブリックサブネットに配置しています。

  • インスタンスタイプ: t2.medium
  • OS: t2.medium
  • docker: docker-ce 20.10.7

クライントは私のラップトップです。各ホストには私のラップトップからのインバウンドを許可するセキュリティグループルールを設定してあります。

今回はmanager3台に設定を追加して外部から操作可能にします。

手順

証明書準備

以降の手順はmanagerの内どれか1台で実施します。rootで作業する想定です。

TLSで通信したいためCAの認証局を作ります。

$ openssl genrsa -aes256 -out ca-key.pem 4096
# pass phraseは適当な4文字以上の文字列を入れる。

$ openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
# CNはDockerホストのパブリックDNS名などクライアントから名前解決可能なホスト名にする。

サーバーの秘密鍵とCSRを作成します。

$ openssl genrsa -out server-key.pem 4096
$ openssl req -subj "/CN=<Dockerホスト名①>" -sha256 -new -key server-key.pem -out server.csr
# CNはmanagerの内どれか一台代表でOK。後ほどsubjectAltNameで他のmanagerも設定します。

サーバー用の拡張設定をファイルに保存します。ここで全managerのパブリックDNS名やパブリックIPアドレスの設定を追加しておきます。

$ echo subjectAltName = DNS:<Dockerホスト①>,DNS:<Dockerホスト②>,DNS:<Dockerホスト③>,IP:<Dockerホスト①>,IP:<Dockerホスト②>,IP:<Dockerホスト③> >> extfile.cnf
$ echo extendedKeyUsage = serverAuth >> extfile.cnf

サーバー証明書を作成します。

$ openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \
  -CAcreateserial -out server-cert.pem -extfile extfile.cnf

クライアントの秘密鍵とCSRを作成します。

$ openssl genrsa -out key.pem 4096
$ openssl req -subj '/CN=client' -new -key key.pem -out client.csr

クライアント用の拡張設定をファイルに保存します。

$ echo extendedKeyUsage = clientAuth > extfile-client.cnf

クライアント証明書を作成します。

$ openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem \
  -CAcreateserial -out cert.pem -extfile extfile-client.cnf

パーミッションを整えておきます。

$ chmod -v 0400 ca-key.pem key.pem server-key.pem
$ chmod -v 0444 ca.pem server-cert.pem cert.pem

作成したca.pemserver-cert.pemserver-key.pemを他のmanagerにもコピーします。(各種ファイルをcatして中身をコピペでもいい。)

dockerd設定

以降の手順はすべてのmanagerで実施します。rootで作業する想定です。

ここから参考手順にないオリジナル手順。dockerdをTLS有効にして起動するためdaemon.jsonを設定します。設定はここを参考にします。

まず各種ファイルをディレクトリに配置します。

$ mkdir /var/docker
$ mv ca.pem /var/docker
$ mv server-cert.pem /var/docker
$ mv server-key.pem /var/docker

daemon.jsonを作成します。(すでにある場合は編集にします。)

$ cat <<EOF > /etc/docker/daemon.json
{
  "tls": true,
  "tlscacert": "/var/docker/ca.pem",
  "tlscert": "/var/docker/server-cert.pem",
  "tlskey": "/var/docker/server-key.pem",
  "hosts": ["tcp://0.0.0.0:2376","unix:///var/run/docker.sock"]
}
EOF

また、上記のようにdaemon.jsonでhostsを指定する場合は/etc/systemd/system/docker.service.d/docker.confを作成しておく必要があります。ネタ元

$ mkdir /etc/systemd/system/docker.service.d/
$ cat <<EOF > /etc/systemd/system/docker.service.d/docker.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd
EOF

上記ファイルを作成したらデーモンリロードしてdockerを起動しなおします。

$ systemctl daemon-reload
$ systemctl restart docker

クライアント設定

以降の手順はクライアントで実施します。

ca.pemcert.pemkey.pemをクライントにコピーします。やり方はお好きな方法でどうぞ。(各種ファイルをcatして中身をクライアントにコピペでもいい。)

資材をクライアントに持って行ったら以下コマンドでリモートのDockerホストに接続できるか確認します。クライアント→Dockerホストでport:2376のインバウンドが許可されていることに注意してください。

$ docker --tlsverify \
    --tlscacert=ca.pem \
    --tlscert=cert.pem \
    --tlskey=key.pem \
    -H=<Dockerホスト①IP>:2376 node ls

上記接続に問題なければ以下コマンドでコンテキストを作成しておきます。名前やhostを変えて他のホストのコンテキストも作っておきます。また、ホストの指定はパブリックDNS名でもよいです。

$ docker context create manager0 --description "remote manager0" --docker "host=tcp://<Dockerホスト①IP>:2376,ca=<ca.pemフルパス>,cert=<cert.pemフルパス>,key=<key.pemフルパス>"
$ docker context create manager1 --description "remote manager1" --docker "host=tcp://<Dockerホスト②IP>:2376,ca=<ca.pemフルパス>,cert=<cert.pemフルパス>,key=<key.pemフルパス>"
$ docker context create manager2 --description "remote manager2" --docker "host=tcp://<Dockerホスト③IP>:2376,ca=<ca.pemフルパス>,cert=<cert.pemフルパス>,key=<key.pemフルパス>"

使用するコンテキストを切り替えます。

$ docker context use manager0

オプションを指定しなくてもリモートのDockerホストにつながることを確認します。

$ docker node ls

動作確認

簡単なcomposeファイルを作成してスタックがデプロイできることを確認します。

$ cat <<EOF > test.yaml
version: "3.9"

services:
  test:
    image: nginx
    deploy:
      replicas: 1
EOF

スタックをデプロイします。

$ docker stack deploy -c test.yaml test

スタックがデプロイできたことを確認します。

$ docker stack ls
$ docker stack services test
$ docker stack ps test

別managerのコンテキストに切り替えても見えることを確認します。

$ docker context use manager1
$ docker node ls
$ docker stack ps test

あとがき

マネージャの前段にLB立ててやる方がカッコいいだろうとなと思いつつ、とりあえず目的は達成できたのでこれで我慢する。

0
1
0

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
0
1