Metonymical Deflection

ゆるく日々のコト・たまにITインフラ

LXC/LXDコンテナのネットワーク設定方法

前々回の続きとなります。
前々回:CentOS7でLXC/LXDのコンテナ環境構築 - Metonymical Deflection

また、前回の内容が理解できていることを前提として記載します。
前回:Linux nmcliコマンドによるBonding VLAN Bridge Interface設定 - Metonymical Deflection

LXC/LXDコンテナは「LightweightなKVM」というイメージで使用しています。
このため、コンテナのトラフィックをBridgeで外部ネットワークに流して使用する場合の設定方法を記載したいと思います。

1.環境

1-1.VMWare
筐体                             : 自作PC
CPU                           : Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz
VMWare              : VMware(R) Workstation 12 Pro 12.5.9 build-7535481  
OS                               : CentOS7.5(1804)
Kernel                           : 3.10.0-862.el7.x86_64
Installed Environment Groups     : Minimal Install

WinおよびVMWare環境は以下の画像で確認してもらった方が良いかもしれません。
Win環境
f:id:metonymical:20180529200243j:plain
VMWare環境
f:id:metonymical:20181027233404p:plain
前々回の記事に加えてNICを追加していますが、実際に使用するのはトータル3つです。
具体的には以下の通りです。
仮想ネットワークエディタ
f:id:metonymical:20181027233530p:plain
ネットワーク接続
f:id:metonymical:20181027233605p:plain
Intel I219のプロパティ
f:id:metonymical:20181027233641p:plain
WindowsによるVLAN Interface設定方法は過去記事を参照ください。
metonymical.hatenablog.com

なお、ベアメタル環境でも同様に設定可能です。

1-2.全体構成

f:id:metonymical:20181027235006j:plain
上図のうちlxdbr0はLXD init時にDefaultで作成されています。
また、Default Profileの設定よりコンテナ作成時にlxdbr0が使用されるように構成されています。

但し、lxdbr0はNATして外部ネットワークに接続されています。私の用途としては、コンテナ上でyumなどを行いたい場合のInternet接続用マネジメントインターフェースとして使用しています。

しかし、KVMライクにLXC/LXDコンテナを使用したいので、今回行う設定は(1)~(2)となります。

具体的には新規でBridge lxdbr30を作成し、コンテナlxc751を収容します。
(1)はnmcliコマンドでも設定可能ですが、ここではlxc networkコマンドを使用して設定を行っていきます。

なお、前々回の続きという想定なので、lxc751というコンテナは既に作成済みという認識で進めます。

1-2.全体の流れ ~概要~
  1. DHCPによるIP固定設定の場合:(1)(2)
  2. 手動によるIP固定設定の場合:(1)(2)

 ※
 流れというよりも、それぞれ別々の設定となります。

1-3.全体の流れ ~コマンドのみ~

以下のコマンドを投入していきます。
やりたいことが既に決まっている方は、構成図とコマンドの内容を見るだけでもよいと思います。

1.DHCPによるIP固定設定の場合
(1)
lxc network create lxdbr30 \
bridge.external_interfaces=ens34 \
ipv4.address=192.168.30.16/24 \
ipv6.address=none
(2)
lxc network attach lxdbr30 lxc751 eth1
lxc config device set lxc751 eth1 ipv4.address 192.168.30.48
lxc start lxc751
lxc exec lxc751 dhclient eth1
lxc list

lxc exec lxc751 cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth1
lxc exec lxc751 vi /etc/sysconfig/network-scripts/ifcfg-eth1
:s/eth0/eth1/g
:wq
lxc exec lxc751 cat /etc/sysconfig/network-scripts/ifcfg-eth1
lxc restart lxc751
lxc list

2.手動によるIP固定設定の場合
(1)
lxc network create lxdbr30 \
bridge.external_interfaces=ens34 \
ipv4.address=none \
ipv6.address=none
(2)
lxc network attach lxdbr30 lxc751 eth1
lxc start lxc751
lxc exec lxc751 cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth1
lxc exec lxc751 vi /etc/sysconfig/network-scripts/ifcfg-eth1
:s/eth0/eth1/g
:s/dhcp/none/g
IPADDR=192.168.30.48  #追記
PREFIX=24        #追記
:wq
lxc exec lxc751 cat /etc/sysconfig/network-scripts/ifcfg-eth1
lxc restart lxc751
lxc list

