docker-proxy #02

dockerでサービスを公開する場合、次2パターンがある

  • 通信をコンテナに転送する
  • ホストで動いているdocker-proxyを利用する

後者はdocker-proxyが仲介する分、パフォーマンス的に劣ると思われる。

docker-proxyの無効化は特定のコンテナに対しては行えず、docker-daemonのグローバルなオプション設定になる。

# vi /etc/docker/daemon.json
{
  ~省略~
        "userland-proxy": false
}
# ss -lp | grep docker-proxy
tcp    LISTEN     0    128  *:https   *:*    users:(("docker-proxy",pid=17639,fd=4))
tcp    LISTEN     0    128  *:http    *:*    users:(("docker-proxy",pid=17651,fd=4))
# systemctl restart docker
# docker ps
 ~省略~
# ss -lp | grep docker-proxy
#

IPv6アクセスの場合はdocker-proxyを利用していた場合、IPv6の転送ルールを設定しないとIPv6によるアクセスが行えなくなる。

まずはコンテナのIPv6を有効化する。docker-composeを編集し、コンテナを再起動する。

version: '2.3'
services:
  httpd:
    image: nginx:1.19.0-alpine
    container_name: 'httpd'
    init: true
    networks:
      nw:
        ipv4_address: "192.168.10.10"
        ipv6_address: "fd00:abcd:abcd:abcd::10"
    ports:
      - 80:80/tcp
      - 443:443/tcp
    restart: unless-stopped

networks:
  nw:
    enable_ipv6: true
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet:  "192.168.10.0/24"
          gateway: "192.168.10.1"
        - subnet:  "fd00:abcd:abcd:abcd::/64"
          gateway: "fd00:abcd:abcd:abcd::1"
    driver_opts:
      com.docker.network.bridge.name: docker_httpd

Firewalldにルールを追加する。

# vi ipv6_nat.sh
====================================================
#!/bin/bash -eux
LANG=C
add_chain="firewall-cmd --permanent --direct --add-chain "
add_rule="firewall-cmd  --permanent --direct --add-rule "

### PREROUTING(dnat)
${add_chain} ipv6 nat DOCKER_DNAT
${add_rule}  ipv6 nat DOCKER_DNAT 100 -p tcp --dport 80   -j DNAT --to-destination fd00:abcd:abcd:abcd::10
${add_rule}  ipv6 nat DOCKER_DNAT 110 -p tcp --dport 443  -j DNAT --to-destination fd00:abcd:abcd:abcd::10

${add_rule}  ipv6 nat PREROUTING 100 -i eth0 -j DOCKER_DNAT

### POSTROUTING(snat)
${add_chain} ipv6 nat DOCKER_SNAT
${add_rule}  ipv6 nat DOCKER_SNAT 100 -o eth0 -s fd00:abcd:abcd:abcd::64 -j MASQUERADE

${add_rule}  ipv6 nat POSTROUTING 100 -o eth0 -j DOCKER_SNAT

作成したスクリプトを適用し、コンテナ内部から外部へのIPv6通信確認を行う。今回は公開されているDNSサーバへのpingテストとしている。

# sh ipv6_nat.sh
# firewall-cmd --reload
success
# docker exec -it httpd /bin/sh
/ # ip a | grep fd00
    inet6 fd00:abcd:abcd:abcd::20/64 scope global flags 02
/ #
/ # ping 2606:4700:4700::1111
PING 2606:4700:4700::1111 (2606:4700:4700::1111): 56 data bytes
64 bytes from 2606:4700:4700::1111: seq=0 ttl=55 time=9.830 ms

外部からの通信確認も行う。

# curl -gv "http://[ホストのIPv6アドレス]"
*   Trying ホストのIPv6アドレス:80...
* Connected to ホストのIPv6アドレス (ホストのIPv6アドレス) port 80 (#0)

上手くいかない場合はパケット転送の有効化が出来ているかを確認する。openSUSEの場合はyastから設定可能。

# sysctl -a | grep forward
~省略~
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.all.mc_forwarding = 0
~省略~

v6の転送周りの設定は未だ安定しない感じがする。今回はraspberry pi4+openSUSE Tumbleweedで設定ができたが、同じくopenSUSEのLeapを使っている別サーバではNICの転送設定を行うとDHCPv6がうまく動かなくなり、期待通りの動きをしなかった。