📚

LXCコンテナのネットワーク

2024/05/02に公開

LXCコンテナを作成した時のホストとのネットワークについて

ProxmoxでLXCコンテナを作成した時、lxcのコマンドラインでPID(プロセスID)を知ることができる。下の例だとPID=1329130。
LinkにはNICっぽい名前が入る。下の例だとveth111i0。このveth111i0とホストの関係をネットワークの面で詳しく見ていく。

親ホスト
root@pve1:~# lxc-ls
111  
root@pve1:~# lxc-ls -f
NAME STATE   AUTOSTART GROUPS IPV4           IPV6                                                      UNPRIVILEGED 
111  RUNNING 0         -      192.168.10.103 dead:beef:dead:beef:be24:11ff:febf:ee9b, dd41:1630:f594::81d true         
root@pve1:~# lxc-info 111 
Name:           111
State:          RUNNING
PID:            1329130     ★これ
IP:             192.168.10.103
IP:             dead:beef:dead:beef:be24:11ff:febf:ee9b
IP:             dead:beef:dead:beef::81d
Link:           veth111i0     ★これ
 TX bytes:      70.95 KiB
 RX bytes:      3.59 MiB
 Total bytes:   3.66 MiB

親ホストでは8個のネットワークインターフェイスが見える。

親ホスト
root@pve1:~# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master vmbr0 state UP mode DEFAULT group default qlen 1000
    link/ether b0:41:6f:0b:a4:47 brd ff:ff:ff:ff:ff:ff
3: wlo1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether f4:6d:3f:c2:1e:6f brd ff:ff:ff:ff:ff:ff
    altname wlp2s0
4: vmbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether b0:41:6f:0b:a4:47 brd ff:ff:ff:ff:ff:ff
53: veth111i0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master fwbr111i0 state UP mode DEFAULT group default qlen 1000
    link/ether fe:1c:df:49:ab:21 brd ff:ff:ff:ff:ff:ff link-netnsid 0
54: fwbr111i0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 76:d1:50:8f:33:88 brd ff:ff:ff:ff:ff:ff
55: fwpr111p0@fwln111i0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master vmbr0 state UP mode DEFAULT group default qlen 1000
    link/ether c6:b7:08:c2:2c:91 brd ff:ff:ff:ff:ff:ff
56: fwln111i0@fwpr111p0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master fwbr111i0 state UP mode DEFAULT group default qlen 1000
    link/ether 76:d1:50:8f:33:88 brd ff:ff:ff:ff:ff:ff

そのうち、bridgeは2つ。vmbr0(以下A)とfwbr111i0(以下B)

親ホスト
root@pve1:~# ip link show type bridge
4: vmbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether b0:41:6f:0b:a4:47 brd ff:ff:ff:ff:ff:ff
54: fwbr111i0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 76:d1:50:8f:33:88 brd ff:ff:ff:ff:ff:ff

vethernetは3つ。@の後の文字列で対向がある程度わかる。masterでブリッジがわかる。
veth111i0(B1): bridge fwbr111i0(B)に接続。対向はこの情報だけでは不明(後述するが正体はコンテナ側のeth0)
fwpr111p0(A1): bridge vmbr(A)に接続。対向はB2
fwln111i0(B2): bridge fwbr111i0(B)に接続。対向はA1

親ホスト
root@pve1:~# ip link show type veth
53: veth111i0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master fwbr111i0 state UP mode DEFAULT group default qlen 1000
    link/ether fe:1c:df:49:ab:21 brd ff:ff:ff:ff:ff:ff link-netnsid 0
55: fwpr111p0@fwln111i0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master vmbr0 state UP mode DEFAULT group default qlen 1000
    link/ether c6:b7:08:c2:2c:91 brd ff:ff:ff:ff:ff:ff
56: fwln111i0@fwpr111p0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master fwbr111i0 state UP mode DEFAULT group default qlen 1000
    link/ether 76:d1:50:8f:33:88 brd ff:ff:ff:ff:ff:ff

最初に説明してなかったが、enp1s0(A2)はmaster vmbr0とあるので、これはbridge vmbr0に接続

こんな感じで2つのBridgeがつながっている。A2は物理NICで、外部につながっている。

  +---------------------------------+    +------------------------------------+
  |             vmbr0(A)            |    |             fwbr111i0(B)           |
  +-- enp1s0(A2) -- fwpr111p0(A1) --+    +-- fwln111i0(B2) -- veth111i0(B1) --+
             |            |                         |
external NW--+            +-------------------------+

子コンテナでip linkを実行するとNICは2つ。
loはループバック
eth0は-dをつけると"veth"と出てくるのでvethernet
対向はlink-netnsidが0なので、子コンテナとは別のネットワークネームペースにあり、if53なので、その相手のネットワークネームスペース内でのインデックスが53
今のところコンテナを1個しか作成していないシンプルな構成なのでこれに当てはまるのは親ホストネットワークネームスペースのveth111i0しかないが、もう少しちゃんと見てみる。

子コンテナ
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0@if53: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether bc:24:11:bf:ee:9b brd ff:ff:ff:ff:ff:ff link-netnsid 0
root@docker01:~# ip -d link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0  allmulti 0 minmtu 0 maxmtu 0 addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 tso_max_size 524280 tso_max_segs 65535 gro_max_size 65536 
2: eth0@if53: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether bc:24:11:bf:ee:9b brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 0  allmulti 0 minmtu 68 maxmtu 65535 
    veth addrgenmode eui64 numtxqueues 16 numrxqueues 16 gso_max_size 65536 gso_max_segs 65535 tso_max_size 524280 tso_max_segs 65535 gro_max_size 65536

