モチベーションと概要
- Dockerのコンテナでも簡単にIPv6でサービスしたい。
- docker composeでIPv4と同じノリでやりたい
- 色んな方法が乱立していてわからない
- 執筆現在で一番楽な方法をまとめた。
- IPv6 NAPT を利用するので、それぞれの信条によっては相容れないかもしれない。
初稿時点(2023年)ではExperimental
な機能を利用しています。
新しめの機能を利用しているため、あなたが読んでる時には仕様が変わっている可能性があります。
環境
# docker --version
Docker version 27.3.1, build ce12230
# uname -r
6.8.0-45-generic
# cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=24.04
DISTRIB_CODENAME=noble
DISTRIB_DESCRIPTION="Ubuntu 24.04.1 LTS"
- 改訂時点(2024/11)でlatestなversionのdocker
手順
後述する"自作bridgeでNAPT法"をベースに、dockerに最近実装された新しい機能を使って、自分でNATルールのケアをしなくて済むようにした...という内容。
1. /etc/docker/daemon.json
: IPv6関連機能を有効化
{
"ipv6": true,
"ip6tables": true,
"userland-proxy": false,
"fixed-cidr-v6": "fd00:ace:cafe:beaf::/80"
}
項目の説明
-
IPv6
:true
にしてコンテナがIPv6を利用するようにする。
-
ip6tables
: IPv4と同様にDNATによるポートフォワーディングを行う。 -
user-land-proxy
: ip6tablesによるDNATを使う場合は通常使われないので、無効化する。 -
fixed-cidr-v6
: default bridge(docker0
)が使うIPv6 prefixを明示的に指定する場合がある。一般的にはULAの使用が推奨される。
しかしにULAはアドレス選択ポリシーでプライベートIPv4アドレスに負けるので1、IPv4を無効化出来ない現状のdocker network実装ではIPv6シングルスタック環境で動作させる時に困る。アドレス選択ポリシーをオーバライドすることも可能ですが、IPv6インターネットで利用されてない別のアドレス2を使う荒業も無きにしもあらず。
おすすめ設定には書いてませんが、よく使われるオプションは下記の通り。
{
"experimental": true,
"default-address-pools": [
{ "base": "fd00:beaf:cafe::/48", "size": 64 }
]
}
-
experimental
: 初稿時点ではexperimentalな機能だったのでflagが必要だったが、本稿改訂時点では不要になったみたい。少し前のバージョンでは必要。 -
"default-address-pools": docker composeや
docker network create --ipv6 MYBRIDGE
でbrdigeを作成する際に、割り当てられるIPv6 ネットワークを変更することができる。指定しない場合、自動的にULAが都度生成される。
2. /etc/sysctl.conf
を編集 IPv6 Forwardingを有効化
IPv4はdockerデーモンが勝手に有効化してくれるが、初稿時点(2023)ではIPv6に関しては自前で有効化する必要があった。
改訂時点(2024/11)では勝手にやってくれるようになっているので、新しい環境では気にしなくても良い。
net.ipv6.conf.all.forwarding = 1
sysctl -p
で有効化
3. docker再起動
systemctl stop docker.socket
systemctl stop docker
systemctl start docker
4. default bridgeにIPv6アドレスがついていることを確認
root@netbox:/opt/netbox-docker# ip addr show docker0 | grep inet6
inet6 "fd00:ace:cafe:beaf::1/80 scope global tentative
inet6 fe80::1/64 scope link tentative
5. 動かしたいアプリのdocker-composeに下記を追加
ここではサービスの例にnginxを挙げている。
version: '3'
services:
nginx:
restart: unless-stopped
image: nginx:latest
ports:
- '80:80'
- '443:443'
networks:
default:
enable_ipv6: true
もし割り当てられるprefixを明示的に指定したい場合、下記のようにする。
networks:
default:
enable_ipv6: true
ipam:
config:
- subnet: fdca:dead:cafe:ace::/80 # 好きなprefix。最低限/112があれば良いはず。
gateway: fdca:dead:cafe:ace::1 # ホスト側につくアドレス
6. 起動して確認
docker compose up -d
dockerデーモンが勝手に、1)outbound用のNAPTルール作成 2) inbound用のDNATルール作成 までやってくれる。
# ip6tables-save -t nat
*nat
:PREROUTING ACCEPT [937:73340]
:INPUT ACCEPT [2:128]
:OUTPUT ACCEPT [137:13412]
:POSTROUTING ACCEPT [930:76752]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -o br-b6440381d435 -m addrtype --src-type LOCAL -j MASQUERADE
-A POSTROUTING -s fdca:dead:cafe:ace::/64 ! -o br-b6440381d435 -j MASQUERADE
-A POSTROUTING -o docker0 -m addrtype --src-type LOCAL -j MASQUERADE
-A POSTROUTING -s fd00:ace:cafe:beaf::1/80 ! -o docker0 -j MASQUERADE
-A POSTROUTING -s fdca:dead:cafe:ace::3/128 -d fdca:dead:cafe:ace::3/128 -p tcp -m tcp --dport 443 -j MASQUERADE
-A POSTROUTING -s fdca:dead:cafe:ace::3/128 -d fdca:dead:cafe:ace::3/128 -p tcp -m tcp --dport 80 -j MASQUERADE
-A DOCKER -p tcp -m tcp --dport 443 -j DNAT --to-destination [fdca:dead:cafe:ace::3]:443
-A DOCKER -p tcp -m tcp --dport 80 -j DNAT --to-destination [fdca:dead:cafe:ace::3]:80
COMMIT
参考情報:これまで筆者がやってきた方法たち
Docker Proxy を利用する方法
- メリット: 楽
- デメリット:
- コンテナ内からIPv6 Internetへのアクセスが出来ない
- IPv6はdockerホスト内のproxy経由で、IPv4は通常はNAPT + ポートフォワード、とプロトコルファミリーによってサービス方法が変わるので直感的でない。
自作bridgeでNAPT法
-
docker network create
で自作bridgeを作成。 - IPv6 NAPT ruleを追加
a. コンテナ -> Internet用のNAPTルール
b. Internet -> コンテナ:特定ポートへのDNATのルール - netfilter-persistent等で保存
- docker-composeで自作bridgeをコンテナにアサイン
- netfilter-persistent等で保存
- メリット:
- コンテナ内からもIPv6 Internetへのアクセスが出来る
- 自作bridgeに割り当てたネットワークプレフィックスによっては、アドレス選択ポリシーの関係でプライベートIPv4アドレスに負ける
- コンテナ内からもIPv6 Internetへのアクセスが出来る
- デメリット:
- NAPTルールが再起動後に綺麗に効くようにするために工夫が必要
その他
NAPTを使わないIPv6らしい方法もあるが、可搬性が良くないのであまりオススメできない。
参考リンク