そんな今日この頃の技術ネタ

本家側に書くほどでもない小ネタ用

Docker MachineのGenericドライバでCentOS7にプロビジョニングする時に引っかかったことメモ

docker-machine -v
docker-machine version 0.7.0, build a650a40

にて。

週末に VirtualBoxドライバでdocker-machineなんかの動作を確認

blue1st-tech.hateblo.jp

意外なほどサクッと動いてくれたので意気揚々と出社してみたものの、 いざ 会社の環境(CentOS7サーバ群)でGenericドライバを使って動かそうとするとどうにも上手くいかない

ありがちなところでファイアウォールかと思いfirewalldを止めてみてもダメ、 色々いじった環境だからかと思いクリーンインストール状態のサーバを用意してもらってもダメ。

だが不思議なことに一部のサーバはすんなり動いている。


-Dオプション付けてみてもイマイチ何が引っかかってるのか分からず探し方に問題があったのかググッてもそれらしい情報も見つからずで今週前半はこの問題に頭を悩ませていたのだが、今日ついに解決法に到達!

なんのことはない、CentOS7からは非推奨になりデフォルトでインストールされなくなった net-toolsをyumで入れれば良かった のだ!!

(どうやらdocker-machineが内部的にnetstat使ってるっぽい)

(あと正確には docker-engine用にfirewalldの2376ポートを開ける 必要がある)

ログの情報も断片的だしぐぐってもドンピシャな情報も無かったしで苦労したけど、 ヒントはGithubのissueにあった。英語苦手だけど、こういうことあると勉強しなきゃなーって思わせられるところ。

そんなわけでいうべき内容はもう全部言っちゃったけど、 検証環境づくりとか詳細とか。


Vagrantで検証環境を作成する

実体サーバを用いることを想定し、 VagrantでCentOS7の仮想マシンを用意した上でGenericドライバを用いてクラスタを作る。

Vagrant自体の準備は↓で。

blue1st-tech.hateblo.jp


仮想マシンの作成

ディレクトリの準備

ひとまずホームディレクトリ以下に仮想マシン用のディレクトリを用意する。

便宜的にmaster、node1、node2とする。

mkdir swarm{,/master,/node1,/node2}
cd swarm
tree
.
├── master
├── node1
└── node2


BOXの追加

OSイメージをひとまずダウンロードしておく。

vagrant box add CentOS7 https://github.com/holms/vagrant-centos7-box/releases/download/7.1.1503.001/CentOS-7.1.1503-x86_64-netboot.box


ネットワークの準備

masterの準備をする。

cd master
vagrant init CentOS7
vim Vagrantfile
# private_network項のコメントアウトを外し、任意のIPアドレスに書き換える
vagrant up
vagrant ssh-config
# 項の鍵のパスを確認しておく

node1、node2についても同様の作業を行い、それぞれのIPと鍵のパスをメモっておく。

本記事では下記の値とする。

VM ipアドレス
master 192.168.33.10 ~/swarm/master/.vagrant/machines/default/virtualbox/private_key
node1 192.168.33.11 ~/swarm/node1/.vagrant/machines/default/virtualbox/private_key
node2 192.168.33.12 ~/swarm/node2/.vagrant/machines/default/virtualbox/private_key


☆ Docker Machineのための下準備

VMに入ってdocker-machineのための準備をする。

cd master
vagrant ssh
# 以下VM内での操作
sudo firewall-cmd --permanent --add-port=2376/tcp
sudo yum install -y net-tools
exit
#VMの外に出る

(ここが今回の記事の本題だったんだけど、全体からするとえらいちっちゃい分量…)

同様の操作をnode1、node2についても行う。


Dockerまわり

Docker Machine

いよいよ肝心のDocker Machine。

tokenを使った方法は前回載せたので、今回はネットワーク内のconsulを使用する形で。

httpl://192.168.77.6:8500/ で起動させていて、今回はswarmというキーの下に情報が収まる感じとする。

クラスタの登録

masterをswarm-masterとしてnode1、node2をクラスタとして登録していく。

(若干不安になる程度には時間かかるのでお茶でも飲んで気長にやろう)

docker-machine create -d generic --generic-ip-address=192.168.33.10 --generic-ssh-key ~/swarm/master/.vagrant/machines/default/virtualbox/private_key --generic-ssh-user vagrant --swarm --swarm-master --swarm-discovery consul://192.168.77.6:8500/swarm master
docker-machine create -d generic --generic-ip-address=192.168.33.11 --generic-ssh-key ~/swarm/node1/.vagrant/machines/default/virtualbox/private_key --generic-ssh-user vagrant --swarm --swarm-discovery consul://192.168.77.6:8500/swarm node1
docker-machine create -d generic --generic-ip-address=192.168.33.12 --generic-ssh-key ~/swarm/node2/.vagrant/machines/default/virtualbox/private_key --generic-ssh-user vagrant --swarm --swarm-discovery consul://192.168.77.6:8500/swarm node2


docker-machine lsコマンドで確認。

