Dockerはサービス起動時に勝手にIPフォワーディングを有効にする

# TL;DR

- Docker上のコンテナがインターネットもしくは他コンテナとIPで通信するにはIPフォワーディングの仕組みを使う。
- dockerd立ち上げ時に `--ip_forward=false` を指定しない場合、デフォルト動作でIPフォワーディングの設定がされてない場合設定をしてくれる。
- ただしdockerd起動後にCentOSで `systemctl restart network` などを行いIPフォワーディングの設定がオフになっても自動でオンに戻ったりはしないので気をつけよう。
  - インターネット接続をするコンテナを動かすサーバーでは `/etc/sysctl.conf` に `net.ipv4.ip_forward = 1` と書いて必ずIPフォワーディングを有効にする、もしくは `--net=host` を指定してホストネットワークを使うなど。

# 背景

先日、Kubernetesクラスターのノードの静的ルーティングを変更する必要があり、ルーティング設定ファイルを編集した後に `systemctl restart network` を行いました。

するとなぜかコンテナからインターネットに接続できなくなり、焦ってOS再起動を行いコンテナを再立ち上げしたところ再びつながるようになりました。

その後 `/var/log/messages` などを調べてみるとnetworkサービスの再起動によりIPフォワーディングの設定がリセットされていたことがわかりました。

# 実験

実際に試してみました。

## 動作確認環境

以下の環境で確認を行いました。

- Ubuntu 18.04 on VirtualBox
- Docker-ce 18.09.4

## 手順

まずdockerdを止めた状態でOSを起動し、IPフォワーディングが無効になっていることを確認します。

```console
$ sudo sysctl -a 2>/dev/null| grep -E 'net.*forward'
net.ipv4.conf.all.forwarding = 0
net.ipv4.conf.all.mc_forwarding = 0
net.ipv4.conf.default.forwarding = 0
net.ipv4.conf.default.mc_forwarding = 0
net.ipv4.conf.enp0s3.forwarding = 0
net.ipv4.conf.enp0s3.mc_forwarding = 0
net.ipv4.conf.lo.forwarding = 0
net.ipv4.conf.lo.mc_forwarding = 0
net.ipv4.ip_forward = 0
net.ipv4.ip_forward_use_pmtu = 0
net.ipv6.conf.all.forwarding = 0
net.ipv6.conf.all.mc_forwarding = 0
net.ipv6.conf.default.forwarding = 0
net.ipv6.conf.default.mc_forwarding = 0
net.ipv6.conf.enp0s3.forwarding = 0
net.ipv6.conf.enp0s3.mc_forwarding = 0
net.ipv6.conf.lo.forwarding = 0
net.ipv6.conf.lo.mc_forwarding = 0
```

確認したらdockerdを起動します。引数に `--ip_forward=false` をつけていない普通の状態で立ち上げます。

```console
$ sudo systemctl start docker

$ sudo sysctl -a 2>/dev/null| grep -E 'net.*forward'
net.ipv4.conf.all.forwarding = 1
net.ipv4.conf.all.mc_forwarding = 0
net.ipv4.conf.default.forwarding = 1
net.ipv4.conf.default.mc_forwarding = 0
net.ipv4.conf.docker0.forwarding = 1
net.ipv4.conf.docker0.mc_forwarding = 0
net.ipv4.conf.enp0s3.forwarding = 1
net.ipv4.conf.enp0s3.mc_forwarding = 0
net.ipv4.conf.lo.forwarding = 1
net.ipv4.conf.lo.mc_forwarding = 0
net.ipv4.ip_forward = 1
net.ipv4.ip_forward_use_pmtu = 0
net.ipv6.conf.all.forwarding = 0
net.ipv6.conf.all.mc_forwarding = 0
net.ipv6.conf.default.forwarding = 0
net.ipv6.conf.default.mc_forwarding = 0
net.ipv6.conf.docker0.forwarding = 0
net.ipv6.conf.docker0.mc_forwarding = 0
net.ipv6.conf.enp0s3.forwarding = 0
net.ipv6.conf.enp0s3.mc_forwarding = 0
net.ipv6.conf.lo.forwarding = 0
net.ipv6.conf.lo.mc_forwarding = 0
```

IPフォワーディングが有効になりました。

UbuntuではCentOSなどのように `sudo systemctl restart network.service` ではなく `sudo systemctl restart systemd-networkd` なので再起動してみたのですが、IPフォワーディング設定はリセットされてないようでした。

なので明示的にオフにしてみます。

```console
$ sudo sysctl -w net.ipv4.ip_forward=0

$ docker run --rm -it alpine
WARNING: IPv4 forwarding is disabled. Networking will not work.
```

IPフォワーディングが無効の状態で立ち上げたコンテナからはインターネットに接続できず、apkパッケージのインストールなどができなくなっていました。

# リンク

- [Networking overview](https://docs.docker.com/network/)
  - [Use bridge networks](https://docs.docker.com/network/bridge/)
  - [Understand container communication](https://docs.docker.com/v17.09/engine/userguide/networking/default_network/container-communication/)
- [Docker on Vagrant（CentOS7）でDockerから外部に出ていけない現象](https://blog.suusuke.info/2018/08/23/docker-on-vagrant%EF%BC%88centos7%EF%BC%89%E3%81%A7docker%E3%81%8B%E3%82%89%E5%A4%96%E9%83%A8%E3%81%AB%E5%87%BA%E3%81%A6%E3%81%84%E3%81%91%E3%81%AA%E3%81%84%E7%8F%BE%E8%B1%A1/)