시리즈
- [KlosedStack #1] Intro: https://blog.isu.kim/14
- [KlosedStack #2] Vagrant + Libvirt: https://blog.isu.kim/15
배경
지난 시간에는, KlosedStack에서 사용할 VM을 Vagrant로 Libvirt를 사용해 생성했다. 이제는 각 VM끼리 연결을 해줘야한다. 연결에는 OpenvSwitch를 사용할 예정이다.
토폴로지
살짝 복잡해보이지만 어렵지 않다. 간단하게 생각을 하면 다음의 구조와 같다.
- 각 VM의 경우 내부
eth1
번에 호스트 머신의macvtap
인터페이스를 붙인다. 또한 VM 내부의eth1
에 IP를 10.0.35.0/24 대역으로 준다. 호스트 A의 VM은10.0.35.211
, 호스트 B의 VM은10.0.35.212
를 받게 설정한다. - 각
macvtap
인터페이스는veth
를 사용하여 브릿지랑 연결해준다. 브릿지 쌍은veth1a
그리고veth1b
로 설정했다.veth1a
는macvtap
에, 그리고veth1b
는 브릿지인lb1
에 붙게 설정한다. - 이후 브릿지
lb1
을 OVS 브릿지인br-private
에 붙여준다.br-private
에는10.0.35.11
또는10.0.35.12
로 IP를 설정한다. 이후 두개의 브릿지를 VXLAN으로 연결한다. 연결의 경우 각eth1
번으로 연결을 해준다. 이렇게 하는 이유는,eth0
의 경우 외부 인터넷 접속이 있지만, 사실eth1
의 경우 그냥 스위치에 물려있고 인터넷 접속이 없는 그냥 인터페이스이기 때문이다.
이렇게 설정하면, 각 VM끼리, 그리고 br-private
에서 VM끼리, 또한 반대로도 모든 통신이 가능하다.
나는 네트워크 전문가가 아니다... 이 셋업을 만들어낼라고 엄청난 삽질을 했다. N 교수님이 이 토폴로지를 보시면 경악을 금치 못하실 수도 있다.
전제 + 주의사항
이 게시글은 OVS를 친절하게 바닥부터 알려주려고 만든 글은 아니다... 그래서 ovs-vsctl
와 같은 명령어, ip
, ifconfig
, firewall-cmd
와 같은 명령어는 그냥 알고 있다고 전제하고 시작할 예정이다.
또한 br-private
과 eth0
을 설정하는 방안은 너무 인터넷에 잘 알려져있으니 다루지 않을 예정이다.
뿐만 아니라, 이 게시글은 reboot를 살아남지 못한다. reboot시 대부분의 인터페이스는 날라갈 것이다. 이것에 대한 얘기는 추후 다시 다룰 예정이다.
br-private
설정
br-private
를 만들어주고 VXLAN을 연결해주자
sudo ovs-vsctl add-br br-private
sudo ifconfig br-private up
여기까지 하면, br-private
인터페이스가 올라올 것이다. 이후 각 br-private
을 VXLAN으로 연결해준다.
호스트 1 (10.0.30.111)
sudo ovs-vsctl add-port br-private vxlan0 -- set interface vxlan0 type=vxlan options:remote_ip=10.0.30.112 options:df_default=true options:egress_pkt_mark=0 options:in_key=flow options:out_key=flow options:dst_port=48317 options:tag=123
호스트 2 (10.0.30.112)
sudo ovs-vsctl add-port br-private vxlan0 -- set interface vxlan0 type=vxlan options:remote_ip=10.0.30.111 options:df_default=true options:egress_pkt_mark=0 options:in_key=flow options:out_key=flow options:dst_port=48317 options:tag=123
여기서 주의할 점이 하나 있다. 끝 없는 삽질로 알아낸 사실인데,
You see unexplained packet drops on VXLAN networks using VXLAN port 4789.
ESXi에서 VXLAN을 4789번 UDP 포트로 사용하면 패킷이 드랍 날 수 있다. 자세한 내용은 다음의 게시글을 참고하면 된다. https://kb.vmware.com/s/article/52936
따라서, 나의 경우, ESXi를 사용중이므로 4789번 포트를 사용하면 안되기 때문에, 48317번 UDP를 사용했다. 이를 위한 방화벽을 내려줘야한다. 또한 10.0.0.0/8을 허용하자. 이후 reload
sudo firewall-cmd --permanent --add-port=4789/udp --add-port=8472/udp --add-port=48317/udp
sudo firewall-cmd --permanent --zone=trusted --add-source=10.0.0.0/8
sudo firewall-cmd --reload
이제 테스트를 위해, 각 br-private
에다가 각각 10.0.35.11
그리고 10.0.35.12
를 할당하자.
sudo ifconfig br-private 10.0.35.11 up
sudo ifconfig br-private 10.0.35.12 up
이후 라우팅과 ip forward 옵션을 켜주자.
sudo sysctl net.ipv4.ip_forward=1
sudo ip route add 10.0.35.0/24 dev br-private
이제 10.0.35.11
에서 10.0.35.12
를 ping 해보자
잘된다! VXLAN을 통해서 패킷이 잘 날라다니는 것을 확인할 수 있다. 조금 더 궁금하다면, tcpdump로 UDP 48317번이 어떻게 통신하는지를 보면 된다. 10.0.30.112에서 eth1번을 확인하면 된다.
sudo tcpdump -vv -i eth1 udp port 48317
결과로 잘 나오는 것을 확인할 수 있다.
veth, 브릿지 설정
사실 이실직고를 하자면, veth 말고 그냥 브릿지를 바로 가져다가 Vagrant에 붙여도 된다. 하지만 나는 지금 Neutron을 참고해가면서 설정을 하고 있다.
따라서, VM의 eth1번과 호스트의 macvtap 인터페이스가 연결되면, macvtap 인터페이스에 veth를 붙여서 이를 브릿지로 연결하려고 한다. 이는 다음처럼 하면 된다.
sudo ip link add veth1a type veth peer name veth1b
sudo ip link add lb1 type bridge
sudo ip link set veth1b master lb1
sudo ovs-vsctl add-port br-private lb1
간단하게, veth pair를 만들고, 브릿지를 만든 다음 OVS의 br-private 브릿지에 붙여준다. 이후 이 두개의 인터페이스를 up 상태로 만들어주자
sudo ifconfig lb1 up
sudo ifconfig veth1b up
사실 나는 네트워크 지식이 거의 없다. 사실 이전에는 브릿지 자체에다가 IP를 줘야하는줄 알았는데, 그게 아니였다. 혹시라도 "어? 브릿지에 IP를 줘야지 통신이 되지 않을까?" 라는 의문을 가진 사람이 있으면 도움이 되었으면 좋겠다.
이렇게 하면 우선 어느정도 설정이 되었다. 지금 veth1a 쪽은 Vagrant에 연결할 준비가 완료되었다!
Vagrant 설정
Vagrant의 Vagrantfile은 다음처럼 작성하면 된다.
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2204" # Ubuntu 22.04
config.vm.box_check_update = false
config.vm.network :public_network, :bridge => 'veth1a', :dev => 'veth1a', ip: "10.0.35.211"
config.vm.provider :libvirt do |libvirt|
# Disable KVM and use pure QEMU
libvirt.driver = "qemu"
libvirt.memory = "2048" # Set the VM memory to 2GB
libvirt.cpus = 2 # Set the number of CPUs to 2
end
config.vm.provision "shell", inline: <<-SHELL
# Update the system packages
sudo apt-get update
# Additional provisioning steps can be added here
SHELL
end
이 중, public_network와 private_network의 차이점은 간단하게 생각하면 다음과 같다.
- private_network: Vagrant가 virbr1 또는 virbr0으로 자동으로 할당해주는 192.168.121.0/24 대역의 IP이다. 이는 그냥 자동으로 할당된다. VM의 eth0으로 할당된다.
- public_network: 우리의 경우, veth가 여기로 들어가면 된다. VM의 eth1로 할당된다.
이렇게 설정하면, 호스트 머신의 virbr0 또는 virbr1인터페이스가 192.168.121.0/24 대역을 eth0으로 NAT 해준다. 즉, VM이 인터넷 접속을 private_network로 할 수 있게 된다. 이름은 private_network 이지만 뭔가 이상할 지 몰라도 인터넷 접속이 가능해진다 ㅋㅋ....
그리고 public_network를 통해 10.0.35.211을 eth1로 할당해서 br-private 터널 사이에 존재하는 모든 IP와 통신이 가능해진다.
자세한 사항들은
https://github.com/vagrant-libvirt/vagrant-libvirt/issues/349
여기서
config.vm.network :public_network, :bridge => 'veth1a', :dev => 'veth1a', ip: "10.0.35.211"
이렇게 쓰는 방법을 알려줄 것이고
https://developer.hashicorp.com/vagrant/docs/networking
여기에서는 private_network 그리고 public_network에 대한 자세한 설명이 적혀있으니, 참고하면 좋을 것이다.
이후
vagrant up
을 해주면, Vagrant가 알아서 VM을 띄워줄 것이다.
이러면 잘 뜬 것이다.
default: SSH address: 192.168.121.55:22 default: SSH username: vagrant default: SSH auth method: private key default: Warning: Connection refused. Retrying... default: Warning: Connection refused. Retrying... default: Warning: Connection refused. Retrying... default: Warning: Connection refused. Retrying... default: Warning: Connection refused. Retrying...
중간에 이런 문구가 뜰 수 있을텐데, 이는 무시하면 된다. 사실 정확히는 원인은 못찾았으나, VM이 생성중이라 SSH 키를 넣지 못해서 생겼다고 추측중이다... 아닐수도 있다.
이후
vagrant ssh
를 통해서 VM 안으로 들어가보자.
- 위의 터미널이 호스트 2번 (10.0.30.112) 의 VM 이고, 얘는 정상적으로 10.0.35.212를 받았다.
- 아래의 터미널이 호스트 1번 (10.0.30.111) 의 VM 이고, 얘도 정상적으로 10.0.35.211을 받았다.
얘도 지금 터널을 통해 10.0.35.212에서 10.0.35.211로 ICMP가 잘 날라감을 확인할 수 있다.
검증
이게 ping만 찍히는게 아닌지, 아니면 정말로 인터넷이 서로 되는지를 확인하고자, 간단하게 TCP 통신으로 확인해보자. 한쪽 VM에서 1000MB짜리 랜덤 파일을 만들고, scp로 넘겨줄 것이다
VM 1번에서 (10.0.35.211)
dd if=/dev/urandom of=random_file.txt bs=1M count=1000
scp random_file.bin isu@10.0.35.212:/home/isu
잘 날라간다, 대략 15.9MB/s 니까, 100mbps 정도는 나오는 것 같다.
결론 + 다음 얘기
이번 게시글을 통해, 다른 host (node)에서 동작하는 VM들이 OVS의 VXLAN을 통해 통신할 수 있음을 확인했다. 나는 네트워크 전문가가 아니기에, 이번 게시글에는 잘못된 내용이 있을 수 있다. 따라서 적당히 걸러서 듣는것을 추천한다.
현재, Vagrant가 생성하는 VM이 qemu를 통해 동작한다. VNC를 사용할 수 있지만, 지금 이걸 설정을 잘못해놓아서 외부에서 확인할 수 없다. 이를 다루는 얘기를 하려고 한다.
또한 이렇게 생성된 Vagrant의 경우 Block storage가 해당 node에 존재한다. 이렇게 되면, 만약 node에 문제가 생기거나, VM을 다른 node로 스케쥴링 해야할 경우 데이터가 모두 날아간다... 따라서 이를 극복하기 위해 Ceph를 구성하여 block storage에 마운트 하여 Vagrant를 사용할 예정이다.
+ 본격적인 구현 관련된 얘기는 좀더 아키텍쳐가 정해지면 해보려고 한다.
'Playground > KlosedStack' 카테고리의 다른 글
[KlosedStack #2] Vagrant + Libvirt (0) | 2023.06.30 |
---|---|
[KlosedStack #1] Intro (0) | 2023.06.30 |