Kubernetesなしでdockerを複数台で動かしてみる (flannel編)

このエントリはKubernetesアドベントカレンダー2014の8日目です。

今日はKubernetesの効果を理解するために、Kubernetesなしで構成を組んでみます。 dockerだけで組むのは先日やってみたので、 昨日紹介したflannelを使って実装します。

構成

手元のMacBookAirのVirtualBox上に、CentOS7を2台起動します。

host01上のコンテナにhost02上のコンテナから直接アクセスできるようなれば、Kubernetesのようなアクセス分散が実現できそうです。

  • eth0(NAT): 10.0.2.0/24
  • eth1(Hostonly): 172.16.0.0/16(host01: 172.16.1.1, host02: 172.16.2.1)
  • docker0: flannel全体: 172.17.0.0/16, host01: flannel次第, host02: flannel次第

flannelは各サーバで起動するものなので各サーバに配置、etcdはhost01だけで起動します(Raftが過半数投票でleaderを決める方式なので、2台だと永遠に選出が終わらない模様)。

設定手順

host01

iptablesを全パスにしたら、 nmcli を使ってNetowrkManagerからeth1に対してIPアドレスを設定します。 先日と同様にコネクション名が中途半端に日本語で扱いづらいので、uuidを抽出して利用しています。 ここまでは前回と同じ手順です。

firewall-cmd --set-default-zone=trusted

ETH1_UUID=$(nmcli --fields uuid,device con show | grep -w eth1 | awk '{print $1}')
nmcli con mod ${ETH1_UUID:?} ipv4.method manual ipv4.addresses "172.16.1.1/16"
nmcli con up ${ETH1_UUID:?}

自分の eth1 のIPアドレスを設定したら、etcd(とetcdctl)とflannelをビルドします。

yum -y install golang
yum -y install git

git clone https://github.com/coreos/etcd.git /opt/etcd
cd /opt/etcd
git checkout v0.4.6
./build
cp bin/etcd /usr/local/sbin/.

git clone https://github.com/coreos/etcdctl.git /opt/etcdctl
cd /opt/etcdctl
git checkout v0.4.5
./build
cp bin/etcdctl /usr/local/sbin/.

yum -y install kernel-headers
git clone https://github.com/coreos/flannel.git /opt/flannel
cd /opt/flannel
git checkout v0.1.0
./build
cp bin/flanneld /usr/local/sbin/.

準備ができたら1.etcd、2.flannelの順に起動します。 flannelを起動する前に、etcdctlを使ってflannel用の設定をetcdに投入しておきます。 うまく起動しない場合は /tmp/etcd.log/tmp/flanneld.log を見てみてください。

flannelの起動オプションで、他ホストとIPマスカレードで通信するために -ip-masq=true を、etcdと通信するために -etcd-endpoint=〜 を、flannelが通信するために使う(ネットワークアドレス帯決定にも使う)インターフェイスを -iface=〜 で指定します。

etcd -name=host01 -data-dir=/tmp/etcd -addr=172.16.1.1:4001 -peer-addr=172.16.1.1:7001 >/tmp/etcd.log 2>&1 &
etcdctl mk /coreos.com/network/config '{"Network":"172.17.0.0/16"}'
flanneld -ip-masq=true -etcd-endpoint=http://172.16.1.1:4001 -iface=eth1 >/tmp/flanneld.log 2>&1 &

起動に成功すると、 flannel0 というインターフェイスが作成されてルーティングが設定されます。 そしてその情報が /run/flannel/subnet.env に出力されます。

[root@localhost flannel]# ip addr show flannel0
4: flannel0:  mtu 1472 qdisc pfifo_fast state UNKNOWN qlen 500
    link/none
    inet 172.17.59.0/16 scope global flannel0
       valid_lft forever preferred_lft forever
[root@localhost flannel]# ip route
default via 10.0.2.2 dev eth0  proto static  metric 1024
10.0.2.0/24 dev eth0  proto kernel  scope link  src 10.0.2.15
172.16.0.0/16 dev eth1  proto kernel  scope link  src 172.16.1.1
172.17.0.0/16 dev flannel0  proto kernel  scope link  src 172.17.59.0
[root@localhost flannel]# cat /run/flannel/subnet.env
FLANNEL_SUBNET=172.17.59.1/24
FLANNEL_MTU=1472

この /run/flannel/subnet.env をもとに、dockerの起動オプションに --bip=CIDR (と --mtu=MTU )を指定して、 docker0 が利用するアドレス帯を指定します。 systemdの設定ファイルを書き換えて EnvironmentFile=-/run/flannel/subnet.env 行を追加するのと、 ExecStart の引数に --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU} を追加します。

変更したら daemon-reload して再読み込みしてから起動します。

yum -y install docker
sed -i -r 's@^(ExecStart=.*)@EnvironmentFile=-/run/flannel/subnet.env\n\1 --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}@' /usr/lib/systemd/system/docker.service
systemctl daemon-reload
systemctl start docker.service
[root@localhost ~]# cat /usr/lib/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.io
After=network.target
Requires=docker.socket