2.DHCPによるIP固定設定の場合

物理インターフェースとBridgeインターフェースを1対1でアサインします。
nmcliよりもコマンド数は少ないです
(1)Bridgeインターフェースlxdbr30の作成+ens34をlxdbr30にアタッチ*1
(2)lxdbr30にコンテナlxc751のeth1をアタッチ+IP設定

(1)Bridgeインターフェースlxdbr30の作成+ens34をlxdbr30にアタッチ

投入コマンド
lxc network create lxdbr30 \
bridge.external_interfaces=ens34 \
ipv4.address=192.168.30.16/24 \
ipv6.address=none

出力例
[root@c756 ~]# lxc network create lxdbr30 \
> bridge.external_interfaces=ens34 \
> ipv4.address=192.168.30.16/24 \
> ipv6.address=none
Network lxdbr30 created
[root@c756 ~]# lxc network list
+---------+----------+---------+-------------+---------+
|  NAME   |   TYPE   | MANAGED | DESCRIPTION | USED BY |
+---------+----------+---------+-------------+---------+
| ens33   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens34   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens37   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens38   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens39   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens40   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| lxdbr0  | bridge   | YES     |             | 1       |
+---------+----------+---------+-------------+---------+
| lxdbr30 | bridge   | YES     |             | 0       |
+---------+----------+---------+-------------+---------+
[root@c756 ~]# lxc network show lxdbr30
config:
  bridge.external_interfaces: ens34
  ipv4.address: 192.168.30.16/24
  ipv6.address: none
description: ""
name: lxdbr30
type: bridge
used_by: []
managed: true
status: Created
locations:
- none

lxdbr30が作成され、物理インターフェースens34にもアタッチされました。
また、コンテナに対してDHCPIPアドレス割り当てを行うため、lxdbr30自身にもIPアドレスを設定しています。

(2)lxdbr30にコンテナlxc751のeth1をアタッチ+IP設定

投入コマンドその1
lxc network attach lxdbr30 lxc751 eth1
lxc config device set lxc751 eth1 ipv4.address 192.168.30.48
lxc start lxc751
lxc exec lxc751 dhclient eth1

出力例
[root@c756 ~]# lxc network attach lxdbr30 lxc751 eth1
[root@c756 ~]# lxc config device set lxc751 eth1 ipv4.address 192.168.30.48
[root@c756 ~]# lxc start lxc751
[root@c756 ~]# lxc exec lxc751 dhclient eth1
[root@c756 ~]# lxc list
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
|  NAME   |  STATE  |         IPV4         |                     IPV6                     |    TYPE    | SNAPSHOTS |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
| lx75mas | STOPPED |                      |                                              | PERSISTENT |           |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
| lxc751  | RUNNING | 192.168.30.48 (eth1) | fd42:d3a:78c6:6d8c:216:3eff:fe8f:a6c3 (eth0) | PERSISTENT |           |
|         |         | 10.106.42.75 (eth0)  |                                              |            |           |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+

lxdbr30にコンテナlxc751のeth1をアタッチし、コンテナのIP設定を行っています。
その後コンテナを起動し、lxc751のeth1上でdhclientコマンドを実行しています。
「コンテナのIP設定」と記載しましたが厳密には異なります。
これは、LXDの管理下におかれているlxdbr30に対して、DHCP固定IP 設定を行っています。
なお、上記コマンドの場合、恒久設定ではないためコンテナ上で設定ファイルを作成します。

投入コマンドその2
lxc exec lxc751 cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth1
lxc exec lxc751 vi /etc/sysconfig/network-scripts/ifcfg-eth1
:s/eth0/eth1/g
:wq
lxc exec lxc751 cat /etc/sysconfig/network-scripts/ifcfg-eth1
lxc restart lxc751

出力例
[root@c756 ~]# lxc exec lxc751 cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth1
[root@c756 ~]# lxc exec lxc751 vi /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
HOSTNAME=LXC_NAME
NM_CONTROLLED=no
TYPE=Ethernet
MTU=
DHCP_HOSTNAME=`hostname`

#コンテナのviが起動されるため、sed(:s/eth0/eth1/g)して保存(:wq)します。

