Profile picture

[Docker] 도커 네트워크(network)

JaehyoJJAng2023년 04월 07일

▶︎ 들어가기 앞서

‣ veth interface

랜카드에 연결된 실제 네트워크 인터페이스가 아닌, 가상으로 생성한 네트워크 인터페이스이다.

일반적인 네트워크 인터페이스와는 달리 패킷을 전달받으면, 자신에게 연결된 다른 네트워크 인터페이스로 패킷을 보내주기 때문에 항상 쌍(pair)으로 생성해야 한다.


‣ NET namespace

리눅스 격리 기술인 namespace 중 네트워크와 관련된 부분을 말한다.

네트워크 인터페이스를 각각 다른 namespace에 할당함으로써 서로가 서로를 모르게끔 설정할 수 있다.


▶︎ 도커 네트워크

‣ 가상 네트워크

네트워크 가상화는 네트워크 기능, 하드웨어 리소스, 소프트웨어 리소스를 하드웨어와 별도의 가상 네트워크로 전달할 수 있게 해주는 것을 의미함.

image
도커는 가상화 기술을 통해 네트워크 리소스를 가상화 할 수 있다.

물리적으로 존재하지 않고 논리적으로만 존재하는 것이다.

이렇게 논리적으로 네트워크 환경을 구성하는 기술을 **SDN(Software Defined Network)**라고도 부른다.


‣ Bridge

도커 네트워크에서는 브릿지(Bridge)라는 가상의 도커용 네트워크 드라이버가 존재해서 각 컨테이너들에게 IP를 할당하거나 관리할 수 있다.

우선 브릿지는 기본적으로 172.17.0.1 이라는 IP 주소를 기본값으로 사용하며, 사용자가 직접 브릿지를 생성할 수 있으며 IP 대역도 지정이 가능하다.

ifconfig -a | grep -A1 'docker'
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255

같은 브릿지 네트워크 망을 사용하는 컨테이너들은 브릿지를 통해서 서로 자유롭게 통신이 가능하다.

같은 네트워크를 공유하고 있으니 당연한 소리이기도 하다.

반대로 서로 다른 브릿지 네트워크 망끼리는 통신이 불가능하다.
image


‣ 가상 인터페이스

image
보통 외부 또는 내부와 통신을 하려면

랜선이라 불리는 이더넷 케이블이 컴퓨터의 랜카드의 물리 인터페이스에 연결되고,

해당 라인은 IP 주소를 L3 장비(라우터,공유기 ..)로부터 할당받게 된다.

즉, 사진처럼 192.168.0.10의 IP를 할당 받았다면 앞으로 192.168.0.10 주소로 오는 모든 데이터는 eth0 인터페이스가 전부 수신 받는 것이다.

이 과정은 가상 네트워크 환경에서도 동일하게 적용된다.

하지만 말 그대로 가상이기 때문에 랜선을 꽂고 실제 아이피를 할당해주는 모든 작업이 소프트웨어적으로 발생한다.

우선 도커를 설치하면 도커는 docker0 이라 불리는 가상 네트워크 인터페이스를 호스트 OS에 설치한다.

그리고 컨테이너가 생성될 때 마다 Veth라 불리는 가상의 인터페이스들이 하나씩 생성되며 아이피 주소도 브릿지로부터 할당 받는다.


확인을 위해 아래와 같이 nginx 컨테이너를 도커 네트워크의 Bridge를 연결해서 생성해주고 해당 컨테이너의 IP를 확인해보자.

$ docker run -d -it --name nginx --network=bridge nginx:latest
$ docker container inspect nginx | jq '.[].NetworkSettings.Networks.bridge.Gateway  
"172.17.0.1"

Bridge로부터 아이피를 할당받은 것을 확인할 수 있었다.


‣ 도커 DNS

image
도커는 컨테이너들이 기본적으로 사용할 수 있는 DNS 서버를 제공한다.

이 DNS 서버에는 IP 주소와 도메인명이 저장되어 있다.

여기서 도메인은 컨테이너의 이름으로 자동 저장된다.

