はじめに
QNAP NASのContainer Stationで動かすDockerコンテナをIPv6対応させたかったので、IPv6対応させるために行った作業についてまとめます。
QNAP NASのDocker Networkについて
QNAP NASのコンテナネットワークはQNAP NASのコンテナサービスとなる「Container Station」と仮想ネットワーク等を管理する「ネットワークと仮想スイッチ」サービスを使ってQNAP NASのコンテナとネットワークは管理されております。
また、QNAP NASではqnet
というDockerの専用ドライバを使用することでQNAP NASが所属するネットワークにNAT、IPマスカレード無しでコンテナを接続することができるため、「Container Station」で作成したDockerコンテナサービスを直接公開することができます。
そのため、私も今までIPv4アドレスを割り振ったサービスをローカルでいくつか公開して使っていたのですが、qnet
ドライバは現状IPv6に対応していないようなので、qnet
ドライバでIPv6に対応したネットワークを作成できませんでした。
調べた結果、qnet
ドライバではIPv6を有効化できませんが、bridge
であればIPv6対応したネットワークを作成することができたため、今回は以下のようなネットワークを作っていきたいと思います。
Docker NetworkでのbridgeタイプのIPv4とIPv6の動作について
Dockerで仮想スイッチを作成する際、bridge
タイプで作成した場合、Dockerコンテナから外のネットワークへの通信はIPマスカレードでの通信となることから、Dockerコンテナに割り振られているIPv4アドレスに対して、外から直接アクセスすることはできません。
但し、現状のDockerのBridgeドライバではIPv6はアドレス変換が行われずに直接ルーティングでアクセスできるようになっております。
アドレス変換を行わずにIPv6ネットワークを使用する方法はbridge
以外でもmacvlan
のドライバを使用する方法もありますが、macvlan
ドライバを使用した場合はコンテナを動作させているホストマシン(今回の例で言うとQNAP NAS)と直接通信することが不可となるため、QNAP NASで実行しているサービスを利用できなくなることから、今回はbridge
ドライバでネットワークを作成しようと思います。
IPv6通信用bridgeネットワークの作成
IPv6を使えるように有効化したbridge
ネットワークを作成します。
IPv6を有効化したbridge
ネットワークは「Container Station」や「ネットワークと仮想スイッチ」からでは作成できないため、QNAP NASにSSH接続を行い、コマンド操作でIPv6対応したbridge
ネットワークを作成します。
docker network create \
--driver bridge \
--scope local \
--opt iface=eth0 \
--ipv6 \
--ipam-opt iface=eth0 \
--ipam-driver default \
--subnet fd00:0:0:2::/64 \
--gateway fd00:0:0:2::1 \
bridge-ipv6-eth0
create後の結果が以下となります。
qnet-static-eth0-fab139
が元々作成済みのIPv4通信用ネットワーク、bridge-ipv6-eth0
がIPv6用に作成したネットワークとなります。
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
c69ee8ec48f0 bridge bridge local
85bee7f2bb05 bridge-ipv6-eth0 bridge local
172cc8f12d59 host host local
3e1cc3fb4df2 none null local
b62342c908aa qnet-static-eth0-fab139 qnet local
今回作成したbridge-ipv6-eth0
はIPv6用なのでIPv4の設定は行いませんでしたが、IPv4を無効化することはできないようなので、作成後docker network inspect
コマンドで確認すると自動でIPv4のネットワークも割り当てられていることが確認できます。
[
{
"Name": "bridge-ipv6-eth0",
"Id": "85bee7f2bb050f984d61db1508172731f44a2ef7ec12539f7ee29006417b2368",
"Created": "2025-07-21T13:48:54.828101226+09:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": true,
"IPAM": {
"Driver": "default",
"Options": {
"iface": "eth0"
},
"Config": [
{
"Subnet": "172.29.0.0/24"
},
{
"Subnet": "fd00:0:0:2::/64",
"Gateway": "fd00:0:0:2::1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {
"iface": "eth0",
"parent": "eth0"
},
"Labels": {}
}
]
Dockerコンテナの作成
IPv6用ネットワークを作成したため、IPv4のネットワークとIPv6のネットワークに接続したDockerコンテナを作成します。
今回はDockerコンテナ上のインタフェースとしては2つのインタフェースを持ち、IPv4通信はqnet
ドライバで作成済みのネットワーク、IPv6通信は先ほど作成したbridge
ドライバで作成したネットワークを使用して通信するように設定します。
Dockerコンテナの作成はQNAP NASにインストールされているContainer Stationで作成しますが、Container Stationの「コンテナ」からは2つのインタフェースを指定したコンテナの作成はできないため、「アプリケーション」からDocker Compose
の形式で2つのインタフェースを設定したコンテナをデプロイします。
以下テスト用に作成したDocker Compose
の例。
services:
docker-test:
image: alpine:latest
container_name: docker-test
hostname: docker-test
restart: always
networks:
qnet-static-eth0-fab139:
ipv4_address: 192.168.30.100
bridge-ipv6-eth0:
ipv6_address: fd00:0:0:2::100
cap_add:
- NET_ADMIN
command: >
/bin/sh -c "
ip route del default &&
ip route add default via 192.168.30.1 &&
while :; do sleep 10; done
"
networks:
qnet-static-eth0-fab139:
external: true
ipam:
config:
- subnet: 192.168.30.0/24
- gateway: 192.168.30.1
bridge-ipv6-eth0:
external: true
enable_ipv6: true
ipam:
config:
- subnet: fd00:0:0:2::/64
- gateway: fd00:0:0:2::1
それぞれのDockerネットワークに接続するためのネットワーク設定(後述で補足)と、コンテナを停止させないようにするためのwhile
ループ設定を入れています。
複数インタフェースが存在する場合のルーティング設定
Dockerコンテナのネットワーク設定は、コンテナ起動時にDHCPで設定されるため、Docker Compose
等で指定すれば自動的にIPやデフォルトゲートウェイが設定されます。
ただ、複数のインタフェースに所属させるような場合のデフォルトゲートウェイ設定は早いもの勝ちになるようで、意図したインタフェースにデフォルトゲートウェイ設定を行うようなことが難しいようです。
今回IPv4に所属するインタフェースが2つあるため、物理ネットワークセグメント側をデフォルトゲートウェイとしたいのですが、Docker Compose
の設定だけではgateway
設定を行わなかった場合であっても仮想ネットワークセグメント側にデフォルトゲートウェイが設定されてしまったため、上記のようにcommand
でルーティング設定を意図的に設定するようにしました。
ルータへのルーティング設定
IPv4通信で使用するインタフェースはqnet
ドライバのネットワークに接続していることから、Dockerホスト側(QNAP NAS)と同じネットワークに接続しているように見えます。
IPv6通信で使用するインタフェースはDockerホスト内に構成されたDockerネットワークに隔離されていることから、Dockerホストがルーティングして内部のDockerコンテナに届ける必要があるため、ルータにルーティング設定を行い、物理ネットワークとDockerネットワーク間で相互に通信できるように設定します。
私の環境では上記の構成図で言うと物理ネットワークセグメント内でヤマハルータを使用しているため、以下のようにゲートウェイをQNAP NASに指定してコマンド設定しました。
ipv6 route fd00:0:0:2::/64 gateway fd00:0:0:1::5%lan1
テスト用Dockerコンテナからの疎通確認
一通り設定が終わったので先程作成したテスト用コンテナに接続して疎通確認してみます。
docker ps # コンテナIDの確認
docker exec -it [先ほど作成したAlpineのコンテナID] /bin/sh
以下、今回作ったテスト用コンテナのIP状態とIPv4/IPv6ルーティングテーブル。
# ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
728: eth1@if729: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP qlen 1000
link/ether 02:42:c2:89:38:2e brd ff:ff:ff:ff:ff:ff
inet 192.168.30.100/24 brd 192.168.30.255 scope global eth1
valid_lft forever preferred_lft forever
730: eth0@if731: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:1d:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.29.0.2/24 brd 172.29.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fd00:0:0:2::100/64 scope global flags 02
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe1d:2/64 scope link
valid_lft forever preferred_lft forever
# ip route show
default via 192.168.30.1 dev eth1
172.29.0.0/24 dev eth0 scope link src 172.29.0.2
192.168.30.0/24 dev eth1 scope link src 192.168.30.100
command
で設定したため、想定通りデフォルトゲートウェイが物理ネットワークセグメント側に向いています。
# ip -6 route show
fd00:0:0:2::/64 dev eth0 metric 256
fe80::/64 dev eth0 metric 256
default via fd00:0:0:2::1 dev eth0 metric 1024
IPv6は物理ネットワークセグメント側(qnet
)ではそもそも有効化していない(できない)ため想定通りデフォルトゲートウェイが仮想ネットワークセグメント側に向いています。
物理ネットワークセグメントに存在するヤマハルータに対して、Dockerコンテナからヤマハルータに疎通確認を行った結果が以下となります。
# ping -c 3 192.168.30.1
PING 192.168.30.1 (192.168.30.1): 56 data bytes
64 bytes from 192.168.30.1: seq=0 ttl=255 time=1.432 ms
64 bytes from 192.168.30.1: seq=1 ttl=255 time=0.221 ms
64 bytes from 192.168.30.1: seq=2 ttl=255 time=0.216 ms
--- 192.168.30.1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.216/0.623/1.432 ms
# ping6 -c 3 fd00:0:0:1::1
PING fd00:0:0:1::1 (fd00:0:0:1::1): 56 data bytes
64 bytes from fd00:0:0:1::1: seq=0 ttl=63 time=0.568 ms
64 bytes from fd00:0:0:1::1: seq=1 ttl=63 time=0.295 ms
64 bytes from fd00:0:0:1::1: seq=2 ttl=63 time=0.307 ms
--- fd00:0:0:1::1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.295/0.390/0.568 ms
ヤマハルータにルーティング設定を行ったことで、IPv4通信は直接物理ネットワークセグメント間で通信、IPv6通信はルーティングで各セグメント間を繋ぐことで想定のネットワーク設定を行うことができました。
おわりに
今回はQNAP NASに搭載されているDockerを使い、IPv6で通信できるように設定を行ってみました。
qnet
ドライバのように、Dockerのネットワークと物理ネットワークを直接IPv6で繋ぐことはできませんでしたが、NAT変換せずにルーティングだけでアクセスすることができるようになりました。
qnet
ドライバがIPv6対応して、QNAP NASが接続している物理ネットワークと直接通信できるようになればネットワーク構成がもう少しシンプルになるため、今後の対応を期待して待とうと思います。