AWS
docker
docker-com

docker networkとAWSのIP帯がかぶったときの話

Retty Advent Calendar 2018 3日目の記事です。
昨日は @tkngue さんの記事で、 Webサービスを支えるユーザログ基盤開発@Retty でした。

はじめに

今年はDocker本を出版したりと割とDockerに絡む機会が多かったのでアドベントカレンダーでもDockerについてのネタを書きます。
今回のネタはdocker-composeでローカルの開発環境を立ち上げたときにAWSのRDSに接続できなかったときの話です。

docker networkとAWSのIP帯がかぶったときの話

顛末

自分は普段からDockerで開発環境を動かしながらローカルディスクの内容をvolume mountさせつつ開発をしてます。
それもあり、docker-composeで開発環境の定義をして up するだけで立ち上がるようにしています。
その時にアプリケーションサーバやRedisなどのサーバはDockerでたてているのですが、データベースだけは共用のAWSにあるRDSインスタンスにつないでいます。

ちょうどこんな感じのイメージです。
IMG_1442.JPG

日々平穏に開発できていたのですが、ある日 docker-compose up -d とやったところコンテナは立ち上がるけれど、アプリケーションサーバからDBサーバに接続がうまくできなくてエラーになってしまうことが起きました。

なんでだろうと調べまくってましたが、周りのメンバーは別に困ってないし、つながっていないのは自分だけでした。
Dockerを使って発生するようになったことだったので、Docker周りのネットワークが怪しいと踏んで調査をしました。

確認したこと

まず対象のRDSインスタンスのプライベートIPをAWSコンソールで確認したところ、 172.aaa.bbb.ccc というアドレスでした。
(RettyではオフィスのネットワークとAWSのネットワークをつないで、172系の一部のプライベートIP(全部じゃないよ!)のAWSのサーバとはオフィスのネットワークからたどり着けるようになっています)

次にDockerのnetworkが利用しているIP帯を調べてみました。

$ docker network ls -q | xargs docker network inspect
[
    {
        "Name": "bridge",
        "Id": "6c89228e028c7125d70ecc6a1754d3e33e5c21fc866c15b94e17b0213741164c",
        "Created": "2018-11-22T11:15:24.003600281Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },

    ・・・中略・・・

        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

上記コマンドを打つと利用しているdocker network帯がずらずらっと出てくるのですが、デフォルトでは利用するのが172系のIPを利用したネットワークが作られてます。
上記の出力の中の Subnet という箇所をgrepするとプライベートIPのサブネット定義がわかります。

出力を確認していったところ、今回はRDSの 172.aaa.bbb.ccc のIPをサブネットに含めてしまうようなネットワークができあがっていました。
つまりRDSに送ろうとしていたネットワークリクエストはdocker networkのほうに吸い込まれて行き場を失い接続に失敗していた、というのが原因でした。

図にするとこんな感じ。

IMG_6097.JPG

解消方法

docker-compose.yml ではdocker networkに関する定義もかけます。
また自分の定義したnetworkに対してサービスを所属させたい場合にはサービスの networks に定義したネットワーク名を指定することで、そのネットワークに所属させることができます。
下記の例でいえば 172.xxx.yyy.0/24 というサブネットに redis と application のサービスが所属した状態で起動できるようになります。

version: '3'

services:
 redis:
   image: redis
   networks:
    - retty
 application:
   image: sample:latest
   ports:
    - "8080:80"
   volumes:
    - .:/srv/apps
   networks:
    - retty

networks:
  retty:
    driver: bridge
    ipam:
      driver: default
      config:
       - subnet: 172.xxx.yyy.0/24

おわりに

最初はなんで接続ができないんだよ!とめっちゃ憤ってましたが、単純に自分が不用意にdocker-composeでnetworkを作りまくってしまっていたせいでした。
今回のこの記事が誰かの助けになれば幸いということで年末の禊としたいと思います :pray: