Dockerとnet.ipv4.conf.all.forwarding

Docker containerから外部へのアクセスができなくなった時の原因と直し方です。

何が起こったか

centosをリスタートかsystemctl restart network.serviceすると net.ipv4.conf.all.forwarding0 になってしまいます。

$ sysctl net.ipv4.conf.all.forwarding
net.ipv4.conf.all.forwarding = 0

net.ipv4.conf.all.forwarding が0になってしまうとDockerコンテナと外のネットワークのパケットのforwardingができなくなり、外部とのネットワークが繋がらない状態になります。
ドキュメントにも書かれています。

これはDocker imageをbuildするときも同じです。

CIでこれをやってしまい、Docker imageのbuild時にyum installしている部分でネットワークに接続されず、かつ必要なパッケージがインストールされずにDocker imageがbuildされてしまいました。
ログを見ると warning は出ているのですが error ではないためbuildは継続され、正常にDocker imageが作成されます。アプリケーションを実行すると実行に必要なパッケージがインストールされていないため、アプリケーション側でエラーが出ます。

下記はnet.ipv4.conf.all.forwarding が0の状態でDocker buildをした出力の一部です。

3行目で---> [Warning] IPv4 forwarding is disabled. Networking will not work.が出力されていることから、IPv4 forwardingが無効になっていることがわかります。また、 Removing intermediate container c0b08184ced5でもわかるようにbuildは続行されています。

ネットワークエラーでパッケージはインストールされないがDocker buildは続行される

Step 3/5 : RUN yum -y update; yum -y install rsync; yum clean all; yum install -y openssh-clients
---> [Warning] IPv4 forwarding is disabled. Networking will not work.
---> Running in c0b08184ced5
Loaded plugins: fastestmirror, ovl

One of the configured repositories failed (Unknown),
and yum doesn't have enough cached data to continue. At this point the only
safe thing yum can do is fail. There are a few ways to work "fix" this:

1. Contact the upstream for the repository and get them to fix the problem.

2. Reconfigure the baseurl/etc. for the repository, to point to a working
upstream. This is most often useful if you are using a newer
distribution release than is supported by the repository (and the
packages for the previous distribution release still work).

3. Run the command with the repository temporarily disabled
yum --disablerepo= ...

4. Disable the repository permanently, so yum won't use it by default. Yum
will then just ignore the repository until you permanently enable it
again or use --enablerepo for temporary usage:

yum-config-manager --disable
or
subscription-manager repos --disable=

5. Configure the failing repository to be skipped, if it is unavailable.
Note that yum will try to contact the repo. when it runs most commands,
so will have to try and fail each time (and thus. yum will be be much
slower). If it is a very temporary problem though, this is often a nice
compromise:

yum-config-manager --save --setopt=.skip_if_unavailable=true

Cannot find a valid baseurl for repo: base/7/x86_64
Could not retrieve mirrorlist http://mirrorlist.centos.org/?release=7&arch=x86_64&repo=os&infra=container error was
12: Timeout on http://mirrorlist.centos.org/?release=7&arch=x86_64&repo=os&infra=container: (28, 'Resolving timed out after 30544 milliseconds')
Loaded plugins: fastestmirror, ovl

---> d6d1bd8a8271
Removing intermediate container c0b08184ced5

原因

これが発生する原因としては2つあります。

network serviceのscript

起動時のスクリプトでnet.ipv4.ip_forward=0を実行しています。

/etc/init.d/network

...
stop)
sysctl -w net.ipv4.ip_forward=0 > /dev/null 2>&1
...

networkをリスタートした時sysctl -w net.ipv4.ip_forward=0が実行されます。

動作の確認

$ sudo sysctl net.ipv4.conf.all.forwarding=1
net.ipv4.conf.all.forwarding = 1
$ sudo systemctl restart network.service
$ sysctl net.ipv4.conf.all.forwarding
net.ipv4.conf.all.forwarding = 0

/etc/sysctl.conf

/etc/sysctl.confnet.ipv4.ip_forward=0を設定している場合でも0になってしまいます。

/etc/sysctl.conf

net.ipv4.ip_forward=0

動作の確認

$ sudo sysctl net.ipv4.conf.all.forwarding=1
net.ipv4.conf.all.forwarding = 1
$ sudo systemctl restart network.service
$ sysctl net.ipv4.conf.all.forwarding
net.ipv4.conf.all.forwarding = 0

対策

/etc/sysctl.confnet.ipv4.ip_forward=1を設定します。

/etc/sysctl.conf

net.ipv4.ip_forward=1

Docker buildでも問題なくビルドされるので、少し気づきにくい不具合でした。
ホストOSをリスタートしたりnetwork serviceをリスタートするときは設定を確認すると良いかもしれません。