技術備忘記

日々調べたこととかとりとめなく

Docker network周りでハマった話

何をしたか

Docker Swarm + Composeな構成を、VPNなどネットワーク的な制約が幾つかある環境に構築しました。 その際にいくつかハマり、学びがあったので記事にしたいと思います。

バージョンなど

ホストOS

cat /etc/redhat-release 
CentOS Linux release 7.2.1511 (Core) 

docker

docker version
Client:
 Version:      1.11.0
 API version:  1.23
 Go version:   go1.5.4
 Git commit:   4dc5990
 Built:        Wed Apr 13 18:40:36 2016
 OS/Arch:      linux/amd64

Server:
 Version:      1.11.0
 API version:  1.23
 Go version:   go1.5.4
 Git commit:   4dc5990
 Built:        Wed Apr 13 18:40:36 2016
 OS/Arch:      linux/amd64

docker-compose

docker-compose -v
docker-compose version 1.7.0, build 0d7bf73

ハマったこと

  • ネットワークの作成時にsubnetを指定しない時の挙動
  • Docker Composeが隠蔽しているネットワークの作成
  • docker_gwbridgeの利用するネットワーク

よくよく公式ドキュメントを読むと、普通に書いてあることがほとんどですが、きちんと読まず適宜ググりながら作業してしまったため、色々な情報に振り回され結果解決に時間がかかってしまいました。反省。

それぞれ少し補足していきます。

ネットワークの作成時にsubnetを指定しない時の挙動

Docker v1.9から、Dockerが通常使うネットワークのセグメントとは別に、ユーザー独自のネットワークを定義できるようになりました。 おそらく日頃Dockerを触っている方はほとんどご存知だと思いますし、私も存在は知っていました。

ただし、私が構築するシステムでは特に独自ネットワークは必要ないと思い、あまり詳しく追っていませんでした。 (これは大きな間違いでした。後ほど触れます)

で、subnetを指定しない時どうなるか。結論を言ってしまうと、

Dockerがデフォルトで使用するネットワークとは別の、Docker側で用意されているネットワーク領域のうち一つが自動で適用されます。

Dockerが使用するネットワークであるdocker0(デフォルト172.17.0.0/16)が、私の環境では内部LANと競合するのはわかっていたので、予め別のネットワークを割り当てていました。 しかし、自分が予期しないところで作成していたbridgeネットワークがこのルールに適用されたため、 sshが突如繋がらなくなるなど予期しない挙動に苦しまされました。

ちなみに、公式ドキュメントにはこの旨しっかりと記載があります。

Note : It is highly recommended to use the --subnet option when creating a network. If the --subnet is not specified, the docker daemon automatically chooses and assigns a subnet for the network and it could overlap with another subnet in your infrastructure that is not managed by docker. Such overlaps can cause connectivity issues or failures when containers are connected to that network.

せっかくなのでDockerのコードちょっとだけ見ました。

docker/libnetwork/ipamutils/utils.go

var (
    // PredefinedBroadNetworks contains a list of 31 IPv4 private networks with host size 16 and 12
    // (172.17-31.x.x/16, 192.168.x.x/20) which do not overlap with the networks in `PredefinedGranularNetworks`
    PredefinedBroadNetworks []*net.IPNet
    // PredefinedGranularNetworks contains a list of 64K IPv4 private networks with host size 8
    // (10.x.x.x/24) which do not overlap with the networks in `PredefinedBroadNetworks`
    PredefinedGranularNetworks []*net.IPNet

    initNetworksOnce sync.Once
)    

この辺が使われているようです。

Docker Composeが隠蔽しているネットワークの作成

Docker Compose、便利ですよね。 docker-compose up で開発環境を一発で立ち上げたり、docker-compose scale では ホストをまたいだSwarm cluster内でのコンテナの立ち上げを、非常に簡単に行うことができます。

ただし、便利、簡単ゆえにですが、裏側でのネットワークの作成を開発環境等では意識しておらず、前述の環境下でハマりました。

Docker Compose で Swarmクラスタ上にコンテナの立ち上げを行う際には、以下のネットワークが必要になります。

  • {サービス名}_default

    • overlay ネットワーク。swarm manager、nodeを横断して一つ作られる
    • 名前は指定なしの場合。別のネットワークを設定可能。
  • docker_gwbridge

    • bridge ネットワーク。swarm nodeで一つずつ作成される
    • overlay ネットワーク上に所属するコンテナから外部アクセスする際に使用する
    • 複数overlayネットワーク間で共通してこの一つのネットワークが利用される

先ほど大きな間違いだったと述べたのはまさにここで、 Dockerのクラスタを組む、イコール独自ネットワークを作るということに他ならないのです。

何が問題だったかというと、

自動作成される

これらのネットワークは、存在しない場合は自動で作成されます。 便利なのですが、逆にこのネットワークが問題になった時にとてもわかりにくいです。(知ってしまえば簡単ですが)

docker_gwbridgeの利用するネットワーク

docker_gwbridgeはbridgeネットワークなので、ホスト側の設定として反映されます。 存在しない場合デフォルトで作成され、かつ使用するネットワークがDockerに自動で決められるため、環境によっては前述のとおり非常に困ることになります。

言ってしまえば、今回私が苦しんだ原因の9割がこの動きのせいでした・・

docker_gwbridgeのsubnet指定

ところで、docker_gwbridgeは自動で作られてしまうし、subnetはどうやって指定すれば良いのでしょうか。 これはドキュメントにも載っておらず、最後の悩みとなりました。

で、また調べてみると、docker compose scale する前に事前に作っておけとのこと。

github.com

docker network create --opt com.docker.network.bridge.enable_icc=false --subnet={your prefered subnet} docker_gwbridge

※ コメントでは --opts とありましたがtypoだと思われます。

なんともwork aroundな解ですが、overlay networkの仕組みはまだ流動的なようなので、一旦これで良しとしました。

結論

なんだかんだで、公式ドキュメントにしっかりと目を通すことが大事です。 stackoverfl○wやQ○itaに頼りすぎると痛い目を見ます。いやホント・・