Dockerコンテナが使用するIPレンジを変更する

環境はCentOS6.x以上もしくはCoreOS。Docker Docsに記載されている内容を実践して、少し知見を付け加えたものです。

前提：Dockerコンテナのネットワーク構成
==============================
Dockerサービスを起動すると自動的に`docker0`と呼ばれるbridgeが作成され、すべてのコンテナはこのブリッジに接続される。

```bash
$ ip a show docker0
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ba:8a:43:a5 brd ff:ff:ff:ff:ff:ff
    inet 172.17.42.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:baff:fe8a:43a5/64 scope link
       valid_lft forever preferred_lft forever
```

`docker0`はホスト側と競合しないIPレンジを自動で引っ張ってきて、自身のIPもそこから割り当てる。コンテナが起動されると、コンテナの`eth0`はveth（Virtual Ethernet）として`docker0`に接続され、先のIPレンジから固有のIPアドレスが付与される。

```bash
$ brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.0242ba8a43a5       no              veth114c2f3
                                                        veth11751c2
                                                        veth34ea7d8
```

```bash
$ docker inspect `docker ps -ql`|grep "IPAddress"
        "IPAddress": "172.17.0.34",
```

`docker0`が使用するIPはランダムではないらしく、動作を見た限りでは基本的に`172.17.42.1/16`が割り当てられている。

コンテナ用IPレンジの変更
==============================
`172.17.0.0/16`が`docker0`に割り当てられると、当然ながらホストOSのルーティングテーブルも書き換わる。`/16`とかなり広いレンジのクラスBアドレスが割り当てられることから、既存ネットワークとの関係でこれが不都合となることは往々にしてある。その場合にはIPレンジを任意のものとすることができる。

追記（2016-06-07）
----
以下手順ではDocker用のブリッジをすべて手動で作成してからDockerを起動しているが、Dockerは起動時にブリッジを自動生成するため、オプションだけでブリッジのIPレンジを変えることができる。`/etc/default/docker`での起動オプションに、`--fixed-cidr=192.168.1.0/25`オプションでコンテナ用IPレンジが指定できる。

参照：[Customize the docker0 bridge](https://docs.docker.com/engine/userguide/networking/default_network/custom-docker0/)

ブリッジの手動作成
--------------------

まず、すでにDockerが起動している場合はサービスを停止し、`docker0`のブリッジを破棄する。

```bash
$ sudo systemctl stop docker
$ sudo ip link set dev docker0 down
$ sudo brctl delbr docker0
```

次に、新たな仮想ブリッジを手動で作成し、コンテナで使用したいIPレンジからIPアドレスを割り当てる。

```bash
$ sudo brctl addbr bridge0
$ sudo ip a add 192.168.1.1/24 dev bridge0
$ sudo ip link set dev bridge0 up
```

Docker起動オプションの設定
--------------------
あとはオプション`-b=bridge0`を与えてDockerサービスを再起動すれば良い話だが、サービス起動時に永続的にオプションを付加させるため、`/etc/default/docker`にこれを追記する。

```bash
$ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker
```

### systemd

さらにCentOS7やCoreOSで、Dockerがsystemd管理下にある場合、unitファイルを編集して`/etc/default/docker`を`EnvironmentFile`に指定する必要がある。

```service:docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.com
After=docker.socket early-docker.target network.target
Requires=docker.socket early-docker.target

[Service]
EnvironmentFile=-/etc/default/docker
MountFlags=slave
LimitNOFILE=1048576
LimitNPROC=1048576
ExecStart=/usr/lib/coreos/dockerd daemon --host=fd:// $DOCKER_OPTS $DOCKER_OPT_BIP $DOCKER_OPT_MTU $DOCKER_OPT_IPMASQ

[Install]
WantedBy=multi-user.target
```

### cloud-config.yml

CoreOSの場合はunitファイルの直接編集ができないため、`cloud-config.yml`の`units`で設定する。

```yaml:cloud-config.yml
#cloud-config
coreos:
  units:
    - name: docker.service
      content: |
        [Unit]
        Description=Docker Application Container Engine
        Documentation=http://docs.docker.com
        After=docker.socket early-docker.target network.target
        Requires=docker.socket early-docker.target

        [Service]
        EnvironmentFile=-/etc/default/docker
        MountFlags=slave
        LimitNOFILE=1048576
        LimitNPROC=1048576
        ExecStart=/usr/lib/coreos/dockerd daemon --host=fd:// $DOCKER_OPTS $DOCKER_OPT_BIP $DOCKER_OPT_MTU $DOCKER_OPT_IPMASQ

        [Install]
        WantedBy=multi-user.target
```

サービス起動。

```bash
# CentOS6.x
$ sudo service docker start
# CentOS7.x
$ sudo systemctl daemon-reload
$ sudo systemctl start docker
# CoreOS
$ sudo coreos-cloudinit --from-file /usr/share/oem/cloud-config.yml
$ sudo systemctl start docker
```


~~TODO~~
==============================
~~ブリッジ作成を手でやってしまったので、起動時に自動生成できないか検討する。~~
先の追記で達成。


参考
==============================

Docker Network
--------------------
* [Advanced networking - Docker Documentation](https://docs.docker.com/v1.5/articles/networking/)
* [Dockerのネットワーク管理とnetnsの関係 - めもめも](http://enakai00.hatenablog.com/entry/20140424/1398321672)

/etc/default/docker
--------------------
* [DOCKER_OPTS do not work in config file /etc/default/docker · Issue #9889 · docker/docker](https://github.com/docker/docker/issues/9889)
* [Configuring and running Docker](https://docs.docker.com/engine/articles/configuring/)

cloud-config.yml
--------------------
* [Customizing docker](https://coreos.com/os/docs/latest/customizing-docker.html)