[리눅스 네트워크] 1개의 NIC에서 Veth를 이용하여 멀티 IP 구성하기 (Update. 2020.04.30)
Veth peer 구성부터 활용까지
집에서 오픈스택 기반 Private 클라우드를 구축하던 도중 호스트 네트워크 구성 단계에서 문제가 발생했습니다.
veth는 Virtual Ethernet Devices의 약자로, 한 쌍의 인터페이스가 Peer로 서로 연결된 가상 인터페이스입니다. 가상의 인터페이스이기 때문에 물리 NIC와 달리 임의로 생성 가능하고, 생성시 반드시 하나의 peer 인터페이스를 함께 생성해야 합니다. 생성 방법은 다음과 같습니다.
# 포맷: ip link add [name] type veth peer name [peer-name]
# 예시: veth0 과 veth1을 생성하고 link 상태를 up.
[root@Compute0 ~]# ip link add veth0 type veth peer name veth1
[root@Compute0 ~]# ip link set up veth0
[root@Compute0 ~]# ip link set up veth1
[root@Compute0 ~]# ifconfig
[root@Compute0 ~]# ifconfig veth1 && ifconfig veth0
veth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.0.25 netmask 255.255.255.0 broadcast 0.0.0.0
inet6 xxxx::xxxx:xxxx:xxxx:xxxx prefixlen 64 scopeid 0x20
ether xx:xx:xx:xx:xx:xx txqueuelen 1000 (Ethernet)
RX packets 424719 bytes 427581571 (407.7 MiB)
RX errors 0 dropped 1 overruns 0 frame 0
TX packets 388158 bytes 150649891 (143.6 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 xxxx::xxxx:xxxx:xxxx:xxxx prefixlen 64 scopeid 0x20
ether xx:xx:xx:xx:xx:xx txqueuelen 1000 (Ethernet)
RX packets 388160 bytes 150650023 (143.6 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 424721 bytes 427581719 (407.7 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth는 특히 리눅스 시스템에서 분리된 Network Stack을 터널링 할 때 유용합니다. 오픈스택이나 도커 등에서 많이 사용되는데, 이에 관해서 다룰 기회가 있으면 추후에 다루도록 하겠습니다.
이제 방법은 간단합니다. 리눅스 시스템에 브릿지를 하나 생성해주고 기존 물리 포트인 eno0와 veth0를 bridge로 묶어 주기만 하면 됩니다. 이때 주의할 점은 현재 ssh로 eno0 포트에 연결하여 작업중인 경우, 콘솔 작업을 대비해야 합니다. 왜냐하면 bridge인 br0와 eno0가 묶임으로써, ip 할당은 이제 eno0가 아닌 br0에 할당되기 때문에 eno0로의 직접 연결은 끊기기 때문입니다.
# 포맷: ip link add type veth peer name
# 예시: veth0 과 veth1을 생성하고 link 상태를 up.
[root@Compute0 ~]# brctl addbr br0
[root@Compute0 ~]# brctl addif br0 eno0
[root@Compute0 ~]# brctl addif br0 veth0
[root@Compute0 ~]# ip link set up br0
[root@Compute0 ~]# brctl show br0
bridge name bridge id STP enabled interfaces
br0 8000.1c697a096271 no eno1
veth0
[root@Compute0 ~]# ip addr add 10.0.0.25/24 dev veth1
[root@Compute0 ~]# ip addr add 192.168.0.25/24 dev br0
이제 다시 관리용 인터페이스인 192.168.0.25에 ssh로 접속하여 작업할 수 있습니다. 그리고 veth1을 통해 같은 10.0.0.0/24 대역의 다른 ip와 통신할 수 있습니다.
[root@Compute0 ~]# ping 10.0.0.26
PING 10.0.0.26 (10.0.0.26) 56(84) bytes of data.
64 bytes from 10.0.0.26: icmp_seq=1 ttl=64 time=0.627 ms
64 bytes from 10.0.0.26: icmp_seq=2 ttl=64 time=0.753 ms
64 bytes from 10.0.0.26: icmp_seq=3 ttl=64 time=0.847 ms
원리는 간단합니다.
아래 그림과 같이, 우선 현재 veth0는 l2 브릿지로 eno0와 묶였기 때문에 실제 물리 포트를 공유할 수 있는 상태가 되었습니다. 여기에 veth0와 veth1이 peer로 서로 터널링 구성된 상태에서 veth1이 외부에서 ip를 받은 상태이기 때문에, 10.0.0.0/24 대역의 ip는 자연스럽게 포트를 타고 유입되는 구조입니다. 결과적으로 bridge와 veth 피어링 방식을 활용하면 굳이 ip rule, route로 명시적 경로를 지정하지 않아도 1개의 NIC를 활용하여 다수의 네트워크를 구성할 수 있습니다.
물론 veth를 활용한 방법만 있는 것은 아니고 macvtap 등 다른 가상 인터페이스를 활용한 구성도 가능합니다.
마지막 구성단계가 한 가지 더 남았습니다. ip 명령을 통해 생성한 veth 인터페이스 타입은 기존 물리 nic나 linuxbridge와 같이 /etc/sysconfig/network-script/ (RHEL계열 기준)에서 ifcfg-* 방식으로 스크립팅이 안됩니다. 따라서 재부팅 상황을 대비하여 부팅단계에서 브릿지와 veth 인터페이스를 생성하고 브릿지에 바인딩하기 위한 스크립트를 별도로 만들어줘야 합니다. 저의 경우, 아래와 같이 /var/tmp/ 에 쉘 스크립트를 하나 작성하여 재부팅 할 때도 자동으로 인터페이스를 세팅하도록 구성했습니다.
* 수정사항: 기존에는 재부팅 상황에 대비하여 브릿지용 /etc/sysconfig/network-scripts/ifcfg-br0 스크립트를 통해 브릿지 인터페이스(br0)를 사전에 생성하는 것을 전제로 작성하였습니다. 하지만 네트워크 스크립트를 통해 브릿지를 생성하면, 이후 #brctl addif br0 veth0 명령이 먹히지 않음을 확인하였습니다. 따라서 아래 커맨드 리스트와 같이, 브릿지 생성부터 dns 설정까지 create_interface.sh 스크립트에서 전부 실행하도록 개선하였습니다.
[root@Compute0 ~]# vim /var/tmp/create_interface.sh
#!/bin/bash
ip link add veth0 type veth peer name veth1
ip link set up veth0
ip link set up veth1
brctl addbr br0
ip link set up br0
ip addr add 192.168.0.25/24 dev br0
route add default gw 192.168.0.1 dev br0
echo "nameserver 8.8.8.8" > /etc/resolv.conf
brctl addif br0 veth0
ip addr add 10.0.0.25/24 dev veth1
'Network > Configuration' 카테고리의 다른 글
[Linux Network] Avahi를 활용하여 간단하게 Host, IP 알아내기 (0) | 2020.04.01 |
---|---|
Iptime 포트포워딩 기능을 활용하여 외부에서 내부 서버 접속하기 (0) | 2020.02.15 |