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

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

CentOS7環境でのDocker Machine/Swarm/Composeのマルチホストネットワークを試す

ここ一週間ほどDocker周辺ツールをいじっていて、 どうせだからマルチホストネットワークの雰囲気も掴んでおこうと試行錯誤していた今日この頃。

blue1st-tech.hateblo.jp

ツールそのものの使い方は把握できたしサクッといけるだろうと高をくくっていたら意外と苦戦してしまった。

結果的にいえば引っかかりどころは

  • CentOS7&firewalld環境において自動で開こうとしては失敗するポートを手動で開けておかなければいけない
  • Docker ComposeのVersion2フォーマットを把握し、単体でのlink機能から置き換える必要がある

あたりだろうか。


そんなわけで、これまで同様にVagrantで検証環境を用意して試してみた。


前提

以下のような環境を対象とする。

  • 既にConsulサーバがネットワーク内で立ち上がっている
  • プロビジョニング対象はCentOS7
  • あくまでfirewalldを使用する


幸いなことに別件である程度使い慣れていたConsul。

blue1st.hateblo.jp

無ければ公式であるようにDockerで立ち上げても良いし、 普通に導入するのもさほど難しくはないだろう。


Docker Machineは本来であれば必要なことを全てお膳立てしてくれるツールなのだが… 残念ながらCentOS7ではそうすんなり行かない。

firewalldを止めてiptablesを使うか、 もしくは予めポートを開けておく必要があるのだ。

blue1st-tech.hateblo.jp

非推奨のツールを使い続けるのは気が進まないわけで、 手動でポートを開ける方を選択した。

(もっともDocker Machine自体netstatが必要だったりするわけだけど)


Vagrant

先にも述べたけどCentOS7を対象としてDocker MachineやSwarmを動かすには、 net-toolsをインストールして必要なポートを開ける必要がある。

この必要なポートというのを調べるのが意外と難儀したんだけど、 結果的に言えば

  • Docker Engine用に2375/tcp、2376/tcp
  • Swarmで他のコンテナとの通信用に4789/udp、7946/tcp、7946/udp
  • Swarm Managerを立ち上げるマシンは更に3376/tcp

あたりを開けておけば良い。

その辺りを加味して下記のように検証環境をセッティングした。

blue1st-tech.hateblo.jp

Vagrant.configure(2) do |config|
  config.vm.box = "CentOS7"
  config.vm.box_url = "https://github.com/holms/vagrant-centos7-box/releases/download/7.1.1503.001/CentOS-7.1.1503-x86_64-netboot.box"

  config.vm.define "master" do |server|
    server.vm.network "private_network", ip: "192.168.33.10"
    server.vm.provision "shell", inline: <<-SHELL
       sudo firewall-cmd --permanent --add-port=3376/tcp
       sudo firewall-cmd --reload
    SHELL
  end
  config.vm.define "node1" do |server|
    server.vm.network "private_network", ip: "192.168.33.11"
  end
  config.vm.define "node2" do |server|
    server.vm.network "private_network", ip: "192.168.33.12"
  end

  config.vm.provision "shell", inline: <<-SHELL
    sudo yum update
    sudo yum install -y net-tools
    sudo firewall-cmd --permanent --add-port=2375/tcp --add-port=2376/tcp --add-port=4789/udp --add-port=7946/tcp --add-port=7946/udp
    sudo firewall-cmd --reload
  SHELL
end

Swarmクラスタ作成

前回同様に192.168.77.6:8500でConsulが動いているという前提で。

マルチホストネットワークのためにengine-opt項が2つほど足されていることに注意。