[root@c756 ~]# lxc exec lxc751 cat /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
BOOTPROTO=dhcp
ONBOOT=yes
HOSTNAME=LXC_NAME
NM_CONTROLLED=no
TYPE=Ethernet
MTU=
DHCP_HOSTNAME=`hostname`
[root@c756 ~]# lxc restart lxc751
[root@c756 ~]# lxc list
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
|  NAME   |  STATE  |         IPV4         |                     IPV6                     |    TYPE    | SNAPSHOTS |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
| lx75mas | STOPPED |                      |                                              | PERSISTENT |           |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
| lxc751  | RUNNING | 192.168.30.48 (eth1) | fd42:d3a:78c6:6d8c:216:3eff:fe8f:a6c3 (eth0) | PERSISTENT |           |
|         |         | 10.106.42.75 (eth0)  |                                              |            |           |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+

「lxc exec lxc751」によりコンテナ上でコマンドを実行できます。
ifcfg-eth0 をコピーして、DEVICE=eth1に書き換え、コンテナを再起動しています。
しばらくして、lxc listによりeth1のアドレスが取得できていればOKです。

3.手動によるIP固定設定の場合

やっていることは前項と同様です。
では、何が異なるか?と言いますと、lxdbr30にIPアドレスを設定したくない場合を想定しています。
具体的には、以下のような構成の場合です。
f:id:metonymical:20181028010926j:plain
コンテナlxc751からLBまで、LBからコンテナlxc752までをそれぞれ同一VLANとしたい場合、Bridgeインターフェース上でIPアドレスを設定してしまうと、ホストOS上のRoutingテーブルにlxdbr30とlxdbr31がconnectedで載ってきてしまうため、LBまで到達せずに内部で折り返してしまいます。
一方でnet.ipv4.ip_forwardを無効にしてしまうと、今度はlxdbr0で稼働しているNAT+Routingが動作しなくなるため、lxdbr30にIPアドレスを設定せずに構成する方法を記載します。

(1)Bridgeインターフェースlxdbr30の作成+ens34をlxdbr30にアタッチ

投入コマンド
lxc network create lxdbr30 \
bridge.external_interfaces=ens34 \
ipv4.address=none \
ipv6.address=none

出力例
[root@c756 ~]# lxc network create lxdbr30 \
> bridge.external_interfaces=ens34 \
> ipv4.address=none \
> ipv6.address=none
Network lxdbr30 created
[root@c756 ~]# lxc network list
+---------+----------+---------+-------------+---------+
|  NAME   |   TYPE   | MANAGED | DESCRIPTION | USED BY |
+---------+----------+---------+-------------+---------+
| ens33   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens34   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens37   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens38   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens39   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens40   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| lxdbr0  | bridge   | YES     |             | 1       |
+---------+----------+---------+-------------+---------+
| lxdbr30 | bridge   | YES     |             | 0       |
+---------+----------+---------+-------------+---------+
[root@c756 ~]# lxc network show lxdbr30
config:
  bridge.external_interfaces: ens34
  ipv4.address: none
  ipv6.address: none
description: ""
name: lxdbr30
type: bridge
used_by: []
managed: true
status: Created
locations:
- none

lxdbr30が作成され、物理インターフェースens34にもアタッチされました。
但し、lxdbr30自身にはIPアドレスが設定されていません。

(2)lxdbr30にコンテナlxc751のeth1をアタッチ+IP設定

投入コマンドその1
lxc network attach lxdbr30 lxc751 eth1
lxc start lxc751

出力例
[root@c756 ~]# lxc network attach lxdbr30 lxc751 eth1
[root@c756 ~]# lxc start lxc751
[root@c756 ~]# lxc list
+---------+---------+---------------------+----------------------------------------------+------------+-----------+
|  NAME   |  STATE  |        IPV4         |                     IPV6                     |    TYPE    | SNAPSHOTS |
+---------+---------+---------------------+----------------------------------------------+------------+-----------+
| lx75mas | STOPPED |                     |                                              | PERSISTENT |           |
+---------+---------+---------------------+----------------------------------------------+------------+-----------+
| lxc751  | RUNNING | 10.106.42.75 (eth0) | fd42:d3a:78c6:6d8c:216:3eff:fe8f:a6c3 (eth0) | PERSISTENT |           |
+---------+---------+---------------------+----------------------------------------------+------------+-----------+

lxdbr30にコンテナlxc751のeth1をアタッチしましたが、コンテナのIPは設定されていません。

