仮想化通信

日本仮想化技術株式会社の公式エンジニアブログ

DockerとMTU設定

通常の使い方ではMTUを設定する必要はありません。ただ、仮想マシンの中でDockerを動かさなければならないとか、そういう時にMTUを変更しないといけない場合があります。

例えばこれはOpenStackインスタンスの中でpingを実行しているところです。コンピュートエンジンとしてはLinux KVM、ネットワークはOVNを使っています。Linuxは特に設定を変更しない限りMTU 1500がデフォルトです。

$ ping -M do -s 1500 -c 4 google.com
PING google.com (142.251.222.46) 1500(1528) bytes of data.
ping: local error: Message too long, mtu=1442
ping: local error: Message too long, mtu=1442
ping: local error: Message too long, mtu=1442
ping: local error: Message too long, mtu=1442

--- google.com ping statistics ---
4 packets transmitted, 0 received, +4 errors, 100% packet loss, time 3071ms

$ ping -M do -s 1412 -c 3 google.com
PING google.com (142.251.42.142) 1412(1440) bytes of data.
1420 bytes from nrt12s45-in-f14.1e100.net (142.251.42.142): icmp_seq=1 ttl=112 time=5.96 ms
1420 bytes from nrt12s45-in-f14.1e100.net (142.251.42.142): icmp_seq=2 ttl=112 time=4.15 ms
1420 bytes from nrt12s45-in-f14.1e100.net (142.251.42.142): icmp_seq=3 ttl=112 time=2.59 ms

--- google.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 2.589/4.233/5.960/1.377 ms

MTUが適切ではないと何が起きるか

例えば上記のような特殊な環境でコンテナーや仮想マシン内で外部との通信が通らなくなります。具体的にいうとpipツールなどでモジュールをインストール、更新するときに接続できなかったり、apt, yum, dnfなどが通らなかったりします。

DockerのデフォルトのインターフェイスのMTUを変更する

Dockerは何も指定しない限り、デフォルトで生成されるdocker0のインターフェイスから外のネットワークを通信します。 このdocker0のMTUを変える方法は次のような方法です。

$ sudo mkdir -p /etc/docker
$ sudo vi /etc/docker/daemon.json
{
  "mtu": 1412  
}

$ sudo systemctl restart docker

$ ip a s docker0
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1412 qdisc noqueue state DOWN group default 
    link/ether 02:42:ac:01:f1:44 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever

MTUが変わりました。 ただ、これでは docker network createで作ったネットワークのMTUは1500のままです。

Docker Networkで作成したインターフェイスのMTUを変更する

すでに作ったネットワークの変更をするのはできないようです。 新しくMTUを指定したDocker Networkを作って、それを使ってコンテナを起動し直しましょう。

ネットワークは次のように作成します(指定するMTUの最適値はpingで確認しましょう)。

docker network create com.docker.network.driver.mtu=1412 yugaplus-network2 

作ったインターフェイスを確認してみると、brとついたインターフェイスが生成されます。docker network createでドライバーを指定しないと生成されるのはブリッジです。ただこのブリッジは仮想マシンでよく使われるLinuxブリッジとは異なり、外部からコンテナーに直接アクセスできるようなインターフェイスではありません。

67: br-20e6136cf94d: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1412 qdisc noqueue state UP group default 
    link/ether 02:42:d0:e1:d0:07 brd ff:ff:ff:ff:ff:ff
    inet 172.19.0.1/16 brd 172.19.255.255 scope global br-20e6136cf94d
       valid_lft forever preferred_lft forever
    inet6 fe80::42:d0ff:fee1:d007/64 scope link 
       valid_lft forever preferred_lft forever

あとは例えばdocker-compose.ymlでこのネットワークを使ってコンテナを実行するようにすれば良いというわけです。 例えばこのような感じですね。

services:
  yugabyte1:
    image: software.yugabyte.com/yugabytedb/yugabyte:2.25.0.0-b489
    restart: unless-stopped
    command: bin/yugabyted start --background=false
    ports:
      - "15433:15433"
      - "5433:5433"
    volumes:
      - yugabyte1-vol:/home/yugabyte/yb_data
    networks:
      - yugaplus-network2
volumes:
  yugabyte1-vol:
networks:
  yugaplus-network2:
    external: true

あとは次のコマンドで起動し直すだけです。

docker compose down 
docker compose up -d

コンテナ作成後に作ったインターフェイスを確認してみると...br-から始まるのがDocker Networkで作ったブリッジ、vethから始まるのが各コンテナーのインターフェイスです。それぞれMTU 1412が割り当てられています。

67: br-20e6136cf94d: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1412 qdisc noqueue state UP group default 
    link/ether 02:42:d0:e1:d0:07 brd ff:ff:ff:ff:ff:ff
    inet 172.19.0.1/16 brd 172.19.255.255 scope global br-20e6136cf94d
       valid_lft forever preferred_lft forever
    inet6 fe80::42:d0ff:fee1:d007/64 scope link 
       valid_lft forever preferred_lft forever
213: veth78d9ada@if212: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1412 qdisc noqueue master br-20e6136cf94d state UP group default 
    link/ether ca:84:dc:bb:fe:94 brd ff:ff:ff:ff:ff:ff link-netnsid 2
    inet6 fe80::c884:dcff:febb:fe94/64 scope link 
       valid_lft forever preferred_lft forever