서론: 컨테이너 간 통신과 데이터 관리의 핵심

Docker를 활용한 애플리케이션 배포에서 가장 중요한 두 가지 주제가 바로 네트워크볼륨입니다. 여러 컨테이너로 구성된 마이크로서비스 아키텍처에서 컨테이너 간 통신은 필수적이며, 컨테이너가 삭제되어도 데이터가 유지되어야 하는 상황은 매우 흔합니다.

이번 5편에서는 Docker의 네트워크 모델과 볼륨 시스템을 심층적으로 다루며, 실제 운영 환경에서 활용할 수 있는 실용적인 예제들을 함께 살펴보겠습니다.

1. Docker 네트워크 개요

1.1 Docker 네트워크의 필요성

컨테이너는 기본적으로 격리된 환경에서 실행됩니다. 하지만 실제 애플리케이션에서는 웹 서버가 데이터베이스와 통신하고, API 게이트웨이가 여러 마이크로서비스와 연결되어야 합니다. Docker 네트워크는 이러한 컨테이너 간 통신을 안전하고 효율적으로 관리할 수 있게 해줍니다.

1.2 네트워크 관련 기본 명령어

# 네트워크 목록 조회
docker network ls

# 네트워크 상세 정보 확인
docker network inspect [네트워크명]

# 네트워크 생성
docker network create [네트워크명]

# 네트워크 삭제
docker network rm [네트워크명]

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

2. Docker 네트워크 종류

2.1 Bridge 네트워크 (기본값)

Bridge 네트워크는 Docker의 기본 네트워크 드라이버로, 같은 호스트 내에서 컨테이너들이 통신할 수 있게 해줍니다. Docker를 설치하면 자동으로 docker0라는 브릿지 네트워크가 생성됩니다.

# 기본 bridge 네트워크로 컨테이너 실행
docker run -d --name web1 nginx

# 기본 bridge 네트워크 정보 확인
docker network inspect bridge

특징:

  • 동일 호스트의 컨테이너 간 통신 지원
  • 호스트와 컨테이너 간 NAT(Network Address Translation) 사용
  • 포트 매핑(-p 옵션)으로 외부 접근 허용
  • 기본 bridge에서는 컨테이너 이름으로 통신 불가 (IP만 가능)

2.2 Host 네트워크

Host 네트워크는 컨테이너가 호스트의 네트워크 스택을 직접 사용합니다. 네트워크 격리가 없으므로 성능은 좋지만 보안상 주의가 필요합니다.

# host 네트워크로 컨테이너 실행
docker run -d --network host --name web-host nginx

# 별도 포트 매핑 없이 호스트의 80번 포트에서 직접 접근 가능

특징:

  • 호스트와 동일한 네트워크 환경 사용
  • NAT 오버헤드 없어 네트워크 성능 우수
  • 포트 매핑 필요 없음 (호스트 포트 직접 사용)
  • Linux에서만 완전 지원 (macOS, Windows는 제한적)

2.3 None 네트워크

None 네트워크는 컨테이너의 네트워크를 완전히 비활성화합니다. 네트워크가 전혀 필요 없는 배치 작업이나 보안이 중요한 환경에서 사용합니다.

# none 네트워크로 컨테이너 실행
docker run -d --network none --name isolated alpine sleep 3600

# 네트워크 인터페이스 확인 (lo만 존재)
docker exec isolated ip addr

특징:

  • 네트워크 인터페이스 없음 (loopback만 존재)
  • 외부 통신 완전 차단
  • 최고 수준의 네트워크 격리

2.4 Overlay 네트워크

Overlay 네트워크는 여러 Docker 호스트에 걸쳐 컨테이너 간 통신을 가능하게 합니다. Docker Swarm이나 Kubernetes와 같은 클러스터 환경에서 필수적입니다.

# Swarm 모드 활성화 필요
docker swarm init

# overlay 네트워크 생성
docker network create -d overlay my-overlay-network

