Metonymical Deflection

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

CentOS8 小ネタ集その2:Cockpit machineのインストール

Cockpit上で仮想マシンを管理できるようになります。

Defaultではcockpit-machinesがインストールされていないようなので、インストールした後にCockpitのサービス起動設定を実施するだけです。

1.インストール&自動起動設定

dnf -y install cockpit-machines && \
systemctl enable --now cockpit.socket && \
systemctl start --now cockpit.socket

2.Cockpitへのログイン

ブラウザを起動した後、CentOS8上のCockpitにアクセスします。

https://CentOS8のIP:9090/

ブラウザに以下の画面が表示されますので、ssh接続時と同様のCredential(Username/Passwd)でログインしてください。
f:id:metonymical:20191013120213p:plain

3.仮想マシン設定画面

以下の通り、Cockpit上で仮想マシンの作成や編集などができるようになります。
f:id:metonymical:20191013120343p:plain


以上です。

3.最後に

Virt-Managerほど柔軟に設定できないようなので、VNC serverなどと併用するのがよいかと思います。
しかし、起動中の仮想マシンのステータスが見たいときなどは重宝すると思います。

CentOS8 小ネタ集その1:VNC serverの設定

CentOS8におけるtigervnc-serverの設定方法を記載します。
2021/04/14追記
CentOS8.3における設定方法を追記しました。6.5.CentOS8.3の設定方法を参照してください。

小ネタ集ってほどでもないですが、サクサクっと記載します。

1.インストールと設定ファイルコピー

dnf -y install tigervnc-server && \
cp -a /usr/lib/systemd/user/vncserver@.service /etc/systemd/system/vncserver@:1.service

2.設定ファイルの編集

=追記、=コメントアウト

vi /etc/systemd/system/vncserver@:1.service

[Service]
Type=forking
PIDFile=/root/.vnc/%H%i.pid

ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :'
#ExecStart=/usr/bin/vncserver %i
ExecStart=/usr/sbin/runuser -l root -c "/usr/bin/vncserver %i"
ExecStop=/usr/bin/vncserver -kill %i

sedでサクッと設定したい場合は以下の通り。

sed -i -e '/^Type/a PIDFile=/root/.vnc/%H%i.pid' /etc/systemd/system/vncserver@:1.service
sed -i -e 's/ExecStart=/#ExecStart=/g' /etc/systemd/system/vncserver@:1.service
sed -i -e '/^#ExecStart=/a ExecStart=/usr/sbin/runuser -l root -c "/usr/bin/vncserver %i"' /etc/systemd/system/vncserver@:1.service

3.Passwd設定と一時起動&停止

vncpasswd
vncserver :1
vncserver -kill :1

4.ロックファイルの削除

rm /tmp/.X11-unix/X

⇒Tabで/Xのあとを補完すると、以下のような数字が表示される
rm /tmp/.X11-unix/X1024

上記のようにXのあとが1024であれば、合わせて以下のファイルも削除しておく。
rm /tmp/.X1024-lock

5.Service自動起動&起動

systemctl daemon-reload
systemctl enable vncserver@:1.service
systemctl start vncserver@:1.service

6.解像度変更

vi /usr/bin/vncserver

#$geometry = "1024x768";
$geometry = "1600x1200";

sedでサクッと設定したい場合は以下の通り。

sed -i -e '/$geometry/s/1024x768/1600x1200/g' /usr/bin/vncserver

6.5.CentOS8.3の設定方法

CentOS8.3におけるVNC Serverの設定方法が少し変わっています。*1

dnf -y install tigervnc-server && \
echo "session=gnome" >> /etc/tigervnc/vncserver-config-defaults && \
echo ":1=root" >> /etc/tigervnc/vncserver.users && \
mkdir /root/.vnc && \
echo "geometry=1600x1200" >> /root/.vnc/config && \
cp -p /usr/lib/systemd/system/vncserver@.service /etc/systemd/system/vncserver@:1.service && \
vncpasswd

上記コマンドにてパスワード入力後、以下のようにサービスの自動起動設定を行ってください。

systemctl daemon-reload
systemctl enable vncserver@:1.service
systemctl start vncserver@:1.service

以上です。

7.最後に

VNC serverが必要なケースとしては、Virt-Managerを起動するときなのですが、CentOS8からはCockpitの使用が推奨されています。
しかし、実際にCockpitでVMを作成したところ、NWインターフェース周りが柔軟に設定*2できないようだった*3ので、引き続きVNCのお世話になっています。

*1:インストールから解像度設定やサービスファイルのコピー、パスワード設定までワンラインで設定可能です。

*2:virsh editでxmlファイルをゴリゴリ編集すればよいだけなのですが。。

*3:SR-IOVの設定ができずでした

CentOS8 kickstartによるインストール

kickstartによるインストールのサンプルファイルをいくつかピックアップしてみたいと思います。

サンプルとしては以下の通り。*1

  • KVM(CentOS7.6)上にCentOS8をServerGUIでインストール
  • DL360G8上にCentOS8をServerGUIでインストール
  • KVM(CentOS7.6)上にCentOS8をminimalでインストール

2019/10/14追記*2

  • KVM(CentOS8.0)上にCentOS8をServerGUIでインストール
  • KVM(CentOS8.0)上にCentOS8をminimalでインストール


これ以外にも応用はいくらでもできると思います。

1.KVM(CentOS7.6)上にCentOS8をServerGUIでインストール

1-1.kickstartファイルの作成
vi c80gui.ks

# Network information
network  --bootproto=static --device=eth0 --onboot=on --ip=192.168.0.100 --gateway=192.168.0.1 --netmask=255.255.255.0 --nameserver=192.168.0.1 --noipv6
network  --bootproto=dhcp --device=eth1 --onboot=off --noipv6
network  --hostname=c80mas.md.jp

# Root password
rootpw --plaintext TESTPASSWD
user --groups=wheel --name=rsadmin --password=TESTPASSWD --plaintext

# System services
services --disabled="bolt,colord,cups,fwupd,ModemManager,packagekit,smartd,sssd-kcm,sssd,wpa_supplicant" --enabled="chronyd"
# Firewall configuration
firewall --disabled
# SELinux configuration
selinux --disabled

# Disk partitioning information
part /boot --fstype="ext4" --ondisk=vda --size=1024
part pv.1 --fstype="lvmpv" --ondisk=vda --size=1024 --grow
volgroup cl --pesize=4096 pv.1
logvol swap --fstype="swap" --recommended --name=swap --vgname=cl
logvol / --fstype="xfs" --grow --size=1024 --name=root --vgname=cl

cmdline
install
eula --agreed
# Use CDROM installation media
cdrom
# Run the Setup Agent on first boot
firstboot --enable
# Keyboard layouts
keyboard --vckeymap=us --xlayouts='us'
# System language
lang en_US.UTF-8
# System timezone
timezone Asia/Tokyo --isUtc --nontp
# X Window System configuration information
xconfig  --startxonboot
zerombr
bootloader --location=mbr --boot-drive=vda --append="crashkernel=auto biosdevname=0 net.ifnames=0 console=tty0 console=ttyS0,115200n8"
clearpart --none --initlabel

# repo
repo --name="AppStream" --baseurl=file:///run/install/repo/AppStream
ignoredisk --only-use=vda

%packages
@^graphical-server-environment
@container-management
@development
@virtualization-client
@virtualization-hypervisor
@virtualization-tools
kexec-tools
%end

%post
dnf -y install cockpit-machines
systemctl enable --now cockpit.socket
systemctl start --now cockpit.socket
dnf -y install epel-release
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
dnf -y install https://www.elrepo.org/elrepo-release-8.0-2.el8.elrepo.noarch.rpm
sed -i -e "s/#options kvm_intel nested=1/options kvm_intel nested=1/g" /etc/modprobe.d/kvm.conf
sed -i -e '/^pool/a server 192.168.0.1 iburst' /etc/chrony.conf
sed -i -e 's/^pool/#pool/g' /etc/chrony.conf
dnf -y install tigervnc-server
cp -a /usr/lib/systemd/user/vncserver@.service /etc/systemd/system/vncserver@:1.service
sed -i -e '/^Type/a PIDFile=/root/.vnc/%H%i.pid' /etc/systemd/system/vncserver@:1.service
sed -i -e 's/ExecStart=/#ExecStart=/g' /etc/systemd/system/vncserver@:1.service
sed -i -e '/^#ExecStart=/a ExecStart=/usr/sbin/runuser -l root -c "/usr/bin/vncserver %i"' /etc/systemd/system/vncserver@:1.service
sed -i -e '/$geometry/s/1024x768/1600x1200/g' /usr/bin/vncserver
systemctl set-default multi-user.target

#dnf update -y

%end
reboot --eject

<補足1>

  1. NW, Credential, Service, Diskなど環境によって変更する頻度が多いパラメータを上位に記載しています。
  2. Serviceのうちdisabledは、私が不要ものを記載しているため、素の状態で使用したい場合はコメントアウトしてください。
  3. eulaが効かず、OSインストール&Reboot後に手動でContinueしないとダメな場合があります。
  4. %packagesのうち、"@^graphical-server-environment"以下は、私が必要なものを記載しているため、素の状態で使用したい場合はコメントアウトしてください。
  5. %postには、私が必要なものを記載しているため、素の状態で使用したい場合はコメントアウトしてください。
1-2.qcow2ファイルの作成
qemu-img create -f qcow2 /var/lib/libvirt/images/c80mas.qcow2 20G
1-3.virt-installの実行
virt-install --connect=qemu:///system \
 --name=c80mas \
 --disk /var/lib/libvirt/images/c80mas.qcow2,format=qcow2,bus=virtio \
 --network bridge=br0,model=virtio \
 --network bridge=br0,model=virtio \
 --initrd-inject=./c80gui.ks \
 --extra-args='ks=file:/c80gui.ks biosdevname=0 net.ifnames=0 console=tty0 console=ttyS0,115200n8' \
 --vcpus=2 \
 --ram=2048 \
 --accelerate \
 --hvm \
 --location='/var/lib/libvirt/images/CentOS-8-x86_64-1905-dvd1.iso' \
 --nographics \
 --os-type=linux \
 --os-variant=centos7.0 \
 --arch=x86_64

<補足2>
"--network"にPortGroupを使用したい場合は、過去記事を参照してください。

2.DL360G8上にCentOS8をServerGUIでインストール

2-1.kickstartファイルの作成
# Network information
network  --bootproto=static --device=eno1 --ip=192.168.0.240 --netmask=255.255.255.0 --gateway=192.168.0.1 --nameserver=192.168.0.1 --noipv6 --activate
network  --hostname=c80mas.md.jp
#network  --bootproto=dhcp --device=eno2 --onboot=off --ipv6=auto
#network  --bootproto=dhcp --device=eno3 --onboot=off --ipv6=auto
#network  --bootproto=dhcp --device=eno4 --onboot=off --ipv6=auto
#network  --bootproto=dhcp --device=ens1f0 --onboot=off --ipv6=auto
#network  --bootproto=dhcp --device=ens1f1 --onboot=off --ipv6=auto

# Root password
rootpw --plaintext TESTPASSWD
user --groups=wheel --name=rsadmin --password=TESTPASSWD

# System services
services --disabled="bolt,colord,cups,fwupd,ModemManager,packagekit,smartd,sssd-kcm,sssd,wpa_supplicant" --enabled="chronyd"
# Firewall configuration
firewall --disabled
# SELinux configuration
selinux --disabled

# System bootloader configuration
bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=sda
# Partition clearing information
clearpart --all --initlabel --drives=sda
# Disk partitioning information
part /boot --fstype="xfs"   --ondisk=sda --size=1024
part pv.1  --fstype="lvmpv" --ondisk=sda --size=1    --grow
volgroup cl --pesize=4096 pv.1
logvol /    --fstype="xfs"  --name=root --vgname=cl --size=1 --grow
logvol swap --fstype="swap" --name=swap --vgname=cl --recommended

# X Window System configuration information
xconfig  --startxonboot
# License agreement
eula --agreed
# Use CDROM installation media
cdrom
# Use graphical install
#graphical
text
# Run the Setup Agent on first boot
firstboot --enable
# Keyboard layouts
keyboard --vckeymap=us --xlayouts='us'
# System language
lang en_US.UTF-8

# System timezone
timezone Asia/Tokyo --isUtc --nontp
# repo
repo --name="AppStream" --baseurl=file:///run/install/repo/AppStream
ignoredisk --only-use=sda

%packages
@^graphical-server-environment
@container-management
@development
@virtualization-client
@virtualization-hypervisor
@virtualization-tools
kexec-tools
%end

%addon com_redhat_kdump --enable --reserve-mb=auto
%end

%anaconda
pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok
pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty
%end
# Reboot after installation
reboot --eject

<補足3>

  1. 基本的には補足2に記載した内容と同様です。
  2. "reboot --eject"のうち、ejectオプションが効かないときがあるようなので、手動でejectしてください。

あとの操作方法は過去記事と同様です。
<補足4>
以下の起動オプションを入力する際、DL360G8pとDL360G8eで挙動が少し異なりました。

inst.ks=hd:sdb:/ks.cfg

DL360G8pの場合

inst.ks=hd:sdb:/ks.cfg

DL360G8eの場合

inst.ks=hd:sda:/ks.cfg

上記に伴いDL360G8eの場合にはkickstartファイルにおいても、"sda"を"sdb"に置換してください。

3.KVM(CentOS7.6)上にCentOS8をminimalでインストール

3-1.kickstartファイルの作成

さほど検証していないため、参考程度として記載します。

vi c80cui.ks


cmdline
install
eula --agreed
# Use CDROM installation media
cdrom
# Run the Setup Agent on first boot
firstboot --enable

# Keyboard layouts
keyboard --vckeymap=us --xlayouts='us'
# System language
lang en_US.UTF-8

# Network information
network  --bootproto=static --device=eth0 --onboot=on --ip=192.168.0.100 --gateway=192.168.0.1 --netmask=255.255.255.0 --nameserver=192.168.0.1 --noipv6
network  --bootproto=dhcp --device=eth1 --onboot=off --noipv6
network  --hostname=c80mas.md.jp

