Metonymical Deflection

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

CentOS8 小ネタ集その3:Nested KVMの設定

CentOS8におけるNested KVMの設定です。

1.Nestedの設定

sed -i -e "s/#options kvm_intel nested=1/options kvm_intel nested=1/g" /etc/modprobe.d/kvm.conf

上記はIntelCPUの場合の設定です。
AMDの場合は、/etc/modprobe.d/kvm.confを直接開けば設定可能です。

2.仮想マシン側の設定

virsh edit vm-name

<cpu mode='custom' match='exact'> 
を
<cpu mode='host-passthrough'>
に変更して保存。

以上です。

3.最後に

大した内容ではありませんが、CentOS7からほんの少しだけ変更されていたため、知っておくと何かと便利なので記載しました。

小ネタ集その1~3以外にも、SELinuxやchrony、HugePage、run-level変更など小ネタはあるのですが、CentOS7からの変更はないので、あえて記載するほどでもないかなと思っています。

ちなみに、CentOS8ではnmcliコマンドに変更はないため、NW系コマンドはnmcliに統一してしまった方が効率的だと思います。

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の用途の違いかなと思っているので、あまり深入りはしませんでした。