# overlay 네트워크에서 서비스 생성
docker service create --name web --network my-overlay-network nginx

특징:

  • 다중 호스트 간 컨테이너 통신 지원
  • VXLAN 기술을 사용한 가상 네트워크
  • Swarm 모드에서 자동 서비스 디스커버리
  • 내장된 로드 밸런싱 기능

3. 사용자 정의 네트워크

3.1 사용자 정의 Bridge 네트워크

기본 bridge 네트워크 대신 사용자 정의 bridge 네트워크를 사용하면 여러 이점이 있습니다.

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

# 특정 서브넷과 게이트웨이 지정
docker network create \
    --driver bridge \
    --subnet 172.20.0.0/16 \
    --gateway 172.20.0.1 \
    my-custom-network

# 네트워크에 컨테이너 연결
docker run -d --name db --network my-app-network mysql:8.0
docker run -d --name web --network my-app-network nginx

사용자 정의 네트워크의 장점:

  • 자동 DNS 해석: 컨테이너 이름으로 통신 가능
  • 더 나은 격리: 다른 네트워크의 컨테이너와 자동 격리
  • 동적 연결: 실행 중인 컨테이너를 네트워크에 연결/분리 가능
  • 설정 가능: 서브넷, 게이트웨이, IP 범위 등 커스터마이징

3.2 컨테이너 이름으로 통신하기

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

# MySQL 컨테이너 실행
docker run -d \
    --name mysql-db \
    --network app-net \
    -e MYSQL_ROOT_PASSWORD=secret \
    mysql:8.0

# 웹 애플리케이션에서 mysql-db라는 이름으로 접근 가능
docker run -d \
    --name webapp \
    --network app-net \
    -e DB_HOST=mysql-db \
    my-webapp:latest

4. 컨테이너 간 통신

4.1 동일 네트워크 내 통신

# 네트워크 생성
docker network create backend

# 두 컨테이너를 같은 네트워크에 연결
docker run -d --name server1 --network backend alpine sleep 3600
docker run -d --name server2 --network backend alpine sleep 3600

# server1에서 server2로 ping 테스트
docker exec server1 ping -c 3 server2

4.2 여러 네트워크에 연결

하나의 컨테이너를 여러 네트워크에 연결할 수 있습니다. 이는 프록시나 게이트웨이 역할을 하는 컨테이너에 유용합니다.

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

# 데이터베이스는 backend에만 연결
docker run -d --name db --network backend mysql:8.0

# 웹 서버는 frontend에 연결
docker run -d --name web --network frontend nginx

# API 서버는 양쪽 네트워크에 연결
docker run -d --name api --network frontend node:18
docker network connect backend api

4.3 네트워크 연결 및 해제

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

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

# 특정 IP 주소로 연결
docker network connect --ip 172.20.0.100 my-network container-name

5. DNS와 서비스 디스커버리

5.1 내장 DNS 서버

Docker는 사용자 정의 네트워크에서 내장 DNS 서버(127.0.0.11)를 제공합니다. 이를 통해 컨테이너 이름이나 네트워크 별칭으로 다른 컨테이너를 찾을 수 있습니다.

# DNS 설정 확인
docker exec webapp cat /etc/resolv.conf
# nameserver 127.0.0.11
# options ndots:0

5.2 네트워크 별칭 (Alias)

# 네트워크 별칭 설정
docker run -d \
    --name mysql-primary \
    --network app-net \
    --network-alias db \
    --network-alias database \
    mysql:8.0

# db 또는 database라는 이름으로도 접근 가능
docker run --rm --network app-net alpine ping -c 2 db

5.3 라운드 로빈 DNS

같은 네트워크 별칭을 가진 여러 컨테이너가 있으면 Docker DNS는 라운드 로빈 방식으로 IP를 반환합니다.

# 같은 별칭으로 여러 웹 서버 실행
docker run -d --name web1 --network app-net --network-alias webserver nginx
docker run -d --name web2 --network app-net --network-alias webserver nginx
docker run -d --name web3 --network app-net --network-alias webserver nginx

