CoreOS + flannel で複数ホスト間コンテナ通信をする

Posted on
qiita Docker CoreOS flannel

この記事はQiitaの記事をエクスポートしたものです。内容が古くなっている可能性があります。

CoreOS が提供する flannel を使って、複数の CoreOS マシンを跨いで Docker コンテナ同士通信できるようにする、というお話です。

flannel

もともと Kubernates には似たようなホスト間通信機能がついていたのですが、Google Compute Engine (GCE) 上でしか使えないという欠点がありました。これを取り出し、汎用的に使えるようにしたのが flannel です。

また、似た機能を持つものに weave がありますが、weave は導入が少々面倒な上に相手ホストの IP を明示的に指定してあげないといけません。その点 flannel は CoreOS 上での導入が簡単で、相手の IP を知らなくてもよく透過的に利用できるという利点があります。ホストに割り振られる IP が不定である EC2 + VPC 構成でも使いやすいでしょう。

イメージ図はこんな感じです。

flannel

(from https://github.com/coreos/flannel/blob/master/packet-01.png)

試してみる

以下で紹介する CoreOS VM を含めたサンプルリポジトリです。あわせてご利用ください: dtan4/coreos-flannel-sample

cloud-config

まず cloud-config はこんな感じです。flanneld.service というのを定義しています。

#cloud-config

coreos:
  etcd:
    discovery: https://discovery.etcd.io/<token>
    addr: $public_ipv4:4001
    peer-addr: $public_ipv4:7001
  fleet:
    public-ip: $public_ipv4
  flannel:
    interface: $public_ipv4
  units:
    - name: etcd.service
      command: start
    - name: fleet.service
      command: start
    - name: flanneld.service
      drop-ins:
        - name: 50-network-config.conf
          content: |
            [Unit]
            Description=flanneld
            After=etcd.service
            Requires=etcd.service

            [Service]
            ExecStartPre=/usr/bin/etcdctl set /coreos.com/network/config '{ "Network": "10.1.0.0/16" }'
      command: start
    - name: docker-tcp.socket
      command: start
      enable: true
      # After(Requires)=flanneld.service を忘れないこと!
      content: |
        [Unit]
        Description=Docker Socket for the API
        After=flanneld.service
        Requires=flanneld.service

        [Socket]
        ListenStream=2375
        Service=docker.service
        BindIPv6Only=both

        [Install]
        WantedBy=sockets.target

注意すべきは、unit の起動順序を etcd -> flannel -> docker とする必要があることです。flannel は etcd にマッピング情報を配置し、Docker は flannel が構築したネットワークの上で動作するためです。


余談ですが、flanneld.service は初回起動時に flannel の Docker イメージを pull してきます。docker.service が起動してないのに変ですね。 これは、flanneld.service の中で独自に Docker (early-docker.service) を起動することで実現しています。 詳しくは Configuring flannel Networking の “Under the Hood” を読んでください。

起動

CoreOS クラスタを立ち上げます。サンプルリポジトリだと2台の CoreOS VM (core-01, core-02) が起動します。

$ vagrant up

立ち上がったらもうひとつターミナルを開き、それぞれのマシンにログインします。

$ vagrant ssh core-01
$ vagrant ssh core-02

両方の VM 上で bash コンテナを立ち上げ、コンテナに割り振られた IP アドレスを確認します(Ubuntu イメージを pull するので多少時間がかかります)。

core@core-01$ docker run -it --rm ubuntu /bin/bash
# 略
root@a46062460b1e:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
8: eth0: <BROADCAST,UP,LOWER_UP> mtu 1472 qdisc noqueue state UP group default
    link/ether 02:42:0a:01:0f:03 brd ff:ff:ff:ff:ff:ff
    inet 10.1.15.3/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:aff:fe01:f03/64 scope link
       valid_lft forever preferred_lft forever
core@core-02$ docker run -it --rm ubuntu /bin/bash
# 略
root@686f6558b05c:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
8: eth0: <BROADCAST,UP,LOWER_UP> mtu 1472 qdisc noqueue state UP group default
    link/ether 02:42:0a:01:51:03 brd ff:ff:ff:ff:ff:ff
    inet 10.1.81.3/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:aff:fe01:5103/64 scope link
       valid_lft forever preferred_lft forever

core-01 上の bash コンテナには 10.1.15.3、core-02 上の bash コンテナには 10.1.81.34 が割り当てられています。 では、それぞれのコンテナからもう一方のマシン上のコンテナに ping を打ってみます。

root@a46062460b1e:/# ping -c 5 10.1.81.3
PING 10.1.81.3 (10.1.81.3) 56(84) bytes of data.
64 bytes from 10.1.81.3: icmp_seq=1 ttl=60 time=0.794 ms
64 bytes from 10.1.81.3: icmp_seq=2 ttl=60 time=0.772 ms
64 bytes from 10.1.81.3: icmp_seq=3 ttl=60 time=1.37 ms
64 bytes from 10.1.81.3: icmp_seq=4 ttl=60 time=1.14 ms
64 bytes from 10.1.81.3: icmp_seq=5 ttl=60 time=1.15 ms

--- 10.1.81.3 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4003ms
rtt min/avg/max/mdev = 0.772/1.048/1.378/0.234 ms
root@686f6558b05c:/# ping -c 5 10.1.15.3
PING 10.1.15.3 (10.1.15.3) 56(84) bytes of data.
64 bytes from 10.1.15.3: icmp_seq=1 ttl=60 time=0.868 ms
64 bytes from 10.1.15.3: icmp_seq=2 ttl=60 time=1.38 ms
64 bytes from 10.1.15.3: icmp_seq=3 ttl=60 time=1.59 ms
64 bytes from 10.1.15.3: icmp_seq=4 ttl=60 time=2.06 ms
64 bytes from 10.1.15.3: icmp_seq=5 ttl=60 time=1.05 ms

--- 10.1.15.3 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4011ms
rtt min/avg/max/mdev = 0.868/1.391/2.065/0.423 ms

お互い、相手ホストのコンテナへの疎通確認ができました。めでたいですね :tada: 以上が flannel を使った複数ホスト間コンテナ通信の例でした。

注意点

flannel は マルチキャストパケットを通さない ので、例えば Elasticsearch の multicast discovery といったものは使えません。ユニキャストは通るのでなんとかして頑張りましょう。

REF