Haconiwa + flannel でコンテナ間オーバーレイネットワークを試してみた
こんにちわ。
寒気きびしき折柄、皆様いかがお過ごしですか。
ブログ書くのも1年ぶりなんですが、開発合宿でHaconiwa + flannelを試してみたので、メモのように書き残しておこうと思います。
今回使ったHaconiwaですが、udzuraさんというスーパーエンジニアの方が作ったmruby製コンテナエンジンで、ロリポップマネージドクラウドというサーバーサービスでも利用されています。
flannelは、LinuxのVXLAN機能を用いてオーバーレイネットワークを実現するツールで、Kubernetesと組み合わせて利用されています。
今回この2つを組み合わせて実現するのはこのようなネットワークです。 検証環境
Vagrantfileは、こんな感じで行きます。
Vagrantfileの作成が終わったら、vagrant upしvagrant statusで起動していることを確認します。
起動を確認したら、vagrant ssh をしてnode1,2で設定していきます。
hostsを編集しておきます。
設定が終わったら、etcdを再起動します
member listで確認し、node1,2があれば完了です。
上手くいかない場合は、/var/lib/etcd/default/* を一度削除し、再度etcdの再起動をお試しください。
etcdクラスターの構築は、こちらの記事を参考にさせていただきました。
etcdにflannel用のサブネットを登録します。
node-2からetcdに登録されていることを確認してみます。
flannelと必要なパッケージ類をインストールします。
今回flannelは、v0.10.0 を使用します。
node-1,2 で作業を行います。
/etc/systemd/system/flanneld.service というファイルを作成し、flannelをsystemdに登録します。
flannelを起動させます。
flannelが起動したことを確認します。
ip a コマンドを打つとflannelのIFができているのを確認できます。
また、 etcdctl ls /coreos.com/network/subnets/ でサブネットの確認も可能です。
Haconiwaの使い方は、udzuraさんのこちらの記事を参考にさせていただきました。
Haconiwaのバージョンは、0.9.5 を使用します。
まずは、Haconiwaをインストールします。
node-1,2 で作業を行います。
今回、bootstrapを使用するため、先にインストールしておきます。
Haconiwaが使えるようなったので、hacofileという設定ファイルを作成していきます。
作られた
bootstrap/provisionのブロックを以下のように変更します。
最後のendの前の行に以下を追加します。
container_ip については、flannelのセグメントと同じにしてください。
設定ファイルの編集が終わったら、Haconiwa用のブリッジを作成します。
haconiwa create でDSLに沿ってコンテナのrootfsの作成とプロビジョニングを行います。
ここでコンテナ用のforwarding設定を行います。
では、最後にコンテナを起動してみましょう。
まずは、コンテナ内から外部ともう一台のコンテナに対してpingを打ってみて、そのパケットをtcpdumpで確認してみます。
この通り問題なくパケット通信ができていることが確認できます。
次に、VXLAN(OTV)のポートである8472のUDPで確認してみます。
UDPで確認するのは、VXLANがL2パケットをL3パケット(UDPパケット)にカプセル化して通信するプロトコルだからです。
今後できれば、flannelを使ったオーバーレイネットワークの構築とHaconiwaの起動を自動化しコンテナ同士の専用ネットワーク環境を提供できるようにしてみたいと思っています。
ではでは。
寒気きびしき折柄、皆様いかがお過ごしですか。
ブログ書くのも1年ぶりなんですが、開発合宿でHaconiwa + flannelを試してみたので、メモのように書き残しておこうと思います。
今回使ったHaconiwaですが、udzuraさんというスーパーエンジニアの方が作ったmruby製コンテナエンジンで、ロリポップマネージドクラウドというサーバーサービスでも利用されています。
flannelは、LinuxのVXLAN機能を用いてオーバーレイネットワークを実現するツールで、Kubernetesと組み合わせて利用されています。
今回この2つを組み合わせて実現するのはこのようなネットワークです。 検証環境
- ゲストOS: Ubuntu 16.04.5 LTS
- VirtualBox 5.1.18
- Vagrant 2.1.5
Vagrantfileは、こんな感じで行きます。
# coding: utf-8
# -*- mode: ruby -*-
#
Vagrant.configure(2) do |config|
(1..2).each do |i|
vm_name = "node#{i}"
config.vm.define vm_name do |s|
s.vm.box = "ubuntu/xenial64"
s.vm.hostname = vm_name
private_ip = "172.16.10.#{i+10}"
s.vm.network "private_network", ip: private_ip
s.vm.provider "virtualbox" do |v|
v.gui = false
v.cpus = 2
v.memory = 1024
end
end
end
end
Vagrantfileの作成が終わったら、vagrant upしvagrant statusで起動していることを確認します。
$ vagrant up
$ vagrant status
Current machine states:
node1 running (virtualbox)
node2 running (virtualbox)
起動を確認したら、vagrant ssh をしてnode1,2で設定していきます。
hostsを編集しておきます。
# vim /etc/hosts
127.0.0.1 localhost
172.16.10.11 node1
172.16.10.12 node2
127.0.1.1 ubuntu-xenial ubuntu-xenial
etcdクラスター構築
flannelは、etcdというkvsを使用してサブネットなどのネットワーク情報を共有するため、最初にetcdを入れていきます。apt install -y etcd
node-1,2
の /etc/default/etcd
ファイルを以下のようにします。node1
ETCD_NAME="node1"
ETCD_LISTEN_PEER_URLS="http://172.16.10.11:2380,http://172.16.10.11:7001"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://172.16.10.11:2380"
ETCD_INITIAL_CLUSTER="node1=http://172.16.10.11:2380,node2=http://172.16.10.12:2380"
ETCD_INITIAL_CLUSTER_STATE-"new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_ADVERTISE_CLIENT_URLS="http://172.16.10.11:2379"
node2
ETCD_NAME="node2"
ETCD_LISTEN_PEER_URLS="http://172.16.10.12:2380,http://172.16.10.12:7001"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://172.16.10.12:2380"
ETCD_INITIAL_CLUSTER="node1=http://172.16.10.11:2380,node2=http://172.16.10.12:2380"
ETCD_INITIAL_CLUSTER_STATE-"new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_ADVERTISE_CLIENT_URLS="http://172.16.10.12:2379"
設定が終わったら、etcdを再起動します
# systemctl restart etcd
member listで確認し、node1,2があれば完了です。
# etcdctl member list
e81c3c06663b0f99: name=node1 peerURLs=http://172.16.10.11:2380 clientURLs=http://172.16.10.11:2379
eb58b9faeb1ee792: name=node2 peerURLs=http://172.16.10.12:2380 clientURLs=http://172.16.10.12:2379
上手くいかない場合は、/var/lib/etcd/default/* を一度削除し、再度etcdの再起動をお試しください。
etcdクラスターの構築は、こちらの記事を参考にさせていただきました。
flannel
ここからflannelの構築を行っていきます。etcdにflannel用のサブネットを登録します。
root@node1:~# etcdctl set /coreos.com/network/config '{ "Network": "10.254.0.0/16", "Backend": {"Type": "vxlan"}}'
{ "Network": "10.254.0.0/16", "Backend": {"Type": "vxlan"}}
node-2からetcdに登録されていることを確認してみます。
root@node2:~# etcdctl get /coreos.com/network/config
{ "Network": "10.254.0.0/16", "Backend": {"Type": "vxlan"}}
flannelと必要なパッケージ類をインストールします。
今回flannelは、v0.10.0 を使用します。
node-1,2 で作業を行います。
# apt-get update
# apt-get install -y linux-libc-dev golang gcc
# wget https://github.com/coreos/flannel/releases/download/v0.10.0/flanneld-amd64
# mv flanneld-amd64 /usr/local/bin/flanneld
# chmod 755 /usr/local/bin/flanneld
/etc/systemd/system/flanneld.service というファイルを作成し、flannelをsystemdに登録します。
[Unit]
Description=Flannel daemon
Requires=network-online.target
After=network-online.target
[Service]
Restart=on-failure
ExecStart=/usr/local/bin/flanneld -iface enp0s8
[Install]
WantedBy=multi-user.target
flannelを起動させます。
# systemctl start flanneld.service
# systemctl enable flanneld.service
flannelが起動したことを確認します。
ip a コマンドを打つとflannelのIFができているのを確認できます。
4: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default
link/ether da:28:b8:4a:88:03 brd ff:ff:ff:ff:ff:ff
inet 10.254.68.0/32 scope global flannel.1
valid_lft forever preferred_lft forever
inet6 fe80::d828:b8ff:fe4a:8803/64 scope link
valid_lft forever preferred_lft forever
また、 etcdctl ls /coreos.com/network/subnets/ でサブネットの確認も可能です。
# etcdctl ls /coreos.com/network/subnets/
/coreos.com/network/subnets/10.254.68.0-24
/coreos.com/network/subnets/10.254.96.0-24
これで、flannelの準備は完了です。
Haconiwa
ここから、Haconiwaを使用してコンテナを作成していきます。Haconiwaの使い方は、udzuraさんのこちらの記事を参考にさせていただきました。
Haconiwaのバージョンは、0.9.5 を使用します。
まずは、Haconiwaをインストールします。
node-1,2 で作業を行います。
# wget --content-disposition https://packagecloud.io/udzura/haconiwa/packages/ubuntu/xenial/haconiwa_0.9.5-1_amd64.deb/download.deb
# apt install -y ./haconiwa_0.9.5-1_amd64.deb
今回、bootstrapを使用するため、先にインストールしておきます。
# apt-get install -y debootstrap ssh
Haconiwaが使えるようなったので、hacofileという設定ファイルを作成していきます。
# haconiwa new flannel.haco
assign new haconiwa name = haconiwa-052a9cc3
assign rootfs location = /var/lib/haconiwa/052a9cc3
create flannel.haco
作られた
flannel.haco
は文法としては普通のRubyのスクリプトです。bootstrap/provisionのブロックを以下のように変更します。
config.bootstrap do |b|
b.strategy = "debootstrap"
b.variant = "minbase"
b.debian_release = "stretch"
end
config.provision do |p|
p.run_shell <<-SHELL
apt -y update
apt -y install procps iproute2 ruby iputils-ping net-tools
SHELL
end
最後のendの前の行に以下を追加します。
container_ip については、flannelのセグメントと同じにしてください。
config.cgroup["cpu.cfs_period_us"] = 100000
config.cgroup["cpu.cfs_quota_us"] = 30000
config.cgroup["pids.max"] = 128
config.network.container_ip = "10.254.68.2"
config.network.namespace = config.name
config.network.bridge_name = 'haconiwa0'
config.network.veth_host = veth = "veth#{::SHA1.sha1_hex(config.name)[0, 4]}"
config.network.veth_guest = 'eth0'
config.capabilities.allow 'cap_sys_chroot'
config.capabilities.allow 'cap_net_bind_service'
設定ファイルの編集が終わったら、Haconiwa用のブリッジを作成します。
# haconiwa init --bridge --bridge-ip=10.254.68.1/24
haconiwa create でDSLに沿ってコンテナのrootfsの作成とプロビジョニングを行います。
# haconiwa create flannel.haco
ここでコンテナ用のforwarding設定を行います。
# /sbin/sysctl -w net.ipv4.ip_forward=1
# iptables -t nat -A POSTROUTING -s 10.254.0.0/16 -j MASQUERADE
では、最後にコンテナを起動してみましょう。
$ haconiwa run flannel.haco -T -- /bin/bash
Create lock: #<Lockfile path=/var/lock/.haconiwa-052a9cc3.hacolock>
Container fork success and going to wait: pid=11130
root@haconiwa-052a9cc3:/#
動作確認
最後にICMPレベルでの動作確認をしてみます。まずは、コンテナ内から外部ともう一台のコンテナに対してpingを打ってみて、そのパケットをtcpdumpで確認してみます。
root@haconiwa-052a9cc3:/# ping 8.8.8.8 -c 3
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=61 time=17.5 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=61 time=17.3 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=61 time=17.2 ms
root@node1:/home/ubuntu# tcpdump -tt -n -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on haconiwa0, link-type EN10MB (Ethernet), capture size 262144 bytes
1544288778.536551 IP 10.254.68.2 > 8.8.8.8: ICMP echo request, id 33, seq 1, length 64
1544288778.554063 IP 8.8.8.8 > 10.254.68.2: ICMP echo reply, id 33, seq 1, length 64
1544288779.539363 IP 10.254.68.2 > 8.8.8.8: ICMP echo request, id 33, seq 2, length 64
1544288779.556688 IP 8.8.8.8 > 10.254.68.2: ICMP echo reply, id 33, seq 2, length 64
1544288780.541221 IP 10.254.68.2 > 8.8.8.8: ICMP echo request, id 33, seq 3, length 64
1544288780.558376 IP 8.8.8.8 > 10.254.68.2: ICMP echo reply, id 33, seq 3, length 64
root@haconiwa-052a9cc3:/# ping 10.254.96.2 -c 3
PING 10.254.96.2 (10.254.96.2) 56(84) bytes of data.
64 bytes from 10.254.96.2: icmp_seq=1 ttl=62 time=0.871 ms
64 bytes from 10.254.96.2: icmp_seq=2 ttl=62 time=1.00 ms
64 bytes from 10.254.96.2: icmp_seq=3 ttl=62 time=0.849 ms
root@node1:/home/ubuntu# tcpdump -tt -n -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on haconiwa0, link-type EN10MB (Ethernet), capture size 262144 bytes
1544289287.677196 IP 10.254.68.2 > 10.254.96.2: ICMP echo request, id 34, seq 1, length 64
1544289287.678028 IP 10.254.96.2 > 10.254.68.2: ICMP echo reply, id 34, seq 1, length 64
1544289288.676404 IP 10.254.68.2 > 10.254.96.2: ICMP echo request, id 34, seq 2, length 64
1544289288.677360 IP 10.254.96.2 > 10.254.68.2: ICMP echo reply, id 34, seq 2, length 64
1544289289.677979 IP 10.254.68.2 > 10.254.96.2: ICMP echo request, id 34, seq 3, length 64
1544289289.678692 IP 10.254.96.2 > 10.254.68.2: ICMP echo reply, id 34, seq 3, length 64
この通り問題なくパケット通信ができていることが確認できます。
次に、VXLAN(OTV)のポートである8472のUDPで確認してみます。
UDPで確認するのは、VXLANがL2パケットをL3パケット(UDPパケット)にカプセル化して通信するプロトコルだからです。
root@haconiwa-052a9cc3:/# ping 8.8.8.8 -c 3
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=61 time=18.0 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=61 time=17.2 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=61 time=19.7 ms
root@node1:/home/ubuntu# tcpdump -i enp0s8 udp port 8472
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp0s8, link-type EN10MB (Ethernet), capture size 262144 bytes
root@haconiwa-052a9cc3:/# ping 10.254.96.2 -c 3
PING 10.254.96.2 (10.254.96.2) 56(84) bytes of data.
64 bytes from 10.254.96.2: icmp_seq=1 ttl=62 time=0.721 ms
64 bytes from 10.254.96.2: icmp_seq=2 ttl=62 time=0.903 ms
64 bytes from 10.254.96.2: icmp_seq=3 ttl=62 time=0.416 ms
root@node1:/home/ubuntu# tcpdump -i enp0s8 udp port 8472
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp0s8, link-type EN10MB (Ethernet), capture size 262144 bytes
17:26:38.048623 IP node1.40725 > node2.8472: OTV, flags [I] (0x08), overlay 0, instance 1
IP 10.254.68.0 > 10.254.96.2: ICMP echo request, id 39, seq 1, length 64
17:26:38.049108 IP node2.42908 > node1.8472: OTV, flags [I] (0x08), overlay 0, instance 1
IP 10.254.96.2 > 10.254.68.0: ICMP echo reply, id 39, seq 1, length 64
17:26:39.050556 IP node1.40725 > node2.8472: OTV, flags [I] (0x08), overlay 0, instance 1
IP 10.254.68.0 > 10.254.96.2: ICMP echo request, id 39, seq 2, length 64
17:26:39.051274 IP node2.42908 > node1.8472: OTV, flags [I] (0x08), overlay 0, instance 1
IP 10.254.96.2 > 10.254.68.0: ICMP echo reply, id 39, seq 2, length 64
17:26:40.051365 IP node1.40725 > node2.8472: OTV, flags [I] (0x08), overlay 0, instance 1
IP 10.254.68.0 > 10.254.96.2: ICMP echo request, id 39, seq 3, length 64
17:26:40.051637 IP node2.42908 > node1.8472: OTV, flags [I] (0x08), overlay 0, instance 1
IP 10.254.96.2 > 10.254.68.0: ICMP echo reply, id 39, seq 3, length 64
最後に
今回は、Haconiwaというコンテナとflannelを使ってオーバーレイネットワークを構築し通信が出来ることを確認するところまでやってみました。今後できれば、flannelを使ったオーバーレイネットワークの構築とHaconiwaの起動を自動化しコンテナ同士の専用ネットワーク環境を提供できるようにしてみたいと思っています。
ではでは。