CKA를 준비해보자 29일차 - Network Namespaces

0

CKA

목록 보기
29/43

Network Namespaces

network namespace는 docker와 같은 container에서 host의 network를 나누기 위해서 사용한다.

container를 만들면, 각 container들끼리 격리되기를 원할 것이다. 즉, container에 동작하는 process는 다른, container와 격리되어 동작하기를 원한다는 말이다. 이를 가능하게 해주는 것이 바로 process namespace이다.

container에서 ps aux를 통해서 process들을 확인하면 다음과 같다.

ps aux
USER        PID ...
root        1   ...

container안에 동작하는 process의 ID가 1인 것을 확인할 수 있다.

그런데, 이러한 container를 구동하는 host에서 ps aux로 같은 process를 확인하면 다음이 나온다.

ps aux
USER        PID ...
root        3816

같은 process이지만, container안과 밖이 서로 다른 process ID를 가지게 되는 것이다. 이것이 가능한 이유는 process들끼리 container상에서는 격리되었지만, host에서는 통합되어 확인할 수 있기 때문이다.

network namespace 역시도 마찬가지이다. host는 자신의 network interface와 routing table, ARP table을 가지는데 다음과 같다.

------------Host----------
|                        |
|                        |           
|                       eth0 --------------- LAN
|                   (192.168.1.2)       (192.168.1.0)
|Routing Table, ARP table|
--------------------------

이제 container를 만드는데, container에 network namespace를 부여하도록 하자. network namespace가 부여된 container는 host에 network관련 정보에 대한 가시성이 사라지게 된다.

network namespace안에서의 container는 virtual network interface를 갖게되고, 각 routing table, ARP table도 갖게된다.

------------Host-----------
| ----Container----       |
| |               |       |
| |             veth0     |                              
| | RT table, ARP |      eth0 --------------- LAN
| -----------------    (192.168.1.2)       (192.168.1.0)
|Routing Table, ARP table|
--------------------------

linux에서 network namespace를 만들기 위해서는 다음의 명령어를 사용한다.

ip netns add red
ip netns add blue

redblue network namespace를 만든 것이다.

ip netns
red
blue

host의 network interface를 확인하듯이 ip link를 namespace에 쓰고 싶다면 다음과 같이 두 가지 방법으로 쓸 수 있다.

ip -n red link
ip netns exec red ip link

host의 ARP를 확인하는 방법은 다음과 같다.

arp
Address         HWtype  ...
172.17.0.21     ether   ...

container 내의 ARP를 확인하는 방법은 다음과 같다.

ip netns exec red arp

그러나 아무것도 안나올 것이다.

route table역시도 마찬가지이다.

ip netns exec red route

왜 그럴까?? 이는 만들어진 network namespace는 어떠한 network interface를 가지고 있지 않으며, host network를 볼 수 없는 상태이다. 이들에게 network 연결성을 제공해주기 위해서 virtual한 network interface를 부여하도록 하자.

ip link add veth-red type veth peer name veth-blue

다음의 명령어로 veth-redveth-blue를 만들어, 다이렉트로 연결하기위한 준비를 한 것이다. virtual ethernet을 즉 생성을 한 것이다.

veth-red-----veth-blue

다음으로 각 veth들을 network namespace에 연결시켜주도록 하자.

ip link set veth-red netns red
ip link set veth-blue netns blue

다음과 같이 된다.

-----red-----           -----red-----
|           |           |           |
|       veth-red-----veth-blue      |
|           |           |           |
-------------           -------------

이제 각 veth에 주소값을 주기위해서 IP를 부여하도록 하자.

ip -n red addr add 192.168.15.1 dev veth-red
ip -n blue addr add 192.168.15.1 dev veth-blue

이제 각 veth마다 IP를 부여해주었다.

-----red-----           -----red-----
|           |           |           |
|       veth-red-----veth-blue      |
|    (192.168.15.1) (192.168.15.2)  |
-------------           -------------

이제 두 veth를 실행시켜 link연결을 시켜주도록 하자.

ip -n red link set veth-red up
ip -n blue link set veth-blue up

잘 연결되었는 지 확인하기위해서 red network namespace에서 veth-blue에 요청을 보내보도록 하자.

ip netns exec red ping 192.168.15.2

성공하는 것을 볼 수 있을 것이다.

이제 ARP와 route table을 보도록 하자.

ip netns exec red arp
Address         HWtype ...  Iface
192.168.15.2    ether  ...  veth-red

veth-red에서 veth-blue192.168.15.2에 ARP 테이블이 만들어진 것을 볼 수 있다. 반대로 blue namespace에서 확인하면 다음과 같다.

ip netns exec blue arp
Address         HWtype ...  Iface
192.168.15.1    ether  ...  veth-blue

재밌는 것은 이 두 network namespace를 호스팅하고 있는 host에서는 arp를 실행해도 이들의 정보가 나오지 않는다. 왜냐하면 연결되지 않았기 때문에 알 방도가 없는 것이다.

