[docker] docker 네트워크 - 네트워킹 자습서 (4)

업데이트:     Updated:

카테고리:

태그:

🎯네트워킹 자습서

  • 브리지 네트워크 자습서
  • 호스트 네트워킹 자습서

브리지 네트워크 자습서

  • 기본 브리지 네트워크: Docker가 자동으로 설정 하는 기본 bridge 네트워크를 사용하는 방법을 보여줍니다.
  • 사용자 정의 브리지 네트워크: 동일한 Docker 호스트에서 실행되는 컨테이너를 연결하기 위해 고유한 사용자 지정 브리지 네트워크를 만들고 사용하는 방법을 보여줍니다.

기본 브리지 네트워크 사용

  • 프로덕션 환경에서 기본 브리지 네트워크를 사용하는 것은 권장되지 않습니다.
  • 프로덕션 환경에서 사용하려는 경우 사용자 정의 브리지 네트워크 사용을 고려하십시오.
# TODO 1. docker network ls
$ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
b0639baf7651   bridge    bridge    local
58579e13e100   host      host      local
64fd52749656   none      null      local

# TODO 2. alpine 이미지의 기본 쉘인 ash를 실행하는 두 개의 컨테이너를 시작합니다.
$ docker run -dit --name alpine1 alpine ash
3a5c906729cc8f1bfa85ad1cc1cb84ad56188865ec521eb8bf17e7ed7b076c13
$ docker run -dit --name alpine2 alpine ash
d1fe432fb7d15985292d3b5b4ae31dc781ec358e8231e1e9466eeedc9e76f31b

# --network 플래그를 지정하지 않았기 때문에 기본 브리지 네트워크에 연결됩니다.

