시리즈
- [KlosedStack #1] Intro: https://blog.isu.kim/14
- [KlosedStack #2] Vagrant + Libvirt: https://blog.isu.kim/15
- [KlosedStack #3] Vagrant + OVS https://blog.isu.kim/16
배경
지난주에 여러 인터페이스를 사용하는 서버 셋업으로 OVS + Vagrant를 구성했었다. 이후 목요일에 N 교수님께 해당 내용을 랩미팅 때 발표했었다. 그리고 돌아온 피드백.
어 좋은데, 단일 인터페이스로 안될까? 그리고 VM에서 eth0 그리고 eth1 쓰는거 말고 인터페이스 하나로 하게 하자, MASQUERADE 하면 될꺼야!
라는 피드백을 받았다. 사실 MASQUERADE 생각을 했었으나, 그동안 잘못한 점이 하나가 있었다. OVS 브릿지에 MASQUERADE를 하고, 해당 CIDR를 MASQUERADE 했긴 했다. 하지만 VM 내부에서 eth1의 게이트웨이를 브릿지로 설정하지 않아서, 이게 NAT가 안되었다... 역시 박사 학위가 있으신 분들은 다르다... (어쩌면 내가 댕청한거겠지만...)
그래서 이번에는 단일 인터페이스를 가지고, VM이 외부 통신 그리고 내부 통신도 가능하게 구성해보려고 한다.
토폴로지
이번에는 조금 더 간단하다.
이번에 만든 토폴로지는 위의 그림과 같다. 그림은 Neutron의 그림체를 차용해서 그렸다. 이걸 간단하게 설명하면 다음과 같다.
- 각 VM의 경우,
eth1
과 호스트의macvtap
과 인터페이스를 붙인다. 또한 VM 내부의eth1
의 IP 대역은 10.0.40.0/24 대역으로 설정해준다. 호스트 A의 VM의 경우,eth1
의 IP는10.0.40.213
그리고 게이트웨이는10.0.40.13
으로 설정해준다. 마찬가지로 비슷하게 호스트 B의 VM도 설정해준다. - 각
macvtap
은 지난번처럼veth
를 통해서 브릿지랑 연결해준다. 브릿지는 이번에br-tun
이라는 브릿지만 사용할 것이다. 이후br-tun
은 VXLAN을 통해 서로에게 오버레이를 만들어준다. - 각
br-tun
인터페이스에 10.0.40.13 또는 10.0.40.14를 설정해주고, 여기다가 NAT을 걸어준다. 이렇게 되면 VM이 외부 인터넷이랑 통신이 가능해질 것이다.
이렇게 설정하면, 각 VM끼리, 그리고 VM에서 외부 인터넷으로 통신이 된다.
마찬가지로, 이번에도 다시 당부하는 부분은, 나는 네트워크 전문가가 아니다. 이 셋업 때문에 살짝 삽질을 했다. 아무튼 그냥 참고만 하면 좋겠다.
br-tun 설정
지난번에는 br-int
이 eth0
을 포트로 가지고, 그리고 br-tun
에 IP를 할당해주는 방식이였다. 하지만, 이번에는 br-tun
만 가지고 있다. 따라서, 굳이 그런 설정 안해주고 그냥 다음을 따라하면 된다.
br-tun
을 만들어주고, VXLAN을 연결해주자.
sudo ovs-vsctl add-br br-tun
호스트 1(192.168.100.139)에서
sudo ovs-vsctl add-port br-tun vxlan0 -- set interface vxlan0 type=vxlan options:remote_ip=192.168.100.196 options:df_default=true options:egress_pkt_mark=0 options:in_key=flow options:out_key=flow options:dst_port=48317 options:tag=321
호스트 2(192.168.100.196)에서
sudo ovs-vsctl add-port br-tun vxlan0 -- set interface vxlan0 type=vxlan options:remote_ip=192.168.100.139
options:df_default=true options:egress_pkt_mark=0 options:in_key=flow options:out_key=flow options:dst_port=48317 options:tag=321
이후 firewall-cmd
를 통해서 VXLAN의 방화벽을 설정해주자. 지난번에도 언급했지만, ESXi의 버그 때문에, 4789번으로 VXLAN을 사용하지 못한다. 따라서 나는 48317번 UDP 포트를 사용한다. 이를 위해서 포트를 개방하고, 설정을 reload해주자.
sudo firewall-cmd --permanent --add-port=4789/udp --add-port=8472/udp --add-port=48317/udp
sudo firewall-cmd --reload
이후, 각 호스트에서 br-tun
의 IP를 할당해주고, 인터페이스를 켜주자. (순서대로 호스트 1과 호스트 2의 명령어이다.)
sudo ifconfig br-tun 10.0.40.13 up
sudo ifconfig br-tun 10.0.40.14 up
이렇게 되면, 라우팅 설정이 안되어있다. 따라서, route 명령어를 통해서 10.0.40.0/24 대역을 br-tun
으로 들어가게 설정해주자.
sudo ip route add 10.0.40.0/24 dev br-tun
이제 기본적으로 OVS를 통해 br-tun
끼리의 통신이 가능하다. 여기서 확인해보면, 10.0.40.13에서 10.0.40.14로 ping을 할 수 있다. 역 또한 같다.
VM 설정 + 테스트
VM에서 사용할 인터페이스들을 만들어주자. 필요한 것은 다음과 같다.
- 한쪽은
veth1a
그리고 다른쪽은veth1b
로 연결된 veth lb1
이라는 이름을 가진 리눅스 브릿지lb1
을br-tun
의 포트로 가짐
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-tun lb1
이후 인터페이스를 불러오자.
sudo ifconfig lb1 up
sudo ifconfig veth1b up
간단하다. 이후 VM을 생성해주면 된다. 예시 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.40.213"
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
SHELL
end
이를 통해 Ubuntu 22.04를 가진 qemu (또는 kvm) VM을 만들 수 있다. 위의 config.vm.network
의 ip
부분을 설정해주면 VM에 원하는 ip를 할당해줄 수 있다.
이제 VM을 만들어보자!
vagrant up
vagrant ssh
이후 간단하게, eth1
로 8.8.8.8 에 ping을 해보자. 아마 안될 것이다.
당연히 될리가 없다. 이제 하나씩 설정을 해주자.
NAT 설정
호스트에서 방화벽 그리고 포워딩 설정을 해주자.
sudo sysctl net.ipv4.ip_forward=1
sudo firewall-cmd --permanent --zone=trusted --add-source=10.0.0.0/8
sudo firewall-cmd --reload
이후 iptables를 통해서 MASQUERADE를 해주자.
sudo iptables -t nat -A POSTROUTING -s 10.0.40.0/24 -o eth0 -j MASQUERADE
VM에서 게이트웨이 설정을 해주자.
게이트웨이 설정은 다양하지만, 나는 그냥 netplan을 사용할 예정이다. Vagrant의 경우 /etc/netplan/50-vagrant.yaml
를 생성한다. 따라서, 여기다가 게이트웨이 설정을 해주면 된다.
---
network:
version: 2
renderer: networkd
ethernets:
eth1:
addresses:
- 10.0.40.213/24
routes:
- to: default
via: 10.0.40.13
nameservers:
addresses: [8.8.8.8, 8.8.4.4]
이렇게 설정해주면, 10.0.40.213을 사용하는 VM의 게이트웨이를 10.0.40.13으로 설정할 수 있다. 이후
sudo netplan apply
를 통해서 해당 변경 사항을 저장해주자.
검증
이후 검증을 하면 된다.
Ping 테스트
ping 8.8.8.8 -I eth1
를 통해서, ping을 해보자.
정상적으로 ping이 된다.
Curl 테스트
curl https://google.com --interface eth1
정상적으로 eth1
을 통해 curl을 할 수 있다. 즉 TCP 패킷이 잘 도착한다.
이게 정말로 우리 VM 내부의 eth1
을 통해서 나가는지 테스트를 해야한다. 아니면 이게 VM의 eth0
을 통해서 virbr
로 나가는지도 알아야한다. 그걸 보기 위해서 호스트에서 간단하게 tcpdump
를 통해서 lb1
을 보면 된다.
sudo tcpdump -i lb1 -vv tcp
보면 syd09s13-in-f14.1e100.net 으로 데이터가 잘 날라간다. 이게 찾아보니 구글 서버였다. 아무튼 이를 통해서 우리가 원하는 경로로 패킷이 날라감을 확인할 수 있었다.
이러면 생기는 문제가 있다. 바로 VM 내부에는 eth0
그리고 eth1
이 둘다 있다는 것이다. 이를 처리하기 위해서 netplan
으로 eth0
을 날려버리자.
아마 기본으로는 /etc/netplan/00-installer-config.yaml
그리고 /etc/netplan/01-netcfg.yaml
이렇게 두개가 eth0
을 담당하는 파일일 것이다. 우선 날려버린다.
sudo rm /etc/netplan/00-installer-config.yaml
sudo rm /etc/netplan/01-netcfg.yaml
이후 /etc/netplan/50-vagrant.yaml
에다가 다음의 사항만 추가해주자.
---
network:
version: 2
renderer: networkd
ethernets:
eth1:
addresses:
- 10.0.40.214/24
routes:
- to: default
via: 10.0.40.14
nameservers:
addresses: [8.8.8.8, 8.8.4.4]
eth0:
activation-mode: off
인터넷을 찾아보니, activation-mode: off
를 통해서 인터페이스를 완전히 내릴 수 있다고 한다. 이러면 우리 유저에게는 eth1
만 있다고 뻥을 칠 수 있다!
보다시피, 이제 인터페이스가 하나만 남아있다. 또한 라우팅 테이블 또한 192.168.121.0/24에 해당하는것이 없어졌다. 이제는 10.0.40.0/24만 라우팅 대상이다!
이제 또 ping, curl을 해보면
문제 없이 TCP, ICMP가 모두 오간다.
결론 + 다음 얘기
이를 통해서 VM이 외부로 인터페이스 하나만을 가지고 통신할 수 있음을 확인했다. 물론 환상적이고 아주 깔끔한 솔루션은 아니지만, 그래도 나름 나쁘지는 않은 것 같다. 분명 한 1달 후에 다시 이 글을 보면, 얘가 왜 이딴 생각을 했을까? 하는 의문이 들겠지만 아무튼 그렇다.
사실 다음 얘기는 Ceph + Vagrant 였는데, 이거 먼저 해결하고 하는게 마음이 편할 것 같아서 이거 먼저 했다.