그런데, 이러한 network namespace가 많아지게 되면, 일일히 하나하나 veth를 만들고 각각을 연결해주기 어렵다. 그래서 virtual switch라는 개념이 나오게 된다.

host에 virtual switch를 만들고, virtual host를 각 namespace들에 연결하면 되는 것이다. 그런데 어떻게 만드는가? 여기에는 여러 solution들이 있는데, 가장 유명한 것이 Linux Bridge이다.

생성하는 방법도 간단한데, 다음과 같다.

ip link add v-net-0 type bridge

이렇게 하면 v-net-0라는 virtual switch가 만들어진다. 해당 virtual switch는 host에서도 확인 가능한데, ip link를 통해서 확인해볼 수 있다.

이제 v-net-0을 실행시켜주도록 하자.

ip link set dev v-net-0 up

다음으로 위에서 우리가 만든 veth들은 이제 필요하지 않으므로 삭제시켜주도록 하자.

ip -n red link del veth-red

veth-blue도 같이 사라진다. 이는 veth가 pair로 생성되었기 때문이다.

---red---           ---blue--
|       |           |       |
|       |           |       |
|       |           |       |
---------           ---------

        ----v-net-0---
        |192.168.15.0|
        --------------

--green--           --bloack-
|       |           |       |
|       |           |       |
|       |           |       |
---------           ---------

새로운 veth를 생성하여 virtual switch에 연결시켜주도록 하자.

ip link add veth-red type veth peer name veth-red-br
ip link add veth-blue type veth peer name veth-blue-br

각 veth 쌍을 만들어낸 것인데, 그림과 같다.

----------       -------------
|veth-red|-------|veth-red-br|
----------       -------------

-----------       --------------
|veth-blue|-------|veth-blue-br|
-----------       --------------

이제, veth-redveth-blue는 각가의 namespace로 연결시키고, veth-red-brveth-blue-br은 virtual switch인 v-net-0에 연결시켜주도록 하자.

ip link set veth-red netns red
ip link set veth-red-br master v-net-0

ip link set veth-blue netns blue
ip link set veth-blue-br master v-net-0

그림과 같이 되는 것이다.

---red---              ---blue--
|       |              |       |
|   veth-red        veth-blue  |
|       | |         |  |       |
--------- |         |  ---------
          |         |
          |         |
  --------|-v-net-0-|-------------
  |       |         |            |
  |  -----|---------|------------|
  |  |veth-red-br||veth-blue-br| |
  |  --------------------------- |
  |         192.168.15.0         |
  --------------------------------      
        

--green--           --bloack-
|       |           |       |
|       |           |       |
|       |           |       |
---------           ---------

이제 ip를 할당시켜주도록 하자.

ip -n red addr add 192.168.15.1 dev veth-red
ip -n blue addr add 192.168.15.2 dev veth-blue

ip -n red link set veth-red up
ip -n blue link set veth-blue up

ip를 virtual switch인 bridge와 같은 대역을 쓰는 것에 주의하자.

이제 virtual switch를 통해서 red와 blue namespace는 서로 연결된다.

192.168.15.1           192.168.15.2
---red---              ---blue--
|       |              |       |
|   veth-red        veth-blue  |
|       | |         |  |       |
--------- |         |  ---------
          |         |
          |         |
  --------|-v-net-0-|-------------
  |       |         |            |
  |  -----|---------|------------|
  |  |veth-red-br||veth-blue-br| |
  |  --------------------------- |
  |       192.168.15.0           |
  --------------------------------      
        

--green--           --bloack-
|       |           |       |
|       |           |       |
|       |           |       |
---------           ---------

그런데, host에서도 그럼 red namespace인 192.168.15.1에 접근이 가능한가?? 시도해보면 실패할 것이다.

ping 192.168.15.1
Not Reachable!

virtual switch는 실제로 host의 network interface이다. 따라서, virtual switch에도 host가 IP를 달아주어 host와 연결해주어야 하는 것이다.

ip addr add 192.168.15.5/24 dev v-net-0

이제 ping을 보내보도록 하자.

ping 192.168.15.1

성공한 것을 볼 수 있다.

아래와 같이 virtual switch와 host A가 연결된 것을 볼 수 있다.

----------------Host A--------------------
|                                        |
|   192.168.15.1         192.168.15.2    |
|   ---red---              ---blue--     |
|   |       |              |       |     |
|   |   veth-red        veth-blue  |     |
|   |       | |         |  |       |     |
|   --------- |         |  ---------     | 
|             |         |                |
|             |         |                |
|     --------|-v-net-0-|-------------   |
|     |       |         |            |   |
|     |  -----|---------|------------|   |
|     |  |veth-red-br||veth-blue-br| |   |
|     |  --------------------------- |   |
|     |         192.168.15.5         |   |
|     --------------------------------   |
|                   |                    |
-------------------eth0-------------------
               (192.168.1.2)

그런데, 다음과 같이 LAN을 타고 다른 network와 연결되고 싶은 경우는 어떻게해야할까??