ネットワークネームスペースはip netns addで作成した場合は名前が付くので識別しやすいし、名前とID(PID)の関連が/var/配下に保存されるのでip netns ...コマンドで操作可能だが、lxcだと名前がつかない
ip netns系のコマンドではほぼ何もわからない。

親ホスト
root@pve1:~# ip netns
root@pve1:~# ip netns list-id 
nsid 0
子コンテナ
root@docker01:~# ip netns
root@docker01:~# ip netns list-id
nsid 0 

調べるにはもう少しプリミティブなlsns(namespace list), nsenter(namespace enter)を使う。

nslsで各種ネームスペースが表示される。

親ホスト
root@pve1:~# lsns
        NS TYPE   NPROCS     PID USER    COMMAND
4026531834 time      312       1 root    /lib/systemd/systemd --system --deserialize=23
4026531835 cgroup    293       1 root    /lib/systemd/systemd --system --deserialize=23
4026531836 pid       293       1 root    /lib/systemd/systemd --system --deserialize=23
4026531837 user      293       1 root    /lib/systemd/systemd --system --deserialize=23
4026531838 uts       289       1 root    /lib/systemd/systemd --system --deserialize=23
4026531839 ipc       293       1 root    /lib/systemd/systemd --system --deserialize=23
4026531840 net       293       1 root    /lib/systemd/systemd --system --deserialize=23
4026531841 mnt       287       1 root    /lib/systemd/systemd --system --deserialize=23
4026532447 mnt         1     538 root    ├─/lib/systemd/systemd-udevd
4026532448 uts         1     538 root    ├─/lib/systemd/systemd-udevd
4026532764 mnt         2    1078 _chrony ├─/usr/sbin/chronyd -F 1
4026532765 uts         2    1078 _chrony ├─/usr/sbin/chronyd -F 1
4026532773 mnt         1 1329110 root    ├─/usr/bin/lxc-start -F -n 111
4026532783 user       19 1329130 100000  │ ├─/sbin/init
4026532784 mnt        17 1329130 100000  │ ├─/sbin/init
4026532785 uts        18 1329130 100000  │ ├─/sbin/init
4026532786 ipc        19 1329130 100000  │ ├─/sbin/init
4026532787 pid        19 1329130 100000  │ ├─/sbin/init
4026532788 cgroup     19 1329130 100000  │ ├─/sbin/init
4026532790 net        19 1329130 100000  │ └─/sbin/init
4026532936 uts         1 1329309 100000  │   ├─/lib/systemd/systemd-logind
4026532937 mnt         1 1329309 100000  │   ├─/lib/systemd/systemd-logind
4026532938 mnt         1 1329317 100998  │   └─/lib/systemd/systemd-networkd
4026532821 uts         1     946 root    ├─/lib/systemd/systemd-logind
4026532823 mnt         1     946 root    └─/lib/systemd/systemd-logind
4026531862 mnt         1      86 root    kdevtmpfs

-t netでネットワークネームスペースがわかる。1行目はPIDが1で親ホスト自体が使っているネットワークネームスペース。
2行目はPIDが1329130で、冒頭のlxc-infoで見たようにコンテナの筆頭プロセス(/sbin/init)のIDになっている。これが子コンテナのネットワークネームスペース。
NETNSIDが0なので、親ホストネットワークネームスペースでのlink-nsid 0はPID 1329130が所属するネットワークネームスペースであるとわかる。

親ホスト
root@pve1:~# lsns -t net
        NS TYPE NPROCS     PID USER      NETNSID NSFS COMMAND
4026531840 net     293       1 root   unassigned      /lib/systemd/systemd --system --deserialize=23
4026532790 net      19 1329130 100000          0      /sbin/init

ターゲットにPIDを指定してnsenterすると、そのネームスペース内でコマンド実行できる。子コンテナでのip linkと同じ出力が見れる。

親ホスト
root@pve1:~# nsenter -t 1329130 -n ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0@if53: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether bc:24:11:bf:ee:9b brd ff:ff:ff:ff:ff:ff link-netnsid 0

子供の方から親の情報を見ることはできない。

子コンテナ
root@docker01:~# lsns
        NS TYPE   NPROCS   PID USER            COMMAND
4026531834 time       20     1 root            /sbin/init
4026532783 user       20     1 root            /sbin/init
4026532784 mnt        18     1 root            /sbin/init
4026532785 uts        19     1 root            /sbin/init
4026532786 ipc        20     1 root            /sbin/init
4026532787 pid        20     1 root            /sbin/init
4026532788 cgroup     20     1 root            /sbin/init
4026532790 net        20     1 root            /sbin/init
4026532936 uts         1   100 root            |-/lib/systemd/systemd-logind
4026532937 mnt         1   100 root            |-/lib/systemd/systemd-logind
4026532938 mnt         1   108 systemd-network `-/lib/systemd/systemd-networkd
root@docker01:~# lsns -t net
        NS TYPE NPROCS PID USER    NETNSID NSFS COMMAND
4026532790 net      20   1 root unassigned      /sbin/init

子供側も追加すると以下のようなネットワークになっている。

[network namespace X (host)]
  +---------------------------------+    +------------------------------------+
  |             vmbr0(A)            |    |             fwbr111i0(B)           |
  +-- enp1s0(A2) -- fwpr111p0(A1) --+    +-- fwln111i0(B2) -- veth111i0(B1) --+
             |            |                         |               |
external NW--+            +-------------------------+               |
====================================================================|=============
[network namespace Y (container)]                                   |
                                                        container:eth0

以下にDockerもインストールした構成について書いています。
https://zenn.dev/takai404/articles/c424552ae8d695

Discussion