Saturday, September 28, 2024

[KVM] Bridge Network trong KVM

-

Tổng quan

KVM được biết đến là một cơ sở hạ tầng ảo hóa cho nhân Linux. KVM cũng cung cấp các mô hình mạng trong việc ảo hóa network. Các mô hình bao gồm:

  • NAT
  • Host-only
  • Linux-bridge

Trong đó Linux-bridge là một mô hình ảo hóa mạng được hỗ trợ bởi KVM. Linux bridge là một công nghệ cung cấp switch ảo để giải quyết vấn đề ảo hóa Network bên trong các máy vật lý. Ở bài viết này mình sẽ giới thiệu về mô hình Bridge trên KVM.

Chúng ta có thể thấy rằng có một con switch được tạo ra nằm bên trong của máy vật lý. Các VM kết nối đến đây để có thể liên lạc được với nhau. Nếu muốn liên lạc ra bên ngoài ta có thể kết nối con switch này với card mạng trên máy vật lý của ta (giống như ta dùng dây kết nối switch với router). Ta có thể kết nối switch với 1 hoặc nhiều port.

Cấu trúc linux bridge

Trong đó:

  • Bridge ở đây là switch ảo
  • Tap hay tap interface là giao diện mạng để các VM kết nối với switch do Linux bridge tạo ra(nó hoạt động ở lớp 2 của mô hình OSI)
  • fd: Forward data có nhiệm vụ chuyển dữ kiệu từ VM tới switch.

Switch ảo do Linux bridge tạo ra có chức năng tương tự với 1 con switch vật lý.

Ta có thể thấy rõ hơn cách kết nối của VM ra ngoài internet. Khi máy vật lý của ta có card mạng kết nối với internet (không phải card wireless). Trên switch ảo của ta sẽ phải có đường để kết nối ra ngoài internet (cụ thể là kết nối với card mạng của máy vật lý). Ta có thể hình dung card mạng trên máy vật lý sẽ được gắn trực tiếp vào switch ảo nên ta có thể thấy sau khi add switch ảo và card vật lý có cùng địa chỉ MAC. Và trên card vật lý sẽ không còn địa chỉ IP mà nó được gắn cho switch ảo.

