리눅스 네트워크 네임스페이스란?
•
하나의 호스트에서 여러 개의 격리된 네트워크 공간을 형성하는 기술.
◦
호스트 자체도 하나의 네트워크 네임스페이스를 가진다고 볼 수 있다 → Root Namespace
◦
즉, 일반적으로 호스트의 1번 프로세스(init)에 할당된 Root Namespace를, 자식 프로세스들이 모두 공유하는 구조로 이루어져 있다.
•
각 네트워크 네임스페이스마다 네트워크 인터페이스, 라우팅 테이블, 포워딩 테이블을 가진다.
•
격리된 네임스페이스에 할당된 프로세스는, 다른 네임스페이스에 영향을 줄 수 없다.
•
리눅스는 네트워크 외에도 다양한 네임스페이스를 지원한다. 네임스페이스는 컨테이너(container) 기반의 가상화 기술을 지탱하는 주요 기능.
실습이 필요할 경우, 가상머신을 사용할 것을 권장합니다. 여기서는 Ubuntu 20.04를 사용하였습니다.
아래 실습 자료는 ‘참고자료’ 섹션에서 소개하는 44bits 블로그의 예제를 따릅니다.
리눅스 네트워크 네임스페이스 실습
•
호스트와 격리된 네임스페이스에 Nginx 서버를 띄우고, 접속하는 것을 목표로 한다.
•
ip 명령어를 많이 사용할 예정… 이 김에 친숙해지자!
Host
+--------------------------------------------------+
| +--------------+ |
[lo]+ [lo]+ | |
| | [Nginx] | |
[eth0]+ +-------->[veth1]+ | |
| | | direct_netns| |
[veth0]+<---------------+ +--------------+ |
| |
| Root Namespace |
+--------------------------------------------------+
Bash
복사
실습에서 구현할 네트워크 구성도
1. 네트워크 디바이스 확인
•
먼저, 호스트의 네트워크 인터페이스를 확인한다.
$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 02:18:ce:0d:00:12 brd ff:ff:ff:ff:ff:ff
Bash
복사
2. 가상 인터페이스 만들기
•
호스트와 새로운 네트워크 네임스페이스를 연결하는 가상 네트워크 인터페이스를 만들어야 한다.
•
veth : 가상 이더넷 인터페이스(Virtual Ethernet Interface)를 의히하며, 항상 쌍으로 만들어진다. veth pair로 서로 다른 네임스페이스를 연결한다.
# veth0과 veth1을 만든다.
$ sudo ip link add veth0 type veth peer name veth1
# 만들어진 가상 네트워크 인터페이스 확인.
$ ip -br link
lo UNKNOWN 00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
eth0 UP 02:18:ce:0d:00:12 <BROADCAST,MULTICAST,UP,LOWER_UP>
veth1@veth0 DOWN be:d4:d8:12:d3:e8 <BROADCAST,MULTICAST,M-DOWN>
veth0@veth1 DOWN 5a:ce:e1:3b:6a:17 <BROADCAST,MULTICAST,M-DOWN>
Bash
복사
3. 새로운 네트워크 네임스페이스 만들기
•
direct_netns라는 이름의 네트워크 네임스페이스를 만든다.
•
netns 오브젝트는 네트워크 네임스페이스를 관리한다.
•
해당 네임스페이스는 /var/run/netns/ 안에 생성된다. 하지만 해당 네임스페이스에서 네트워크 설정을 해야하는 경우, /etc/netns/<NAME>/ 경로에서 수정을 해야한다.
◦
가령, 네트워크 네임스페이스의 resolv.conf 파일을 따로 만들고 싶은 경우, /etc/netns/<NAME>/resolv.conf 파일을 생성/수정해야 한다.
$ sudo ip netns add direct_netns
# 만들어진 네트워크 네임스페이스 목록 확인하기.
$ ip netns list # 또는 ls /var/run/netns
direct_netns
Bash
복사
•
ip netns exec으로 특정 네트워크 네임스페이스에서 프로세스를 실행시킬 수 있다.
•
하지만 매번 위 명령어 입력하기가 슬슬 귀찮아진다면, ip netns exec bash로 해당 네트워크 네임스페이스에 들어가, 호스트에서와 동일하게 커맨드를 입력할 수도 있다. (물론 exit 명령어로 언제든지 나올 수 있다.)
# direct_netns에서 ip 명령어를 실행하여, 해당 네임스페이스의 네트워크 인터페이스 확인.
$ sudo ip netns exec direct_netns ip -br link
lo DOWN 00:00:00:00:00:00 <LOOPBACK>
Bash
복사
현재 새롭게 만들어진 네트워크 네임스페이스에는 루프백 인터페이스만 생성되어 있다.
4. 격리된 네임스페이스에서 Nginx 서버 실행하기
•
direct_netns 네임스페이스의 루프백 인터페이스를 활성화한다.
$ sudo ip netns exec direct_netns ip link set dev lo up
$ sudo ip netns exec direct_netns ip -br link
lo UNKNOWN 00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
Bash
복사
활성화는 되어있지만, 연결된 네트워크가 없기 때문에 UNKNOWN으로 표시된다.
•
호스트에 Nginx를 설치하고, 호스트 위에서 동작하지 않도록 설정한다.
$ sudo apt updage
$ sudo apt install nginx-core
# nginx 동작 확인
$ curl 127.0.0.1
# 만약 웹페이지 데이터가 불러와진다면, 서비스를 중지한다.
$ sudo systemctl stop nginx
$ sudo systemctl disable nginx
Bash
복사
•
Nginx를 direct_netns의 포어그라운드로 실행한다.
$ sudo ip netns exec direct_netns nginx -g 'daemon off;'
Bash
복사
•
터미널 창을 새로 열어서, 호스트와 direct_netns 네임스페이스의 연결 상태를 확인한다.
•
direct_netns의 Nginx 서버는 잘 돌아가는 상태.
•
하지만 아직 두 네임스페이스가 연결되지 않았기에, 호스트에서 direct_netns의 네임스페이스로 접근할 수 없다.
# direct_netns의 Nginx 서버는 잘 돌아간다.
$ sudo ip netns exec direct_netns curl 127.0.0.1
<!DOCTYPE html>
...
# 하지만 호스트에서 direct_netns의 Nginx 서버로 접근할 수는 없다.
$ curl 127.0.0.1
curl: (7) Failed to connect to 127.0.0.1 port 80: Connection refused
Bash
복사
Host
+--------------------------------------------------+
| +--------------+ |
[lo]+ [lo]+ | |
| | [Nginx] | |
[eth0]+ | | |
| | direct_netns| |
[veth0]+<---+ +--------------+ |
| | |
[veth1]+<---+ Root Namespace |
+--------------------------------------------------+
Bash
복사
현재까지의 네트워크 인터페이스의 상태.
5. 각 네임스페이스를 가상 인터페이스로 연결하기
•
현재 veth0(@veth1)과 veth1(@veth0) 인터페이스는 모두 호스트 네임스페이스에 있는 상태.
•
veth0은 호스트 네임스페이스에 남겨놓고, veth1을 direct_netns에 옮겨놓는다.
$ sudo ip link set veth1 netns direct_netns
# 호스트 네임스페이스의 네트워크 디바이스 목록 출력
$ ip -br link
lo UNKNOWN 00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
eth0 UP 02:18:ce:0d:00:12 <BROADCAST,MULTICAST,UP,LOWER_UP>
veth0@if3 DOWN 5a:ce:e1:3b:6a:17 <BROADCAST,MULTICAST>
# direct_netns 네임스페이스의 네트워크 디바이스 목록 출력
$ sudo ip netns exec direct_netns ip -br link
lo UNKNOWN 00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
veth1@if4 DOWN be:d4:d8:12:d3:e8 <BROADCAST,MULTICAST>
Bash
복사
•
가상 인터페이스를 활성화하기 위해선, 먼저 IP를 할당해야 한다.
# 호스트의 veth0 인터페이스에 IP 할당
$ sudo ip a add 10.200.0.2/24 dev veth0
# direct_netns의 veth1 인터페이스에 IP 할당
$ sudo ip netns exec direct_netns ip a add 10.200.0.3/24 dev veth1
Bash
복사
•
ping으로 각 인터페이스의 활성 상태를 확인해본다.
$ ping 10.200.0.3
PING 10.200.0.3 (10.200.0.3) 56(84) bytes of data.
64 bytes from 10.200.0.3: icmp_seq=1 ttl=64 time=0.043 ms
64 bytes from 10.200.0.3: icmp_seq=2 ttl=64 time=0.039 ms
^C
--- 10.200.0.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1029ms
rtt min/avg/max/mdev = 0.039/0.041/0.043/0.002 ms
$ sudo ip netns exec direct_netns ping 10.200.0.2
PING 10.200.0.2 (10.200.0.2) 56(84) bytes of data.
64 bytes from 10.200.0.2: icmp_seq=1 ttl=64 time=0.023 ms
64 bytes from 10.200.0.2: icmp_seq=2 ttl=64 time=0.035 ms
^C
--- 10.200.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1029ms
rtt min/avg/max/mdev = 0.023/0.029/0.035/0.006 ms
Bash
복사
•
마지막으로, direct_netns에서 실행되는 Nginx를, veth 인터페이스로 호스트에서 접근할 수 있는지 확인해본다.
$ curl 10.200.0.3
<!DOCTYPE html>
...
Bash
복사
Host
+--------------------------------------------------+
| +--------------+ |
[lo]+ [lo]+ | |
| | [Nginx] | |
[eth0]+ +-------->[veth1]+ | |
| | 10.200.0.3| direct_netns| |
[veth0]+<---------------+ +--------------+ |
10.200.0.2 |
| Root Namespace |
+--------------------------------------------------+
Bash
복사
완성된 모습. 아주 잘 작동한다!