다음의 Host A에서 Host B로 LAN을 통해 연결된다고 하자.

----------------Host A--------------------
|                                        |
|   192.168.15.1         192.168.15.2    |
|   ---red---              ---blue--     |
|   |       |              |       |     |
|   |   veth-red        veth-blue  |     |
|   |       | |         |  |       |     |
|   --------- |         |  ---------     | 
|             |         |                |
|             |         |                |
|     --------|-v-net-0-|-------------   |
|     |       |         |            |   |
|     |  -----|---------|------------|   |
|     |  |veth-red-br||veth-blue-br| |   |
|     |  --------------------------- |   |
|     |         192.168.15.5         |   |
|     --------------------------------   |
|                   |                    |
-------------------eth0-------------------
               (192.168.1.2)
                    |
                    |
                   LAN
                (192.168.1.0)
                    |
                    |
                ----Host B----
                |192.168.1.3 |
                --------------

Host A에 있는 blue에서 Host B에 연결하고 싶지만 route가 잡혀있지 않아 불가능하다. 즉, blue입장에서 알고 있는 network란 virtual switch인 192.168.15.0뿐이다. 192.168.1.0에 대해서는 모를 수 밖에 없다.

ip netns exec blue route
Destination         Gateway     ...
192.168.15.0        0.0.0.0     ...

라우팅 테이블이 셋팅되지 않은 상황이므로 ping이 가지 않을 것이다. 즉 192.168.1.0/24을 못찾는 것이다. 따라서, 이를 해결하기 위해서 gateway에 연결하는 것인데, 이 gateway가 바로 virtual bridge이다. 이는 linux bridge가 host와 ARP, route table을 공유하기 때문에 virtual switch localhost로 전달된 packet이 host에서 처리되는 것처럼 쓸 수 있다. 따라서, 외부 LAN에도 접근이 가능한 것이다.

ip nets exec blue ip route add 192.168.1.0/24 via 192.168.15.5

192.168.15.5를 gateway로 두어 192.168.1.0/24로 향하는 모든 packet을 192.168.15.5를 통하여 가도록 하고 있다. 그렇게되면 host와 연결된 브릿지에서 해당 packet을 받아 마치 host에서 처리해주는 것처럼 사용할 수 있다.

그러나 ping을 시켰을 때 unreachable이 나오진 않지만 packet이 전달되지 않을 것이다. 이는 NAT문제이다. 즉, network namespace안에서 쓰이는 192.168.15.0/24 ip는 host A에서만 쓰이는 private IP이므로 host B가 알턱이 없다. 따라서, 해당 IP로 응답을 보내지 못하는 것이다. 즉, 전달은 됐지만 어디로 응답을 전송할 지 모르겠는 것이다.

따라서, NAT를 통해서 192.168.15.5/24에서의 packet 출발지 IP를 Host의 IP로 변환 설정하여 전달하도록 하는 것이다.

iptables -t nat -A POSTROUTING -s 192.168.15.0/24 -j MASQUERADE

이제 다시 blue에서 192.168.1.3에 ping을 보내면 성공할 것이다.

ip netns exec blue ping 192.168.1.3

마지막으로 LAN이 internet과 연결되어 있다고 하자.

----------------Host A--------------------
|                                        |
|   192.168.15.1         192.168.15.2    |
|   ---red---              ---blue--     |
|   |       |              |       |     |
|   |   veth-red        veth-blue  |     |
|   |       | |         |  |       |     |
|   --------- |         |  ---------     | 
|             |         |                |
|             |         |                |
|     --------|-v-net-0-|-------------   |
|     |       |         |            |   |
|     |  -----|---------|------------|   |
|     |  |veth-red-br||veth-blue-br| |   |
|     |  --------------------------- |   |
|     |         192.168.15.5         |   |
|     --------------------------------   |
|                   |                    |
-------------------eth0-------------------
               (192.168.1.2)
                    |
                    |
                   LAN ------------- Internet
                (192.168.1.0)
                    |
                    |
                ----Host B----
                |192.168.1.3 |
                --------------

문제는 각 namespace들이 Internet에 연결되지 않는다는 것이다.

ip netns exec blue ping 8.8.8.8
Connect: Network is unreachable

이는 route table에 default가 설정되어 있지 않기 때문에 발생한 문제이다. 따라서 다음의 명령어로 default를 추가시켜주도록 하자.

ip netns exec blue ip route add default via 192.168.15.5
Destination     Gateway         Genmask         ...     Iface
192.168.15.0    0.0.0.0         255.255.2550    ...     veth-blue
192.168.1.0     192.168.15.5    255.255.2550    ...     veth-blue
default         192.168.15.5    255.255.2550    ...     veth-blue

즉 virtual switch를 gateway삼고 있는 것을 볼 수 있다.

이제 문제없이 internet에 접속할 수 있게 될 것이다.

단, 반대는 불가능하다. 즉, 192.168.1.3에서 blue의 IP인 192.168.15.2에 바로 요청을 보낼 순 없다.

0개의 댓글