그래서 컨테이너들은 기본적으로 컨테이너의 IP가 아닌 컨테이너의 이름으로 통신할 수 있는 것이다.

위 사진의 구성처럼

second-bridge 네트워크를 생성하고 컨테이너 A와 컨테이너 B를 생성한 상태라고 가정할 때,

A에서는 요청을 보낼 때 도메인 명을 컨테이너 B로 지정하면

먼저 도커 DNS를 통해서 컨테이너 B의 IP 주소인 10.0.0.3이라는 IP를 받아온다.

그리고 이 IP로 요청을 보내는 것이다.

컨테이너 B가 재시작 되어서 IP가 10.0.0.4로 변경되더라도 도메인 서버에 즉시 업데이트가 되기 때문에

컨테이너 A는 컨테이너 B라는 도메인만 사용하면 요청을 정상적으로 보낼 수 있게된다.


간단한 테스트를 위해 testNet이라는 도커 네트워크를 생성하고

nginx1, nginx2 라는 이름을 가진 두 개의 컨테이너를 생성해보도록 하자.

# 도커 네트워크 생성
$ docker network create --driver=bridge --subnet=10.0.0.0/24 testNet

# 도커 컨테이너 생성
$ docker run -d -it --name nginx1 -p 80:80 --network=testNet devwikirepo/pingbuntu
$ docker run -d -it --name nginx2 -p 81:80 --network=testNet devwikirepo/pingbuntu

nginx1 컨테이너에 접속하여 nginx2 컨테이너 이름으로 ping 테스트를 해보도록 하자.

$ docker exec -it nginx1 ping -c 2 nginx2

image
컨테이너 이름으로도 통신이 가능한 것을 확인하였다.


🔴 Bridge Network

기본으로 생성되는 Bridge 네트워크는 이 DNS 기능이 제공되지 않는다.

사용자가 직접 생성한 브릿지 네트워크만 컨테이너의 이름을 통해서 통신이 가능하다.


‣ 도커 네트워크 구조

도커는 위에서 언급한 veth interface와 NET namespace를 사용해 네트워크를 구성한다.
참고로 mac이나 window는 veth interface가 VM 안에 감춰져 있기 때문에 확인이 어렵다.
image


도커를 생성하면 3가지 형태의 network가 생김을 확인할 수 있다.

$ sudo docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
6b6ce553a425        bridge              bridge              local
81a18bc9cc40        host                host                local
576b0223f9cf        none                null                local

bridge 네트워크를 확인해보면 172.17.0.0/16 대역을 할당했음을 아래 명령어를 실행하여 확인해볼 수 있다.

$ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "6b6ce553a425c9392c5a65b8dcd2a57e1665289354b97f430758b745b1dc86a7",
        ...
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
        ...
    }
...
]

그리고 172.17.0.0/16 대역은 docker0로 매핑되어 있다.

$ ip route | grep 'docker'
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown

docker0는 veth interface와 매핑된 브릿지임을 확인할 수 있다.

# bridge-utils 패키지가 미설치된 경우 아래 명령어 실행하여 설치
$ sudo apt-get install -y bridge-utils

$ brctl show docker0
bridge name	bridge id		STP enabled	interfaces
docker0		8000.02423df329a4	no
$ ip link ls | egrep "docker|veth"
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
18: veth6ccab66@if17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-39fed30460d7 state UP mode DEFAULT group default
20: veth1d21aac@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-39fed30460d7 state UP mode DEFAULT group default
22: veth62032a7@if21: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
  • 컨테이너는 namespace로 격리되고, 통신을 위한 네트워크 인터페이스(eth0)를 할당 받는다.
  • host의 veth interface가 생성되고 컨테이너 내의 eth0과 연결된다.
  • host의 veth interface는 docker0 이라는 다른 veth interface와 연결된다.

도커 컴포즈로 컨테이너를 띄우는 경우에는 네트워크가 어떻게 구성될까?

테스트를 위해 아래 깃허브 프로젝트를 clone 받아온 후, Docker Compose를 실행 시켜보자.

git clone https://github.com/woowacourse/service-practice.git
cd service-practice && cd lb
docker build -t node-server .
docker-compose -p practice up -d