[Service]
Type=notify
EnvironmentFile=-/etc/sysconfig/docker
EnvironmentFile=-/etc/sysconfig/docker-storage
EnvironmentFile=-/run/flannel/subnet.env
ExecStart=/usr/bin/docker -d $OPTIONS $DOCKER_STORAGE_OPTIONS --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}
Restart=on-failure
LimitNOFILE=1048576
LimitNPROC=1048576

[Install]
Also=docker.socket
WantedBy=multi-user.target

起動すると docker0 が作成されます。

[root@localhost flannel]# ip addr show docker0
5: docker0:  mtu 1500 qdisc noqueue state DOWN
    link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
    inet 172.17.59.1/24 scope global docker0
       valid_lft forever preferred_lft forever
[root@localhost ~]# ip route
default via 10.0.2.2 dev eth0  proto static  metric 1024
10.0.2.0/24 dev eth0  proto kernel  scope link  src 10.0.2.15
172.16.0.0/16 dev eth1  proto kernel  scope link  src 172.16.1.1
172.17.0.0/16 dev flannel0  proto kernel  scope link  src 172.17.59.0
172.17.59.0/24 dev docker0  proto kernel  scope link  src 172.17.59.1

これでhost01は準備完了です。

host02

host02もhost01と同様に設定します。テキトーにコピペしてIPアドレスなどが重複しないよう気をつけましょう。

firewall-cmd --set-default-zone=trusted

ETH1_UUID=$(nmcli --fields uuid,device con show | grep -w eth1 | awk '{print $1}')
nmcli con mod ${ETH1_UUID:?} ipv4.method manual ipv4.addresses "172.16.2.1/16"
nmcli con up ${ETH1_UUID:?}

自分の eth1 のIPアドレスを設定したら、flannelをビルドします。 (host01でビルド済みのものをコピーしてもよいです)

yum -y install golang
yum -y install git

yum -y install kernel-headers
git clone https://github.com/coreos/flannel.git /opt/flannel
cd /opt/flannel
git checkout v0.1.0
./build
cp bin/flanneld /usr/local/sbin/.

準備ができたらflannelを起動します。 うまく起動しない場合は /tmp/flanneld.log を見てみてください。

flanneld -ip-masq=true -etcd-endpoint=http://172.16.1.1:4001 -iface=eth1 >/tmp/flanneld.log 2>&1 &

起動に成功すると、 flannel0 というインターフェイスが作成されます。 そしてその情報が /run/flannel/subnet.env に出力されます。

[root@localhost flannel]# ip addr show flannel0
4: flannel0:  mtu 1472 qdisc pfifo_fast state UNKNOWN qlen 500
    link/none
    inet 172.17.51.0/16 scope global flannel0
       valid_lft forever preferred_lft forever
[root@localhost flannel]# cat /run/flannel/subnet.env
FLANNEL_SUBNET=172.17.51.1/24
FLANNEL_MTU=1472

systemdの設定ファイルを書き換えて、 daemon-reload して再読み込みしてから起動します。

yum -y install docker
sed -i -r 's@^(ExecStart=.*)@EnvironmentFile=-/run/flannel/subnet.env\n\1 --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}@' /usr/lib/systemd/system/docker.service
systemctl daemon-reload
systemctl start docker.service
[root@localhost flannel]# ip addr show docker0
5: docker0:  mtu 1500 qdisc noqueue state DOWN
    link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
    inet 172.17.51.1/24 scope global docker0
       valid_lft forever preferred_lft forever
[root@localhost ~]# ip route
default via 10.0.2.2 dev eth0  proto static  metric 1024
10.0.2.0/24 dev eth0  proto kernel  scope link  src 10.0.2.15
172.16.0.0/16 dev eth1  proto kernel  scope link  src 172.16.2.1
172.17.0.0/16 dev flannel0  proto kernel  scope link  src 172.17.51.0
172.17.51.0/24 dev docker0  proto kernel  scope link  src 172.17.51.1

動作確認

前回と同じ手順で確認しましょう。

host01

docker run -d -P --name ngx nginx:latest
[root@localhost ~]# docker inspect -f '{{ .NetworkSettings.IPAddress }}' ngx
172.17.59.2

host02

[root@localhost ~]# docker run --rm -it centos:centos7 bash
[root@79917733444f /]# curl -v 172.17.59.2 2>&1 | grep '^<' | head
< HTTP/1.1 200 OK
< Server: nginx/1.7.8
< Date: Sat, 06 Dec 2014 02:35:04 GMT
< Content-Type: text/html
< Content-Length: 612
< Last-Modified: Tue, 02 Dec 2014 13:35:07 GMT
< Connection: keep-alive
< ETag: "547dc00b-264"
< Accept-Ranges: bytes
<

疎通できました!

まとめ

flannelを使うとホスト間通信が楽!


See also