# System services
#services --enabled=chronyd
# Firewall configuration
firewall --disabled
# SELinux configuration
selinux --disabled

# repo
repo --name="AppStream" --baseurl=file:///run/install/repo/AppStream
ignoredisk --only-use=vda

zerombr
bootloader --location=mbr --boot-drive=vda --append="crashkernel=auto biosdevname=0 net.ifnames=0 console=tty0 console=ttyS0,115200n8"
clearpart --none --initlabel

# Disk partitioning information
part /boot --fstype="ext4" --ondisk=vda --size=1024
part pv.1 --fstype="lvmpv" --ondisk=vda --size=1024 --grow
volgroup cl --pesize=4096 pv.1
logvol swap --fstype="swap" --recommended --name=swap --vgname=cl
logvol / --fstype="xfs" --grow --size=1024 --name=root --vgname=cl

# Root password
rootpw --plaintext TESTPASSWD
# System timezone
timezone Asia/Tokyo --isUtc --nontp
user --groups=wheel --name=rsadmin --password=TESTPASSWD --plaintext
# X Window System configuration information
xconfig  --startxonboot

%packages
@^minimal-environment
kexec-tools
%end

%post

%end
reboot --eject
3-2.qcow2ファイルの作成
qemu-img create -f qcow2 /var/lib/libvirt/images/c80mas.qcow2 20G
3-3.virt-installの実行
virt-install --connect=qemu:///system \
 --name=c80mas \
 --disk /var/lib/libvirt/images/c80mas.qcow2,format=qcow2,bus=virtio \
 --network bridge=br0,model=virtio \
 --network bridge=br0,model=virtio \
 --initrd-inject=./c80cui.ks \
 --extra-args='ks=file:/c80cui.ks biosdevname=0 net.ifnames=0 console=tty0 console=ttyS0,115200n8' \
 --vcpus=2 \
 --ram=2048 \
 --accelerate \
 --hvm \
 --location='/var/lib/libvirt/images/CentOS-8-x86_64-1905-dvd1.iso' \
 --nographics \
 --os-type=linux \
 --os-variant=centos7.0 \
 --arch=x86_64

以下、2019/10/14に追記しました。
NWインターフェース名を変更していますが、それに伴い「--append」や「--extra-args」の設定も変更しています。

4.KVM(CentOS8.0)上にCentOS8をServerGUIでインストール

4-1.kickstartファイルの作成
vi c80gui.ks

# Network information
network  --bootproto=static --device=enp1s0 --onboot=on --ip=192.168.0.100 --gateway=192.168.0.1 --netmask=255.255.255.0 --nameserver=192.168.0.1 --noipv6
network  --bootproto=dhcp --device=enp2s0 --onboot=off --noipv6
network  --hostname=c80mas.md.jp

# Root password
rootpw --plaintext TESTPASSWD
user --groups=wheel --name=rsadmin --password=TESTPASSWD --plaintext

# System services
services --disabled="bolt,colord,cups,fwupd,ModemManager,packagekit,smartd,sssd-kcm,sssd,wpa_supplicant" --enabled="chronyd"
# Firewall configuration
firewall --disabled
# SELinux configuration
selinux --disabled

# Disk partitioning information
part /boot --fstype="ext4" --ondisk=vda --size=1024
part pv.1 --fstype="lvmpv" --ondisk=vda --size=1024 --grow
volgroup cl --pesize=4096 pv.1
logvol swap --fstype="swap" --recommended --name=swap --vgname=cl
logvol / --fstype="xfs" --grow --size=1024 --name=root --vgname=cl


cmdline
install
eula --agreed
# Use CDROM installation media
cdrom
# Run the Setup Agent on first boot
firstboot --enable
# Keyboard layouts
keyboard --vckeymap=us --xlayouts='us'
# System language
lang en_US.UTF-8
# System timezone
timezone Asia/Tokyo --isUtc --nontp
# X Window System configuration information
xconfig  --startxonboot
zerombr
bootloader --location=mbr --boot-drive=vda --append="crashkernel=auto console=tty0 console=ttyS0,115200n8"
clearpart --none --initlabel

# repo
repo --name="AppStream" --baseurl=file:///run/install/repo/AppStream
ignoredisk --only-use=vda

%packages
@^graphical-server-environment
@container-management
@development
@virtualization-client
@virtualization-hypervisor
@virtualization-tools
kexec-tools
%end

%post
dnf -y install cockpit-machines
systemctl enable --now cockpit.socket
systemctl start --now cockpit.socket
dnf -y install epel-release
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
dnf -y install https://www.elrepo.org/elrepo-release-8.0-2.el8.elrepo.noarch.rpm
sed -i -e "s/#options kvm_intel nested=1/options kvm_intel nested=1/g" /etc/modprobe.d/kvm.conf
sed -i -e '/^pool/a server 192.168.0.1 iburst' /etc/chrony.conf
sed -i -e 's/^pool/#pool/g' /etc/chrony.conf
dnf -y install tigervnc-server
cp -a /usr/lib/systemd/user/vncserver@.service /etc/systemd/system/vncserver@:1.service
sed -i -e '/^Type/a PIDFile=/root/.vnc/%H%i.pid' /etc/systemd/system/vncserver@:1.service
sed -i -e 's/ExecStart=/#ExecStart=/g' /etc/systemd/system/vncserver@:1.service
sed -i -e '/^#ExecStart=/a ExecStart=/usr/sbin/runuser -l root -c "/usr/bin/vncserver %i"' /etc/systemd/system/vncserver@:1.service
sed -i -e '/$geometry/s/1024x768/1600x1200/g' /usr/bin/vncserver
systemctl set-default multi-user.target

#dnf update -y

%end
reboot --eject
4-2.qcow2ファイルの作成
qemu-img create -f qcow2 /var/lib/libvirt/images/c80mas.qcow2 20G
4-3.virt-installの実行
virt-install --connect=qemu:///system \
 --name=c80mas \
 --disk /var/lib/libvirt/images/c80mas.qcow2,format=qcow2,bus=virtio \
 --network bridge=br0,model=virtio \
 --network bridge=br0,model=virtio \
 --initrd-inject=./c80gui.ks \
 --extra-args='ks=file:/c80gui.ks console=tty0 console=ttyS0,115200n8' \
 --vcpus=2 \
 --ram=2048 \
 --accelerate \
 --hvm \
 --location='/var/lib/libvirt/images/CentOS-8-x86_64-1905-dvd1.iso' \
 --nographics \
 --os-type=linux \
 --os-variant=rhel8.0 \
 --arch=x86_64

5.KVM(CentOS8.0)上にCentOS8をminimalでインストール

5-1.kickstartファイルの作成
vi c80cui.ks

# Network information
network  --bootproto=static --device=enp1s0 --onboot=on --ip=192.168.0.100 --gateway=192.168.0.1 --netmask=255.255.255.0 --nameserver=192.168.0.1 --noipv6
network  --bootproto=dhcp --device=enp2s0 --onboot=off --noipv6
network  --hostname=c80mas.md.jp

# Root password
rootpw --plaintext TESTPASSWD
user --groups=wheel --name=rsadmin --password=TESTPASSWD --plaintext

# Firewall configuration
firewall --disabled
# SELinux configuration
selinux --disabled

# Disk partitioning information
part /boot --fstype="ext4" --ondisk=vda --size=1024
part pv.1 --fstype="lvmpv" --ondisk=vda --size=1024 --grow
volgroup cl --pesize=4096 pv.1
logvol swap --fstype="swap" --recommended --name=swap --vgname=cl
logvol / --fstype="xfs" --grow --size=1024 --name=root --vgname=cl

cmdline
install
eula --agreed
# Use CDROM installation media
cdrom
# Run the Setup Agent on first boot
firstboot --enable
# Keyboard layouts
keyboard --vckeymap=us --xlayouts='us'
# System language
lang en_US.UTF-8
# System timezone
timezone Asia/Tokyo --isUtc --nontp
# X Window System configuration information
xconfig  --startxonboot
zerombr
bootloader --location=mbr --boot-drive=vda --append="crashkernel=auto console=tty0 console=ttyS0,115200n8"
clearpart --none --initlabel

# repo
repo --name="AppStream" --baseurl=file:///run/install/repo/AppStream
ignoredisk --only-use=vda

%packages
@^minimal-environment
kexec-tools
%end

%post

%end
reboot --eject
5-2.qcow2ファイルの作成
qemu-img create -f qcow2 /var/lib/libvirt/images/c80mas.qcow2 20G
5-3.virt-installの実行
virt-install --connect=qemu:///system \
 --name=c80mas \
 --disk /var/lib/libvirt/images/c80mas.qcow2,format=qcow2,bus=virtio \
 --network bridge=br0,model=virtio \
 --network bridge=br0,model=virtio \
 --initrd-inject=./c80cui.ks \
 --extra-args='ks=file:/c80cui.ks console=tty0 console=ttyS0,115200n8' \
 --vcpus=2 \
 --ram=2048 \
 --accelerate \
 --hvm \
 --location='/var/lib/libvirt/images/CentOS-8-x86_64-1905-dvd1.iso' \
 --nographics \
 --os-type=linux \
 --os-variant=rhel8.0 \
 --arch=x86_64


以上です。

10.最後に

以下のサイトを参考にさせて頂きました。
virt-install で KVM に CentOS8 を無人インストール - Qiita

/root/anaconda-ks.cfgを参考にすれば色々試せると思いますので、自分なりにやってみることをおススメします。

*1:minimalはもうあまり使わないかなと思ったので重要度下げてます。

*2:libvirtdなどのVersionの違いにより、インターフェース名の指定方法が変わっているため追記しました。NW周りは重要度高いので。

CentOS7 ovs(Open vSwitch)+ovnのネットワーク設定方法

ovs+ovnのoverlayネットワークを構築し、KVM仮想マシンとDockerコンテナのトラフィックをBridgeで外部ネットワークに流して使用する場合の設定方法を記載したいと思います。
これにより、仮想マシンとコンテナと外部ネットワーク機器が同一VLANで通信可能になります。
ただ、実用性の観点で冗長化できないため、あまり使えないかもしれませんが、ovnの仕組みを理解する上では活用できるかと思います。

1.環境

1-1.VMWare
筐体                             : 自作PC(Win10pro)
CPU                           : Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz
VMWare              : VMware(R) Workstation 15 Pro 15.1.0 build-13591040  
OS                               : CentOS7.6(1810)
Kernel                           : 3.10.0-957.el7.x86_64
Installed Environment Groups     : Server with GUI
Add-Ons for Selected Environment : Virtualization Client, Virtualization Hypervisor, Virtualization Tools 
ovs&ovn                          : 2.11.1

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

1-2.全体構成その1:Underlay

f:id:metonymical:20190721175822p:plain

1-3.全体構成その2:Overlay

f:id:metonymical:20190721175834p:plain
補足
「'」が付いている箇所は、主に「'」が付いていない箇所を設定すると自動設定されます。*1

1-4 .全体の流れ ~概要~
  1. ovs+ovnのビルドとインストール
  2. ovs+ovnの設定
  3. docker+consulのクラスタ設定
  4. (1)~(7)の設定
1-5 .全体の流れ ~コマンドのみ~

以下のコマンドを投入していきます。
やりたいことが既に決まっている方は、構成図とコマンドの内容を見るだけでもよいと思います。
しかし、ovs+ovnやdocker+consulの設定もそこそこボリュームがあるため、(1)~(7)の辿り着くまでが少々しんどいかもしれません。。

(1)
docker network create -d openvswitch --subnet=192.168.31.0/24 ovs

(2)
vi /etc/sysconfig/network-scripts/ifcfg-br-ext

DEVICE=br-ext
DEVICETYPE=ovs
TYPE=OVSBridge
BOOTPROTO=static
NM_CONTROLLED=no
ONBOOT=yes
HOTPLUG=no

vi /etc/sysconfig/network-scripts/ifcfg-ens36

DEVICE=ens36
ONBOOT=yes
DEVICETYPE=ovs
TYPE=OVSPort
OVS_BRIDGE=br-ext
BOOTPROTO=none
NM_CONTROLLED=no
OVS_OPTIONS="vlan_mode=trunk trunks=300-301"
HOTPLUG=no