생성된 lb-lb-1 컨테이너의 디폴트 게이트웨이를 확인해보자.

$ docker container inspect lb-lb-1 | jq '.[].NetworkSettings.Networks.lb_default.Gateway'
"172.18.0.1"

$ ip route
172.18.0.0/16 dev br-754310d33f5c proto kernel scope link src 172.18.0.1

$ ip link ls
4: br-754310d33f5c: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
   link/ether 02:42:cd:76:d1:f1 brd ff:ff:ff:ff:ff:ff

docker-compose로 띄우면 다른 네트워크 대역을 가진다. docker-compose로 컨테이너를 띄우면 compose로 묶은 범위에 맞춰 브릿지를 하나 더 생성하기 때문이다. 따라서 서로 경유하는 브릿지가 다르므로 docker-compose로 띄운 컨테이너와 일반 컨테이너간의 통신은 불가능하다.


그러나 위와 같은 상황에서도 방법은 하나 있다.

먼저 docker network create 로 'external' 이라는 도커 네트워크를 생성해보자.

$ docker network create external

그리고 docker-compose에 아래 내용을 추가해주자.

version: "3.3"

services:
  image: nginx
  networks:
    - "external-net"
  ...

networks:
  - external-net:
    name: external
    external: true

docker network create로 생성된 'external' 이라는 외부 도커 네트워크를 사용하겠다고 docker-compose에 networks 옵션을 사용하여 명시해주면 된다.

그리고 통신하고자 하는 다른 일반 컨테이너도 'external' 이라는 도커 네트워크로 묶어주면 docker-compose로 생성된 컨테이너와 일반 컨테이너 간 통신이 가능해지기는 한다.


# 포트포워딩 설정과 함께 컨테이너를 생성합니다.
$ docker container run -d -p 8081:80 nginx
16cd67c48e5721a6b666192b8960875c720168bf6c5e3ed2138fb04c492447c6

$ sudo docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
16cd67c48e57        nginx               "/docker-entrypoint.…"   4 seconds ago       Up 3 seconds        0.0.0.0:8081->80/tcp   trusting_bhabha

# Host의 8081포트가 listen 임을 확인합니다.
$ sudo netstat -nlp | grep 8081
tcp6       0      0 :::8081                 :::*                    LISTEN      10009/docker-proxy

# docker-proxy 라는 프로세스가 해당 포트를 listen 하고 있음을 볼 수 있습니다.
# docker-proxy는 들어온 요청을 해당하는 컨테이너로 넘기는 역할만을 수행하는 프로세스입니다.
# 컨테이너에 포트포워딩이나 expose를 설정했을 경우 같이 생성됩니다.

$ iptables -t nat -L -n
Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  0.0.0.0/0            0.0.0.0/0
RETURN     all  --  0.0.0.0/0            0.0.0.0/0
RETURN     all  --  0.0.0.0/0            0.0.0.0/0
RETURN     all  --  0.0.0.0/0            0.0.0.0/0
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8081 to:172.17.0.2:80

# 보시다시피 모든 요청을 DOCKER Chain 으로 넘기고, DOCKER Chain 에서는 DNAT를 통해 포트포워딩을 해주고 있음을 볼 수 있습니다.
# 이 iptables 룰은 docker daemon이 자동으로 설정합니다.

기본적으로 컨테이너는 외부와 통신이 불가능하다.

그러나 포트포워딩을 설정하여 외부에 컨테이너를 공개할 수 있다.

docker container의 네트워크 모드는 bridge, host, container, none 등 총 4개가 존재한다.


▶︎ 도커 네트워크 실습

Info. 네트워크 조회

docker network ls 커맨드를 사용하여 현재 생성되어 있는 Docker 네트워크 목록을 조회할 수 있다.

docker network ls

NETWORK ID     NAME      DRIVER    SCOPE
01148fff8c35   bridge    bridge    local
0a5d707b4146   host      host      local
c3356923ba47   none      null      local

bridge , host , none 은 docker 데몬이 실행되면서 디폴트로 생성되는 네트워크이다.