# master
docker-machine create -d generic --generic-ssh-user vagrant --generic-ssh-key ~/cluster/.vagrant/machines/master/virtualbox/private_key --generic-ip-address 192.168.33.10 --swarm --swarm-master --swarm-discovery consul://192.168.77.6:8500 --engine-opt cluster-store=consul://192.168.77.6:8500 --engine-opt cluster-advertise=eth1:2376 master
#node1
docker-machine create -d generic --generic-ssh-user vagrant --generic-ssh-key ~/cluster/.vagrant/machines/node1/virtualbox/private_key --generic-ip-address 192.168.33.11 --swarm --swarm-discovery consul://192.168.77.6:8500 --engine-opt cluster-store=consul://192.168.77.6:8500 --engine-opt cluster-advertise=eth1:2376 node1
#node2
docker-machine create -d generic --generic-ssh-user vagrant --generic-ssh-key ~/cluster/.vagrant/machines/node2/virtualbox/private_key --generic-ip-address 192.168.33.12 --swarm --swarm-discovery consul://192.168.77.6:8500 --engine-opt cluster-store=consul://192.168.77.6:8500 --engine-opt cluster-advertise=eth1:2376 node2
#switch
eval "$(docker-machine env --shell bash --swarm master)"

Version2フォーマットのdocker-compose.yml

マルチホストネットワークを使うにはVersion2のフォーマットを使うのが良いようだ。

頭にversion: '2'をつけるのと、 ネットワークはnetworks項に定義して用いる。

そしてservices項のそれぞれコンテナのところで定義されたネットワークを指定する。


(もっちょい面白い例を思いつけばよかったんだけど・・・)ひとまずdebianでも動かしてみる。

master固定のコンテナfrontnode1node2用のbackというコンテナを動かしてみる。

environment項にconstrait:nodeを指定することで、コンテナを動かすホストを固定することができる。

version: "2"
services:
  front:
    image: debian:latest
    command: tail -f /dev/null
    environment:
      -  constraint:node==master
    networks: 
     - test
 
  back:
    image: debian:latest
    command: tail -f /dev/null
    environment:
      -  constraint:node==node*
    networks:
      - test

networks:
  test:
    driver: overlay

立ち上げた上でbackを2つに増やしてみる。

docker-compose up -d
docker-compose scale back=2
docker ps

意図通りmasterfrontコンテナ、node1or2backが収まっている。

CONTAINER ID     IMAGE       COMMAND           CREATED         STATUS          PORTS          NAMES
4fd7e89b38aa        debian:latest   "tail -f /dev/null"   7 hours ago     Up 3 seconds                   node2/cluster_back_2
0c28f9134b22        debian:latest   "tail -f /dev/null"   8 hours ago     Up 2 seconds                   node1/cluster_back_1
a5b01227e59a        debian:latest   "tail -f /dev/null"   8 hours ago     Up 4 seconds        192.168.33.10:80->80/tcp    master/cluster_front_1


masterに入って…

docker-compose exec front bash

ひとまずdigでもインストールしてみてbackという名を引くと接続先のIPがかえってくることが確認できる。

apt-get update && apt-get install -y dnsutils 
dig back                       

; <<>> DiG 9.9.5-9+deb8u6-Debian <<>> back
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 21661
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;back.                IN  A

;; ANSWER SECTION:
back.         600 IN  A   10.0.1.4
back.         600 IN  A   10.0.1.3

;; Query time: 0 msec
;; SERVER: 127.0.0.11#53(127.0.0.11)
;; WHEN: Sun May 29 12:40:31 UTC 2016
;; MSG SIZE  rcvd: 62


実際的な例としてはプロキシ用のコンテナなんかを固定のホストでポート開けて動かしておいて、 そこにスケール可能なアプリケーションサーバを接続していくようなイメージになるだろうか。

この辺りの用例はそのうちやってみようと思うところ。



ちょっと前まではlink機能使った環境変数によるコンテナ間連携が"イケてる方法"だったけど、 それではマルチホスト環境の動的な運用には対応しきれないケースも出てくる。

マルチホストネットワークを見据えた上での非推奨だったわけだ。


単一ホストでVersion1フォーマットでの運用とは感覚的に変わってしまう部分が少なからずあって、 前からDocker Composeを使ってた身とするとちょっと戸惑う面もある。

だが、考えてみればホスト名でIP引いてくる形というのはより一般的なネットの方法論なわけで、 例え単一ホスト環境でもこのような方法とVersion2フォーマットに慣れていった方が良さそうな気がする。