docker-machine ls
NAME     ACTIVE      DRIVER    STATE     URL                SWARM         DOCKER    ERRORS
master   * (swarm)   generic   Running   tcp://192.168.33.10:2376   master (master)   v1.11.1  
node1    -       generic   Running   tcp://192.168.33.11:2376   master       v1.11.1   
node2    -       generic   Running   tcp://192.168.33.12:2376   master       v1.11.1   

3台の情報を確認できる。


またconsulで指定したキーの箇所も使われていることが見て取れる。

f:id:blue1st:20160527005255p:plain


Swarm Masterに切り替え

クラスタを操作するためにdockerコマンドがmasterに向くように設定。

eval "$(docker-machine env --shell bash --swarm master)"

確認するとクラスタっぽくなってるのが読み取れる。

docker info
略
Nodes: 3
 master: 192.168.33.10:2376
  略
  └ Labels: executiondriver=, kernelversion=3.10.0-229.el7.x86_64, operatingsystem=CentOS Linux 7 (Core), provider=generic, storagedriver=devicemapper
  └ Error: (none)
  └ UpdatedAt: 2016-05-26T14:38:43Z
  └ ServerVersion: 1.11.1
 node1: 192.168.33.11:2376
  略
  └ Labels: executiondriver=, kernelversion=3.10.0-229.el7.x86_64, operatingsystem=CentOS Linux 7 (Core), provider=generic, storagedriver=devicemapper
  └ Error: (none)
  └ UpdatedAt: 2016-05-26T14:38:50Z
  └ ServerVersion: 1.11.1
 node2: 192.168.33.12:2376
  略
  └ Labels: executiondriver=, kernelversion=3.10.0-229.el7.x86_64, operatingsystem=CentOS Linux 7 (Core), provider=generic, storagedriver=devicemapper
  └ Error: (none)
  └ UpdatedAt: 2016-05-26T14:38:32Z
  └ ServerVersion: 1.11.1
  #略

Dockerでコンテナを立ち上げてみる

docker-compose.yml作成

前回同様にnginxを立てることを想定してみる。

nginx:
  image: nginx:latest
  ports:
    - "80:80"

前回言及したようにホスト側のポートを固定してしまうのは本来的にはコンテナ運用の趣旨に反するのだが、 案件的には必要だったりするので一応。


起動

てなわけでとりあえず立ち上げ。

docker-compose up -d

例によって全台でイメージはプルされるっぽい。

Pulling nginx (nginx:latest)...

node2: Pulling nginx:latest...
master: Pulling nginx:latest...
node1: Pulling nginx:latest...
Creating swarm_nginx_1

確認。

docker ps

どうやら今回はnode1が立ち上がったもよう。

CONTAINER ID     IMAGE       COMMAND          CREATED         STATUS      PORTS                   NAMES
4401ce708eeb        nginx:latest    "nginx -g 'daemon off"   21 seconds ago      Up 14 seconds   192.168.33.11:80->80/tcp, 443/tcp   node1/swarm_nginx_1


スケーリング

スケーリング。

docker-compose scale nginx=3

ポートの件警告はされるけど実行してくれる。

WARNING: The "nginx" service specifies a port on the host. If multiple containers for this service are created on a single host, the port will clash.
Creating and starting swarm_nginx_2 ... done
Creating and starting swarm_nginx_3 ... done

確認。

docker ps
CONTAINER ID     IMAGE       COMMAND          CREATED          STATUS          PORTS                   NAMES
851f781a7a42        nginx:latest    "nginx -g 'daemon off"   About a minute ago   Up About a minute   192.168.33.10:80->80/tcp, 443/tcp   master/swarm_nginx_3
33c702157492        nginx:latest    "nginx -g 'daemon off"   About a minute ago   Up About a minute   192.168.33.12:80->80/tcp, 443/tcp   node2/swarm_nginx_2
4401ce708eeb        nginx:latest    "nginx -g 'daemon off"   2 minutes ago        Up 2 minutes    192.168.33.11:80->80/tcp, 443/tcp   node1/swarm_nginx_1

ちゃんと分配されることが確認できる。


ポート固定で台数以上を指定しちゃった場合。

 docker-compose scale nginx=4

当然エラー。

WARNING: The "nginx" service specifies a port on the host. If multiple containers for this service are created on a single host, the port will clash.
Creating and starting swarm_nginx_4 ... error

ERROR: for swarm_nginx_4  Unable to find a node that satisfies the following conditions 
[port 80 (Bridge mode)]

ちなみにホスト側のポートを指定しなければ勝手にポート番号が変わって開く。

consulとか使って動的にプロキシの設定を変更するとかマルチホストネットワークでゴニョゴニョとかありそうだけど、 今回の案件的にはいらない要素だったのでそこまでは調べてない。

docs.docker.com

docs.docker.com

このへんはそのうち。


折角なんで色々

起動するホストを明示したりしてみる。

web-mst:
  image: nginx:latest
  environment:
    - "constraint:node==master"
web-api:
  image: nginx:latest
  environment:
    - "constraint:node==node*"
web-usr:
  image: nginx:latest
  environment:
    - "constraint:node==node*"
