Docker & Kubernetes 완전 정복 5편: Docker 네트워크와 볼륨
Docker & Kubernetes Complete Guide Part 5: Docker Network and Volume
서론: 컨테이너 간 통신과 데이터 관리의 핵심
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가 왜 필요한지, 그 아키텍처는 어떻게 구성되어 있는지, 핵심 오브젝트들은 무엇인지 알아보겠습니다.