$ ifconfig enp6s0
enp6s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether 00:30:48:db:6c:5e  txqueuelen 1000  (Ethernet)
        RX packets 37075255  bytes 30351706205 (30.3 GB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 18350891  bytes 13225504313 (13.2 GB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        device interrupt 16  memory 0xfbce0000-fbd00000

$ ifconfig br0
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.13.228  netmask 255.255.254.0  broadcast 192.168.13.255
        inet6 fe80::230:48ff:fedb:6c5e  prefixlen 64  scopeid 0x20<link>
        ether 00:30:48:db:6c:5e  txqueuelen 1000  (Ethernet)
        RX packets 26611549  bytes 26856341341 (26.8 GB)
        RX errors 0  dropped 2  overruns 0  frame 0
        TX packets 13609391  bytes 12831819181 (12.8 GB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

$ brctl show
bridge name	bridge id		STP enabled	interfaces
br0		8000.003048db6c5e	yes		enp6s0

Và bây giờ trên các VM muốn giao tiếp với nhau hoặc ra ngoài internet ta chỉ cần kết nối VM đó với switch ảo. Lúc này card mạng trên VM sẽ được gắn với 1 cổng của switch ảo thông qua tap interface và cổng này có tên là br. Ở đây có tên là br0

Khi ta kết nối vào switch ảo các VM sẽ nhận địa chỉ IP cùng với dải địa chỉ IP của card mà ta add và switch và các địa chỉ IP này sẽ được cấp bởi dịch vụ DHCP trên router.

Địa chỉ của card mạng gắn với switch ảo, với mô hình này gói tin bên trong VM đi ra ngoài mạng sẽ đi từ VM đến thẳng card vật lý gắn với switch ảo và đi ra ngoài mạng.

Chuẩn bị

Một máy chạy hệ điều hành CentOS 7 hoặc Ubuntu cài đặt KVM có một card mạng kết nối với internet và cài đặt một VM bên trong máy đó. Chú ý máy vật lý ở đây là máy cài KVM. Máy này có thể là một máy ảo nhưng ở đây ta coi nó như một server vật lý.

Tạo mô hình Bridge trên KVM

Để list tất cả các network đang có trong server, sử dụng lệnh virsh net-list –all. Bạn sẽ thấy có 1 network default mặc định khi cài KVM sẽ tự tạo ra.

$ virsh net-list --all
 Name                 State    Autostart   Persistent
-------------------------------------------------------
 default              inactive no          yes

Bây giờ bạn hãy xem thông tin card mạng enp6s0, đây chính là card mạng vật lý đang nối với thiết bị network ở ngoài và nó đang được gán ip là 192.168.13.228.

$ ifconfig enp6s0
enp6s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.13.228  netmask 255.255.254.0  broadcast 192.168.13.255
        ether 00:30:48:db:6c:5e  txqueuelen 1000  (Ethernet)
        RX packets 37098477  bytes 30355784188 (30.3 GB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 18362175  bytes 13228221261 (13.2 GB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        device interrupt 16  memory 0xfbce0000-fbd00000

Bước tiếp theo bạn hãy tạo 1 card mạng bridge có tên là br0 (card này bạn có thể tự đặt tên mà bạn muốn). Card br0 sẽ được đặt ip, gateway, … giống như card vật lý và nó cũng sẽ được gắn với card vật lý enp6s0.

cat > /etc/netplan/00-installer-config.yaml << 'OEF'
network:
  version: 2
  renderer: networkd

  ethernets:
    enp6s0:
      dhcp4: false
      dhcp6: false

  bridges:
    br0:
      interfaces: [ enp6s0 ]
      addresses: [ 192.168.13.228/23 ]
      gateway4: 192.168.12.5
      mtu: 1500
      nameservers:
        addresses: [ 8.8.8.8, 1.1.1.1 ]
      parameters:
        stp: true
        forward-delay: 4
      dhcp4: no
      dhcp6: no
OEF

Sau khi chuẩn bị xong file cấu hình, bạn hãy chạy lệnh dưới để áp dụng thay đổi. Máy chủ của bạn sẽ rớt mạng 1 lát để cập nhật cấu hình. Sau khoảng 5-10s nếu mọi cấu hình của bạn đúng, máy chủ của bạn sẽ có kết nối trở lại.

sudo netplan generate 
sudo netplan --debug apply

Và đây là kết quả sau khi áp dụng config network mới. Card mạng bridge br0 đã được tạo và được gắn ip 192.168.13.228 như đã khai báo còn card mạng vật lý bây giờ đã không còn được gắn ip.

$ ifconfig enp6s0
enp6s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether 00:30:48:db:6c:5e  txqueuelen 1000  (Ethernet)
        RX packets 37098477  bytes 30355784188 (30.3 GB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 18362175  bytes 13228221261 (13.2 GB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        device interrupt 16  memory 0xfbce0000-fbd00000

$ ifconfig br0
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.13.228  netmask 255.255.254.0  broadcast 192.168.13.255
        inet6 fe80::230:48ff:fedb:6c5e  prefixlen 64  scopeid 0x20<link>
        ether 00:30:48:db:6c:5e  txqueuelen 1000  (Ethernet)
        RX packets 26633879  bytes 26859945910 (26.8 GB)
        RX errors 0  dropped 2  overruns 0  frame 0
        TX packets 13619670  bytes 12834414371 (12.8 GB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Tiếp theo để thêm network mới, bạn sử dụng file xml với nội dung như dưới, để ý một số trường như sau:

  • mode=bridge: sử dụng mode bridge.
  • bridge name=’br0′: dùng card mạng bridge bạn đã tạo ở bước trên gắn vào đây.
  • bridged-network chính là tên của network bạn sẽ tạo.
cat > ./bridged-network.xml << 'OEF'
<network>
    <name>bridged-network</name>
    <forward mode="bridge" />
    <bridge name="br0" />
</network>
OEF

Sử dụng lệnh virsh net-define <file_network_xml> để define network này.

$ virsh net-define ./bridged-network.xml
Network bridged-network defined from ./bridged-network.xml

Dùng lệnh virsh net-list –all để list network, bạn đã thấy network có tên bridged-network đã xuất hiện nhưng nó đang ở trạng thái inactive. Ở trạng thái này network chưa thể sử dụng được.

$ virsh net-list --all
 Name                 State    Autostart   Persistent
-------------------------------------------------------
 bridged-network      inactive no          yes

Để enable network này, sử dụng lệnh virsh net-start <file_network_xml> để start nó.

$ virsh net-start bridged-network
Network bridged-network started

Sau khi start network xong, bạn thấy network đã chuyển qua trạng thái active, tức là lúc này network đã có thể sử dụng được nhưng mà tuỳ chọn Autostart đang ở trạng thái no, bạn hãy chuyển tuỳ chọn Autostart sang yes để khi máy chủ KVM khởi động lại, network sẽ tự start luôn.

$ virsh net-list --all
 Name                 State    Autostart   Persistent
-------------------------------------------------------
 bridged-network      active   no          yes

Sử dụng lệnh virsh net-autostart <file_network_xml> để enable tính năng này.

$ virsh net-autostart bridged-network
Network bridged-network marked as autostarted

Và đây là kết quả khi mình đã config xong một network.

$ virsh net-list --all
 Name                 State    Autostart   Persistent
-------------------------------------------------------
 bridged-network      active   yes         yes

Để xem thông tin tóm tắt một network bạn có thể sử dụng lệnh virsh net-info <file_network_xml>.

$ virsh net-info bridged-network
Name:           bridged-network
UUID:           de6d9dd4-1700-493c-a2c2-5c2838e425d2
Active:         yes
Persistent:     yes
Autostart:      yes
Bridge:         br0

Kiểm tra.

Mình sẽ tạo 1 máy ảo có tên test-bridged-network để kiểm tra network này như sau. Đầu tiên tạo file sshkey cho username ubuntu.

sudo mkdir -p /kvm-volumes-hdd/test-bridged-network/ssh-keygen
sudo chmod +x /kvm-volumes-hdd/test-bridged-network
sudo chmod 600 /kvm-volumes-hdd/test-bridged-network/ssh-keygen
cd /kvm-volumes-hdd/test-bridged-network/ssh-keygen
ssh-keygen -t rsa -b 4096 -f id_rsa -C hoanghd -N "" -q

Tạo 1 ổ đĩa chứ hệ điều hành, mình tạo 1 ổ đĩa có dung lượng 10G.

qemu-img create -b /kvm-volumes-hdd/images/bionic-server-ubuntu1804-cloudimg-amd64.img -f qcow2 /kvm-volumes-hdd/test-bridged-network/os-test-bridged-network.qcow2 10G

Xem lại thông tin ổ đĩa vừa tạo.

$ qemu-img info /kvm-volumes-hdd/test-bridged-network/os-test-bridged-network.qcow2
image: /kvm-volumes-hdd/test-bridged-network/os-test-bridged-network.qcow2
file format: qcow2
virtual size: 10 GiB (10737418240 bytes)
disk size: 196 KiB
cluster_size: 65536
backing file: /kvm-volumes-hdd/images/bionic-server-ubuntu1804-cloudimg-amd64.img
Format specific information:
    compat: 1.1
    lazy refcounts: false
    refcount bits: 16
    corrupt: false

Tiếp theo bạn tạo file cloud_init.cfg khai báo 1 số thông tin cơ bản cho máy ảo.

cat > /kvm-volumes-hdd/test-bridged-network/cloud_init.cfg << OEF
#cloud-config
hostname: test-bridged-network
fqdn: test-bridged-network.hoanghd.com
manage_etc_hosts: true
users:
  - name: ubuntu
    sudo: ALL=(ALL) NOPASSWD:ALL
    groups: users, admin
    home: /home/ubuntu
    shell: /bin/bash
    lock_passwd: true
    ssh-authorized-keys:
      - $(cat /kvm-volumes-hdd/test-bridged-network/ssh-keygen/id_rsa.pub)
  - name: hoanghd 
    sudo: ALL=(ALL) NOPASSWD:ALL
    groups: users, admin
    home: /home/hoanghd
    shell: /bin/bash
    lock_passwd: false

package_update: true
packages_upgrade: true
packages:
  - qemu-guest-agent
  - traceroute

# only cert auth via ssh (console access can still login)
ssh_pwauth: false
disable_root: false
chpasswd:
  list: |
     hoanghd:Hoanghd164
  expire: False

runcmd:
  - sudo touch /etc/cloud/cloud-init.disabled
OEF

Tạo file cấu hình network.

cat > /kvm-volumes-hdd/test-bridged-network/network_config_static.cfg << 'OEF'
version: 2
ethernets:
  enp1s0:
     dhcp4: false
     addresses: [ 192.168.13.231/23 ]
     gateway4: 192.168.12.5
     nameservers:
       addresses: [ 1.1.1.1, 8.8.8.8 ]
OEF

Giờ mình tạo 1 disk mới có tên test-bridged-network-seed.qcow2 và mình mount 2 file config cloud_init.cfgnetwork_config_static.cfg vào disk này. Mục đích để lúc khởi động kvm sẽ đọc ổ đĩa này để load các file config.

cloud-localds -v --network-config=/kvm-volumes-hdd/test-bridged-network/network_config_static.cfg /kvm-volumes-hdd/test-bridged-network/test-bridged-network-seed.qcow2 /kvm-volumes-hdd/test-bridged-network/cloud_init.cfg

Bạn có thể xem lại thông tin disk này bằng lệnh dưới.

$ qemu-img info /kvm-volumes-hdd/test-bridged-network/test-bridged-network-seed.qcow2
image: /kvm-volumes-hdd/test-bridged-network/test-bridged-network-seed.qcow2
file format: raw
virtual size: 368 KiB (376832 bytes)
disk size: 368 KiB

Bây giờ hãy run máy ảo bằng lệnh dưới.

virt-install --name test-bridged-network \
  --virt-type kvm --memory 4096 --vcpus 4 \
  --boot hd,menu=on \
  --disk path=/kvm-volumes-hdd/test-bridged-network/test-bridged-network-seed.qcow2,device=cdrom \
  --disk path=/kvm-volumes-hdd/test-bridged-network/os-test-bridged-network.qcow2,device=disk \
  --graphics vnc \
  --os-type Linux --os-variant ubuntu18.04 \
  --network network:bridged-network \
  --console pty,target_type=serial \
  --noautoconsole

Nếu không gặp lỗi, bạn sẽ thấy đầu ra xuất hiện như dưới.

Starting install...
Domain creation completed.

Giờ hãy list VM chúng ta thấy VM vừa tạo đã ở trạng thái running

$ virsh list --all
 Id   Name                      State
-----------------------------------------
 6    test-bridged-network      running

Và đây là kết quả.

$ virsh console test-bridged-network
Connected to domain test-bridged-network
Escape character is ^]

Ubuntu 18.04.6 LTS test-bridged-network ttyS0

test-bridged-network login: hoanghd
Password:

Last login: Sat Dec 10 14:10:53 UTC 2022 on ttyS0
Welcome to Ubuntu 18.04.6 LTS (GNU/Linux 4.15.0-197-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sat Dec 10 14:11:49 UTC 2022

  System load:  0.26              Processes:             122
  Usage of /:   12.0% of 9.51GB   Users logged in:       0
  Memory usage: 3%                IP address for enp1s0: 192.168.13.231
  Swap usage:   0%

0 updates can be applied immediately.

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings

hoanghd@test-bridged-network:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:35:ad:8e brd ff:ff:ff:ff:ff:ff
    inet 192.168.13.231/23 brd 192.168.13.255 scope global enp1s0
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe35:ad8e/64 scope link
       valid_lft forever preferred_lft forever

hoanghd@test-bridged-network:~$ ip route
default via 192.168.12.5 dev enp1s0 proto static
192.168.12.0/23 dev enp1s0 proto kernel scope link src 192.168.13.231

hoanghd@test-bridged-network:~$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=57 time=30.5 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=57 time=30.4 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=57 time=31.1 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=57 time=30.9 ms

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 30.492/30.786/31.175/0.353 ms

LEAVE A REPLY

Please enter your comment!
Please enter your name here

4,956FansLike
256FollowersFollow
223SubscribersSubscribe
spot_img

Related Stories