docker-compose up -d
Creating swarm_web-usr_1
Creating swarm_web-api_1
Creating swarm_web-mst_1
docker ps
CONTAINER ID     IMAGE       COMMAND          CREATED          STATUS          PORTS           NAMES
372204dbd280        nginx:latest    "nginx -g 'daemon off"   About a minute ago   Up 53 seconds   80/tcp, 443/tcp     node2/swarm_web-api_1
a513761b8d0d        nginx:latest    "nginx -g 'daemon off"   About a minute ago   Up 46 seconds   80/tcp, 443/tcp     node1/swarm_web-usr_1
a8ca9785e70f        nginx:latest    "nginx -g 'daemon off"   About a minute ago   Up 51 seconds   80/tcp, 443/tcp     master/swarm_web-mst_1


サービスごとにスケール数を変えてみる。

docker-compose scale web-api=4 web-usr=5 web-mst=2
Creating and starting swarm_web-api_2 ... done
Creating and starting swarm_web-api_3 ... done
Creating and starting swarm_web-api_4 ... done
Creating and starting swarm_web-usr_2 ... done
Creating and starting swarm_web-usr_3 ... done
Creating and starting swarm_web-usr_4 ... done
Creating and starting swarm_web-usr_5 ... done
Creating and starting swarm_web-mst_2 ... done
docker ps
CONTAINER ID     IMAGE       COMMAND          CREATED         STATUS      PORTS           NAMES
ae15a4e493ae        nginx:latest    "nginx -g 'daemon off"   21 seconds ago      Up 16 seconds   80/tcp, 443/tcp     master/swarm_web-mst_2
b10b639b5a92        nginx:latest    "nginx -g 'daemon off"   41 seconds ago      Up 25 seconds   80/tcp, 443/tcp     node2/swarm_web-usr_4
e153d6aeae7d        nginx:latest    "nginx -g 'daemon off"   41 seconds ago      Up 26 seconds   80/tcp, 443/tcp     node2/swarm_web-usr_3
01e700d25ab4        nginx:latest    "nginx -g 'daemon off"   41 seconds ago      Up 21 seconds   80/tcp, 443/tcp     node1/swarm_web-usr_5
d0df4789fbc1        nginx:latest    "nginx -g 'daemon off"   41 seconds ago      Up 24 seconds   80/tcp, 443/tcp     node1/swarm_web-usr_2
67f9d9ab3f73        nginx:latest    "nginx -g 'daemon off"   54 seconds ago      Up 40 seconds   80/tcp, 443/tcp     node2/swarm_web-api_4
5cf4430e86e7        nginx:latest    "nginx -g 'daemon off"   54 seconds ago      Up 42 seconds   80/tcp, 443/tcp     node1/swarm_web-api_3
7a21657ab3ee        nginx:latest    "nginx -g 'daemon off"   54 seconds ago      Up 40 seconds   80/tcp, 443/tcp     node2/swarm_web-api_2
372204dbd280        nginx:latest    "nginx -g 'daemon off"   3 minutes ago       Up 3 minutes    80/tcp, 443/tcp     node2/swarm_web-api_1
a513761b8d0d        nginx:latest    "nginx -g 'daemon off"   3 minutes ago       Up 3 minutes    80/tcp, 443/tcp     node1/swarm_web-usr_1
a8ca9785e70f        nginx:latest    "nginx -g 'daemon off"   3 minutes ago       Up 3 minutes    80/tcp, 443/tcp     master/swarm_web-mst_1

指定通り、web-mstはmasterでのみ、それ以外はnodeで分散されていることが確認できる。


掃除

Docker側

docker-compose kill
eval "$(docker-machine env -u)"
docker-machine rm master node1 node2


Consul側

WebUI上からswarmのキーを削除。


Vagrant側

cd master #それぞれのディレクトリで
vagrant halt
vagrant destory #もうイメージいらないなら


まとめ

そんなこんなでちょっと本題以外の分量が多くなっちゃったけど、一応まとめ。

CentOS7が入った実機でクラスタリングしたい場合には

  1. ちゃんとグローバルネットワークに接続できる
  2. 既存のDocker(Engineじゃない)関連のパッケージをアンインストール(yum remove docker*とかで)
  3. sudoがパスワードなしでできる操作アカウントを用意(generic-ssh-userで指定する)
  4. 3のユーザでsshアクセス可能な鍵を用意
  5. 予めnet-toolsをインストール
  6. 予めdocker-engine用に2376ポート(任意に変更は可能)を開けておく

といった手順を踏めば良さそう。



今回はVM全部にベタに操作していったけど、本来ならイメージをコピーして必要な箇所だけ変えるとかで実験も時短できたかもしれない。

この辺はまだ僕のVagrant力が足りないところなんで、今後学んでいきたいところ。

プログラマのためのDocker教科書 インフラの基礎知識&コードによる環境構築の自動化

プログラマのためのDocker教科書 インフラの基礎知識&コードによる環境構築の自動化

実践 Vagrant

実践 Vagrant

追記

やりようはあったようだ。

blue1st-tech.hateblo.jp