Podman Network

김재현·2024년 2월 16일
0
post-thumbnail

Podman Network

Podman 컨테이너 환경을 운영할 때, 기본적으로 Host, Bridge 두 가지를 사용한다.
Host 모드는 10.65 대역(외부망)을 사용하고, Bridge 모드는 10.88.0.0/16 대역(NAT)을 사용한다.

  • Podman VS KVM
  1. Podman 의 네트워크는 Port 를 기반으로 통신한다.
  2. KVM 의 네트워크는 IP 를 기반으로 통신한다.

1. Bridge - NAT

Podman 을 설치할 경우 기본적으로 생성되는 네트워크이다.
컨테이너 이미지를 실행할 때 기본적으로 선택되는 네트워크이며, NAT 로 동작하기 때문에 실행된 컨테이너 내부에 IP가 할당된다.

[root@jh-container-rocky86 ~]# podman network ls
NETWORK ID    NAME        DRIVER
2f259bab93aa  podman      bridge

[root@jh-container-rocky86 ~]# podman network ls --filter name=podman --format json
[
  {
    "name": "podman",
    "id": "2f259bab93aaaaa2542ba43ef33eb990d0999ee1b9924b557b7be53c0b7a1bb9",
    "driver": "bridge",
    "network_interface": "cni-podman0",
    "created": "2024-02-16T11:40:06.43855213+09:00",
    "subnets": [
      {
        "subnet": "10.88.0.0/16",
        "gateway": "10.88.0.1"
      }
    ],
    "ipv6_enabled": false,
    "internal": false,
    "dns_enabled": false,
    "ipam_options": {
      "driver": "host-local"
    }
  }
]

[root@jh-container-rocky86 ~]# ip addr show dev cni-podman0
3: cni-podman0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether 3e:2d:92:12:e5:3f brd ff:ff:ff:ff:ff:ff
    inet 10.88.0.1/16 brd 10.88.255.255 scope global cni-podman0
       valid_lft forever preferred_lft forever
    inet6 fe80::3c2d:92ff:fe12:e53f/64 scope link 
       valid_lft forever preferred_lft forever

KVM 환경에서도 기본 네트워크가 생성되는데, 이 또한 NAT 를 사용한다.

[root@is1 ~]# virsh net-list | grep default
 default            active   yes         yes

[root@is1 ~]# virsh net-info default
Name:           default
UUID:           dd1b83fe-7489-4041-8851-a63d7d24476a
Active:         yes
Persistent:     yes
Autostart:      yes
Bridge:         virbr0

[root@is1 ~]# virsh net-dumpxml default 
<network>
  <name>default</name>
  <uuid>dd1b83fe-7489-4041-8851-a63d7d24476a</uuid>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:9f:0a:3b'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254'/>
    </dhcp>
  </ip>
</network>

[root@is1 ~]# ip addr show dev virbr0
30: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether 52:54:00:9f:0a:3b brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
       valid_lft forever preferred_lft forever

Podman/KVM 기본 NAT 네트워크의 공통점은 Host 서버를 경유하여 외부와 통신이 가능하다는 점이다.

아래 예시는 외부에서 MariaDB에 어떻게 접근이 가능한 것인지 확인할 수 있다.

  1. Host 서버의 podman 상태를 확인한다.
[root@jh-container-rocky86 ~]# podman ps
CONTAINER ID  IMAGE                             COMMAND     CREATED             STATUS                 PORTS                    NAMES
f7f874049900  docker.io/library/mariadb:latest  mariadbd    About a minute ago  Up About a minute ago  0.0.0.0:13306->3306/tcp  jh-mariadb01
  1. Host 서버의 포트 상태를 확인한다.
    13306 포트가 'LISTEN' 상태임을 알 수 있다.
[root@jh-container-rocky86 ~]# netstat -antp | grep 3306
tcp        0      0 0.0.0.0:13306           0.0.0.0:*               LISTEN      59714/conmon
  1. 목적지인 3306 포트를 확인한다.
    이 포트를 확인할 수 있는 위치는 바로 컨테이너 내부이다.
    mariadb:latest 이미지에는 # netstat 명령어가 없으므로 # ss 명령어로 확인한다.
    3306 포트가 'LISTEN' 상태임을 알 수 있다.
[root@jh-container-rocky86 ~]# podman exec -it jh-mariadb01 bash