投入コマンドその2
lxc exec lxc751 cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth1
lxc exec lxc751 vi /etc/sysconfig/network-scripts/ifcfg-eth1
:s/eth0/eth1/g
:s/dhcp/none/g
IPADDR=192.168.30.48  #追記
PREFIX=24        #追記
:wq
lxc exec lxc751 cat /etc/sysconfig/network-scripts/ifcfg-eth1
lxc restart lxc751

出力例
[root@c756 ~]# lxc exec lxc751 cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth1
[root@c756 ~]# lxc exec lxc751 vi /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
HOSTNAME=LXC_NAME
NM_CONTROLLED=no
TYPE=Ethernet
MTU=
DHCP_HOSTNAME=`hostname`

#コンテナのviが起動されるため、sedで置換してIPとPrefixを追記して保存します。

[root@c756 ~]# lxc exec lxc751 cat /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
BOOTPROTO=none
IPADDR=192.168.30.48
PREFIX=24
ONBOOT=yes
HOSTNAME=LXC_NAME
NM_CONTROLLED=no
TYPE=Ethernet
MTU=
DHCP_HOSTNAME=`hostname`
[root@c756 ~]# lxc restart lxc751
[root@c756 ~]# lxc list
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
|  NAME   |  STATE  |         IPV4         |                     IPV6                     |    TYPE    | SNAPSHOTS |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
| lx75mas | STOPPED |                      |                                              | PERSISTENT |           |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+
| lxc751  | RUNNING | 192.168.30.48 (eth1) | fd42:d3a:78c6:6d8c:216:3eff:fe8f:a6c3 (eth0) | PERSISTENT |           |
|         |         | 10.106.42.75 (eth0)  |                                              |            |           |
+---------+---------+----------------------+----------------------------------------------+------------+-----------+

ifcfg-eth0 をコピーして、DEVICE=eth1に書き換え、コンテナを再起動しています。
しばらくして、lxc listによりeth1のアドレスが表示されていればOKです。

4.補足1:nmcliコマンドでBridgeを作成した場合

nmcliコマンドでBridgeインターフェースを作成しても、lxc上で利用可能です。
しかし、nmcliコマンドで作成した場合、lxdの管理下から外れるため、以下のようにMANAGED=NOとなります。

[root@c756 ~]# lxc network list
+---------+----------+---------+-------------+---------+
|  NAME   |   TYPE   | MANAGED | DESCRIPTION | USED BY |
+---------+----------+---------+-------------+---------+
| ens33   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens34   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens37   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens38   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens39   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| ens40   | physical | NO      |             | 0       |
+---------+----------+---------+-------------+---------+
| lxdbr0  | bridge   | YES     |             | 1       |
+---------+----------+---------+-------------+---------+
| lxdbr30 | bridge   | NO      |             | 0       |
+---------+----------+---------+-------------+---------+

nmcliでBridgeを作成した場合、LXDクラスタを組んだときなどに困りそうな予感はしていますが、もう少し検証してみようと思います。

なお、LXC/LXDのネットワーク周りの設定は以下の公式サイトに詳細が記載されています。
https://lxd-ja.readthedocs.io/ja/latest/networks/

5.補足2:PortForwarding設定

コンテナ内のサービスを外部に公開したい場合、今回解説したBridgeの他に、Defaultで作成されるlxdbr0上でPortForwardingを行う方法があります。

lxc config device add lxc751 httpd proxy listen=tcp:0.0.0.0:80 connect=tcp:localhost:80

lxc751:コンテナ名
httpd:任意の名前
listen=tcp:0.0.0.0:80:ホスト側の待受けポート*2
connect=tcp:localhost:80:コンテナ側(lxc751)の待受けポート

以上です。

6.最後に

以下のサイトを参考にさせて頂きました。
Home - LXDドキュメント翻訳プロジェクト
第535回 LXD 3.0のネットワーク設定:Ubuntu Weekly Recipe|gihyo.jp … 技術評論社

LXC/LXDはコンテナ起動後、ちょいちょいいじりたい時に便利だなと思っています。
なので「LightweightなKVM」とか「KVMライク」といった使い方が、私にはマッチしています。

ちなみに、SR-IOVやCloud-initにも対応しているため、そちらの検証もやってみたいなと思います。

*1:lxcコマンドでは、アサインではなく、アタッチという言葉を使っているため統一します。

*2:IPはホストOSの物理インターフェースのIPアドレスにアクセスしてください。