# webserver로 요청하면 세 컨테이너 중 하나로 연결됨
docker run --rm --network app-net alpine nslookup webserver

6. 데이터 영속성의 중요성

6.1 컨테이너의 휘발성

컨테이너는 본질적으로 휘발적(ephemeral)입니다. 컨테이너가 삭제되면 컨테이너 내부에 저장된 모든 데이터도 함께 사라집니다. 이는 데이터베이스, 사용자 업로드 파일, 설정 파일 등 중요한 데이터를 다룰 때 심각한 문제가 됩니다.

# 컨테이너 내부에 파일 생성
docker run -d --name temp-container alpine sh -c "echo 'important data' > /data.txt && sleep 3600"
docker exec temp-container cat /data.txt  # important data

# 컨테이너 삭제
docker rm -f temp-container

# 새 컨테이너에서는 데이터가 없음
docker run --rm alpine cat /data.txt  # 에러: 파일 없음

6.2 데이터 영속성이 필요한 경우

  • 데이터베이스: MySQL, PostgreSQL, MongoDB 등의 데이터 파일
  • 사용자 업로드: 이미지, 문서 등 사용자가 업로드한 파일
  • 로그 파일: 애플리케이션 로그, 접근 로그
  • 설정 파일: 애플리케이션 설정, 인증서
  • 세션 데이터: 캐시, 세션 저장소

7. Docker 볼륨 종류

7.1 Volumes (관리형 볼륨)

Docker가 관리하는 볼륨으로, 가장 권장되는 방식입니다. 볼륨은 Docker의 저장 영역(/var/lib/docker/volumes/)에 생성됩니다.

# 볼륨 생성
docker volume create my-data

# 볼륨 목록 조회
docker volume ls

# 볼륨 상세 정보
docker volume inspect my-data

# 볼륨을 사용하여 컨테이너 실행
docker run -d \
    --name db \
    -v my-data:/var/lib/mysql \
    mysql:8.0

# 또는 --mount 플래그 사용 (더 명시적)
docker run -d \
    --name db \
    --mount source=my-data,target=/var/lib/mysql \
    mysql:8.0

Volumes의 장점:

  • Docker CLI로 쉽게 관리 (백업, 마이그레이션)
  • Linux와 Windows 컨테이너 모두에서 작동
  • 여러 컨테이너 간 안전하게 공유 가능
  • 볼륨 드라이버를 통한 원격 저장소, 암호화 지원
  • 호스트의 파일 시스템 구조에 독립적

7.2 Bind Mounts

호스트의 특정 경로를 컨테이너에 마운트합니다. 개발 환경에서 소스 코드를 컨테이너에 실시간으로 반영할 때 유용합니다.

# 호스트 디렉토리를 컨테이너에 마운트
docker run -d \
    --name web \
    -v /home/user/website:/usr/share/nginx/html \
    nginx

# --mount 플래그 사용 (더 명시적)
docker run -d \
    --name web \
    --mount type=bind,source=/home/user/website,target=/usr/share/nginx/html \
    nginx

# 읽기 전용으로 마운트
docker run -d \
    --name web \
    -v /home/user/website:/usr/share/nginx/html:ro \
    nginx

Bind Mounts의 특징:

  • 호스트의 정확한 경로 지정 필요
  • 호스트 파일 시스템에 직접 접근
  • 개발 환경에서 소스 코드 실시간 반영에 적합
  • 호스트 디렉토리가 없으면 자동 생성 (주의 필요)

7.3 tmpfs Mounts

tmpfs는 호스트의 메모리에 데이터를 저장합니다. 민감한 정보를 일시적으로 저장하거나 고성능이 필요할 때 사용합니다.

# tmpfs 마운트 사용
docker run -d \
    --name cache \
    --tmpfs /app/cache \
    my-app:latest

# --mount 플래그 사용
docker run -d \
    --name secure-app \
    --mount type=tmpfs,destination=/run/secrets,tmpfs-size=64m \
    my-app:latest

