「Docker-proxyでらくらくにIPv6対応しようとしたらいつの間にか出来なくなっていた件」が解決していた件

(自分用の備忘録)

# 2021/04/21: 追記
本問題は2021/04/12にリリースされたDocker version 20.10.6で修正された模様．
やっぱ仕様ではなくバグだった．
ワホーイ

```
Before docker 20.10, published ports were accessible through both IPv4 and IPv6 by default, but the API only included information about the IPv4 (0.0.0.0) 
```

[Docker Engine release note](https://docs.docker.com/engine/release-notes/)

ということでDocker version 20.10.6に上げると解決します．


# やりたいこと 
デュアルスタックのDockerホスト上で、Dockerプロキシを利用してIPv4シングルスタックのDockerコンテナでIPv6のサービスをしたい。

# 共通環境
Ubuntu 20.04

```
# cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.1 LTS"
```

```
# uname -a
Linux server 5.8.0-36-generic #40~20.04.1-Ubuntu SMP Wed Jan 6 10:15:55 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
```



# 期待している挙動

以下のようなdocker-composeで適当なDockerコンテナを起動し、`ports`でポートフォワーディングを実施する。

```yml

version: '3'
services:
  grafana:
    image: grafana/grafana
    ports:
    - 3000:3000
```

コンテナ起動後、該当のポートフォワーディングを行うdocker-proxyプロセスが同時に立ち上がる。

```
root      120970  0.0  0.0 475320  3912 ?        Sl   18:27   0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 3000 -container-ip 172.18.0.4 -container-port 3000

```

- IPv4のトラフィック
iptablesに以下のようなDNATルールが登場するため、docker-proxyプロセスに達する前に処理される。

```
# iptables -t nat -L DOCKER
Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere
RETURN     all  --  anywhere             anywhere
DNAT       tcp  --  anywhere             anywhere             tcp dpt:3000 to:172.18.0.3:3000
```

ちなみに返りのパケットはPOSTROUTINGでIPマスカレードされる

```
# iptables -t nat -L POSTROUTING 

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        anywhere
MASQUERADE  all  --  172.18.0.0/16        anywhere
MASQUERADE  tcp  --  172.18.0.3           172.18.0.3           tcp dpt:3000
MASQUERADE  tcp  --  172.18.0.4           172.18.0.4           tcp dpt:8888

```


- IPv6のトラフィック
IPv6の場合IPv4とは異なりDNATのルールが挿入されず、上述docker-proxyプロセスがL4〜レベルで変換を実施する。


# 実際の挙動

## これまで

確認したバージョン： `Docker version 19.03.14, build 5eb3275d40`

`Type`が`IPv6`になっており、IPv4/IPv6の両方でLISTENすることがわかる。

参考：
[netstatやlsofでLISTENしているアドレスポートが IPv6と表示されてもIPv4でアクセスできる罠
](https://qiita.com/fetaro/items/d5164ba8271114d8a0c8)

```
# lsof -i:3000
COMMAND      PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
docker-pr 120970 root    4u  IPv6 1065660      0t0  TCP *:3000 (LISTEN)

```

## 最近(20.10.6)まで
確認したバージョン： `Docker version 20.10.2, build 2291f61`

`Type`が`IPv4`になっており、IPv4でしかLISTENしていない。
**そのためIPv6でサービス提供が行えていないない**


```
# lsof -i:3000
COMMAND     PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
docker-pr 14845 root    4u  IPv4 6231154      0t0  TCP *:3000 (LISTEN)

```


# 対処方法
Docker versionを20.10.6以降にすると以前(version 19)までの挙動に戻る。
公式ドキュメントを参照して指定したバージョンのdocker-ce, docker-ce-cliをinstallする。

[Install Docker Engine](https://docs.docker.com/engine/install/ubuntu/)

- installできるdocker-ceのバージョンを確認
- 
```
# apt-cache madison docker-ce | head -n 4
 docker-ce | 5:20.10.6~3-0~ubuntu-focal | https://download.docker.com/linux/ubuntu focal/stable amd64 Packages
 docker-ce | 5:20.10.5~3-0~ubuntu-focal | https://download.docker.com/linux/ubuntu focal/stable amd64 Packages
 docker-ce | 5:20.10.4~3-0~ubuntu-focal | https://download.docker.com/linux/ubuntu focal/stable amd64 Packages
 docker-ce | 5:20.10.3~3-0~ubuntu-focal | https://download.docker.com/linux/ubuntu focal/stable amd64 Packages


```

- 現在のdocker-ceをuninstall

```
# apt-get remove docker-ce docker-ce-cli 
```

- 指定したバージョンののdocker-ce, docker-ce-cliをinstall

```
# apt-get install docker-ce=<VERSION_STRING> docker-ce-cli=<VERSION_STRING>  containerd.io
```



# 所感と今後
~~このような仕様変更が行われた経緯に関してはま調べられていないが、**めっちゃ困る**~~
追記： version 20.10.6で修正されました． 
[Docker Engine release note](https://docs.docker.com/engine/release-notes/)