VXLAN을 이용한 오버레이 네트워크를 구성해 보려고 한다.
클라우드 인프라를 위한 네트워크 모델을 고민하고 있다. 일단은 단순한 L3 Flat Network를 생각하고 있지만, AWS VPC와 같은 격리된 (그리고 복잡한)네트워크 구성의 확장 가능성은 열어두려고 한다. 어차피 L3 Flat Network 모델이라면, 이 위에서 오버레이 네트워크 모델을 만드는 건 크게 어려운 일은 아닐 것이다. 오버레이 네트워크 기술을 이해하면, 확장 가능한 L3 Flat Network 구성 설게에 도움이 될 것이다.
구성
KVM과 Docker를 기반으로 테스트 한다.
KVM 인스턴스가 호스트 컴퓨터에 대응한다.
KVM 인스턴스 위에 도커 네트워크를 구성한다.
다른 KVM에 있는 도커들이 통신 하도록 VXLAN으로 오버레이 네트워크를 구성한다.
Host-1 : 192.168.5.2
Host-2 : 192.168.5.3
Open vSwitch 네트워크는 양쪽 모두 172.17.42.0/24로 했다. 가상머신 올리는 방법은 OVS를 이용한 KVM네트워크 구성을 참고하자. KVM이 익숙하지 않다면, VirtualBox등 (사용이 쉬운)가상화 툴을 이용해도 상관 없다. Host-1과 Host-2가 서로 통신할 수 있으면 된다.
Host-1의 도커 네트워크 설정
Host-1과 Host-2에 Docker 네트워크를 구성하고, 컨테이너를 실행 했다. 도커의 기본 브로커는 docker-0인데, VXLAN 설정을 위해서 OVS 브릿지로 구성을 했다.
설정 방법은 Docker 레퍼런스 네트워크를 참고한다. 172.17.42.2와 172.17.42.3 두 개의 컨테이너를 만들었다. 도커 컨테이너에 네트워크를 할당하기 위한 스크립트를 만들었다. Docker 레퍼런스 네트워크에 있는 네트워크 설정 과정을 코드화 했다. 다운로드 ovs_work.sh 스크립트는 VXLAN 설정은 빠져있다. 일단은 도커 네트워크를 만든 다음에 수작업으로 VXLAN을 설정한다.
먼저 OVS 브릿지를 만들고 네트워크를 설정한다.
# ovs-vsctl add-br br0
# ifconfig br0 172.17.42.1/24 up
도커 컨테이너를 만든다.
# docker run --net=none -i -t ubuntu /bin/bash
root@1eaa0000bf9f:/#
컨테이너 "1eaa0000bf9f"에 대한 네트워크를 설정한다. 네트워크 주소는 172.17.42.2로 하자.
vxlan0 인터페이스를 추가 했다. 이 인터페이스의 VNID는 100이며, Host-2와 연결된다.
veth16850-a에 tag 100을 붙인다.
# ovs-vsctl set Port veth1658-a 100
# ovs-vsctl show
6800c940-93e9-4bf6-b719-558afbf05506
Bridge "br0"
Port "veth1658-a"
tag: 100
Interface "veth1658-a"
Port "vxlan0"
tag: 100
Interface "vxlan0"
type: vxlan
options: {key="100", remote_ip="192.168.5.3"}
Port "br0"
Interface "br0"
type: internal
ovs_version: "2.3.1"
각 컨테이너들끼리는 VXLAN을 이용해서 통신을 할 수 있지만, 게이트웨이(172.17.42.1)로는 통신이 안된다. arp 테이블을 보면 172.17.42.1에 대한 ARP 테이블을 완료하지 못했음을 알 수 있다. 현재 br0 포트가 게이트웨이 역할을 하고 있는데, tag를 붙여주지 않았기 때문이다. br0에 태깅한다.
# ovs-vsctl set Port br0 tag=100
# ovs-vsctl show
......
Port "br0"
tag: 100
Interface "br0"
type: internal
ovs_version: "2.1.3"
이제 게이트웨이에 대한 arp 테이블을 완료되고, 외부와 통신이 되는 걸 확인할 수 있을 것이다.
# arp -n
Address HWtype HWaddress Flags Mask Iface
172.17.42.1 ether f6:3e:f8:73:38:47 C eth0
172.17.42.10 ether 02:c2:69:f5:86:c4 C eth0
Host-2의 도커 네트워크 설정
Host-1과 동일하다. 도커 컨테이너의 IP를 172.17.42.10으로 설정했다. 두 개의 컨테이너 172.17.42.10간에 네트워크 통신이 되면 성공이다.
Host-2의 ovs 설정은 아래와 같다.
# ovs-vsctl show
d5385b9e-582c-4f1b-b483-b74ad3d33cb9
Bridge "br0"
Port "vxlan0"
tag: 100
Interface "vxlan0"
type: vxlan
options: {key="100", remote_ip="192.168.5.2"}
Port "br0"
Interface "br0"
type: internal
Port "veth1398-a"
tag: 100
Interface "veth1398-a"
ovs_version: "2.3.1"
VNID를 100으로 하고, remote_ip를 192.168.5.2로 했다. 이제 두 개의 컨테이너가 통신이 되는지 확인하면 된다. 현재의 구성은 아래와 같이 묘사할 수 있겠다.
유저별로 VNID를 다르게 하는 것으로 멀티 터넌트를 서비스 할 수 있다. 위의 구성에 VNID-200을 추가해서 테스트를 진행했다.
# Host-1의 ovs 설정
# ovs-vsctl show
6800c940-93e9-4bf6-b719-558afbf05506
Bridge "br0"
Port "vxlan1"
tag: 200
Interface "vxlan1"
type: vxlan
options: {key="200", remote_ip="192.168.5.3"}
Port "veth1658-a"
tag: 100
Interface "veth1658-a"
Port "vxlan0"
tag: 100
Interface "vxlan0"
type: vxlan
options: {key="100", remote_ip="192.168.5.3"}
Port "br0"
Interface "br0"
type: internal
Port "veth2046-a"
tag: 200
Interface "veth2046-a"
ovs_version: "2.3.1"
# Host-2의 ovs 설정
# ovs-vsctl show
d5385b9e-582c-4f1b-b483-b74ad3d33cb9
Bridge "br0"
Port "vxlan0"
tag: 100
Interface "vxlan0"
type: vxlan
options: {key="100", remote_ip="192.168.5.2"}
Port "br0"
Interface "br0"
type: internal
Port "vxlan1"
tag: 200
Interface "vxlan1"
type: vxlan
options: {key="200", remote_ip="192.168.5.2"}
Port "veth1398-a"
tag: 100
Interface "veth1398-a"
Port "veth1995-a"
tag: 200
Interface "veth1995-a"
ovs_version: "2.3.1"
같은 VNID끼리만 통신되는 걸 확인할 수 있다.
NAT 구성
이렇게 해서 도커들은 L3 로컬 네트워크 상에서 격리된 네트워크를 구성하고, 서로 통신할 수 있게 됐다.
NAT를 통한 인터넷으로의 접근 역시 가능하다. 단 구성을 약간 바꿔야 한다. 인터넷으로 향하는 패킷은 br0로 보내야 하며, 이를 위해서 br0에도 veth와 같은 태그를 붙여줘야 한다. 하지만 br0 인터페이스에는 단지 하나의 태그만 가능하다.
그래서 나는 vxlan 별로 브릿지를 만들기로 했다. VNID 100은 br0, VNID 200은 br1을 가지도록 네트워크를 다시 구성했다.
두 개의 vxlan을 위해서 독립된 브릿지 br0, br1을 만들었다.
두 개의 브릿지들도 태깅을 했다.
이제 0.0.0.0/0으로 향하는 패킷은 태깅된 브릿지로 포트를 통해서 인터넷으로 나가게 된다. 아래와 같이 브릿지 포트에 태깅하면 된다.
br1브릿지를 만든다.
# ovs-vsctl add-br br1
# ifconfig br1 172.17.50.1/24 up
br1을 200으로 태깅한다.
# ovs-vsctl set Port br1 tag=200
# ovs-vsctl show
3e95bbe3-88b3-4b4d-b39f-b9a24cb53a8e
Bridge "br1"
Port "br1"
tag: 200
Interface "br1"
type: internal
# ovs-vsctl show
3e95bbe3-88b3-4b4d-b39f-b9a24cb53a8e
Bridge "br1"
Port "veth2093-a"
tag: 200
Interface "veth2093-a"
Port "br1"
tag: 200
Interface "br1"
type: internal
Port "vxlan1"
tag: 200
Interface "vxlan1"
type: vxlan
options: {key="200", remote_ip="192.168.5.3"}
이 상태에서 도커 컨테이너가 인터넷과 통신을 하려면, 각 Host에서의 SNAT(마스커레이딩)설정이 필요하다. 결과적으로 두 번의 SNAT을 통해서 인터넷과 통신하게 된다.
인터넷 게이트웨이 - IGW
인터넷에서 컨테이너로 접근하는 문제를 해결해보자.
2중 NAT
컨테이너(Ins-1)에 대해서 1.22.3.5 주소로 접근하기를 원한다면, 컨테이너로의 NAT를 위한 NAT-IP를 하나 할당한다. 스위치는 컨테이너의 퍼블릭 아이피를 NAT-IP에 매핑한다. 이렇게 하면 두 번의 NAT로 인스턴스를 찾아갈 수 있다.
이 방식은 DHCP와 같은 네트워크 관리 프로토콜을 사용하기 어렵다는 단점이 있다.
(Stateless NAT를 하면 되니) 스케일링이 용이하고, 트래픽을 완전히 분산할 수 있으며, 고가용성 구성이 용이하다는 장점이 있다.
중앙 IGW
각 호스트에 분산돼 있던 게이트웨이를 중앙에서 관리하는 방법도 있다. 이 방식의 장점은 아래와 같다.
IGW가 DHCP 서버 역할을 수행할 수 있다. 2중 NAT의 경우 IGW가 분산돼 있기 때문에, DHCP와 같이 컨테이너 네트워크가 전역적으로 공유해야할 정보의 관리가 쉽지 않다.
내부의 모든 트래픽이 VXLAN상에서 흐르기 때문에 일관성이 있다.
모든 트래픽이 오버레이 되므로 2중 NAT에 비해서 성능의 희생이 있을 수 있다는 점과 고가용성, 고확장성 시스템의 구성이 좀 더 까다롭다는 단점이 있다.
Contents
Open vSwitch를 이용한 오버레이 네트워크 구성
구성
Host-1의 도커 네트워크 설정
Host-2의 도커 네트워크 설정
테스트
멀티 터넌트
NAT 구성
인터넷 게이트웨이 - IGW
2중 NAT
중앙 IGW
테스트
관련 툴
Recent Posts
Archive Posts
Tags