A. 네트워크 종류

Docker 네트워크는 bridge, host, overlay등 목적에 따라 다양한 종류의 네트워크 드라이버를 지원한다.

  • 브릿지(bridge) 네트워크: 도커 브릿지를 활용해 컨테이너간 통신, NAT 및 포트포워딩 기술을 활용해 외부 통신 지원
  • 호스트(host) 네트워크: 호스트의 네트워크를 공유
    • 모든 컨테이너는 호스트 머신과 동일한 IP를 사용
    • 포트 중복 불가능
  • 오버레이(overlay) 네트워크: Kubernetes에서 사용
    • 호스트 머신이 다수일 때 네트워크 관리 기술
  • Macvlan 네트워크: 컨테이너에 MAC 주소를 할당하여 물리 네트워크 인터페이스에 직접 연결

B. 네트워크 생성

docker network create 커맨드를 사용하여 새로운 Docker network를 생성해보자

$ docker network create --driver=bridge my-net
1e5ad60b467c3dd5e0ff9582bd2be6af0fb0cea2cd78fac45396349093811a77

$ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
01148fff8c35   bridge    bridge    local
0a5d707b4146   host      host      local
1e5ad60b467c   my-net    bridge    local
c3356923ba47   none      null      local

도커 네트워크에 특정 서브넷 대역을 지정하고 싶다면 아래와 같이 실행하면 된다.

$ docker network create --driver=bridge --subnet 10.0.0.0/24 --gateway 10.0.0.1 my-net

C. 네트워크 상세 정보

방금 추가한 네트워크의 상세 정보를 docker network inspect 커맨드로 확인이 가능하다

$ docker network inspect my-net