tmpfs의 특징:

  • 메모리에만 저장되어 매우 빠름
  • 컨테이너 종료 시 데이터 자동 삭제
  • 민감한 데이터(비밀번호, API 키) 임시 저장에 적합
  • Linux에서만 지원

8. 볼륨 생성과 관리

8.1 볼륨 생성 및 조회

# 기본 볼륨 생성
docker volume create app-data

# 라벨을 포함한 볼륨 생성
docker volume create \
    --label project=myapp \
    --label env=production \
    myapp-data

# 모든 볼륨 조회
docker volume ls

# 라벨로 필터링
docker volume ls --filter label=project=myapp

# 특정 볼륨 상세 정보
docker volume inspect app-data

8.2 볼륨 삭제

# 특정 볼륨 삭제 (사용 중이 아닌 경우만)
docker volume rm app-data

# 사용하지 않는 모든 볼륨 삭제
docker volume prune

# 필터와 함께 삭제
docker volume prune --filter label=env=development

8.3 볼륨 공유

# 볼륨 생성
docker volume create shared-data

# 여러 컨테이너에서 동일 볼륨 사용
docker run -d --name writer -v shared-data:/data alpine sh -c "while true; do date >> /data/log.txt; sleep 5; done"
docker run -d --name reader -v shared-data:/data:ro alpine tail -f /data/log.txt

9. 볼륨 드라이버

9.1 로컬 드라이버 옵션

# NFS 볼륨 생성
docker volume create \
    --driver local \
    --opt type=nfs \
    --opt o=addr=192.168.1.100,rw \
    --opt device=:/path/to/share \
    nfs-volume

# 특정 파일시스템 타입으로 볼륨 생성
docker volume create \
    --driver local \
    --opt type=ext4 \
    --opt device=/dev/sdb1 \
    ext4-volume

9.2 서드파티 볼륨 드라이버

다양한 서드파티 볼륨 드라이버를 사용하여 클라우드 스토리지나 분산 파일 시스템을 활용할 수 있습니다.

  • Amazon EBS: AWS의 Elastic Block Store
  • Azure File Storage: Microsoft Azure의 파일 스토리지
  • GlusterFS: 분산 파일 시스템
  • Portworx: 엔터프라이즈 컨테이너 스토리지
  • REX-Ray: 다양한 스토리지 플랫폼 지원

10. 데이터 백업과 복원

10.1 볼륨 백업

# 임시 컨테이너를 사용한 볼륨 백업
docker run --rm \
    -v my-data:/source:ro \
    -v $(pwd):/backup \
    alpine tar cvf /backup/my-data-backup.tar -C /source .

# 압축 백업
docker run --rm \
    -v my-data:/source:ro \
    -v $(pwd):/backup \
    alpine tar czvf /backup/my-data-backup.tar.gz -C /source .

10.2 볼륨 복원

# 새 볼륨 생성
docker volume create my-data-restored

# 백업에서 복원
docker run --rm \
    -v my-data-restored:/target \
    -v $(pwd):/backup \
    alpine tar xvf /backup/my-data-backup.tar -C /target

10.3 컨테이너 간 볼륨 복제

# 원본 볼륨에서 대상 볼륨으로 복제
docker run --rm \
    -v source-volume:/source:ro \
    -v target-volume:/target \
    alpine cp -av /source/. /target/

10.4 데이터베이스 백업 예제

# MySQL 데이터베이스 백업
docker exec mysql-container mysqldump -u root -p'password' --all-databases > backup.sql

# PostgreSQL 데이터베이스 백업
docker exec postgres-container pg_dumpall -U postgres > backup.sql

# MongoDB 데이터베이스 백업
docker exec mongo-container mongodump --archive --gzip > backup.gz

11. 실전 예제: 웹 애플리케이션 스택

11.1 네트워크와 볼륨을 활용한 완전한 스택

# 네트워크 생성
docker network create webapp-network