# TODO 3. docker network inspect bridge
$ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "b0639baf76517dc10dfcc224aa5653c47c465d394d594d06594edab94e336757",
        "Created": "2023-01-25T12:15:14.77016413Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "3a5c906729cc8f1bfa85ad1cc1cb84ad56188865ec521eb8bf17e7ed7b076c13": {
                "Name": "alpine1",
                "EndpointID": "eeccb2d8346a7fd1d5e0ff097bcf3071946bb5ac1c6821661cea603f04ff05a4",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "d1fe432fb7d15985292d3b5b4ae31dc781ec358e8231e1e9466eeedc9e76f31b": {
                "Name": "alpine2",
                "EndpointID": "c5d382fdc5c481b32881d3cdab0ee518a8486edd56655abcd5d71a245f5e6159",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

# 맨 위에는 Docker 호스트와 bridge 네트워크 사이의 게이트웨이 IP 주소를 포함하여 네트워크에 대한 정보가 나열됩니다.
# Containers 키 아래에는 연결된 각 컨테이너가 가진 IP 주소에 대한 정보가 나열됩니다.

# TODO 4. 컨테이너 내부에 attach하여 ip 정보를 확인합니다.
$ docker attach alpine1
/ # ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
458: eth0@if459: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever


# 컨테이너에 접속했을 때 출력되는 '/ #' 문자는 컨테이너내에서 root 유저 프롬프트를 획득하였음을 알 수 있습니다.
# 첫 번째 인터페이스는 루프백이고 etho0@if459 인터페이스는 이전 단계에서 inspect 명령으로 확인한 IP 주소와 같음을 확인할 수 있습니다.

# TODO 5. alpine1 컨테이너에서 핑을 통해 인터넷에 연결할 수 있는지 확인합니다.
/ # ping -c 2 google.com
PING google.com (142.250.206.206): 56 data bytes
64 bytes from 142.250.206.206: seq=0 ttl=54 time=36.682 ms
64 bytes from 142.250.206.206: seq=1 ttl=54 time=35.721 ms

--- google.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 35.721/36.201/36.682 ms

# TODO 6. alpine1 컨테이너에서 alpine2 컨테이너의 IP 주소로 ping 합니다.
/ # ping -c 2 172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.086 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.088 ms

--- 172.17.0.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.086/0.087/0.088 ms

# TODO 7. alpine1 컨테이너에서 alpine2 컨테이너의 이름으로 ping 합니다.
/ # ping -c 2 alpine2
ping: bad address 'alpine2'

# 기본적으로 컨테이너간에는 IP 주소를 이용한 통신이 가능하지만 컨테이너 이름으로는 통신이 불가능함을 알 수 있다.

사용자 정의 브리지 네트워크 사용

# TODO 1. alpine-net 사용자 정의 브리지 네트워크를 만듭니다.
$ docker network create --driver bridge alpine-net
46be04a90dc73334f3a803f02f4c9d2e071f6fde48baf5cca7056c5bc479b430

# --driver bridge 플래그는 기본값이므로 생략할 수 있습니다.

# TODO 2. docker network ls
$ docker network ls
NETWORK ID     NAME         DRIVER    SCOPE
46be04a90dc7   alpine-net   bridge    local
b0639baf7651   bridge       bridge    local
58579e13e100   host         host      local
64fd52749656   none         null      local

# TODO 3. docker network inspect alpine-net
$ docker network inspect alpine-net
[
    {
        "Name": "alpine-net",
        "Id": "46be04a90dc73334f3a803f02f4c9d2e071f6fde48baf5cca7056c5bc479b430",
        "Created": "2023-01-31T10:10:03.563456932Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.112.0/20",
                    "Gateway": "192.168.112.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

# inspect 명령의 결과로 현재 alpine-net 네트워크에 연결된 컨테이너가 없음을 확인할 수 있습니다.
# 게이트웨이 주소가 172.17.0.1인 기본 브리지 네트워크와 달리 이 네트워크의 게이트웨이 주소는 192.168.112.1 입니다.

# TODO 4. 4개의 컨테이너를 만듭니다. 
$ docker run -dit --name alpine1 --network alpine-net alpine ash
4c31b32f68960d229e18af07d3628ff6bb49cd58923439f35a488f0e7ee12095

$ docker run -dit --name alpine2 --network alpine-net alpine ash
dda353744a09c9b776535d7ddfbd2873549dd61bfcaef4e7b67235241f457615

$ docker run -dit --name alpine3 alpine ash
503fc14e7529b2ad4193afe5b355aa4ca5447504ce7bfbd0667633c0b5a15ce6

$ docker run -dit --name alpine4 --network alpine-net alpine ash
b432f1efe117503393747bb157c006f71003ae24eacae05fd64cb82f1dc876a5

$ docker network connect bridge alpine4

# alpine3 컨테이너는 --network 플래그를 사용하지 않았습니다.
# alpine4 컨테이너는 'docker network connect' 명령을 이용해 기본 브리지 네트워크를 추가 연결하였습니다.

# TODO 5.1 bridge 네트워크를 검사합니다.
$ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "b0639baf76517dc10dfcc224aa5653c47c465d394d594d06594edab94e336757",
        "Created": "2023-01-25T12:15:14.77016413Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "503fc14e7529b2ad4193afe5b355aa4ca5447504ce7bfbd0667633c0b5a15ce6": {
                "Name": "alpine3",
                "EndpointID": "244f187fa6be85b1d2814ce81ab9fd6f16be84ad1f46c51324ad27abe70ca8b0",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "b432f1efe117503393747bb157c006f71003ae24eacae05fd64cb82f1dc876a5": {
                "Name": "alpine4",
                "EndpointID": "c29061a43f4ab5d69e9a1fc34cbc8e4851df5179e9a70f0afbdfa272464e89ca",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

# TODO 5.2 alpine-net 네트워크를 검사합니다.
$ docker network inspect alpine-net
[
    {
        "Name": "alpine-net",
        "Id": "46be04a90dc73334f3a803f02f4c9d2e071f6fde48baf5cca7056c5bc479b430",
        "Created": "2023-01-31T10:10:03.563456932Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.112.0/20",
                    "Gateway": "192.168.112.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "4c31b32f68960d229e18af07d3628ff6bb49cd58923439f35a488f0e7ee12095": {
                "Name": "alpine1",
                "EndpointID": "229a0ae43e90fbf25c3988af4f40f51f07fd76f74ccb4fa1e42650f2174189f1",
                "MacAddress": "02:42:c0:a8:70:02",
                "IPv4Address": "192.168.112.2/20",
                "IPv6Address": ""
            },
            "b432f1efe117503393747bb157c006f71003ae24eacae05fd64cb82f1dc876a5": {
                "Name": "alpine4",
                "EndpointID": "bb16c131a432a9f47426a6233021a6b1b61ed50040b7897204b9b4967b6de03a",
                "MacAddress": "02:42:c0:a8:70:04",
                "IPv4Address": "192.168.112.4/20",
                "IPv6Address": ""
            },
            "dda353744a09c9b776535d7ddfbd2873549dd61bfcaef4e7b67235241f457615": {
                "Name": "alpine2",
                "EndpointID": "5982f51cd390e9abed2deb4bf15dfeec090ea67e05cc33f619389ae1d458fe19",
                "MacAddress": "02:42:c0:a8:70:03",
                "IPv4Address": "192.168.112.3/20",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

# alpine3, alpine4 컨테이너는 기본 브리지에 연결되었습니다.
# alpine1, alpine2, alpine4 컨테이너는 alpine-net 네트워크에 연결되었습니다.

# TODO 6. alpine1 컨테이너에 attach 하여 alpine2, alpine4 컨테이너 이름으로 ping 합니다.
$ docker attach alpine1
/ # ping -c 2 alpine2
PING alpine2 (192.168.112.3): 56 data bytes
64 bytes from 192.168.112.3: seq=0 ttl=64 time=1.503 ms
64 bytes from 192.168.112.3: seq=1 ttl=64 time=0.076 ms

--- alpine2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.076/0.789/1.503 ms
/ # ping -c 2 alpine4
PING alpine4 (192.168.112.4): 56 data bytes
64 bytes from 192.168.112.4: seq=0 ttl=64 time=2.980 ms
64 bytes from 192.168.112.4: seq=1 ttl=64 time=0.088 ms

--- alpine4 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.088/1.534/2.980 ms

# 사용자 정의 네트워크에서는 컨테이너 IP 주소로 통신할 수 있을 뿐만 아니라 컨테이너 이름을 IP 주소로 확인할 수도 있습니다. 이 기능을 자동 서비스 검색이라고 합니다.

# TODO 7. alpine3 컨테이너에 ping 합니다.
/ # ping -c 2 alpine3
ping: bad address 'alpine3'

/ # ping -c 2 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes

--- 172.17.0.2 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss

# alpine-net 네트워크에만 연결된 컨테이너에서 alpine3 컨테이너로 통신할 수 있는 방법은 없습니다.

# TODO 8. apine4 컨테이너에 attach 하여 다른 컨테이너에 ping 합니다.
/ # ping -c 2 alpine1
PING alpine1 (192.168.112.2): 56 data bytes
64 bytes from 192.168.112.2: seq=0 ttl=64 time=0.065 ms
64 bytes from 192.168.112.2: seq=1 ttl=64 time=0.097 ms

--- alpine1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.065/0.081/0.097 ms
/ # ping -c 2 alpine2
PING alpine2 (192.168.112.3): 56 data bytes
64 bytes from 192.168.112.3: seq=0 ttl=64 time=0.299 ms
64 bytes from 192.168.112.3: seq=1 ttl=64 time=0.104 ms

--- alpine2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.104/0.201/0.299 ms
/ # ping -c 2 alpine3
ping: bad address 'alpine3'
/ # ping -c 2 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.229 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.115 ms

--- 172.17.0.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.115/0.172/0.229 ms

# alpine4 컨테이너는 기본 브리지 네트워크와 사용자 정의 브리지 네트워크에 모두 연결되어 있습니다.
# 따라서 alpine1, alpine2, alpine3 컨테이너 모두와 통신할 수 있습니다.
# 다만, alpine3 컨테이너는 기본 브리지 네트워크로 연결되어 있기 때문에 컨테이너 이름이 아닌 IP 주소로만 통신할 수 있습니다.

호스트 네트워킹 자습서

  • 이 자습서의 목표는 Docker 호스트의 80 포트에 직접 바인딩 되는 nginx 컨테이너를 시작하는 것입니다.
  • 네트워킹 관점에서 nginx 프로세스가 컨테이너가 아닌 Docker 호스트에서 직접 실행되는 것과 동일한 수준의 격리입니다.
  • 그러나 저장소, 프로세스, 네임스페이스와 같은 다른 모든 리소스에서는 nginx 프로세스가 호스트에서 격리됩니다.
# TODO 1. nginx 컨테이너를 시작합니다. 
$ docker run --rm -d --network host --name my_nginx nginx
da59ee895a0a52edb5f99bedab52e4f9ac64727b4520fac4d10f7b36334e6118

# TODO 2. curl http://localhost:80 으로 이동하여 Nginx에 엑세스 합니다.
$ curl http://localhost:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

# TODO 3. Docker 호스트에서 ifconfig 명령을 사용하여 새 인터페이스가 생성되지 않았는지 검사합니다.
$ ifconfig

# host 네트워크를 통해 생성된 컨테이너는 Docker 호스트에 새로운 인터페이스를 생성하지 않습니다.

# TODO 4. Docker 호스트에서 netstat 명령을 사용하여 80 포트에 바인딩된 프로세스를 확인합니다.
$ docker container inspect my_nginx | grep -w Pid
            "Pid": 7092,
$ netstat -tnlp | grep :80
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      7092/nginx: master  
tcp6       0      0 :::80                   :::*                    LISTEN      7092/nginx: master

📌출처

Docker Docs


👍 개인 공부 기록용 블로그입니다. 오류나 조언이 있으시면 언제든지 댓글 혹은 메일로 남겨주시면 감사하겠습니다! 😄

맨 위로 이동하기

docker 카테고리 내 다른 글 보러가기

댓글남기기