Dockerコンテナネットワーク

Dockerコンテナのネットワーク設定

コンテナのネットワークについては、3つのオプションbridge,host,noneが用意されています。

$ docker network ls

NETWORK ID          NAME                DRIVER              SCOPE
17e324f45964        bridge              bridge              local
6ed54d316334        host                host                local
7092879f2cc8        none                null                local

bridgeモード

コンテナ稼働時にはデフォルトでbridgeモードが選択されます。bridgeモードではコンテナ専用のネットワークが割り当てられ、ホストマシンのネットワークとは隔離されます。“docker network inspect bridge”“ifconfig” コマンドで割り当てられたIPアドレスなどの確認ができます。

$ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "c0c58b4d39d158XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        "Created": "2019-07-29T16:45:03.528703512+09:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

$ ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::42:53ff:fe85:7593  prefixlen 64  scopeid 0x20<link>
        ether 02:42:53:85:75:93  txqueuelen 0  (イーサネット)
        RX packets 1  bytes 28 (28.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 229  bytes 38983 (38.9 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ユーザ定義のbridgeネットワークを作成することも出来ます。コンテナイメージ毎にbridgeネットワークを定義して、コンテナ稼働時にこのネットワークを指定する使用方法が推奨されているようです。

例)以下alpine-netという名称のbridgeネットワークを定義します。

$ docker network create --driver bridge alpine-net

Dockerネットワークリストにより、bridgeモードにalpine-netが追加されていることが確認できます。

$ docker network ls

NETWORK ID          NAME                DRIVER              SCOPE
e9261a8c9a19        alpine-net          bridge              local
17e324f45964        bridge              bridge              local
6ed54d316334        host                host                local
7092879f2cc8        none                null                local
$ docker network inspect alpine-net

[
    {
        "Name": "alpine-net",
        "Id": "e9261a8c9a19eabf2bf1488bf5f208b99b1608f330cff585c273d39481c9b0ec",
        "Created": "2017-09-25T21:38:12.620046142Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

alpineコンテナイメージをネットワーク指定して以下4種類のコンテナを稼働します。

$ docker run -dit --name alpine1 --network alpine-net alpine ash

$ docker run -dit --name alpine2 --network alpine-net alpine ash

$ docker run -dit --name alpine3 alpine ash

$ docker run -dit --name alpine4 --network alpine-net alpine ash

$ docker network connect bridge alpine4

各コンテナに割り当てられるIPアドレス、異なるbridgeネットワーク間通信については、上記リンク先ドキュメントを参照願います。

hostモード

ホストマシンのネットワーク環境をコンテナに適用します。

例)nginxウェブサーバをホストマシンネットワークで稼働させます。(–rmオプション:コンテナ停止時にコンテナを削除。–dオプション:バックグラウンド動作)

$ docker run --rm -d --network host --name my_nginx nginx

コンテナからホストネットワーク上のMySQLサーバへのアクセス

host=localhostを指定するとコンテナ内でのunix socket経由の接続となるためアクセスは拒否されます。MySQLの設定でbind-address=127.0.0.1になっていることを確認の上、host=127.0.0.1を指定します。

host mode

To access MySQL running on the docker host from containers in host mode , you can keep bind-address = 127.0.0.1 in your MySQL configuration and all you need to do is to connect to 127.0.0.1 from your containers:

[vagrant@docker:~] $ docker run --rm -it --network=host mysql mysql -h 127.0.0.1 -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 36
Server version: 5.5.41-0ubuntu0.14.04.1 (Ubuntu)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

note: Do use mysql -h 127.0.0.1 and not mysql -h localhost ; otherwise the MySQL client would try to connect using a unix socket.

同一ネットワーク内で、あるコンテナからコンテナ稼働のMySQLサーバへアクセスする場合
MySQLコンテナ名をホスト名として指定します。

コンテナがデフォルトのBridgeネットワークを使用した場合、ホストマシン外部への転送(フォワーディング)は拒否されています。ホストマシン外部への転送(フォワーディング)を有効にするため、以下対応が必要です。

Enable forwarding from Docker containers to the outside world

By default, traffic from containers connected to the default bridge network is not forwarded to the outside world. To enable forwarding, you need to change two settings. These are not Docker commands and they affect the Docker host’s kernel.

  1. Configure the Linux kernel to allow IP forwarding.
$ sysctl net.ipv4.conf.all.forwarding=1
  1. Change the policy for the iptables FORWARD policy from DROP to ACCEPT .
$ sudo iptables -P FORWARD ACCEPT

These settings do not persist across a reboot, so you may need to add them to a start-up script.

再起動した場合にも設定が反映されるように起動スクリプトに上記2つのコマンドを追加する必要が有ります。

Docker-Composeで指定した各サービスへIPアドレスを付与する場合

$ docker network create --help

Usage:  docker network create [OPTIONS] NETWORK

Create a network

Options:
      --attachable           Enable manual container attachment
      --aux-address map      Auxiliary IPv4 or IPv6 addresses used by Network driver (default map[])
      --config-from string   The network from which to copy the configuration
      --config-only          Create a configuration only network
  -d, --driver string        Driver to manage the Network (default "bridge")
      --gateway strings      IPv4 or IPv6 Gateway for the master subnet
      --ingress              Create swarm routing-mesh network
      --internal             Restrict external access to the network
      --ip-range strings     Allocate container ip from a sub-range
      --ipam-driver string   IP Address Management Driver (default "default")
      --ipam-opt map         Set IPAM driver specific options (default map[])
      --ipv6                 Enable IPv6 networking
      --label list           Set metadata on a network
  -o, --opt map              Set driver specific options (default map[])
      --scope string         Control the network's scope
      --subnet strings       Subnet in CIDR format that represents a network segment

docker-composeファイル内で各サービスにIPアドレスを付与する場合、gatewayアドレスとサブネットを指定します。
EX)

$ docker network create --gateway 172.16.0.1 --subnet 172.16.0.0/24 nginx-proxy

Docker Compose Ver.2でのネットワークの書式

以下の書式でDocker Compose Ver.2では上記警告が表示されるため修正。

修正前

networks:
  default:
    external: true
    name: my-pre-existing-network
networks:
  default:
    external:
      name: ddev_default

修正後

networks:
  default:
    name: ddev_default
    external: true

コンテナ内部のDNS

デフォルトのコンテナ内部のDNSは、ホストマシンの /etc/resolv.conf の内容を引き継ぎますが特定のDNSを指定する場合には --dns フラグを付与します。

DNS services

またホストマシンの /etc/hosts の内容は反映されないため、コンテナの /etc/hosts に反映させるためには --add-host フラグを付与します。

--add-host

bash-5.0# cat /etc/resolv.conf
nameserver 127.0.0.11
options ndots:0

コンテナIPv6サポート

以下IPv6のサブネット(任意)を指定したデーモン設定ファイルを新規作成し再起動。

/etc/docker/daemon.json

{
  "ipv6": true,
  "fixed-cidr-v6": "2001:db8:1::/64"
}

注) 2001:db8:1::/64 はドキュメント内の例示として使用される予約されたIPアドレス