[
    {
        "Name": "my-net",
        "Id": "1e5ad60b467c3dd5e0ff9582bd2be6af0fb0cea2cd78fac45396349093811a77",
        "Created": "2023-04-19T04:25:32.234055588Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

D. 네트워크 연결

컨테이너 하나를 test 라는 이름으로 실행해보자

$ docker run -d -it --name test busybox

컨테이너를 실행할 때 --network 옵션을 명시해주지 않으면 디폴트로 bridge 라는 이름의 디폴트 네트워크에 붙게된다.


$ docker network inspect bridge
(...생략...)
        "Containers": {
            "e45d2943d90f3f4bf0495c161555f610005f5daef8cd27925ff58818f9371849": {
                "Name": "test",
                "EndpointID": "d31d5236b1093f967a3ab1eab2f9ea3ad8ea184f48f1a1619c5bddb9fcbb653b",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
(...생략...)

test 컨테이너를 위에서 생성한 my-net 네트워크에 연결해보자.

$ docker network connect my-net test

my-net 네트워크의 상세정보를 다시 확인해보면 Containers 항목에 test 컨테이너가 추가된 것을 볼 수 있다.


$ docker network inspect my-net

[
    {
        "Name": "my-net",
        "Id": "1e5ad60b467c3dd5e0ff9582bd2be6af0fb0cea2cd78fac45396349093811a77",
        "Created": "2023-04-19T04:25:32.234055588Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "e45d2943d90f3f4bf0495c161555f610005f5daef8cd27925ff58818f9371849": {
                "Name": "test",
                "EndpointID": "a4763c61db9d595ffcbc6d68314c100d6fff57c724b07f187042853885ed6295",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

그리고 test 컨테이너에 IPv4 도 할당이 되었는데 주소는 172.187.0.2/16 이다.


E. 네트워크 연결 해제

하나의 컨테이너는 여러 개의 네트워크에 동시에 연결이 가능하다.

최초에 test 컨테이너를 생성할 때 붙은 bridge 네트워크를 떼어내버리자

컨테이너 연결을 끊을 때는 docker network disconnect 커맨드를 사용한다

$ docker network disconnect bridge test

F. 두번째 컨테이너 연결

네트워크에 홀로 있는 컨테이너는 큰 의미가 없을 것이다.하나의 컨테이너를 더 my-net 네트워크에 연결해보도록 하자

이번에는 --network 옵션을 사용하여 컨테이너를 실행하면서 바로 연결할 네트워크를 지정해보도록 하자

$ docker run -d -it --name test2 --network my-net busybox

my-net 네트워크의 상세 정보를 확인해보면 test2 컨테이너에 IP 172.19.0.2가 할당되어 연결되어 있는 것을 확인할 수 있다!

$ docker network inspect my-net

[
    {
        "Name": "my-net",
        "Id": "986bf74da652868feac39e426f44f6c6c2016d33b047565652c8d84d8bd8c35d",
        "Created": "2023-04-24T12:01:37.037581923Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.19.0.0/16",
                    "Gateway": "172.19.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "331010f87747ecc5c003cf564ad66342dda4e18feb632e8e588862e7be334a30": {
                "Name": "test2",
                "EndpointID": "b34e47acfa97312f15b0568634ba6a017552b385f03dbe84f27c020e534f49c1",
                "MacAddress": "02:42:ac:13:00:02",
                "IPv4Address": "172.19.0.2/16",
                "IPv6Address": ""
            },
            "9377c7ab50b615732233a71d5eb22d04532c0c35b5eb4ff04e4b457d74ffc52f": {
                "Name": "test1",
                "EndpointID": "104d516b2a1ef915937ef4c4edb27a8eef8af6acf408e75338b608a29010e55e",
                "MacAddress": "02:42:ac:13:00:03",
                "IPv4Address": "172.19.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

G. 컨테이너 간 네트워킹

이제 두 개의 컨테이너가 네트워크를 통해 서로 소통이 가능한지 테스트를 진행해보자.

먼저 test1 컨테이너에서 test2 컨테이너를 상대로 ping 명령어를 날려보자


컨테이너 이름을 호스트네임(hostname)처럼 사용할 수도 있다!

$ docker exec test1 ping test2

PING test2 (172.19.0.2): 56 data bytes
64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.249 ms
64 bytes from 172.19.0.2: seq=1 ttl=64 time=0.197 ms
64 bytes from 172.19.0.2: seq=2 ttl=64 time=0.209 ms
64 bytes from 172.19.0.2: seq=3 ttl=64 time=0.320 ms
64 bytes from 172.19.0.2: seq=4 ttl=64 time=0.364 ms

반대로 test2 컨테이너에서 test1 컨테이너를 상대로 ping 명령어를 날려보자. 이번에는 컨테이너 이름 대신 IP를 사용해보자

$ docker exec test2 ping 172.19.0.3

PING 172.19.0.3 (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.169 ms
64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.351 ms
64 bytes from 172.19.0.3: seq=2 ttl=64 time=0.257 ms
64 bytes from 172.19.0.3: seq=3 ttl=64 time=0.367 ms
64 bytes from 172.19.0.3: seq=4 ttl=64 time=0.413 ms

H. 네트워크 제거

마지막으로 docker network rm 커맨드를 사용하여 my-net 네트워크를 삭제해보자.

$ docker network rm my-net

Error response from daemon: error while removing network: network my-net id 1e5ad60b467c3dd5e0ff9582bd2be6af0fb0cea2cd78fac45396349093811a77 has active endpoints

위와 같이 제거하려는 네트워크 상에서 실행 중인 컨테이너가 존재할 시 제거 되지 않는다.

해당 네트워크에 연결되어 실행 중인 모든 컨테이너를 먼저 중지시키고 네트워크를 삭제하면 된다.

$ docker kill $(docker ps -q)
$ docker network rm my-net

I. 네트워크 청소

하나의 호스트 컴퓨터에서 다수의 컨테이너를 돌리다 보면 아무 컨테이너도 연결되어 있지 않은 네트워크가 생기기 마련이다.

이럴 때는 docker network prune 커맨드를 사용하여 불필요한 네트워크를 한 번에 정리하도록 하자

$ yes | docker network prune # 'y' 를 docker network prune 커맨드의 입력으로 넘김

J. 디폴트 네트워크 연결하기

디폴트 네트워크(bridge,host,none)을 Docker Compose에서 연결하려면 어떡해야 할까?

version: "3"

services:
  test:
    image: test/test
    network_mode: <디폹트네트워크명> 

위 처럼 network_mode 옵션을 사용한다 값으로는 디폴트네트워크 이름을 넣어주면 된다


version: "3"

services:
  test:
    image: test/test
    network_mode: bridge

위 컨테이너는 bridge 네트워크에 연결된다


▶︎ 도커 네트워크 연습

‣ 예제 (1)

  1. swapi-net 이라는 도커 네트워크를 생성하고 swapi 컨테이너와 mongodb 컨테이너를 swapi-net 도커 네트워크에 소속 시키자
  2. swapi 라는 컨테이너 이름으로 node.js 기반 컨테이너를 하나 생성하고 mongodb 컨테이너도 생성하도록 하자.

도커 네트워크 생성하기

$ docker network create swapi-net

컨테이너 배포 및 도커 네트워크 연결

# node.js 프로젝트 배포
$ docker run -d -it --name swapi -p 80:3000 --network swapi-net yshrim12/favorite-api:latest

# mongodb 배포
$ docker run -d -it --name mongodb --network swapit-net mongo:latest

swapi-net 네트워크에 연결된 컨테이너 조회하기

$ docker network inspect swapi-net

...(생략)...
        "Containers": {
            "b048620cabaf2a212422d8e7a05800a578c9c1ba38a510c8e5ce22066c065e5c": {
                "Name": "mongodb",
                "EndpointID": "9824df174db1af19280199b413dcb5e890332601fa6f7322c89caa95d2dc8d43",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "b6c19e63fb96e966605f9a9340da4fd547cb0933ebc73533be64ee0a2bfaa3bb": {
                "Name": "swapi",
                "EndpointID": "c14ffc1f0f7ca8f7e3fa1a95835889fabdbb83944c0b2386086c5fbe11ec7b5b",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        },
...(생략)...

다른 컨테이너의 이름을 사용하기 위하여 두 컨테이너를 동일한 네트워크에 소속시켜야 한다!


swapi 컨테이너의 로그를 확인해보자

$ docker logs swapi

(node:1) [MONGODB DRIVER] Warning: Current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.
(Use `node --trace-warnings ...` to show where the warning was created)

정상적으로 동작하는 로그이다.


🚦 Why ?

mongodb 컨테이너를 배포할 때 포트를 게시하지 않은 이유는 무엇일까?

현재 내가 노출할 서비스는 node.js 프로젝트 하나이다.

swapi 컨테이너만 외부로 노출하면 되고 데이터베이스의 경우 외부로 노출할 필요가 없기 때문이다.

swapi 컨테이너가 내부적으로 mongodb 컨테이너와 통신을하고 데이터를 받아오고 받아온 데이터를 외부에 뿌려주는 형식이라고 보면될 것 같다.

생각해보면 데이터베이스 하나만 배포하는 경우는 거의 없고 서비스와 DB를 같이 연동하여 배포하기 때문에 보안적으로도 DB를 외부에 노출시키는 것은 바람직하지 않을 것 같다

‣ 예제 (2)

  • 커스텀 도커 네트워크 생성
  • nginx를 새로 생성한 커스텀 도커 네트워크에 연결
  • --net-alias=web : bridge 네트워크에서만 사용할 수 있는 옵션이다
    • bridge 네트워크 안에서 web 라는 도메인 이름으로 컨테이너 IP를 서치할 수 있도록 내부 도메인에 저장을 해줌

도커 네트워크 생성

# 도커 네트워크 driver를 bridge로 지정
$ docker network create --driver=bridge devops

nginx 컨테이너 생성 및 네트워크 연결

$ docker run -d -it --name nginx \
    --rm \
    --net-alias=web \
    nginx:latest

grafana 컨테이너 생성 및 네트워크 연결

$ docker run -d -it --name grafana \
    --rm \
    --net-alias=hello \
    grafana/grafana

grafana 컨테이너로 접속해 wget 커맨드로 --net-alias로 명령어로 지정해둔 web 도메인으로 접근 테스트하기

$ docker exec -it grafana wget web
$ wget web

Loading script...