root@f7f874049900:/# ss -4ltpn
State    Recv-Q   Send-Q     Local Address:Port       Peer Address:Port   Process   
LISTEN   0        80               0.0.0.0:3306            0.0.0.0:*  
  1. 외부에서 접속을 시도한다.
[root@jh-up-test-rhel84 ~]# mysql -uroot -p -h 10.65.121.86 -P 13306
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 4
Server version: 11.2.2-MariaDB-1:11.2.2+maria~ubu2204 mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> 
  1. 컨테이너 내부에서 외부 서버와의 연결을 확인한다.
    또한 Host 에서 확인해봤을 때 외부 서버의 접속 여부를 확인할 수 없는데, 포트포워딩으로 인해 Host를 통과하여 컨테이너 내부로 접속하기 때문이다.
root@f7f874049900:/# ss -4tpn
State   Recv-Q   Send-Q     Local Address:Port       Peer Address:Port    Process   
ESTAB   0        0             10.88.0.27:3306       10.65.121.84:42300

[root@jh-container-rocky86 ~]# netstat -antp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      885/sshd            
tcp        0      0 0.0.0.0:13306           0.0.0.0:*               LISTEN      59714/conmon        
tcp        0     36 10.65.121.86:22         10.0.9.6:51376          ESTABLISHED 56765/sshd: root [p 
tcp6       0      0 :::22                   :::*                    LISTEN      885/sshd            

2. Bridge - Internal

Internal 네트워크는 내부 네트워크를 얘기하며, KVM으로 비교했을 때 Isolated 네트워크와 동일하다.
내부 네트워크이므로 외부에서 접근이 불가능한 네트워크이다.

  1. Internal 네트워크를 생성 및 확인한다.
[root@jh-container-rocky86 ~]# podman network create --driver bridge --internal --subnet 200.200.200.0/24 --gateway 200.200.200.1 internal-network
internal-network

[root@jh-container-rocky86 ~]# podman network ls
NETWORK ID    NAME              DRIVER
a941d590a508  internal-network  bridge
2f259bab93aa  podman            bridge

[root@jh-container-rocky86 ~]# podman network inspect --format json internal-network 
[
     {
          "name": "internal-network",
          "id": "a941d590a508e7dbc94ce1b2486ca17ed206e324827c304ffaf4620f299c1f6e",
          "driver": "bridge",
          "network_interface": "cni-podman1",
          "created": "2024-02-19T09:31:43.821875969+09:00",
          "subnets": [
               {
                    "subnet": "200.200.200.0/24",
                    "gateway": "200.200.200.1"
               }
          ],
          "ipv6_enabled": false,
          "internal": true,
          "dns_enabled": false,
          "ipam_options": {
               "driver": "host-local"
          }
     }
]
  1. Internal 네트워크로 컨테이너를 실행한다.
[root@jh-container-rocky86 ~]# podman run -itd --network internal-network -p 23306:3306 -e MYSQL_ROOT_PASSWORD=1234 --restart always --name jh-mariadb02 mariadb:latest
b0f903cb9947aa57f5c23404796e37b0985e91edad574fdd45152883c154a870

[root@jh-container-rocky86 ~]# podman ps
CONTAINER ID  IMAGE                             COMMAND     CREATED         STATUS             PORTS                    NAMES
f7f874049900  docker.io/library/mariadb:latest  mariadbd    2 days ago      Up 2 days ago      0.0.0.0:13306->3306/tcp  jh-mariadb01
b0f903cb9947  docker.io/library/mariadb:latest  mariadbd    19 seconds ago  Up 19 seconds ago  0.0.0.0:23306->3306/tcp  jh-mariadb02
  1. 외부에서 접속을 시도한다.
[root@jh-up-test-rhel84 ~]# mysql -uroot -p -h 10.65.121.86 -P 23306
Enter password: 
ERROR 2002 (HY000): Can't connect to MySQL server on '10.65.121.86' (115)
  1. 이전 포스트에서 빌드한 이미지로 2개의 컨테이너를 생성한다.
    ping, ssh 명령어를 사용하여 ip 할당 및 접속 확인을 위해 이전 포스트에서 빌드한 이미지를 사용한다.
[root@jh-container-rocky86 ~]# podman run -itd --network internal-network -p 33306:3306 -e MYSQL_ROOT_PASSWORD=1234 --restart always --name jh-rk86-mariadb03 jh/rk86-mariadb:240208 
72a489ec69815f8309d48a9e0f302c9d36669d0035acab3b94ad79a981da9d40

[root@jh-container-rocky86 ~]# podman run -itd --network internal-network -p 43306:3306 -e MYSQL_ROOT_PASSWORD=1234 --restart always --name jh-rk86-mariadb04 jh/rk86-mariadb:240208 
e4803261008676358f0284f94b8c2457880ddf572b4456956ab67cd797018fe4

[root@jh-container-rocky86 ~]# podman ps
CONTAINER ID  IMAGE                             COMMAND     CREATED             STATUS                 PORTS                    NAMES
f7f874049900  docker.io/library/mariadb:latest  mariadbd    2 days ago          Up 2 days ago          0.0.0.0:13306->3306/tcp  jh-mariadb01
b0f903cb9947  docker.io/library/mariadb:latest  mariadbd    9 minutes ago       Up 9 minutes ago       0.0.0.0:23306->3306/tcp  jh-mariadb02
72a489ec6981  localhost/jh/rk86-mariadb:240208  /sbin/init  About a minute ago  Up About a minute ago  0.0.0.0:33306->3306/tcp  jh-rk86-mariadb03
e48032610086  localhost/jh/rk86-mariadb:240208  /sbin/init  About a minute ago  Up About a minute ago  0.0.0.0:43306->3306/tcp  jh-rk86-mariadb04
  1. 컨테이너 IP 생성 확인 및 Ping 명령어로 통신을 확인한다.
    Internal 대역대로 생성된 컨테이너끼리 통신되는 것을 확인할 수 있다.
[root@jh-container-rocky86 ~]# podman inspect jh-rk86-mariadb03 | grep IPAddress
               "IPAddress": "",
                         "IPAddress": "200.200.200.3",

[root@jh-container-rocky86 ~]# podman inspect jh-rk86-mariadb04 | grep IPAddress
               "IPAddress": "",
                         "IPAddress": "200.200.200.4",

[root@jh-container-rocky86 ~]# podman exec -it jh-rk86-mariadb03 ping 200.200.200.4
PING 200.200.200.4 (200.200.200.4) 56(84) bytes of data.
64 bytes from 200.200.200.4: icmp_seq=1 ttl=64 time=16.5 ms
64 bytes from 200.200.200.4: icmp_seq=2 ttl=64 time=0.057 ms
64 bytes from 200.200.200.4: icmp_seq=3 ttl=64 time=0.054 ms
64 bytes from 200.200.200.4: icmp_seq=4 ttl=64 time=0.056 ms
^C
--- 200.200.200.4 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3074ms
rtt min/avg/max/mdev = 0.054/4.154/16.451/7.099 ms

[root@jh-container-rocky86 ~]# podman exec -it jh-rk86-mariadb04 ping 200.200.200.3
PING 200.200.200.3 (200.200.200.3) 56(84) bytes of data.
64 bytes from 200.200.200.3: icmp_seq=1 ttl=64 time=0.086 ms
64 bytes from 200.200.200.3: icmp_seq=2 ttl=64 time=0.054 ms
64 bytes from 200.200.200.3: icmp_seq=3 ttl=64 time=0.055 ms
64 bytes from 200.200.200.3: icmp_seq=4 ttl=64 time=0.057 ms
^C
--- 200.200.200.3 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3068ms
rtt min/avg/max/mdev = 0.054/0.063/0.086/0.013 ms

3. Host

KVM 환경의 Bridge 대역처럼 Podman 에서도 Bridge 대역을 사용할 수 있다.
cni-podman0 인터페이스처럼 NAT를 거치지 않고 외부로 이어지는 방식이다.
Layer 한개를 축소할 수 있어 성능상 이점이 있다.
# podman network 에서는 확인이 안되는데, 커널에 내장된 기본 네트워크라고 생각하면 된다.

[root@jh-container-rocky86 ~]# podman network ls
NETWORK ID    NAME              DRIVER
a941d590a508  internal-network  bridge
2f259bab93aa  podman            bridge
  1. 기존 컨테이너를 모두 삭제한다.
[root@jh-container-rocky86 ~]# podman ps
CONTAINER ID  IMAGE                             COMMAND     CREATED       STATUS           PORTS                    NAMES
f7f874049900  docker.io/library/mariadb:latest  mariadbd    3 days ago    Up 3 days ago    0.0.0.0:13306->3306/tcp  jh-mariadb01
b0f903cb9947  docker.io/library/mariadb:latest  mariadbd    24 hours ago  Up 24 hours ago  0.0.0.0:23306->3306/tcp  jh-mariadb02
72a489ec6981  localhost/jh/rk86-mariadb:240208  /sbin/init  24 hours ago  Up 24 hours ago  0.0.0.0:33306->3306/tcp  jh-rk86-mariadb03
e48032610086  localhost/jh/rk86-mariadb:240208  /sbin/init  24 hours ago  Up 24 hours ago  0.0.0.0:43306->3306/tcp  jh-rk86-mariadb04

[root@jh-container-rocky86 ~]# podman rm -af
b0f903cb9947aa57f5c23404796e37b0985e91edad574fdd45152883c154a870
e4803261008676358f0284f94b8c2457880ddf572b4456956ab67cd797018fe4
f7f874049900e0b238d8f446dda44d980d2f086344869c3d1b0f57712a449418
72a489ec69815f8309d48a9e0f302c9d36669d0035acab3b94ad79a981da9d40
  1. Host 네트워크로 컨테이너를 실행한다.
    Bridge 대역의 포트를 사용하기 때문에 포트포워딩 개념이 없다.
    따라서 아래와 같이 접근이 불가능한 상황이 발생한다.
    1. -p 옵션을 사용해도 Host 네트워크의 포트를 직접 사용하므로 무시된다.
    2. -p 옵션을 제외해도 포트 넘버가 동일하면 충돌이 일어나 접근이 불가능하다.
      ex) SSH 22번 포트로 접속을 시도하면 컨테이너가 아닌 Host OS로 접속됨.
    3. 컨테이너 내부에서 포트를 변경해도 접근이 불가능하다.
      ex) -p 옵션을 사용하지 않고 컨테이너를 생성한 후, SSH 포트를 변경해도 접근이 불가능하다.

    결론: Host 네트워크를 사용하면 Host OS의 포트를 직접적으로 바인딩하기 때문에 포트 번호가 겹칠 경우 접속이 불가능하다.