# 볼륨 생성
docker volume create mysql-data
docker volume create webapp-uploads

# MySQL 데이터베이스
docker run -d \
    --name mysql \
    --network webapp-network \
    -v mysql-data:/var/lib/mysql \
    -e MYSQL_ROOT_PASSWORD=rootpass \
    -e MYSQL_DATABASE=webapp \
    -e MYSQL_USER=appuser \
    -e MYSQL_PASSWORD=apppass \
    mysql:8.0

# 웹 애플리케이션
docker run -d \
    --name webapp \
    --network webapp-network \
    -v webapp-uploads:/app/uploads \
    -e DB_HOST=mysql \
    -e DB_USER=appuser \
    -e DB_PASSWORD=apppass \
    -e DB_NAME=webapp \
    -p 3000:3000 \
    my-webapp:latest

# Nginx 리버스 프록시
docker run -d \
    --name nginx \
    --network webapp-network \
    -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \
    -p 80:80 \
    nginx:alpine

11.2 Docker Compose로 관리

# docker-compose.yml
version: '3.8'

services:
  mysql:
    image: mysql:8.0
    networks:
      - webapp-network
    volumes:
      - mysql-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: webapp
      MYSQL_USER: appuser
      MYSQL_PASSWORD: apppass

  webapp:
    image: my-webapp:latest
    networks:
      - webapp-network
    volumes:
      - webapp-uploads:/app/uploads
    environment:
      DB_HOST: mysql
      DB_USER: appuser
      DB_PASSWORD: apppass
      DB_NAME: webapp
    depends_on:
      - mysql

  nginx:
    image: nginx:alpine
    networks:
      - webapp-network
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    ports:
      - "80:80"
    depends_on:
      - webapp

networks:
  webapp-network:
    driver: bridge

volumes:
  mysql-data:
  webapp-uploads:

12. 네트워크 및 볼륨 모범 사례

12.1 네트워크 모범 사례

  • 사용자 정의 네트워크 사용: 기본 bridge 대신 사용자 정의 네트워크를 사용하여 DNS 해석과 격리 이점 활용
  • 필요한 포트만 노출: -p 옵션으로 외부에 노출할 포트를 최소화
  • 서비스별 네트워크 분리: 프론트엔드, 백엔드, 데이터베이스 등을 별도 네트워크로 분리
  • 네트워크 별칭 활용: 유연한 서비스 디스커버리를 위해 별칭 사용

12.2 볼륨 모범 사례

  • named 볼륨 사용: 익명 볼륨 대신 명명된 볼륨을 사용하여 관리 용이성 확보
  • 개발 시 bind mount, 프로덕션에서 volume 사용: 환경에 맞는 마운트 방식 선택
  • 정기적인 백업: 중요한 데이터는 반드시 정기적으로 백업
  • 읽기 전용 마운트: 설정 파일 등 변경이 필요 없는 데이터는 :ro 옵션 사용
  • 사용하지 않는 볼륨 정리: docker volume prune으로 주기적으로 정리

결론

Docker 네트워크와 볼륨은 컨테이너 기반 애플리케이션의 핵심 구성 요소입니다. 적절한 네트워크 구성으로 컨테이너 간 안전하고 효율적인 통신을 보장하고, 올바른 볼륨 전략으로 데이터의 영속성과 안전성을 확보할 수 있습니다.

이번 편에서 배운 내용을 요약하면:

  • Docker 네트워크 종류(bridge, host, none, overlay)와 각각의 용도
  • 사용자 정의 네트워크의 장점과 DNS 기반 서비스 디스커버리
  • 볼륨, bind mount, tmpfs의 차이점과 적절한 사용 시나리오
  • 데이터 백업과 복원 전략

다음 6편에서는 드디어 Kubernetes의 기초를 다룹니다. Kubernetes가 왜 필요한지, 그 아키텍처는 어떻게 구성되어 있는지, 핵심 오브젝트들은 무엇인지 알아보겠습니다.