(3)
ovn-sbctl --db=tcp:192.168.30.101:6642 show

ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=physnet301:br-ext
export SW_NAME=$(ovn-nbctl --db=tcp:192.168.30.101:6641 ls-list | awk '{print $2}' | sed s/\(//g | sed s/\)//g)
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-add $SW_NAME l2gwport "" 301
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-addresses l2gwport unknown
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-type l2gwport l2gateway
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-options l2gwport network_name=physnet301 l2gateway-chassis=28928b40-900b-4f48-b4ed-8d9d2f1082fd

(4)
export SW_NAME=$(ovn-nbctl --db=tcp:192.168.30.101:6641 ls-list | awk '{print $2}' | sed s/\(//g | sed s/\)//g)
export IFACE_ID=$(ovs-vsctl get interface vnet1 external_ids:iface-id | sed s/\"//g)
export MAC_ADDR=$(ovs-vsctl get interface vnet1 external_ids:attached-mac | sed s/\"//g)
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-add $SW_NAME $IFACE_ID
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-addresses $IFACE_ID $MAC_ADDR
ovn-nbctl --db=tcp:192.168.30.101:6641 show

(5)
export SW_NAME=$(ovn-nbctl --db=tcp:192.168.30.101:6641 ls-list | awk '{print $2}' | sed s/\(//g | sed s/\)//g)
export IFACE_ID=$(ovs-vsctl get interface vnet1 external_ids:iface-id | sed s/\"//g)
export MAC_ADDR=$(ovs-vsctl get interface vnet1 external_ids:attached-mac | sed s/\"//g)
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-add $SW_NAME $IFACE_ID
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-addresses $IFACE_ID $MAC_ADDR
ovn-nbctl --db=tcp:192.168.30.101:6641 show

(6)
docker run -itd \
--privileged \
--network ovs \
--name c2 \
c76 \
/sbin/init

(7)
docker run -itd \
--privileged \
--network ovs \
--name c3 \
c76 \
/sbin/init

2.ovs+ovnのビルドとインストール

ControllerNode(c76ovn01)にてビルドとインストールを実施します。またDockerもインストールしてしまいます。

2-1.ControllerNode
yum -y install @'Development Tools' rpm-build yum-utils wget libpcap-devel numactl-devel

mkdir -p /root/rpmbuild/SOURCES
cd /root/rpmbuild/SOURCES
wget https://www.openvswitch.org/releases/openvswitch-2.11.1.tar.gz
tar zxvf openvswitch-2.11.1.tar.gz
sed -e 's/@VERSION@/0.0.1/' openvswitch-2.11.1/rhel/openvswitch-fedora.spec.in > ovs.spec

yum-builddep -y ovs.spec && \
cd openvswitch-2.11.1 && \
./boot.sh && \
./configure && \
make rpm-fedora RPMBUILD_OPT="--without check" && \
make rpm-fedora-ovn RPMBUILD_OPT="--without check"

cd /root/rpmbuild/SOURCES/openvswitch-2.11.1/rpm/rpmbuild/RPMS/noarch
yum -y localinstall python-openvswitch-2.11.1-1.el7.noarch.rpm

cd /root/rpmbuild/SOURCES/openvswitch-2.11.1/rpm/rpmbuild/RPMS/x86_64
yum -y localinstall \
openvswitch-2.11.1-1.el7.x86_64.rpm \
ovn-2.11.1-1.el7.x86_64.rpm \
ovn-common-2.11.1-1.el7.x86_64.rpm \
ovn-central-2.11.1-1.el7.x86_64.rpm \
ovn-host-2.11.1-1.el7.x86_64.rpm \
ovn-docker-2.11.1-1.el7.x86_64.rpm

curl -sSL https://get.docker.com/ | sh

systemctl start openvswitch
systemctl enable openvswitch
systemctl start ovn-northd
systemctl enable ovn-northd
systemctl start docker
systemctl enable docker
2-2.ComputeNode

ComputeNode(c76ovn02&c76ovn03)にてビルドとインストールを実施します。違いは、ovn-central-2.11.1-1.el7.x86_64.rpmが無いだけです。

yum -y install @'Development Tools' rpm-build yum-utils wget libpcap-devel numactl-devel

mkdir -p /root/rpmbuild/SOURCES
cd /root/rpmbuild/SOURCES
wget https://www.openvswitch.org/releases/openvswitch-2.11.1.tar.gz
tar zxvf openvswitch-2.11.1.tar.gz
sed -e 's/@VERSION@/0.0.1/' openvswitch-2.11.1/rhel/openvswitch-fedora.spec.in > ovs.spec

yum-builddep -y ovs.spec && \
cd openvswitch-2.11.1 && \
./boot.sh && \
./configure && \
make rpm-fedora RPMBUILD_OPT="--without check" && \
make rpm-fedora-ovn RPMBUILD_OPT="--without check"

cd /root/rpmbuild/SOURCES/openvswitch-2.11.1/rpm/rpmbuild/RPMS/noarch
yum -y localinstall python-openvswitch-2.11.1-1.el7.noarch.rpm

cd /root/rpmbuild/SOURCES/openvswitch-2.11.1/rpm/rpmbuild/RPMS/x86_64
yum -y localinstall \
openvswitch-2.11.1-1.el7.x86_64.rpm \
ovn-2.11.1-1.el7.x86_64.rpm \
ovn-common-2.11.1-1.el7.x86_64.rpm \
ovn-host-2.11.1-1.el7.x86_64.rpm \
ovn-docker-2.11.1-1.el7.x86_64.rpm

curl -sSL https://get.docker.com/ | sh

systemctl start openvswitch
systemctl enable openvswitch
systemctl start ovn-controller
systemctl enable ovn-controller
systemctl start docker
systemctl enable docker

3.ovs+ovnの設定

3-1.Overlay用のInteface設定
c76ovn01
nmcli con add type ethernet autoconnect yes con-name ens37 ifname ens37
nmcli con mod ens37 ipv4.method manual ipv4.addresses 192.168.30.101/24
nmcli con up ens37

c76ovn02
nmcli con add type ethernet autoconnect yes con-name ens37 ifname ens37
nmcli con mod ens37 ipv4.method manual ipv4.addresses 192.168.30.102/24
nmcli con up ens37

c76ovn03
nmcli con add type ethernet autoconnect yes con-name ens37 ifname ens37
nmcli con mod ens37 ipv4.method manual ipv4.addresses 192.168.30.103/24
nmcli con up ens37
3-2.ovnの設定
c76ovn01
ovn-nbctl set-connection ptcp:6641
ovn-sbctl set-connection ptcp:6642
ovs-appctl -t ovsdb-server ovsdb-server/add-remote ptcp:6640
3-3.ovsの設定
c76ovn02
export CENTRAL_IP=192.168.30.101
export ENCAP_TYPE=geneve
export LOCAL_IP=192.168.30.102

ovs-vsctl set Open_vSwitch . external_ids:ovn-remote="tcp:${CENTRAL_IP}:6642"
ovs-vsctl set Open_vSwitch . external_ids:ovn-nb="tcp:${CENTRAL_IP}:6641"
ovs-vsctl set Open_vSwitch . external_ids:ovn-encap-ip=${LOCAL_IP}
ovs-vsctl set Open_vSwitch . external_ids:ovn-encap-type="${ENCAP_TYPE}"

systemctl restart ovn-controller

c76ovn03
export CENTRAL_IP=192.168.30.101
export ENCAP_TYPE=geneve
export LOCAL_IP=192.168.30.103

ovs-vsctl set Open_vSwitch . external_ids:ovn-remote="tcp:${CENTRAL_IP}:6642"
ovs-vsctl set Open_vSwitch . external_ids:ovn-nb="tcp:${CENTRAL_IP}:6641"
ovs-vsctl set Open_vSwitch . external_ids:ovn-encap-ip=${LOCAL_IP}
ovs-vsctl set Open_vSwitch . external_ids:ovn-encap-type="${ENCAP_TYPE}"

systemctl restart ovn-controller
3-4.設定確認

102と103が101とESTABとなっていればOKです。

c76ovn01
ss -ant |grep 6642

出力例
[root@c76ovn01 ~]# ss -ant |grep 6642
LISTEN     0      10           *:6642                     *:*
ESTAB      0      0      192.168.30.101:6642               192.168.30.102:44102
ESTAB      0      0      192.168.30.101:6642               192.168.30.103:34252

上記がOKな場合、br-intが自動生成され、GeneveによるOverlayのトンネル設定も自動で実施されます。また、ovs上では以下のようなステータスとなっていればOKです。

c76ovn02&03
ovs-vsctl show

出力例
[root@c76ovn02 ~]# ovs-vsctl show
e2d97138-977a-4579-bc6a-dfb43d8769cb
    Bridge br-int
        fail_mode: secure
        Port br-int
            Interface br-int
                type: internal
        Port "ovn-925250-0"
            Interface "ovn-925250-0"
                type: geneve
                options: {csum="true", key=flow, remote_ip="192.168.30.103"}
    ovs_version: "2.11.0"
3-5.virshによるovsの設定

c76ovn02&03にてovsのPortGroup設定を実施しておきます。*2

c76ovn02&03
vi /tmp/ovsnw.xml

<network>
<name>ovsnw</name>
<forward mode='bridge'/>
<bridge name='br-int'/>
<virtualport type='openvswitch'/>
<portgroup name='untag' default='yes'>
</portgroup>
<portgroup name='vlan300'>
  <vlan>
    <tag id='300'/>
  </vlan>
</portgroup>
<portgroup name='vlan301'>
  <vlan>
    <tag id='301'/>
  </vlan>
</portgroup>
</network>

virsh net-list
virsh net-define /tmp/ovsnw.xml
virsh net-start ovsnw
virsh net-autostart ovsnw
virsh net-list

4.docker+consulのクラスタ設定

4-1.Dockerの設定その1

Option設定を読込みできるようにします。

c76ovn01&02&03

vi /usr/lib/systemd/system/docker.service

EnvironmentFile=-/etc/sysconfig/docker
EnvironmentFile=-/etc/sysconfig/docker-storage
EnvironmentFile=-/etc/sysconfig/docker-network
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock \
$OPTIONS \
$DOCKER_STORAGE_OPTIONS \
$DOCKER_NETWORK_OPTIONS \
$ADD_REGISTRY \
$BLOCK_REGISTRY \
$INSECURE_REGISTRY

出力例
青文字はコメントアウトしてください。
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
#ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
EnvironmentFile=-/etc/sysconfig/docker
EnvironmentFile=-/etc/sysconfig/docker-storage
EnvironmentFile=-/etc/sysconfig/docker-network
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock \
$OPTIONS \
$DOCKER_STORAGE_OPTIONS \
$DOCKER_NETWORK_OPTIONS \
$ADD_REGISTRY \
$BLOCK_REGISTRY \
$INSECURE_REGISTRY

ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
4-2.Dockerの設定その2
c76ovn01
vi /etc/sysconfig/docker
OPTIONS="--cluster-store=consul://127.0.0.1:8500 --cluster-advertise=192.168.30.101:0"

systemctl daemon-reload
systemctl restart docker

c76ovn02
vi /etc/sysconfig/docker
OPTIONS="--cluster-store=consul://127.0.0.1:8500 --cluster-advertise=192.168.30.102:0"

systemctl daemon-reload
systemctl restart docker

c76ovn03
vi /etc/sysconfig/docker
OPTIONS="--cluster-store=consul://127.0.0.1:8500 --cluster-advertise=192.168.30.103:0"

systemctl daemon-reload
systemctl restart docker
4-3.consulのインストール

consulでクラスタを構成します。
一度設定をミスると色々やっかいだった*3ので、VMWareなどで各Nodeを動作させている方は、この手順を進める前にスナップショットなりクローンを作成しておいた方が良いと思います。

c76ovn01&ovn02&ovn03
yum -y install epel-release && \
yum -y install python-pip && \
pip install pip --upgrade && \
pip install flask

wget https://releases.hashicorp.com/consul/1.5.2/consul_1.5.2_linux_amd64.zip
unzip consul_1.5.2_linux_amd64.zip
mv consul /usr/local/bin
4-4.consulの設定

最初に暗号キーを生成しておきます。生成した暗号キーは全Nodeで共通にしますので、任意の1台で生成すればOKです。ここでは例としてc76ovn01にて生成します。

c76ovn01
consul keygen

出力例
[root@c76ovn01 ~]# consul keygen
az3EW5ykRod6hBS1FiSFAA==

各Nodeごとに設定ファイルを作成します。赤文字の箇所のみ異なっています。

c76ovn01
sudo mkdir -p /etc/consul.d/scripts
sudo mkdir /var/consul

vi /etc/consul.d/config.json
{
    "bootstrap_expect": 3,
    "client_addr": "0.0.0.0",
    "datacenter": "dc1",
    "data_dir": "/var/consul",
    "domain": "consul",
    "enable_script_checks": true,
    "dns_config": {
        "enable_truncate": true,
        "only_passing": true
    },
    "enable_syslog": true,
    "encrypt": "az3EW5ykRod6hBS1FiSFAA==",
    "leave_on_terminate": true,
    "log_level": "INFO",
    "rejoin_after_leave": true,
    "bind_addr": "192.168.30.101",
    "server": true,
    "start_join": [
        "192.168.30.101",
        "192.168.30.102",
        "192.168.30.103"
    ],
    "ui": false
}

c76ovn02
sudo mkdir -p /etc/consul.d/scripts
sudo mkdir /var/consul

vi /etc/consul.d/config.json
{
    "bootstrap_expect": 3,
    "client_addr": "0.0.0.0",
    "datacenter": "dc1",
    "data_dir": "/var/consul",
    "domain": "consul",
    "enable_script_checks": true,
    "dns_config": {
        "enable_truncate": true,
        "only_passing": true
    },
    "enable_syslog": true,
    "encrypt": "az3EW5ykRod6hBS1FiSFAA==",
    "leave_on_terminate": true,
    "log_level": "INFO",
    "rejoin_after_leave": true,
    "bind_addr": "192.168.30.102",
    "server": true,
    "start_join": [
        "192.168.30.101",
        "192.168.30.102",
        "192.168.30.103"
    ],
    "ui": false
}

c76ovn03
sudo mkdir -p /etc/consul.d/scripts
sudo mkdir /var/consul

vi /etc/consul.d/config.json
{
    "bootstrap_expect": 3,
    "client_addr": "0.0.0.0",
    "datacenter": "dc1",
    "data_dir": "/var/consul",
    "domain": "consul",
    "enable_script_checks": true,
    "dns_config": {
        "enable_truncate": true,
        "only_passing": true
    },
    "enable_syslog": true,
    "encrypt": "az3EW5ykRod6hBS1FiSFAA==",
    "leave_on_terminate": true,
    "log_level": "INFO",
    "rejoin_after_leave": true,
    "bind_addr": "192.168.30.103",
    "server": true,
    "start_join": [
        "192.168.30.101",
        "192.168.30.102",
        "192.168.30.103"
    ],
    "ui": false
}
4-5.consulのサービス化設定

consulをサービス化し、自動起動するように設定します。

c76ovn01&02&03
vi /etc/systemd/system/consul.service

[Unit]
Description=Consul Startup process
After=network.target

[Service]
Type=simple
ExecStart=/bin/bash -c '/usr/local/bin/consul agent -config-dir /etc/consul.d/'
TimeoutStartSec=0

[Install]
WantedBy=default.target

systemctl daemon-reload
systemctl start consul
systemctl enable consul

consul members

出力例
全Nodeで同様の出力となります。
[root@c76ovn03 ~]# consul members
Node            Address              Status  Type    Build  Protocol  DC   Segment
c76ovn01.md.jp  192.168.30.101:8301  alive   server  1.5.2  2         dc1  
c76ovn02.md.jp  192.168.30.102:8301  alive   server  1.5.2  2         dc1  
c76ovn03.md.jp  192.168.30.103:8301  alive   server  1.5.2  2         dc1  

[root@c76ovn03 ~]# systemctl status consul
● consul.service - Consul Startup process
   Loaded: loaded (/etc/systemd/system/consul.service; enabled; vendor preset: disabled)
   Active: active (running) since Sun 2019-07-21 16:27:32 JST; 1s ago
 Main PID: 28182 (consul)
    Tasks: 14
   Memory: 18.2M
   CGroup: /system.slice/consul.service
           mq28182 /usr/local/bin/consul agent -config-dir /etc/consul.d/

Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: consul: Adding LAN server c76ovn01.md.jp (Addr: tcp/192.168.30.101:8300) (DC: dc1)
Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: consul: Adding LAN server c76ovn02.md.jp (Addr: tcp/192.168.30.102:8300) (DC: dc1)
Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: serf: EventMemberJoin: c76ovn02.md.jp.dc1 192.168.30.102
Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: serf: Re-joined to previously known node: c76ovn01.md.jp.dc1: 192.168.30.101:8302
Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: agent: Started HTTP server on [::]:8500 (tcp)
Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: consul: Handled member-join event for server "c76ovn01.md.jp.dc1" in area "wan"
Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: consul: Handled member-join event for server "c76ovn02.md.jp.dc1" in area "wan"
Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: agent: (LAN) joining: [192.168.30.101 192.168.30.102 192.168.30.103]
Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: agent: (LAN) joined: 3
Jul 21 16:27:32 c76ovn03.md.jp consul[28182]: agent: started state syncer

ここまで完了したら、一度全Nodeを再起動しておいてください。
再起動完了後、以下のコマンドでDockerとconsulが正常に起動していることを確認してください。

systemctl status docker
systemctl status consul

5.(1)~(7)の設定

5-1.事前準備

ovnのdocker-overlayドライバを各ComputeNodeで起動しておきます。

c76ovn02&03
ovn-docker-overlay-driver --detach
5-2.(1)の設定:DockerOverlaySwitchの作成

(1’)は自動生成されていますが、Overlay上では認識されていません。
以下のコマンドにより、ovnのNorthboundDBにDockerOverlaySwitchが生成されます。それと同時にDocker上のNWとしても認識されます。
c76ovn02もしくはc76ovn03のどちらか一方で設定すればOKです。

c76ovn02 or 03
docker network create -d openvswitch --subnet=192.168.31.0/24 ovs

出力例
[root@c76ovn02 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
7a78f73ce06d        bridge              bridge              local
368be43f05a1        host                host                local
efee695f0f0c        none                null                local
b5fb702e9489        ovs                 openvswitch         global

[root@c76ovn02 ~]# ovn-nbctl --db=tcp:192.168.30.101:6641 show
switch b70b9243-80b3-4ad6-8940-55bff06251fc (b5fb702e948902881b1b933191b9ee83f8dad4eb434a9d27d408d7a2d5fe2aa2)
5-3.(2)の設定:br-extの作成

br-intに無理やりインターフェースをアタッチしても外部とのBridge接続による疎通はできません。この辺りはNeutronのアーキテクチャに近い感じです。br-intとbr-extをPatch接続させて、外部ネットワークとブリッジ接続します。

c76ovn02
3-5に合わせて300-301をTrunkしていますが、今回の構成であれば301のみでOKです。

vi /etc/sysconfig/network-scripts/ifcfg-br-ext

DEVICE=br-ext
DEVICETYPE=ovs
TYPE=OVSBridge
BOOTPROTO=static
NM_CONTROLLED=no
ONBOOT=yes
HOTPLUG=no

vi /etc/sysconfig/network-scripts/ifcfg-ens36

DEVICE=ens36
ONBOOT=yes
DEVICETYPE=ovs
TYPE=OVSPort
OVS_BRIDGE=br-ext
BOOTPROTO=none
NM_CONTROLLED=no
OVS_OPTIONS="vlan_mode=trunk trunks=300-301"
HOTPLUG=no

systemctl restart network
5-4.(3)の設定:br-intとbr-extのPatch接続

先にovn-sbctlコマンドでシャーシIDを取得した後に設定を入れます。

c76ovn02
(3)
ovn-sbctl --db=tcp:192.168.30.101:6642 show

ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=physnet301:br-ext
export SW_NAME=$(ovn-nbctl --db=tcp:192.168.30.101:6641 ls-list | awk '{print $2}' | sed s/\(//g | sed s/\)//g)
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-add $SW_NAME l2gwport "" 301
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-addresses l2gwport unknown
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-type l2gwport l2gateway
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-options l2gwport network_name=physnet301 l2gateway-chassis=28928b40-900b-4f48-b4ed-8d9d2f1082fd
補足その1
ovn-sbctl --db=tcp:192.168.30.101:6642 showの出力例を以下に記載します。
赤文字の箇所をl2gateway-chassis=の後に加えます。
出力例
[root@c76ovn02 ~]# ovn-sbctl --db=tcp:192.168.30.101:6642 show
Chassis "1fdd4703-9c73-4afd-adf3-e0e90b7afb63"
    hostname: "c76ovn03.md.jp"
    Encap geneve
        ip: "192.168.30.103"
        options: {csum="true"}
    Port_Binding "35d89c2d-0505-41aa-b0c6-6aff6f483899"
    Port_Binding "b7131d7ecd548dcc4b6eb38bef0179b1bc75645e5683b69e6131da69d0aed1be"
Chassis "28928b40-900b-4f48-b4ed-8d9d2f1082fd"
    hostname: "c76ovn02.md.jp"
    Encap geneve
        ip: "192.168.30.102"
        options: {csum="true"}
    Port_Binding "16b258df72cb52ddb2527be69578c1f953c9275e154d4107743b0ee3ac13f095"
    Port_Binding "2c5a0afd-b12a-419e-b6f5-718c5d0e6446"
    Port_Binding "l2gwport"
[root@c76ovn02 ~]#
補足その2
設定後、以下のようになっていればOKです。
出力例
[root@c76ovn02 ~]# ovn-nbctl --db=tcp:192.168.30.101:6641 show
switch b70b9243-80b3-4ad6-8940-55bff06251fc (b5fb702e948902881b1b933191b9ee83f8dad4eb434a9d27d408d7a2d5fe2aa2)
    port l2gwport
        type: l2gateway
        parent:
        tag: 301
        addresses: ["unknown"]
[root@c76ovn02 ~]#

[root@c76ovn02 ~]# ovs-vsctl show
090be24a-f730-4d28-a4a0-dcf6d97fe618
    Bridge br-int
        fail_mode: secure
        Port "patch-br-int-to-l2gwport"
            Interface "patch-br-int-to-l2gwport"
                type: patch
                options: {peer="patch-l2gwport-to-br-int"}
        Port "ovn-1fdd47-0"
            Interface "ovn-1fdd47-0"
                type: geneve
                options: {csum="true", key=flow, remote_ip="192.168.30.103"}
        Port br-int
            Interface br-int
                type: internal
    Bridge br-ext
        Port "patch-l2gwport-to-br-int"
            Interface "patch-l2gwport-to-br-int"
                type: patch
                options: {peer="patch-br-int-to-l2gwport"}
        Port br-ext
            Interface br-ext
                type: internal
        Port "ens36"
            trunks: [300, 301]
            Interface "ens36"
    ovs_version: "2.11.1"
[root@c76ovn02 ~]#

ここまででアップリンクに相当する部分が構築できました。
あとは、仮想マシンやコンテナをアタッチしていきます。

コンテナは以下のコマンドで作成したDockerネットワークのovsにアタッチさせるだけで自動設定してくれます。

docker network create -d openvswitch --subnet=192.168.31.0/24 ovs

一方、KVMの仮想マシンについては、もう一工夫必要になります。

5-5.(4)と(5)の設定:KVM仮想マシンのアタッチ

先にvirt-installコマンドなどで仮想マシンを起動しておいてください。
その際、仮想マシンに使用するインターフェースは3-5で設定したPortGroupのうちvlan301を使用するようにしてください。

virt-installはこんな感じです。ポイントは赤文字の箇所です。

virt-install --connect=qemu:///system \
 --name=c7623 \
 --disk /var/lib/libvirt/images/c7623.qcow2,format=qcow2,bus=virtio \
 --network bridge=virbr0,model=virtio \
 --network network=ovsnw,portgroup=vlan301,model=virtio \
 --initrd-inject=./c76min.ks \
 --extra-args='ks=file:/c76min.ks biosdevname=0 net.ifnames=0 console=tty0 console=ttyS0,115200n8' \
 --vcpus=1 \
 --ram=1024 \
 --accelerate \
 --hvm \
 --location='/var/lib/libvirt/images/CentOS-7-x86_64-DVD-1810.iso' \
 --nographics \
 --os-type=linux \
 --os-variant=centos7.0 \
 --arch=x86_64

これにより、以下のような設定になります。ポイントはvnet1とovsnw, vlan301がBridgeしている点です。

vnet0 virbr0 eth0 libvirtでDefault定義
vnet1 ovsnw, vlan301 eth1 3-5で定義

仮想マシンが起動したら以下のコマンドにて、ovn上に登録していきます。
SW_NAME、IFACE_ID、MAC_ADDRを取得し、それをNorthboundDBに登録する形となります。*4

c76ovn02
(4)
export SW_NAME=$(ovn-nbctl --db=tcp:192.168.30.101:6641 ls-list | awk '{print $2}' | sed s/\(//g | sed s/\)//g)
export IFACE_ID=$(ovs-vsctl get interface vnet1 external_ids:iface-id | sed s/\"//g)
export MAC_ADDR=$(ovs-vsctl get interface vnet1 external_ids:attached-mac | sed s/\"//g)
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-add $SW_NAME $IFACE_ID
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-addresses $IFACE_ID $MAC_ADDR
ovn-nbctl --db=tcp:192.168.30.101:6641 show

c76ovn03
(5)
export SW_NAME=$(ovn-nbctl --db=tcp:192.168.30.101:6641 ls-list | awk '{print $2}' | sed s/\(//g | sed s/\)//g)
export IFACE_ID=$(ovs-vsctl get interface vnet1 external_ids:iface-id | sed s/\"//g)
export MAC_ADDR=$(ovs-vsctl get interface vnet1 external_ids:attached-mac | sed s/\"//g)
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-add $SW_NAME $IFACE_ID
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-addresses $IFACE_ID $MAC_ADDR
ovn-nbctl --db=tcp:192.168.30.101:6641 show

出力例
[root@c76ovn02 ~]# ovn-nbctl --db=tcp:192.168.30.101:6641 show
switch b70b9243-80b3-4ad6-8940-55bff06251fc (b5fb702e948902881b1b933191b9ee83f8dad4eb434a9d27d408d7a2d5fe2aa2)
    port l2gwport
        type: l2gateway
        parent:
        tag: 301
        addresses: ["unknown"]
    port 35d89c2d-0505-41aa-b0c6-6aff6f483899
        addresses: ["52:54:00:f6:45:c2"]
    port 2c5a0afd-b12a-419e-b6f5-718c5d0e6446
        addresses: ["52:54:00:d7:a6:96"]
[root@c76ovn02 ~]#
5-6.(6)と(7)の設定:Dockerコンテナのアタッチ

DockerコンテナのアタッチはPlug-Inで自動的にovs&ovnに登録されるため、「--network ovs」だけ忘れずに設定すれば問題ありません。

c76ovn02
(6)
docker run -itd \
--privileged \
--network ovs \
--name c2 \
centos \
/sbin/init

c76ovn03
(7)
docker run -itd \
--privileged \
--network ovs \
--name c3 \
centos \
/sbin/init

構成を確認してみます。

確認コマンド
docker network ls
ovn-nbctl --db=tcp:192.168.30.101:6641 show
ovn-sbctl --db=tcp:192.168.30.101:6642 show
ovs-vsctl show

出力例
ここでは例としてc76ovn03にて実施します。
ovs-vsctl showだけは02&03の両方で出力させます。
[root@c76ovn03 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
116424d7f10a        bridge              bridge              local
db62b02926e4        docker_gwbridge     bridge              local
dcdbfcc3e390        host                host                local
da1e0883a8ed        none                null                local
b5fb702e9489        ovs                 openvswitch         global

[root@c76ovn03 ~]# ovn-nbctl --db=tcp:192.168.30.101:6641 show
switch b70b9243-80b3-4ad6-8940-55bff06251fc (b5fb702e948902881b1b933191b9ee83f8dad4eb434a9d27d408d7a2d5fe2aa2)
    port b7131d7ecd548dcc4b6eb38bef0179b1bc75645e5683b69e6131da69d0aed1be
        addresses: ["02:dc:06:e4:de:3c 192.168.31.2"]
    port 16b258df72cb52ddb2527be69578c1f953c9275e154d4107743b0ee3ac13f095
        addresses: ["02:26:b3:e1:ab:5c 192.168.31.3"]
    port l2gwport
        type: l2gateway
        parent:
        tag: 301
        addresses: ["unknown"]
    port 35d89c2d-0505-41aa-b0c6-6aff6f483899
        addresses: ["52:54:00:f6:45:c2"]
    port 2c5a0afd-b12a-419e-b6f5-718c5d0e6446
        addresses: ["52:54:00:d7:a6:96"]

[root@c76ovn03 ~]# ovn-sbctl --db=tcp:192.168.30.101:6642 show
Chassis "1fdd4703-9c73-4afd-adf3-e0e90b7afb63"
    hostname: "c76ovn03.md.jp"
    Encap geneve
        ip: "192.168.30.103"
        options: {csum="true"}
    Port_Binding "35d89c2d-0505-41aa-b0c6-6aff6f483899"
    Port_Binding "b7131d7ecd548dcc4b6eb38bef0179b1bc75645e5683b69e6131da69d0aed1be"
Chassis "28928b40-900b-4f48-b4ed-8d9d2f1082fd"
    hostname: "c76ovn02.md.jp"
    Encap geneve
        ip: "192.168.30.102"
        options: {csum="true"}
    Port_Binding "16b258df72cb52ddb2527be69578c1f953c9275e154d4107743b0ee3ac13f095"
    Port_Binding "2c5a0afd-b12a-419e-b6f5-718c5d0e6446"
    Port_Binding "l2gwport"

[root@c76ovn02 ~]# ovs-vsctl show
090be24a-f730-4d28-a4a0-dcf6d97fe618
    Bridge br-int
        fail_mode: secure
        Port "16b258df72cb52d"
            Interface "16b258df72cb52d"
        Port "vnet1"
            tag: 301
            Interface "vnet1"
        Port "patch-br-int-to-l2gwport"
            Interface "patch-br-int-to-l2gwport"
                type: patch
                options: {peer="patch-l2gwport-to-br-int"}
        Port "ovn-1fdd47-0"
            Interface "ovn-1fdd47-0"
                type: geneve
                options: {csum="true", key=flow, remote_ip="192.168.30.103"}
        Port br-int
            Interface br-int
                type: internal
    Bridge br-ext
        Port "patch-l2gwport-to-br-int"
            Interface "patch-l2gwport-to-br-int"
                type: patch
                options: {peer="patch-br-int-to-l2gwport"}
        Port br-ext
            Interface br-ext
                type: internal
        Port "ens36"
            trunks: [30, 300, 301]
            Interface "ens36"
    ovs_version: "2.11.1"

[root@c76ovn03 ~]# ovs-vsctl show
2cbade66-e4e8-48e1-83e7-2ff460c1d665
    Bridge br-ext
        Port "ens36"
            trunks: [300, 301]
            Interface "ens36"
        Port br-ext
            Interface br-ext
                type: internal
    Bridge br-int
        fail_mode: secure
        Port "ovn-28928b-0"
            Interface "ovn-28928b-0"
                type: geneve
                options: {csum="true", key=flow, remote_ip="192.168.30.102"}
        Port br-int
            Interface br-int
                type: internal
        Port "b7131d7ecd548dc"
            Interface "b7131d7ecd548dc"
        Port "vnet1"
            tag: 301
            Interface "vnet1"
    ovs_version: "2.11.1"

[root@c76ovn03 ~]# docker container exec c3 ping 192.168.31.2
PING 192.168.31.2 (192.168.31.2) 56(84) bytes of data.
64 bytes from 192.168.31.2: icmp_seq=1 ttl=64 time=0.029 ms
64 bytes from 192.168.31.2: icmp_seq=2 ttl=64 time=0.070 ms
^C
[root@c76ovn03 ~]# docker container exec c3 ping 192.168.31.203
PING 192.168.31.203 (192.168.31.203) 56(84) bytes of data.
64 bytes from 192.168.31.203: icmp_seq=1 ttl=64 time=0.946 ms
64 bytes from 192.168.31.203: icmp_seq=2 ttl=64 time=0.697 ms
^C
[root@c76ovn03 ~]# docker container exec c3 ping 192.168.31.2
PING 192.168.31.2 (192.168.31.2) 56(84) bytes of data.
64 bytes from 192.168.31.2: icmp_seq=1 ttl=64 time=0.028 ms
64 bytes from 192.168.31.2: icmp_seq=2 ttl=64 time=0.073 ms
64 bytes from 192.168.31.2: icmp_seq=3 ttl=64 time=0.027 ms
^C
[root@c76ovn03 ~]# docker container exec c3 ping 192.168.31.202
PING 192.168.31.202 (192.168.31.202) 56(84) bytes of data.
64 bytes from 192.168.31.202: icmp_seq=1 ttl=64 time=2.34 ms
64 bytes from 192.168.31.202: icmp_seq=2 ttl=64 time=2.28 ms
64 bytes from 192.168.31.202: icmp_seq=3 ttl=64 time=2.98 ms
^C
[root@c76ovn03 ~]# docker container exec c3 ping 192.168.31.203
PING 192.168.31.203 (192.168.31.203) 56(84) bytes of data.
64 bytes from 192.168.31.203: icmp_seq=1 ttl=64 time=0.256 ms
64 bytes from 192.168.31.203: icmp_seq=2 ttl=64 time=0.984 ms
64 bytes from 192.168.31.203: icmp_seq=3 ttl=64 time=0.262 ms
^C
[root@c76ovn03 ~]# docker container exec c3 ping 192.168.31.254
PING 192.168.31.254 (192.168.31.254) 56(84) bytes of data.
64 bytes from 192.168.31.254: icmp_seq=1 ttl=64 time=9.48 ms
64 bytes from 192.168.31.254: icmp_seq=2 ttl=64 time=3.94 ms
64 bytes from 192.168.31.254: icmp_seq=3 ttl=64 time=3.91 ms

NorthboundDBとSouthboundDBの状態を確認する以下のコマンドですが

ovn-nbctl --db=tcp:192.168.30.101:6641 show
ovn-sbctl --db=tcp:192.168.30.101:6642 show

図に起こすとこんな感じになります。
f:id:metonymical:20190721180630p:plain
最初に載せた2つの図と合わせて観ると、より明確になってくるかと思います。

6.補足

ComputeNodeを再起動やShutdownしたいときは、以下のようなコマンドで必ずコンテナを終了させた後に、再起動やShutdownしてください。

docker container stop c2

というのも、Dockerコンテナのアタッチ時はほぼほぼ自動で設定してくれていましたが、デタッチ時は上記コマンドのように正常にコンテナを終了させないと、NorthboundDB上にゴミが残ります。場合によっては消せなくなるので、何度も繰り返し試したい方は必ずコンテナを終了させるようにしましょう。

以上です。

7.最後に

以下のサイトを参考にさせて頂きました。
OVN 設定サンプル | OVN config example 2015/12/27
Using OVN with KVM and Libvirt - Scott's Weblog - The weblog of an IT pro focusing on cloud computing, Kubernetes, Linux, containers, and networking
OVN - L2 Breakout Options | Blog @ Weiti.ORG
Dustin Spinhirne: The OVN Gateway Router

ovnは正直取っつきにくいかもしれません。
しかし、openstack stein以降では、ovnが実装されるようなので、今のうちから、しっかり理解しておくことは大切かなと思います。

また、今回はKVMとDockerでしたが、LXC/LXDでも試してみました。
しかし、FakeBridgeを使用する点が障壁となり疎通できませんでした。
さらに、アップリンク側にDPDKも動作させてみたのですが、設定方法は解ったものの、これまた疎通できずで断念しました。
Bridgeではなく、PAT+Routingだったら上手くいくような気がしていますが、取り急ぎ、一旦まとめてみようと思い今回の記事を書いた次第です。

なお、今回はl2gatewayという方法でBridgeさせましたが、localnetという方法もあります。こちらは、全ComputeNodeにてbr-extを作成した後、以下のコマンドでNorthboundDBに登録すれば設定可能です。

export SW_NAME=$(ovn-nbctl --db=tcp:192.168.30.101:6641 ls-list | awk '{print $2}' | sed s/\(//g | sed s/\)//g)
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-add $SW_NAME lcntport "" 301
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-addresses lcntport unknown
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-type lcntport localnet
ovn-nbctl --db=tcp:192.168.30.101:6641 lsp-set-options lcntport network_name=physnet301

localnetの場合、冗長化できそうな雰囲気はありますが、L2ループの懸念があるため、あまり推奨されていないようです。

ただ、いずれにせよ、ovn単体で使うのはあまり現実的ではないと感じたので、やはりopenstackやovirtなどと一緒に使用するのが良いと思います。

*1:例外はあります。例えば、(1')は自動で設定されますが、その後(1)を手動設定した際に初めて利用可能となる、といったケースがあります。また、(2)を手動設定した後、(3)を設定しないと、(2’)や(3’)がNorthboundDB上で認識されない、など。

*2:ここではUntagやvlan300も作成されていますが、vlan301のみでOKです。他は削除して構いません。

*3:私の環境では、正しい設定に直してもエラーが解消されなかったりしました。本編とあまり関係の無いところで時間を取られるのは、しんどいのでスナップショットやクローン化をおススメします。

*4:上記(4)と(5)のコマンドは同じですが、それぞれのComputeNodeにて実行するため取得するIDが異なります。

CentOS7 kickstartによるインストール

kickstartによるインストールのサンプルファイルをいくつかピックアップしてみたいと思います。

サンプルとしては以下3つ。

  • CentOS7上のKVMにminimalでインストール
  • CentOS7上のKVMにServerGUIでインストール
  • DL360G8上にCentOS7をServerGUIでインストール

これ以外にも応用はいくらでもできると思います。

1.CentOS7上のKVMにminimalでインストール

1-1.kickstartファイルの作成
vi c76min.ks

cmdline
install
# Keyboard layouts
keyboard --vckeymap=us --xlayouts='us'
# System language
lang en_US.UTF-8

# Network information
network  --bootproto=dhcp --device=eth0 --onboot=on --noipv6 --activate
#network  --bootproto=static --device=eth0 --ip=192.168.0.100 --netmask=255.255.255.0 --gateway=192.168.0.1 --nameserver=192.168.0.1 --noipv6 --activate
network  --bootproto=static --device=eth1 --ip=192.168.1.100 --netmask=255.255.255.0 --noipv6
network  --hostname=c7623.local.com

zerombr
bootloader --location=mbr --boot-drive=vda --append="crashkernel=auto biosdevname=0 net.ifnames=0 console=tty0 console=ttyS0,115200n8"
clearpart --none --initlabel

# Disk partitioning information
part /boot --ondisk=vda --size=1024 --fstype="xfs"
part pv.1  --ondisk=vda --size=1024 --grow
volgroup centos --pesize=4096 pv.1
logvol swap  --fstype="swap" --name=swap --vgname=centos --recommended
logvol /     --fstype="xfs"  --name=root --vgname=centos --size=1024 --grow

# Root password
rootpw --plaintext TESTPASSWORD
# System timezone
timezone Asia/Tokyo --isUtc --nontp
user --groups=wheel --name=user1 --password=TESTPASSWORD --plaintext
# X Window System configuration information
xconfig  --startxonboot

%packages
@^minimal
@core
kexec-tools
chrony

%end
reboot --eject
1-2.qcow2ファイルの作成
qemu-img create -f qcow2 /var/lib/libvirt/images/c7623.qcow2 20G
1-3.virt-installの実行
virt-install --connect=qemu:///system \
 --name=c7623 \
 --disk /var/lib/libvirt/images/c7623.qcow2,format=qcow2,bus=virtio \
 --network bridge=virbr0,model=virtio \
 --network network=ovsnw,portgroup=vlan301,model=virtio \
 --initrd-inject=./c76min.ks \
 --extra-args='ks=file:/c76min.ks biosdevname=0 net.ifnames=0 console=tty0 console=ttyS0,115200n8' \
 --vcpus=1 \
 --ram=1024 \
 --accelerate \
 --hvm \
 --location='/var/lib/libvirt/images/CentOS-7-x86_64-DVD-1810.iso' \
 --nographics \
 --os-type=linux \
 --os-variant=centos7.0 \
 --arch=x86_64
1-4.補足

上記1-3のvirt-installコマンドのうち、

 --network network=ovsnw,portgroup=vlan301,model=virtio \

の部分は
以下のようにovsにてスイッチを作成し、net-defineによって定義した場合の設定となります。

vi /tmp/ovsnw.xml

<network>
<name>ovsnw
<forward mode='bridge'/>
<bridge name='ovsbr0'/>
<virtualport type='openvswitch'/>
<portgroup name='untag' default='yes'>
</portgroup>
<portgroup name='vlan11'>
  <vlan>
    <tag id='11'/>
  </vlan>
</portgroup>
<portgroup name='vlan300'>
  <vlan>
    <tag id='300'/>
  </vlan>
</portgroup>
<portgroup name='vlan301'>
  <vlan>
    <tag id='301'/>
  </vlan>
</portgroup>
<portgroup name='vlan302'>
  <vlan>
    <tag id='302'/>
  </vlan>
</portgroup>
</network>

virsh net-define /tmp/ovsnw.xml
virsh net-start ovsnw
virsh net-autostart ovsnw
virsh net-list

2.CentOS7上のKVMにServerGUIでインストール

2-1.kickstartファイルの作成
vi c76gui.ks

cmdline
install
# Keyboard layouts
keyboard --vckeymap=us --xlayouts='us'
# System language
lang en_US.UTF-8

# Network information
network  --bootproto=dhcp --device=eth0 --onboot=on --noipv6 --activate
#network  --bootproto=static --device=eth0 --ip=192.168.0.100 --netmask=255.255.255.0 --gateway=192.168.0.1 --nameserver=192.168.0.1 --noipv6 --activate
network  --bootproto=static --device=eth1 --ip=192.168.1.100 --netmask=255.255.255.0 --noipv6
network  --hostname=c7625.local.com

zerombr
bootloader --location=mbr --boot-drive=vda --append="crashkernel=auto biosdevname=0 net.ifnames=0 console=tty0 console=ttyS0,115200n8"
clearpart --none --initlabel

# Disk partitioning information
part /boot --ondisk=vda --size=1024 --fstype="xfs"
part pv.1  --ondisk=vda --size=1024 --grow
volgroup centos --pesize=4096 pv.1
logvol swap  --fstype="swap" --name=swap --vgname=centos --recommended
logvol /     --fstype="xfs"  --name=root --vgname=centos --size=1024 --grow

# Root password
rootpw --plaintext TESTPASSWORD
# System timezone
timezone Asia/Tokyo --isUtc --nontp
user --groups=wheel --name=user1 --password=TESTPASSWORD --plaintext
# X Window System configuration information
xconfig  --startxonboot

%packages
@^graphical-server-environment
@base
@core
@desktop-debugging
@development
@fonts
@gnome-desktop
@guest-agents
@guest-desktop-agents
@hardware-monitoring
@input-methods
@internet-browser
@virtualization-client
@virtualization-hypervisor
@virtualization-tools
@x11

%end
reboot --eject
2-2.qcow2ファイルの作成
qemu-img create -f qcow2 /var/lib/libvirt/images/c7625.qcow2 20G
2-3.virt-installの実行
virt-install --connect=qemu:///system \
 --name=c7625 \
 --disk /var/lib/libvirt/images/c7625.qcow2,format=qcow2,bus=virtio \
 --network bridge=virbr0,model=virtio \
 --network network=ovsnw,portgroup=vlan301,model=virtio \
 --initrd-inject=./c76gui.ks \
 --extra-args='ks=file:/c76gui.ks biosdevname=0 net.ifnames=0 console=tty0 console=ttyS0,115200n8' \
 --vcpus=1 \
 --ram=1024 \
 --accelerate \
 --hvm \
 --location='/var/lib/libvirt/images/CentOS-7-x86_64-DVD-1810.iso' \
 --nographics \
 --os-type=linux \
 --os-variant=centos7.0 \
 --arch=x86_64

3.DL360G8上にCentOS7をServerGUIでインストール

3-1.kickstartファイルの作成

作業用PCのテキストエディタなどで作成してください。*1

#version=DEVEL
# X Window System configuration information
xconfig  --startxonboot
# License agreement
eula --agreed
# Use CDROM installation media
cdrom
# Use graphical install
graphical
# Run the Setup Agent on first boot
firstboot --enable
# Keyboard layouts
keyboard --vckeymap=us --xlayouts='us'
# System language
lang en_US.UTF-8

ignoredisk --only-use=sda
# Network information
network  --bootproto=static --device=eno1 --ip=192.168.0.100 --netmask=255.255.255.0 --gateway=192.168.0.1 --nameserver=192.168.0.1 --noipv6 --activate
network  --hostname=c765.local.com
#network  --bootproto=dhcp --device=eno2 --onboot=off --ipv6=auto
#network  --bootproto=dhcp --device=eno3 --onboot=off --ipv6=auto
#network  --bootproto=dhcp --device=eno4 --onboot=off --ipv6=auto
#network  --bootproto=dhcp --device=ens1f0 --onboot=off --ipv6=auto
#network  --bootproto=dhcp --device=ens1f1 --onboot=off --ipv6=auto

# Reboot after installation
reboot --eject
# Root password
rootpw --plaintext TESTPASSWORD
# System timezone
timezone Asia/Tokyo --isUtc --nontp
user --groups=wheel --name=user1 --password=TESTPASSWORD
# System bootloader configuration
bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=sda
# Partition clearing information
clearpart --all --initlabel --drives=sda
# Disk partitioning information
part pv.105 --fstype="lvmpv" --ondisk=sda --size=1    --grow
part /boot  --fstype="xfs"   --ondisk=sda --size=1024
volgroup centos --pesize=4096 pv.105
logvol /     --fstype="xfs"  --name=root --vgname=centos --size=1    --grow
logvol swap  --fstype="swap" --name=swap --vgname=centos --size=4096

%packages
@^graphical-server-environment
@base
@core
@desktop-debugging
@development
@dial-up
@fonts
@gnome-desktop
@guest-agents
@guest-desktop-agents
@hardware-monitoring
@input-methods
@internet-browser
@multimedia
@print-client
@virtualization-client
@virtualization-hypervisor
@virtualization-tools
@x11
kexec-tools
%end

%addon com_redhat_kdump --enable --reserve-mb=auto
%end

%anaconda
pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok
pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty
%end

ファイル名をks.cfgとして、isoやimgファイルなどにイメージ化してください。
ここではイメージ化後のファイル名をks.imgとします。

3-2.イメージファイルのセット

f:id:metonymical:20190721010844p:plain
上図のうち、以下のようにイメージファイルをセットします。

ImageFile RemovalMedhia ks.img
ImageFile CD-ROM/DVD CentOS-7-x86_64-DVD-1810.iso
3-3.起動オプションの設定とインストールの実行

f:id:metonymical:20190721011159p:plain
筐体を起動後、上図が表示されたら
Install CentOS 7を選択し、Tabキーを入力してください。
次に起動オプションの入力を促されるので、以下の通り入力してください。

inst.ks=hd:sdb:/ks.cfg

以下のようにインストールが始まれば、あとは待つだけです。
f:id:metonymical:20190721011458p:plain

以上です。

10.最後に

以下のサイトを参考にさせて頂きました。
KickStartその2(ks.cfg設定ファイルの説明) - のぴぴのメモ

/root/anaconda-ks.cfgを参考にすれば色々試せると思いますので、自分なりにやってみることをおススメします。

*1:graphicalではなく、textの方がインストールは早いのですが、私の環境ではなぜか?インストール中に何度も失敗したためgraphicalにしています。

Dockerコンテナのネットワーク設定方法 OvSとSR-IOV編

DockerコンテナでOvSやSR-IOVを使用する場合の設定方法を記載します。
通常のLinuxBridgeやdockerコマンド(macvlan)を使用したネットワーク設定方法については前回記事
Dockerコンテナのネットワーク設定方法 - Metonymical Deflection
を参照してください。

また、OvSについては以下の過去記事のDocker版となります。
CentOS7 ovs(Open vSwitch)のネットワーク設定方法 - Metonymical Deflection
加えて、SR-IOVについては以下の過去記事のDocker版となります。
Linux nmcliコマンドによるKVM&LXC/LXD with SR-IOVのInterface設定 - Metonymical Deflection

なお、LXC/LXDと異なる点として、Docker側Interfaceの永続化設定までは記載していません。*1

1.構成

1-1.環境
筐体                             : ProLiant DL360p Gen8
System ROM                       : P71 01/22/2018
NIC                              : Intel X520-SR2 ens2f0
NIC                              : HP(Emulex) NC552SFP ens1f0-1
OS                               : CentOS7.6(1810)
Kernel                           : 3.10.0-957.el7.x86_64
Installed Environment Groups     : Server with GUI
Add-Ons for Selected Environment : Virtualization Client, Virtualization Hypervisor, Virtualization Tools 
ovs                              : 2.11.0
1-2.全体構成

f:id:metonymical:20190622154959p:plain
構成図上に(1)~(13)までの番号を割り振りました。
このうち、(3)~(11)までは、過去記事↓
CentOS7 ovs(Open vSwitch)のネットワーク設定方法 - Metonymical Deflection
と同様になるため割愛します。

スイッチ側の設定は以下となります。

interface Port-channel1
 switchport trunk encapsulation dot1q
 switchport trunk allowed vlan 11,300-302
 switchport mode trunk
 spanning-tree portfast trunk
!
interface TenGigabitEthernet0/25
 switchport trunk encapsulation dot1q
 switchport trunk allowed vlan 300-304
 switchport mode trunk
 spanning-tree portfast trunk
 channel-group 1 mode active
!
interface TenGigabitEthernet0/26
 switchport trunk encapsulation dot1q
 switchport trunk allowed vlan 300-304
 switchport mode trunk
 spanning-tree portfast trunk
 channel-group 1 mode active
!
interface TenGigabitEthernet0/27
 switchport trunk encapsulation dot1q
 switchport trunk allowed vlan 300-304
 switchport mode trunk
 spanning-tree portfast trunk
!
interface Vlan300
 ip address 192.168.30.254 255.255.255.0
!
1-3.全体の流れ ~概要~
  1. Bridge作成:(1)
  2. Bonding:(2)
  3. Dockerコンテナをovsbr0にアタッチ:(12)
  4. DockerコンテナをSR-IOVのVFにアタッチ:(13)
1-4.全体の流れ ~コマンドのみ~

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

事前準備1:OvSのインストール
yum install -y https://repos.fedorapeople.org/repos/openstack/openstack-stein/rdo-release-stein-2.noarch.rpm && \
yum install -y openvswitch

事前準備2:Dockerのインストール
curl -sSL https://get.docker.com/ | sh

事前準備3:pipeworkのインストール
curl -sL https://raw.githubusercontent.com/jpetazzo/pipework/master/pipework > /usr/local/bin/pipework
chmod +x /usr/local/bin/pipework

1.Bridge作成
(1)
ovs-vsctl add-br ovsbr0

2.Bonding
(2)
ovs-vsctl add-bond ovsbr0 bond0 ens1f0 ens1f1

1&2の永続化設定
vi /etc/sysconfig/network-scripts/ifcfg-ovsbr0

DEVICE=ovsbr0
DEVICETYPE=ovs
TYPE=OVSBridge
BOOTPROTO=static
NM_CONTROLLED=no
ONBOOT=yes
HOTPLUG=no

vi /etc/sysconfig/network-scripts/ifcfg-ens1f0

DEVICE=ens1f0
NETBOOT=yes
IPV6INIT=no
BOOTPROTO=none
NM_CONTROLLED=no
ONBOOT=yes
HOTPLUG=no

vi /etc/sysconfig/network-scripts/ifcfg-ens1f1

DEVICE=ens1f1
NETBOOT=yes
IPV6INIT=no
BOOTPROTO=none
NM_CONTROLLED=no
ONBOOT=yes
HOTPLUG=no

[LACPの場合]
vi /etc/sysconfig/network-scripts/ifcfg-bond0

DEVICE=bond0
ONBOOT=yes
DEVICETYPE=ovs
TYPE=OVSBond
OVS_BRIDGE=ovsbr0
BOOTPROTO=none
NM_CONTROLLED=no
BOND_IFACES="ens1f0 ens1f1"
OVS_OPTIONS="bond_mode=balance-tcp lacp=active other_config:lacp-time=fast vlan_mode=trunk trunks=300-304"
HOTPLUG=no

[固定LAGの場合]
vi /etc/sysconfig/network-scripts/ifcfg-bond0

DEVICE=bond0
ONBOOT=yes
DEVICETYPE=ovs
TYPE=OVSBond
OVS_BRIDGE=ovsbr0
BOOTPROTO=none
NM_CONTROLLED=no
BOND_IFACES="ens1f0 ens1f1"
OVS_OPTIONS="bond_mode=balance-slb lacp=off vlan_mode=trunk trunks=300-304"
HOTPLUG=no

3.Dockerコンテナをovsbr0にアタッチ
(コンテナ起動)
docker run -itd \
--privileged \
--network bridge \
--name dkc1 \
centos \
/sbin/init

(12)
pipework \
ovsbr0 \
-i eth1 \
dkc1 \
192.168.30.103/24 \
@300

4.DockerコンテナをSR-IOVのVFにアタッチ
(コンテナ起動)
docker run -itd \
--privileged \
--network bridge \
--name dkc2 \
centos \
/sbin/init

(13)
pipework \
--direct-phys enp7s16 \
-i eth1 \
dkc2 \
192.168.30.104/24 \
@300

2.事前準備

2-1.事前準備1:OvSのインストール
yum install -y https://repos.fedorapeople.org/repos/openstack/openstack-stein/rdo-release-stein-2.noarch.rpm && \
yum install -y openvswitch

RDOのSteinのリポジトリをインストールした後、最新のOvSをインストールしています。

2-2.事前準備2:Dockerのインストール
curl -sSL https://get.docker.com/ | sh

最新のDcokerをインストールしています。

2-3.事前準備3:pipeworkのインストール
curl -sL https://raw.githubusercontent.com/jpetazzo/pipework/master/pipework > /usr/local/bin/pipework
chmod +x /usr/local/bin/pipework

pieworkをインストールしています。
OvSとSR-IOVの両方とも同じコマンド体系で設定できるため、pieworkにしました。
ovs-dockerによる方法は最後に記載します。

3.Bridge作成

説明無しでザックリ書きます。
詳細な説明は過去記事を参照してください。
(1)Bridgeの作成

出力結果
[root@c761 ~]# ovs-vsctl add-br ovsbr0
[root@c761 ~]# ovs-vsctl show
b1d3d75a-2c4c-49e7-bc33-06e44a70dfe2
    Bridge "ovsbr0"
        Port "ovsbr0"
            Interface "ovsbr0"
                type: internal
    ovs_version: "2.11.0"

4.Bonding

Bondを作成し、物理インターフェースをBondにアタッチします。
(2)Bond作成+物理アタッチ

出力結果
[root@c761 ~]# ovs-vsctl add-bond ovsbr0 bond0 ens1f0 ens1f1
[root@c761 ~]# ovs-vsctl show
b1d3d75a-2c4c-49e7-bc33-06e44a70dfe2
    Bridge "ovsbr0"
        Port "ovsbr0"
            Interface "ovsbr0"
                type: internal
        Port "bond0"
            Interface "ens1f1"
            Interface "ens1f0"
    ovs_version: "2.11.0"

5.永続化設定

コマンドを打っただけだと、ホストOSをRebootすると消えてしまうので永続化設定を行います。

vi /etc/sysconfig/network-scripts/ifcfg-ovsbr0

DEVICE=ovsbr0
DEVICETYPE=ovs
TYPE=OVSBridge
BOOTPROTO=static
NM_CONTROLLED=no
ONBOOT=yes
HOTPLUG=no

vi /etc/sysconfig/network-scripts/ifcfg-ens1f0

DEVICE=ens1f0
NETBOOT=yes
IPV6INIT=no
BOOTPROTO=none
NM_CONTROLLED=no
ONBOOT=yes
HOTPLUG=no

vi /etc/sysconfig/network-scripts/ifcfg-ens1f1

DEVICE=ens1f1
NETBOOT=yes
IPV6INIT=no
BOOTPROTO=none
NM_CONTROLLED=no
ONBOOT=yes
HOTPLUG=no

[LACPの場合]
vi /etc/sysconfig/network-scripts/ifcfg-bond0

DEVICE=bond0
ONBOOT=yes
DEVICETYPE=ovs
TYPE=OVSBond
OVS_BRIDGE=ovsbr0
BOOTPROTO=none
NM_CONTROLLED=no
BOND_IFACES="ens1f0 ens1f1"
OVS_OPTIONS="bond_mode=balance-tcp lacp=active other_config:lacp-time=fast vlan_mode=trunk trunks=300-304"
HOTPLUG=no

[固定LAGの場合]
vi /etc/sysconfig/network-scripts/ifcfg-bond0

DEVICE=bond0
ONBOOT=yes
DEVICETYPE=ovs
TYPE=OVSBond
OVS_BRIDGE=ovsbr0
BOOTPROTO=none
NM_CONTROLLED=no
BOND_IFACES="ens1f0 ens1f1"
OVS_OPTIONS="bond_mode=balance-slb lacp=off vlan_mode=trunk trunks=300-304"
HOTPLUG=no

設定後はnetworkサービスをリスタート
systemctl restart network

networkサービスのリスタートを行っても正常に動作しない場合、少々ダサいですがホストOSごと再起動してみてください。

6.Dockerコンテナをovsbr0にアタッチ

(コンテナ起動)
docker run -itd \
--privileged \
--network bridge \
--name dkc1 \
centos \
/sbin/init

(12)
pipework \
ovsbr0 \
-i eth1 \
dkc1 \
192.168.30.103/24 \
@300

以下のようにvethが追加されていればOKです。

[root@c763 ~]# ovs-vsctl show
23cda0ca-2d97-4c3f-bd00-d143a1f3a151
    Manager "ptcp:6640"
        is_connected: true
    Bridge "ovsbr0"
        Port "ovsbr0"
            Interface "ovsbr0"
                type: internal
        Port "bond0"
            trunks: [300, 301, 302, 303, 304]
            Interface "ens1f0"
            Interface "ens1f1"
        Port "veth1pl25675"
            tag: 300
            Interface "veth1pl25675"
    ovs_version: "2.11.0"

以下にpipeworkのSyntax出力を記載します。

[root@c763 ~]# pipework
Syntax:
pipework  [-i containerinterface] [-l localinterfacename] [-a addressfamily]  /[@default_gateway] [macaddr][@vlan]
pipework  [-i containerinterface] [-l localinterfacename]  dhcp [macaddr][@vlan]
pipework route  
pipework rule  
pipework tc  
pipework --wait [-i containerinterface]

上記Syntaxより、例えば以下のようにGWとMACを指定した設定も可能になります。
また「@300」を消せばUntagとなります。

(12')
pipework \
ovsbr0 \
-i eth1 \
dkc1 \
192.168.30.103/24@192.168.30.254 \
00:11:22:33:44:55@300

7.DockerコンテナをSR-IOVのVFにアタッチ

(コンテナ起動)
docker run -itd \
--privileged \
--network bridge \
--name dkc2 \
centos \
/sbin/init

(13)
pipework \
--direct-phys enp7s16 \
-i eth1 \
dkc2 \
192.168.30.104/24 \
@300

以下のようにコンテナとVFのMACアドレスが一致していればOKです。

[root@c763 ~]# ip link show enp7s16
12: enp7s16:  mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 1a:6a:a5:b0:49:59 brd ff:ff:ff:ff:ff:ff
[root@c763 ~]# 
[root@c763 ~]# docker container exec -it dkc2 ip link show eth1
36: eth1@if12:  mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 1a:6a:a5:b0:49:59 brd ff:ff:ff:ff:ff:ff link-netnsid 0

ポイントはオプション「--direct-phys enp7s16」にてVFを掴ませている点が、OvSとは異なります。

8.補足1:ovs-dockerによるOvSへのアタッチ

ovs-dockerのwget&実行権限付与
wget -O /usr/local/bin/ovs-docker \
https://raw.githubusercontent.com/openvswitch/ovs/master/utilities/ovs-docker
chmod 755 /usr/local/bin/ovs-docker

(コンテナ起動)
docker run -itd \
--privileged \
--network bridge \
--name dkc3 \
centos \
/sbin/init

(12)-1:OvSへのアタッチとIP設定
ovs-docker add-port ovsbr0 eth1 dkc3 \
--ipaddress="192.168.30.105/24"

(12)-2:Vlanの設定
ovs-docker set-vlan ovsbr0 eth1 dkc3 300

以下のように出力されていればOKです。

[root@c763 ~]# ovs-vsctl show
23cda0ca-2d97-4c3f-bd00-d143a1f3a151
    Manager "ptcp:6640"
    Bridge "ovsbr0"
        Port "ovsbr0"
            Interface "ovsbr0"
                type: internal
        Port "15d5c9395dab4_l"
            tag: 300
            Interface "15d5c9395dab4_l"
        Port "bond0"
            trunks: [300, 301, 302, 303, 304]
            Interface "ens1f0"
            Interface "ens1f1"
    ovs_version: "2.11.0"

一手間増えますが、SR-IOVのVFへのアタッチができないことやovs-dockerもpipeworkもdocker inspectに載ってこないことを考えると、pipeworkで良いのかなと思いました。

9.補足2:Open_vMonitor

補足というか、おまけでOpen_vMonitorをご紹介させてください。

ovs-vsctl set-manager ptcp:6640
docker run -d -p 3000:3000 --name ovsgui01 -h ovsgui01 plvisiondevs/open_vmonitor

ホストOSのIP(192.168.11.213)にアクセス

http://192.168.11.213:3000/enter
 username:admin
 password:admin
 Enter OVSDB IP:192.168.11.213

f:id:metonymical:20190622152119p:plain
以下の画面で各ポートの情報が確認できます。
f:id:metonymical:20190622152217p:plain
多数のコンテナを起動した際は見やすいのかなと思います。

以上です。

10.最後に

以下のサイトを参考にさせて頂きました。
第35回 Open vSwitchで作るDockerのネットワーク(OVSで構築する編) (1/6) - ITmedia エンタープライズ
SR-IOV in Docker containers - Anirban Mukherjee - Medium

永続化設定という課題はありますが、LXC/LXDとはそもそもの用途が異なるため、まぁ、こんなもんかなという感じです。
以下のサイトにLXC/LXDとDockerの比較表があるので参考までに。
Dockerもいいけど、LXCも使おうぜ - Qiita

次のステップとして、DPDKを実装したいと考えていますが、ovnやconsulを使用した構成となるため、CentOS8になってからにしようかなと思っています。
とはいえ、ovnを使い始めるとなると、OpenStackやokdの方がいいかなと少し悩んでいます。

*1:作りこめばできそうですが、LXC/LXDとDockerの用途の違いかなと思っているので、あまり深入りはしませんでした。

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

DockerコンテナのトラフィックをBridgeで外部ネットワークに流して使用する場合の設定方法を記載したいと思います。
Dockerで作成するBridge*1は、ホストOSのiptablesでPATされてしまうため、コンテナと外部NW機器が同一のNWセグメントとして使用できるようにします。

以下の過去記事のDcoker版と考えてください。
LXC/LXDコンテナのネットワーク設定方法 - Metonymical Deflection

なお、設定方法が2種類あります。先に1を記載した後、2を記載したいと思います。

No 設定方法 ホストOSとの疎通性 brctlやipコマンドでの確認可否
1 LinuxBridgeを併用 可能
2 dockerコマンドのみ使用(macvlan) 不可

1.環境

1-1.VMWare
筐体                             : 自作PC(Win10pro)
CPU                           : Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz
VMWare              : VMware(R) Workstation 15 Pro 15.1.0 build-13591040  
OS                               : CentOS7.6(1810)
Kernel                           : 3.10.0-957.el7.x86_64
Installed Environment Groups     : Minimal Install

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

1-2.全体構成

f:id:metonymical:20190616175355p:plain
上図のうちdocker0はDefaultで作成されています。
また、docker0はNATして外部ネットワークに接続されています。私の用途としては、コンテナ上でyumなどを行いたい場合のInternet接続用マネジメントインターフェースとして使用しています。*2

しかし、KVMライクにDockerコンテナを使用したいので、今回行う設定は(1)~(9)となります。
(1)(2)(5)(6)(7):nmcliコマンド
(3)(4)(8)(9):dockerコマンド
となります。

1-2.全体の流れ ~概要~
  • LinuxBridge併用の場合:(1)~(9)
  • dockerコマンドのみの場合:(3)(4)(8)(9)

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

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

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

1.LinuxBridge併用の場合
(1)
nmcli connection add type bridge autoconnect yes con-name br0 ifname br0
nmcli connection modify br0 bridge.stp no
nmcli connection modify br0 ipv6.method ignore
nmcli connection modify br0 ipv4.method manual ipv4.addresses 192.168.30.202/24
nmcli connection up br0
nmcli con show
brctl show

(2)
nmcli connection add type ethernet autoconnect yes con-name ens34 ifname ens34
nmcli connection modify ens34 connection.master br0 connection.slave-type bridge
nmcli connection up ens34
nmcli con show
brctl show

(3)
docker network create -d bridge \
--subnet=192.168.30.0/24 \
--ip-range=192.168.30.0/25 \
--gateway=192.168.30.202 \
--opt com.docker.network.bridge.name=br0 \
br0

(コンテナ起動)
docker run -itd \
--privileged \
--network bridge \
--name dkc1 \
centos \
/sbin/init

(4)
docker network connect br0 dkc1 \
--ip=192.168.30.100

(5)
nmcli connection add type bridge autoconnect yes con-name br301 ifname br301
nmcli connection modify br301 bridge.stp no
nmcli connection modify br301 ipv6.method ignore
nmcli connection modify br301 ipv4.method manual ipv4.addresses 192.168.31.202/24
nmcli connection up br301
nmcli con show
brctl show

(6)
nmcli connection add type vlan autoconnect yes con-name ens34.301 ifname ens34.301 dev ens34 id 301
nmcli con show
brctl show

(7)
nmcli connection modify ens34.301 connection.master br301 connection.slave-type bridge
nmcli connection up ens34.301
nmcli con show
brctl show

(8)
docker network create -d bridge \
--subnet=192.168.31.0/24 \
--ip-range=192.168.31.0/25 \
--gateway=192.168.31.202 \
--opt com.docker.network.bridge.name=br301 \
br301

(コンテナ起動)
docker run -itd \
--privileged \
--network bridge \
--name dkc2 \
centos \
/sbin/init

(9)
docker network connect br301 dkc2 \
--ip=192.168.31.100

2.dockerコマンドのみの場合
(3)
docker network create -d macvlan \
--subnet=192.168.30.0/24 \
--ip-range=192.168.30.0/25 \
--gateway=192.168.30.254 \
-o parent=ens34 br0

(コンテナ起動)
docker run -itd \
--privileged \
--network bridge \
--name dkc1 \
centos \
/sbin/init

(4)
docker network connect br0 dkc1 \
--ip=192.168.30.100

(8)
docker network create -d macvlan \
--subnet=192.168.31.0/24 \
--ip-range=192.168.31.0/25 \
--gateway=192.168.31.254 \
-o parent=ens34.301 br301

(コンテナ起動)
docker run -itd \
--privileged \
--network bridge \
--name dkc2 \
centos \
/sbin/init

(9)
docker network connect br301 dkc2 \
--ip=192.168.31.100

<コンテナ起動コマンドについて補足>
「--network bridge」について、Default定義NWとユーザ定義NWを2つ同時にアタッチしようとすると、以下のようにエラーで弾かれます。このため、まずはDefault定義NWを設定しています。

[root@c76dk01 ~]# docker run -itd \
> --privileged \
> --network bridge \
> --network br0 \
> --name dkc3 \
> c76 \
> /sbin/init
docker: conflicting options: cannot attach both user-defined and non-user-defined network-modes.
See 'docker run --help'.
[root@c76dk01 ~]#

2.LinuxBridge併用の場合

2-1.通常のBridge

nmcliコマンドによりBridgeインターフェースを作成し、コンテナのNICをLinuxBridgeにアタッチします。
(1)(2)Bridgeインターフェースbr0の作成+ens34をbr0にアタッチ
(3)dockerコマンドにてbr0を作成*3
(4)br0にコンテナdkc1のeth1をアタッチ+IP設定

(1)(2)Bridgeインターフェースbr0の作成+ens34をbr0にアタッチ
(1)と(2)は過去記事などを参照してください。

投入コマンド
(1)
nmcli connection add type bridge autoconnect yes con-name br0 ifname br0
nmcli connection modify br0 bridge.stp no
nmcli connection modify br0 ipv6.method ignore
nmcli connection modify br0 ipv4.method manual ipv4.addresses 192.168.30.202/24
nmcli connection up br0
nmcli con show
brctl show
(2)
nmcli connection add type ethernet autoconnect yes con-name ens34 ifname ens34
nmcli connection modify ens34 connection.master br0 connection.slave-type bridge
nmcli connection up ens34
nmcli con show
brctl show

出力例
以下のように出力されていればOKです。
[root@c76dk01 ~]# nmcli con show
NAME       UUID                                  TYPE      DEVICE
br0        5c7da373-af73-4cda-a420-7949eeb6974e  bridge    br0
docker0    227bbb74-0c07-447a-99ec-5f84c6bf61c0  bridge    docker0
ens33      2f7e32c0-adfd-41b1-9698-dff6406af75d  ethernet  ens33
ens34      2849b0b6-1c27-4293-81b3-a07068feb36c  ethernet  ens34

br0が作成され、物理インターフェースens34にもアタッチされます。

(3)dockerコマンドにてbr0を作成

投入コマンド
(3)
docker network create -d bridge \
--subnet=192.168.30.0/24 \
--ip-range=192.168.30.0/25 \
--gateway=192.168.30.202 \
--opt com.docker.network.bridge.name=br0 \
br0

出力例
[root@c76dk01 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
ebc2a0612742        br0                 bridge              local
a6ae25cd104e        bridge              bridge              local
f51b9d166f07        host                host                local
d1023dacb10b        none                null                local

[root@c76dk01 ~]# docker network inspect br0
[
    {
        "Name": "br0",
        "Id": "ebc2a0612742e6b2529fde112c5b2cb465abb6d27fe8623c20b92c7242d573bb",
        "Created": "2019-06-16T18:22:29.649525689+09:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.30.0/24",
                    "IPRange": "192.168.30.0/25",
                    "Gateway": "192.168.30.202"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.name": "br0"
        },
        "Labels": {}
    }
]
docker network create -d bridge \ NWドライバにbridgeを選択。必須
--subnet=192.168.30.0/24 \ サブネットを定義。必須
--ip-range=192.168.30.0/25 \ DHCPで配布されるレンジを定義。任意
--gateway=192.168.30.202 \ GWアドレスを定義。任意。但し、設定しないと192.168.30.1が強制的に設定されます。また、nmcliコマンドで作成したbr0のIPも192.168.30.1に上書きされます。
--opt com.docker.network.bridge.name=br0 \ nmcliコマンドで作成したbr0にアタッチ。必須
br0 Docker上のNWの名前。必須。ですが任意の名前でOK。管理上nmcliコマンドで作成したbr0と名前を一致せています。


(4)br0にコンテナdkc1のeth1をアタッチ+IP設定
続いてコンテナを起動し、コンテナNICのeth1をbr0にアタッチさせます。

投入コマンド
(コンテナ起動)
docker run -itd \
--privileged \
--network bridge \
--name dkc1 \
centos \
/sbin/init

(4)
docker network connect br0 dkc1 \
--ip=192.168.30.100

出力例
[root@c76dk01 ~]# brctl show
bridge name     bridge id               STP enabled     interfaces
br0             8000.000c29d40546       no              ens34
                                                        veth41095a7
docker0         8000.0242f2b40eff       no              veth24c4ace

[root@c76dk01 ~]# docker network inspect br0
[
    {
        "Name": "br0",
        "Id": "e14f9d9ab5f236adee0bfbe95760272e3bfa5d0371804b1bb880164eb7b85c3f",
        "Created": "2019-06-16T18:44:09.13402567+09:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.30.0/24",
                    "IPRange": "192.168.30.0/25",
                    "Gateway": "192.168.30.202"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "b4ec13912196828e074ed21ab4a349afb93a816cf6788f563f36c9e0708a00a5": {
                "Name": "dkc1",
                "EndpointID": "3ddb6c7fd885c94d75d3e7bfbf37facc37778bffb01e7eeee02d42f790bba718",
                "MacAddress": "02:42:c0:a8:1e:64",
                "IPv4Address": "192.168.30.100/24",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.name": "br0"
        },
        "Labels": {}
    }
]
2-2.VlanTagを付ける場合のBridge

nmcliコマンドによりVlan+Bridgeインターフェースを作成し、コンテナのNICをLinuxBridgeにアタッチします。
トラフィックがVlanインターフェースens34.301を通過する際に以下の挙動となります。

コンテナから外部NWへのトラフィック VlanTagが付けられる
外部NWからコンテナへのトラフィック VlanTagが外されたる

(5)(6)(7)Vlanインターフェースens34.301+Bridgeインターフェースbr301の作成+ens34.301をbr301にアタッチ
(8)dockerコマンドにてbr301を作成
(9)br301にコンテナdkc2のeth1をアタッチ+IP設定

(5)(6)(7)Vlanインターフェースens34.301+Bridgeインターフェースbr301の作成+ens34.301をbr301にアタッチ
(1)(2)と同様に過去記事などを参照してください。

投入コマンド
(5)
nmcli connection add type bridge autoconnect yes con-name br301 ifname br301
nmcli connection modify br301 bridge.stp no
nmcli connection modify br301 ipv6.method ignore
nmcli connection modify br301 ipv4.method manual ipv4.addresses 192.168.31.202/24
nmcli connection up br301
nmcli con show
brctl show

(6)
nmcli connection add type vlan autoconnect yes con-name ens34.301 ifname ens34.301 dev ens34 id 301
nmcli con show
brctl show

(7)
nmcli connection modify ens34.301 connection.master br301 connection.slave-type bridge
nmcli connection up ens34.301
nmcli con show
brctl show

出力例
以下のように出力されていればOKです。
[root@c76dk01 ~]# nmcli con show
NAME       UUID                                  TYPE      DEVICE
br0        5c7da373-af73-4cda-a420-7949eeb6974e  bridge    br0
br301      07f444fd-18d5-47a8-a721-39696d4fb0c6  bridge    br301
docker0    d3c2e742-6653-4d56-8b75-10d7f178fc41  bridge    docker0
ens33      2f7e32c0-adfd-41b1-9698-dff6406af75d  ethernet  ens33
ens34      2849b0b6-1c27-4293-81b3-a07068feb36c  ethernet  ens34
ens34.301  9e5eb500-f432-41fb-b72a-2492567a98c4  vlan      ens34.301

br301が作成され、VLANインターフェースens34.301にもアタッチされます。

(8)dockerコマンドにてbr301を作成

投入コマンド
(8)
docker network create -d bridge \
--subnet=192.168.31.0/24 \
--ip-range=192.168.31.0/25 \
--gateway=192.168.31.202 \
--opt com.docker.network.bridge.name=br301 \
br301

出力例
[root@c76dk01 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
e14f9d9ab5f2        br0                 bridge              local
ce879f2b276f        br301               bridge              local
a6ae25cd104e        bridge              bridge              local
f51b9d166f07        host                host                local
d1023dacb10b        none                null                local

[root@c76dk01 ~]# docker network inspect br301
[
    {
        "Name": "br301",
        "Id": "ce879f2b276f71ca45f6f09b993d561f42b3297b40d2964b1518ef64280dfd0f",
        "Created": "2019-06-16T19:08:44.613109443+09:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.31.0/24",
                    "IPRange": "192.168.31.0/25",
                    "Gateway": "192.168.31.202"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.name": "br301"
        },
        "Labels": {}
    }
]
docker network create -d bridge \ NWドライバにbridgeを選択。必須
--subnet=192.168.31.0/24 \ サブネットを定義。必須
--ip-range=192.168.31.0/25 \ DHCPで配布されるレンジを定義。任意
--gateway=192.168.31.202 \ GWアドレスを定義。任意。但し、設定しないと192.168.31.1が強制的に設定されます。また、nmcliコマンドで作成したbr0のIPも192.168.31.1に上書きされます。
--opt com.docker.network.bridge.name=br301 \ nmcliコマンドで作成したbr301にアタッチ。必須
br301 Docker上のNWの名前。必須。ですが任意の名前でOK。管理上nmcliコマンドで作成したbr301と名前を一致せています。


(9)br301にコンテナdkc2のeth1をアタッチ+IP設定
続いてコンテナを起動し、コンテナNICのeth1をbr301にアタッチさせます。

投入コマンド
(コンテナ起動)
docker run -itd \
--privileged \
--network bridge \
--name dkc2 \
centos \
/sbin/init

(4)
docker network connect br301 dkc2 \
--ip=192.168.31.100

出力例
[root@c76dk01 ~]# brctl show
bridge name     bridge id               STP enabled     interfaces
br0             8000.000c29d40546       no              ens34
                                                        veth41095a7
br301           8000.000c29d40546       no              ens34.301
                                                        veth2d8f44e
docker0         8000.0242f2b40eff       no              veth24c4ace
                                                        veth2cc58e3

[root@c76dk01 ~]# docker network inspect br301
[
    {
        "Name": "br301",
        "Id": "ce879f2b276f71ca45f6f09b993d561f42b3297b40d2964b1518ef64280dfd0f",
        "Created": "2019-06-16T19:08:44.613109443+09:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.31.0/24",
                    "IPRange": "192.168.31.0/25",
                    "Gateway": "192.168.31.202"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "2ae29b5d870975ad25f86c674113ea4ef6db077f88c9de13c35d3b9f4dc94ecc": {
                "Name": "dkc2",
                "EndpointID": "0d46e4d5f92e68613096c8103714cf90fafde1ff3145c156cc6a9b76b66dc8fa",
                "MacAddress": "02:42:c0:a8:1f:64",
                "IPv4Address": "192.168.31.100/24",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.name": "br301"
        },
        "Labels": {}
    }
]

以上がLinuxBridge併用の場合となります。

3.dockerコマンドのみの場合

作業工程としては、LinuxBridgeを併用する場合よりもシンプルかつ工程が少ないのでわかりやすいかもしれません。
しかし、ホストOS上では、MACアドレステーブルやarpテーブルの確認が不可能っぽいです。*4
かつ、ホストOSとの疎通性はありません。*5
なお、本項を試す場合は、前項までに作成したコンテナやBridge など*6は全て削除しておいてください。

3-1.通常のBridge

dockerコマンドによりBridgeネットワークを作成し、ens34にアタッチします。
(3)dockerコマンドにてbr0を作成
(4)br0にコンテナdkc1のeth1をアタッチ+IP設定

(3)dockerコマンドにてbr0を作成

投入コマンド
(3)
docker network create -d macvlan \
--subnet=192.168.30.0/24 \
--ip-range=192.168.30.0/25 \
--gateway=192.168.30.254 \
-o parent=ens34 br0

出力例
以下のように出力されていればOKです。
[root@c76dk01 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
92bc5bdf05b4        br0                 macvlan             local
a6ae25cd104e        bridge              bridge              local
f51b9d166f07        host                host                local
d1023dacb10b        none                null                local
docker network create -d macvlan \ NWドライバにmacvlanを指定。必須
--subnet=192.168.30.0/24 \ 2.LinuxBridge併用の場合と同様
--ip-range=192.168.30.0/25 \ 2.LinuxBridge併用の場合と同様
--gateway=192.168.30.254 \ 2.LinuxBridge併用の場合と同様
-o parent=ens34 br0 ens34にアタッチ。必須。名前は2.LinuxBridge併用の場合と同様に任意の名前でOKです。


(4)br0にコンテナdkc1のeth1をアタッチ+IP設定

投入コマンド
(コンテナ起動)
docker run -itd \
--privileged \
--network bridge \
--name dkc1 \
centos \
/sbin/init

(4)
docker network connect br0 dkc1 \
--ip=192.168.30.100

出力例
[root@c76dk01 ~]# docker network inspect br0
[
    {
        "Name": "br0",
        "Id": "92bc5bdf05b4371123b3562325260de03ad2133a63ee6f50a4380bd1bbeeb220",
        "Created": "2019-06-16T19:27:48.575931685+09:00",
        "Scope": "local",
        "Driver": "macvlan",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.30.0/24",
                    "IPRange": "192.168.30.0/25",
                    "Gateway": "192.168.30.254"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "a86cfcb7c7729c2f5aa0ad1c5cbae1a84229328a1342d5670a7e3eb6159c5f39": {
                "Name": "dkc1",
                "EndpointID": "cbfdff9a7d5fd97cabc408c2a2bbb5766c0192c989952997ab09996e6ba3696c",
                "MacAddress": "02:42:c0:a8:1e:64",
                "IPv4Address": "192.168.30.100/24",
                "IPv6Address": ""
            }
        },
        "Options": {
            "parent": "ens34"
        },
        "Labels": {}
    }
]
3-2.VlanTagを付ける場合のBridge

dockerコマンドによりBridgeネットワークとVlanインターフェースを作成し、ens34.301にアタッチします。
(8)dockerコマンドにてbr301とens34.301を作成
(9)br301にコンテナdkc2のeth1をアタッチ+IP設定

dockerコマンドにてbr301とens34.301を作成

投入コマンド
(8)
docker network create -d macvlan \
--subnet=192.168.31.0/24 \
--ip-range=192.168.31.0/25 \
--gateway=192.168.31.254 \
-o parent=ens34.301 br301

出力例
以下のように出力されていればOKです。
[root@c76dk01 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
92bc5bdf05b4        br0                 macvlan             local
8dd7d4bfec8c        br301               macvlan             local
a6ae25cd104e        bridge              bridge              local
f51b9d166f07        host                host                local
d1023dacb10b        none                null                local
docker network create -d macvlan \ NWドライバにmacvlanを指定。必須
--subnet=192.168.31.0/24 \ 2.LinuxBridge併用の場合と同様
--ip-range=192.168.31.0/25 \ 2.LinuxBridge併用の場合と同様
--gateway=192.168.31.254 \ 2.LinuxBridge併用の場合と同様
-o parent=ens34.301 br301 ens34.301とbr301を作成。*7br301をens34.301にアタッチ。必須。名前は2.LinuxBridge併用の場合と同様に任意の名前でOKです。

(9)br301にコンテナdkc2のeth1をアタッチ+IP設定

投入コマンド
(コンテナ起動)
docker run -itd \
--privileged \
--network bridge \
--name dkc2 \
centos \
/sbin/init

(9)
docker network connect br301 dkc2 \
--ip=192.168.31.100

出力例
[root@c76dk01 ~]# docker network inspect br301
[
    {
        "Name": "br301",
        "Id": "8dd7d4bfec8c0717acec3b40bc7cdf3d49ced0e2a2ac0a737d094f1ada2eec8c",
        "Created": "2019-06-16T19:28:00.783746421+09:00",
        "Scope": "local",
        "Driver": "macvlan",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.31.0/24",
                    "IPRange": "192.168.31.0/25",
                    "Gateway": "192.168.31.254"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "9a193996a6928474d792f88b9b72f21fbe8f4b46cd973e8ad2ba39b97d4adcaa": {
                "Name": "dkc2",
                "EndpointID": "279d95c111a3b33a7f8872966d15bd5af5251a4e25d46e31a64772a6930cb1e5",
                "MacAddress": "02:42:c0:a8:1f:64",
                "IPv4Address": "192.168.31.100/24",
                "IPv6Address": ""
            }
        },
        "Options": {
            "parent": "ens34.301"
        },
        "Labels": {}
    }
]

以上です。

4.最後に

以下のサイトを参考にさせて頂きました。
Use macvlan networks | Docker Documentation
macvlan_ipvlan_driver_notes.md · GitHub
外部ネットワーク側からDockerコンテナに通信できる環境を作成する - Qiita

今回の設定方法以外にも「DOCKER_OPTS=」のオプションを設定することでできるようです。

当然ながらDockerは多くのDocに恵まれているため、さほど苦労することなく、やりたい事ができるようになりました。
ただ、今回ご紹介した2種類の方法が同時に記載されているサイトは少なかったことや、過去記事からの延長として、LinuxBridgeやLXC/LXDとの比較ができるという点で、まとめた方が良いなと感じたため記載しました。

私の本職はNWエンジニアなので、最下層レイヤから上位層レイヤに昇っていく過程で、必要になりそうなポイントをクローズアップしながら記載していければいいなと考えています。
また、この流れが出来てしまったので、当然ですが、SR-IOVやDPDK、OvSによるDockerネットワークの設定方法なども、まとめられたらいいなと思います。
さらに、k8sのネットワーク周りまで踏み込んだり、OpenStackNeutron+OVNにも広げていけたら面白うそうだと考えていますので、ご期待ください。

*1:docker network create -d bridgeコマンドで作るBridgeのことです

*2:Dockerの場合はLXCとは異なり、コンテナ起動後にあまりyumなどを実行することはないと思いますが。

*3:作成というよりも、LinuxBridgeにアタッチするとか関連付けをすると言った方が良いかもしれません。

*4:RESTを使えばGETできるかもしれません

*5:トラブった際が少し不安ですね。

*6:nmcliコマンドによるBridge やVLANインターフェース、dockerコマンドによるNW設定やコンテナ

*7:-o parent=ens34.301と指定しただけで、VLANインターフェースを作成してくれるため、かなり楽です。