[BASIC #6] 컨테이너 간 통신: Docker Network 이해하기

2025. 6. 1. 11:44·Docker

0. 들어가며

지금까지 우리는 단일 컨테이너를 실행하고, 데이터를 영구적으로 저장하는 방법까지 배웠다. 하지만 실제 애플리케이션은 대부분 여러 컨테이너로 구성된다.

  • 웹 서버 컨테이너 (Nginx)
  • 애플리케이션 서버 컨테이너 (Spring Boot, Node.js)
  • 데이터베이스 컨테이너 (MySQL, PostgreSQL)

이렇게 여러 컨테이너가 함께 동작하려면 컨테이너 간 통신이 필요하다. 이번 포스팅에서는 컨테이너들이 서로 통신할 수 있게 해주는 Docker Network에 대해 알아보겠다.


 

1. Docker Network의 필요성

1.1. 컨테이너의 격리와 통신

도커 컨테이너는 기본적으로 격리된 환경에서 실행된다. 각 컨테이너는 자신만의 네트워크 네임스페이스를 가지며, 기본적으로는 다른 컨테이너와 격리되어 있다.

[Container A]   [Container B]   [Container C]
    |                |               |
    +----------------+---------------+
                    |
              [Docker Network]
                    |
              [Host Machine]

하지만 애플리케이션을 구성하려면 이 격리된 컨테이너들이 선택적으로 통신할 수 있어야 한다. 예를 들어:

  • 웹 서버는 애플리케이션 서버와 통신해야 한다.
  • 애플리케이션 서버는 데이터베이스와 통신해야 한다.
  • 하지만 데이터베이스는 외부에서 직접 접근할 수 없어야 한다.

이러한 요구사항을 충족시키기 위해 도커는 네트워크 기능을 제공한다.

1.2. 실생활 비유: 아파트 단지

  • 각 컨테이너는 아파트 호수다.
  • Docker Network는 아파트 단지 내부 도로다.
  • 같은 단지(같은 네트워크)에 있는 호수들은 서로 방문할 수 있다.
  • 다른 단지(다른 네트워크)에 있는 호수들은 기본적으로 왕래할 수 없다.
  • 외부 인터넷은 단지 정문을 통해서만 출입할 수 있다.

2. Docker Network의 구조

2.1. 네트워크 구성 요소

                    [외부 인터넷]
                         |
                    [eth0 (호스트)]
                         |
                    [docker0 브리지]
                    /      |      \\
              [veth0]  [veth1]  [veth2]
                  |        |        |
              [C1]       [C2]     [C3]
  • eth0: 호스트 머신의 실제 네트워크 인터페이스. 외부 인터넷과 연결된다.
  • docker0: 도커가 설치될 때 기본으로 생성되는 가상의 브리지 네트워크. 모든 컨테이너를 연결하는 가상의 스위치 역할을 한다.
  • veth (Virtual Ethernet): 각 컨테이너가 생성될 때 컨테이너와 docker0 브리지를 연결하는 가상의 케이블 쌍이다. 한쪽 끝은 컨테이너에, 다른 쪽 끝은 docker0 브리지에 연결된다.

2.2. 컨테이너의 IP 할당

기본적으로 각 컨테이너는 172.17.0.0/16 대역의 IP를 할당받는다.

# 컨테이너의 IP 확인
docker inspect <컨테이너명> | grep IPAddress

실행 결과:

"IPAddress": "172.17.0.2",

 

3. 네트워크 드라이버 종류

도커는 다양한 네트워크 드라이버를 제공한다. 각각 다른 특성과 용도를 가지고 있다.

3.1. bridge (기본값)

가장 기본적인 네트워크 드라이버다. 같은 호스트 내의 컨테이너들이 통신할 수 있도록 해준다.

# 기본 bridge 네트워크 확인
docker network ls

NETWORK ID     NAME      DRIVER    SCOPE
a1b2c3d4e5f6   bridge    bridge    local

특징:

  • 같은 bridge 네트워크에 연결된 컨테이너끼리 통신 가능
  • 외부에서는 포트 매핑(p)을 통해서만 접근 가능
  • 기본 bridge는 DNS 기반 컨테이너 이름 해석을 지원하지 않음 (사용자 정의 bridge는 지원)

3.2. host

컨테이너가 호스트의 네트워크를 직접 사용한다.

docker run -d --network host --name nginx-host nginx

특징:

  • 컨테이너가 별도의 IP를 할당받지 않고 호스트의 IP를 공유
  • 포트 매핑(p) 불필요 (호스트의 포트를 그대로 사용)
  • 네트워크 성능이 중요한 경우 사용
  • 격리 수준이 낮아짐 (포트 충돌 위험)

3.3. none

컨테이너를 네트워크에서 완전히 격리한다.

docker run -d --network none --name isolated ubuntu sleep infinity

특징:

  • 네트워크 인터페이스가 없음
  • 외부와 완전히 차단된 환경이 필요할 때 사용 (보안, 테스트)

3.4. container

다른 컨테이너의 네트워크 네임스페이스를 공유한다.

# 네트워크를 공유할 컨테이너 실행
docker run -d --name shared-network nginx

# 다른 컨테이너가 위 컨테이너의 네트워크를 공유
docker run -it --network container:shared-network ubuntu bash

특징:

  • 두 컨테이너가 같은 IP, 같은 포트 공간을 공유
  • localhost로 서로 통신 가능
  • 주로 사이드카 패턴에서 사용

3.5. overlay (Swarm 모드)

여러 도커 호스트를 하나의 네트워크로 연결한다. (도커 스웜 모드에서 사용)

# Swarm 모드 초기화 후
docker network create -d overlay my-overlay

특징:

  • 여러 물리적 서버에 걸친 컨테이너 간 통신 지원
  • 클러스터 환경에서 사용

 

4. 사용자 정의 네트워크 생성 및 활용

기본 bridge 네트워크도 사용할 수 있지만, 사용자 정의 네트워크를 만드는 것이 여러모로 편리하다.

4.1. 사용자 정의 네트워크의 장점

  1. 자동 DNS 해석: 컨테이너 이름으로 통신 가능
  2. 격리: 다른 네트워크와 분리되어 보안성 향상
  3. 유연성: 네트워크별로 다른 설정 적용 가능

4.2. 네트워크 생성 및 관리

# bridge 타입의 네트워크 생성
docker network create --driver bridge my-network

# 특정 서브넷을 지정하여 생성
docker network create \\
  --driver bridge \\
  --subnet 172.20.0.0/16 \\
  --gateway 172.20.0.1 \\
  my-custom-network

# 네트워크 목록 확인
docker network ls

# 네트워크 상세 정보 확인
docker network inspect my-network

# 네트워크 삭제
docker network rm my-network

# 사용하지 않는 네트워크 모두 삭제
docker network prune

4.3. 컨테이너를 네트워크에 연결

방법 1: 실행 시 연결

# 생성한 네트워크에 연결하여 컨테이너 실행
docker run -d --name app1 --network my-network nginx
docker run -d --name app2 --network my-network ubuntu sleep infinity

방법 2: 실행 중인 컨테이너를 네트워크에 연결

# 먼저 기본 네트워크로 실행
docker run -d --name app3 nginx

# 실행 중인 컨테이너를 네트워크에 추가 연결
docker network connect my-network app3

# 네트워크에서 컨테이너 분리
docker network disconnect my-network app3

5. 실습: 컨테이너 간 통신

5.1. 기본 네트워크에서의 통신

# 두 개의 Ubuntu 컨테이너 실행 (기본 bridge)
docker run -d --name u1 ubuntu sleep infinity
docker run -d --name u2 ubuntu sleep infinity

# u2에서 u1으로 ping 시도
docker exec u2 ping u1
# -> ping: u1: Name or service not known

기본 bridge 네트워크에서는 컨테이너 이름으로 통신할 수 없다. IP 주소를 직접 알아내야 한다.

# u1의 IP 확인
docker inspect u1 | grep IPAddress
# "IPAddress": "172.17.0.2"

# IP로 ping 시도
docker exec u2 ping 172.17.0.2
# -> 성공!

5.2. 사용자 정의 네트워크에서의 통신

# 사용자 정의 네트워크 생성
docker network create test-network

# 같은 네트워크에 컨테이너 실행
docker run -d --name u3 --network test-network ubuntu sleep infinity
docker run -d --name u4 --network test-network ubuntu sleep infinity

# u4에서 u3으로 ping 시도 (컨테이너 이름으로!)
docker exec u4 ping u3
# -> 성공! (ping 응답 확인)

사용자 정의 네트워크에서는 내장 DNS 서버가 컨테이너 이름을 IP 주소로 자동 변환해준다.

5.3. 여러 네트워크에 동시 연결

# 두 번째 네트워크 생성
docker network create second-network

# u3 컨테이너를 second-network에도 연결
docker network connect second-network u3

# u3의 네트워크 정보 확인
docker inspect u3 | grep -A 10 "Networks"

이제 u3는 두 개의 네트워크에 동시에 연결되어 있다.


 

6. 실전: 3-Tier 애플리케이션 네트워크 구성

6.1. 시나리오

다음과 같은 3계층 애플리케이션을 구성해보자.

  • Web Tier: Nginx (외부에 노출)
  • App Tier: Node.js 애플리케이션 (Web에서만 접근 가능)
  • DB Tier: MySQL (App에서만 접근 가능, 외부 차단)

6.2. 네트워크 설계

# 두 개의 네트워크 생성
docker network create frontend-network
docker network create backend-network

네트워크 구조:

[외부 인터넷]
     |
[Web Container]  (frontend-network + backend-network)
     |                |
[App Container] (backend-network + db-network)
                     |
[DB Container]   (db-network)

6.3. 컨테이너 실행

DB Tier (MySQL)

# DB 볼륨 생성
docker volume create mysql-data

# DB 컨테이너 실행 (backend-network만 연결)
docker run -d \\
  --name mysql-db \\
  --network backend-network \\
  -v mysql-data:/var/lib/mysql \\
  -e MYSQL_ROOT_PASSWORD=root \\
  -e MYSQL_DATABASE=myapp \\
  mysql:8.0

App Tier (Node.js)

먼저 간단한 Node.js 앱을 만들어보자.

// app.js
const express = require('express');
const mysql = require('mysql2');
const app = express();

const connection = mysql.createConnection({
  host: 'mysql-db',  // 컨테이너 이름으로 접근!
  user: 'root',
  password: 'root',
  database: 'myapp'
});

app.get('/', (req, res) => {
  res.send('Hello from App Tier!');
});

app.get('/db', (req, res) => {
  connection.query('SELECT NOW()', (err, results) => {
    if (err) {
      res.send('DB connection failed: ' + err);
    } else {
      res.send('DB connected! Time: ' + results[0].NOW);
    }
  });
});

app.listen(3000);

 

# Dockerfile
FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["node", "app.js"]

 

# App 이미지 빌드
docker build -t myapp:latest .

# App 컨테이너 실행 (frontend + backend 네트워크 모두 연결)
docker run -d \\
  --name app-server \\
  --network frontend-network \\
  -p 3000:3000 \\
  myapp:latest

# backend-network에도 연결
docker network connect backend-network app-server

Web Tier (Nginx)

# Nginx 설정 파일 생성
cat > nginx.conf << 'EOF'
events {
    worker_connections 1024;
}

http {
    upstream app {
        server app-server:3000;
    }

    server {
        listen 80;

        location / {
            proxy_pass <http://app>;
            proxy_set_header Host $host;
        }
    }
}
EOF

# Nginx 컨테이너 실행 (frontend-network만 연결)
docker run -d \\
  --name web-server \\
  --network frontend-network \\
  -p 80:80 \\
  -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \\
  nginx

6.4. 테스트

  1. 브라우저에서 http://localhost 접속 → "Hello from App Tier!" 확인
  2. http://localhost/db 접속 → DB 연결 시간 확인

DB 컨테이너는 frontend-network에 연결되어 있지 않으므로, 외부에서는 직접 접근할 수 없다. App 서버를 통해서만 접근 가능하다.


 

7. 네트워크 트러블슈팅

7.1. 자주 사용하는 디버깅 명령어

# 컨테이너의 네트워크 설정 확인
docker inspect <컨테이너명> | grep -A 20 "Networks"

# 컨테이너 내부에서 네트워크 도구 설치
docker exec -it <컨테이너명> apt-get update
docker exec -it <컨테이너명> apt-get install -y iputils-ping curl net-tools

# ping 테스트
docker exec app-server ping mysql-db

# 포트 열림 확인
docker exec app-server curl mysql-db:3306

# DNS 확인
docker exec app-server cat /etc/resolv.conf

7.2. 네트워크 격리 확인

# web-server에서 DB로 직접 접근 시도 (실패해야 정상)
docker exec web-server ping mysql-db
# -> ping: mysql-db: Name or service not known

# app-server에서 DB로 접근 (성공)
docker exec app-server ping mysql-db
# -> 성공!

7.3. 포트 충돌 해결

# 어떤 프로세스가 포트를 사용 중인지 확인
sudo netstat -tulpn | grep 8080

# 실행 중인 컨테이너 중지
docker stop <컨테이너명>

 

8. 네트워크 명령어 요약

명령어  설명
docker network ls 네트워크 목록 확인
docker network create [이름] 새 네트워크 생성
docker network inspect [이름] 네트워크 상세 정보
docker network connect [네트워크] [컨테이너] 컨테이너를 네트워크에 연결
docker network disconnect [네트워크] [컨테이너] 컨테이너를 네트워크에서 분리
docker network rm [이름] 네트워크 삭제
docker network prune 사용하지 않는 네트워크 모두 삭제

 

9. 마치며

이번 포스팅에서는 컨테이너 간 통신을 가능하게 하는 Docker Network에 대해 알아보았다.

  • 도커는 다양한 네트워크 드라이버(bridge, host, none, container, overlay)를 제공한다.
  • 기본 bridge 네트워크는 컨테이너 이름으로 통신할 수 없다.
  • 사용자 정의 네트워크에서는 자동 DNS 해석으로 컨테이너 이름으로 통신 가능하다.
  • 하나의 컨테이너를 여러 네트워크에 연결할 수 있다.
  • 네트워크를 분리하면 보안성을 높일 수 있다.

다음 포스팅에서는 여러 컨테이너로 구성된 애플리케이션을 한 번에 관리하는 방법, 즉 Docker Compose에 대해 알아보겠다.

'Docker' 카테고리의 다른 글

[ADVANCED #2] 도커 이미지 배포와 공유: Docker Hub 활용법  (0) 2025.06.01
[ADVANCED #1] 여러 컨테이너 한 번에 관리하기: Docker Compose  (0) 2025.06.01
[BASIC #5] 데이터를 영구적으로 저장하는 법: Docker Volume  (0) 2025.05.31
[BASIC #4] 나만의 이미지 만들기: Dockerfile 완전 정복  (0) 2025.05.31
[BASIC #3] 밀키트 비유로 완벽 이해하는 도커 이미지와 컨테이너  (0) 2025.05.31
'Docker' 카테고리의 다른 글
  • [ADVANCED #2] 도커 이미지 배포와 공유: Docker Hub 활용법
  • [ADVANCED #1] 여러 컨테이너 한 번에 관리하기: Docker Compose
  • [BASIC #5] 데이터를 영구적으로 저장하는 법: Docker Volume
  • [BASIC #4] 나만의 이미지 만들기: Dockerfile 완전 정복
h6bro
h6bro
백엔드 개발자의 기술 블로그
  • h6bro
    Jun's Tech Blog
    h6bro
  • 전체
    오늘
    어제
    • 분류 전체보기 (241) N
      • Java (18)
        • Core (9)
        • Design Pattern (9)
      • Spring (80)
        • Core (24)
        • MVC (6)
        • DB (10)
        • JPA (26)
        • Monitoring (3)
        • Security (11)
        • WebSocket (0)
      • Database (33)
        • Redis (15)
        • MySQL (18)
      • MSA (16)
        • MSA 기본 (11)
        • MSA 아키텍처 (5)
      • Kafka (30) N
        • Core (18) N
        • Connect (12)
      • ElasticSearch (11)
        • Search (11)
        • Logging (0)
      • Test (4)
        • k6 (4)
      • Docker (9)
      • CI&CD (10)
        • GitHub Actions (6)
        • ArgoCD (4)
      • Kubernetes (18)
        • Core (12)
        • Ops (6)
      • Cloud Engineering (4)
        • AWS Infrastructure (3)
        • AWS EKS (1)
        • Terraform (0)
      • Project (8)
        • LinkFolio (1)
        • Secondhand Market (7)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • Cloud Engineering 포스팅 정리
  • 인기 글

  • 태그

    ㅈ
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
h6bro
[BASIC #6] 컨테이너 간 통신: Docker Network 이해하기
상단으로

티스토리툴바