通常は以下のルール等を用いて作成 (LAN内プリフィックス:FC00::/7

再起動

$ sudo systemctl restart docker

ブリッジモードのIPv6の有効化を確認
注) ホストマシンにルータからIPv6アドレスが割当てられている場合

$ docker network inspect bridge
[
    {
        "Name": "bridge",
        ........
        ........
        "Driver": "bridge",
        "EnableIPv6": true,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                },
                {
                    "Subnet": "2001:db8:1::/64",
                    "Gateway": "2001:db8:1::1"
                }
            ]
        },
.....
.....

IPv4, IPv6対応ブリッジネットワークの作成

Docker Composerで使用するIPv6にも対応したカスタムブリッジネートワークを作成。

$ docker network create --gateway 172.20.0.1 --gateway 2001:db8:1:1::1 --subnet 172.20.0.0/24 --subnet 2001:db8:1:1::0/80 --ipv6 custom_network

注) ホストマシンのデフォルトのブリッジネットワークのサブネットを /64 で割当てたので、カスタムブリッジネットワークに割当てるサブネットは、これより一段低い(16ビット分) /80 とすること。

作成したネットワークの確認

$ docker network inspect custom_network
[
    {
        "Name": "custom_network",
        "Id": "912997c445af3a4718039d304c3b613aa0524659ca17bba5d87b5063a7ca795d",
        "Created": "2023-02-12T22:13:25.210491863+09:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": true,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.20.0.0/24",
                    "Gateway": "172.20.0.1"
                },
                {
                    "Subnet": "2001:db8:1:1::0/80",
                    "Gateway": "2001:db8:1:1::1"
                }
            ]
        },

注) コンテナに上記IPv6に対応したブリッジネットワークを使用する場合、ホスト側でip6tables(nftablesへ移行)によるルールを追加する必要があります。

$ sudo ip6tables -t nat -A POSTROUTING -s  2001:3984:3989::/64 ! -o docker0 -j MASQUERADE

IPv6アドレスの開放ポートの確認


DNS AAAAレコード(IPv6)確認

hostコマンド

$ host -t AAAA google.com
google.com has IPv6 address 2a00:1450:4009:81d::200e

digコマンド

$ dig google.com AAAA

; <<>> DiG 9.16.1-Ubuntu <<>> google.com AAAA
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37561
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;google.com.			IN	AAAA

;; ANSWER SECTION:
google.com.		101	IN	AAAA	2a00:1450:4009:823::200e

;; Query time: 3 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Mon Feb 13 12:18:19 UTC 2023
;; MSG SIZE  rcvd: 67

macvlan-bridge-ipvlan-l2

# IPvlan  (-o ipvlan_mode= Defaults to L2 mode if not specified)
docker network create -d ipvlan \
    --subnet=192.168.1.0/24 \
    -o parent=eth0 db_net_ipv

# Start a container with an explicit name in daemon mode
docker run --net=db_net_ipv --name=ipv1 -itd alpine /bin/sh

# Start a second container and ping using the container name
# to see the docker included name resolution functionality
docker run --net=db_net_ipv --name=ipv2 -it --rm alpine /bin/sh
ping -c 4 ipv1

# NOTE: the containers can NOT ping the underlying host interfaces as
# they are intentionally filtered by Linux for additional isolation.

ufwのIPv6の設定で、以下のフォワードポリシーをデフォルトのドロップからアクセプトに変更するか、特定のアドレス範囲からのフォワードをアクセプトすること。

コンテナ内部からインターネットのIPv6アドレスへのアクセス(ping6コマンドで確認)

以下 daemon.jsonip6tables オプションを追加することで ip6tables による SNAT ルールがDockerデーモン起動時にホストマシンに追加されます。ただし、このオプションは現時点 (Version 23.0.1) では試験的な扱いとなっているようで、 experimental オプションも追加する必要があります。このオプションにより、コンテナ内からIPv6アドレス宛インターネット通信が可能となります。

/etc/docker/daemon.json

{
  "ipv6": true,
  "fixed-cidr-v6": "fd00:ffff::/80",
  "ip6tables": true,
  "experimental": true
}

参考


Dockerデーモンリファレンス