이와 같은 상황을 방지하기 위해 이미지 자체에서 --port 옵션을 사용할 수 있는데,
이 옵션은 Host OS의 포트와 컨테이너의 포트를 연결해주는 포트포워딩과 다르게
컨테이너에 직접 특정 포트를 할당하는 옵션이다.

[root@jh-container-rocky86 ~]# podman run -itd --network host -e MYSQL_ROOT_PASSWORD=1234 --restart always --name jh-mariadb01 mariadb:latest --port 13306
aab0be1586283c32894698c0d4c914929f460ebd86b1e5f3cafceb11392e26cb

[root@jh-container-rocky86 ~]# podman ps
CONTAINER ID  IMAGE                             COMMAND       CREATED        STATUS            PORTS       NAMES
aab0be158628  docker.io/library/mariadb:latest  --port 13306  2 seconds ago  Up 2 seconds ago              jh-mariadb01

[root@jh-container-rocky86 ~]# netstat -antp | grep 3306
tcp        0      0 0.0.0.0:13306           0.0.0.0:*               LISTEN      67109/mariadbd      
tcp6       0      0 :::13306                :::*                    LISTEN      67109/mariadbd  
  1. 다른 서버에서 접속을 시도한다.
[root@jh-up-test-rhel84 ~]# mysql -uroot -p -h 10.65.121.86 -P 13306
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 3
Server version: 11.2.2-MariaDB-1:11.2.2+maria~ubu2204 mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> 

[root@jh-container-rocky86 ~]# ss -4tpn
State    Recv-Q    Send-Q         Local Address:Port          Peer Address:Port     Process                                                                             
ESTAB    0         36              10.65.121.86:22                10.0.9.6:59499     users:(("sshd",pid=62560,fd=5),("sshd",pid=62546,fd=5))                            
ESTAB    0         0               10.65.121.86:13306         10.65.121.84:42306     users:(("mariadbd",pid=67109,fd=43))  
profile
Linux/Cluster/Infra Engineer

0개의 댓글