
도커는 사용해본 사람 대비 "이게 왜 되지?" 싶은 기술 1위라 생각합니다. 저 또한 아직도 이게 왜 되는지 모르겠는데요? 그래도 한번 이해하기 위해 노력해보겠습니다.
우선 Docker를 이해하려면 이미지(Image)와 컨테이너(Container) 그리고 네트워크 개념을 제대로 아는 것이 중요합니다. 그러니 오늘은 이 세 주제에 대해 다뤄보겠습니다.
Docker 이미지는 컨테이너 실행을 위한 모든 요소를 포함한 불변(immutable) 패키지입니다.
운영체제, 애플리케이션 코드, 라이브러리, 실행 파일, 환경 설정 등이 포함되어 있으며, 이를 기반으로 컨테이너가 실행됩니다.

Docker 이미지는 여러 개의 레이어(layer)로 구성됩니다. Docker는 UnionFS (Union File System)를 활용하여 여러 레이어를 겹쳐 하나의 이미지처럼 동작합니다.
Docker는 이러한 레이어를 활용하여 변경된 레이어만 다시 빌드하기 때문에 빠른 빌드 및 배포가 가능합니다. 각 레이어는 읽기 전용(Read-Only)이며, 컨테이너 실행 시 쓰기 가능한(Read-Write) 컨테이너 레이어가 추가됩니다.
➡️ 즉, 도커는 이미지의 레이어를 캐싱해서 빌드 및 배포를 최적화합니다.
Docker는 이미지 빌드 시 캐싱을 적극적으로 활용하여 속도를 최적화합니다.
Dockerfile의 명령어 순서를 기반으로 레이어별 캐시를 재사용.Dockerfile 명령어 순서가 중요한 이유예제)
아래와 같은 Dockerfile이 있다고 가정해봅시다.
FROM python:3.9
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]
FROM python:3.9: 기본 이미지 레이어 (캐싱 가능)WORKDIR /app: 작업 디렉토리 설정 (캐싱 가능)COPY requirements.txt .: 파일 변경 시 새로 빌드RUN pip install -r requirements.txt: 캐시 활용 가능 (파일이 변경되지 않으면 다시 실행되지 않음)COPY . .: 소스 코드 변경 시 항상 다시 실행됨이런 구조에서 requirements.txt가 변경되지 않는다면, pip install 단계는 캐시를 활용하여 다시 실행되지 않습니다. 하지만 COPY . .를 먼저 실행하면, 모든 파일이 변경된 것으로 인식되어 캐싱이 무효화됩니다.
컨테이너는 이미지를 기반으로 실행되는 독립적인 애플리케이션 환경입니다. 가상머신(VM)과 달리 호스트 운영체제(OS)의 커널을 공유하며, 리소스를 효율적으로 관리할 수 있습니다.
컨테이너는 실행 중인 애플리케이션을 감싸는 경량 프로세스로, 필요한 경우 격리된 환경에서 독립적으로 실행 가능합니다.
docker run -d --name my_container(컨테이너 이름) ubuntu:latest(이미지)
리눅스 기반으로 가볍고 효율적인 가상화 환경을 제공하기 위해 컨테이너는 네임스페이스, Cgroups 등을 활용합니다.
네임스페이스 : 컨테이너가 독립적인 환경을 가지도록 하는 Linux 커널 기능
PID (프로세스 네임스페이스): 각 컨테이너에서 별도의 프로세스 ID 공간을 사용
NET (네트워크 네임스페이스): 컨테이너별로 독립적인 네트워크 인터페이스 제공
MNT (마운트 네임스페이스): 컨테이너마다 파일 시스템을 격리하여 사용 가능
UTS (호스트 및 도메인 네임스페이스): 컨테이너에서 별도의 호스트명을 설정 가능
IPC (인터프로세스 통신 네임스페이스): 컨테이너 내 프로세스 간 메모리 공유 격리
Cgroups : 컨테이너가 사용하는 CPU, 메모리, 디스크 I/O 등의 리소스를 제한하는 기능.
# cpu 사용량을 제한하는 명령 가능
docker run --cpus="1.5" ubuntu:latest
UnionFS (OverlayFS) : Unix File System 아님 위에 설명한 도커 이미지의 레이어 구조를 합치기 위한 개념입니다. 여러 개의 읽기 전용 레이어를 하나의 파일 시스템으로 조합 후 최상위에 쓰기 가능한 레이어를 추가하는 방식으로 작동합니다. (완전 도커 이미지와 똑같음. 당연한 것이 이 개념을 차용한 OverlayFS를 사용하기 때문)
Docker는 컨테이너 간 통신을 관리하기 위해 다양한 네트워크 드라이버를 제공합니다. 1 컨테이너 1 어플리케이션을 권장하기 때문에 컨테이너 간 통신이 필수에 외부와도 통신이 가능해야합니다. 말만 들어도 네트워크가 매우 복잡할 거라고 예상이 됩니다.
그래도 알아보자 했으니 조금만 더 힘내봅시다.

우선 흐름을 알아봅시다.
veth 인터페이스를 통해 컨테이너와 Bridge 네트워크가 연결됨iptables를 활용해 외부 네트워크와의 연결 관리추가 내용) ubuntu 환경의
ufw가 docker에 적용 안돼요ㅠㅠ
- ubuntu와 같은 os 사용 시
ufw를 사용하는 경우가 많음- docker는
iptables를 사용하기 때문에ufw설정^^해도 안먹는다- 어떻게 해결하는가? docker의
daemon.json파일 만들어서 iptables :false 설정하기sudo nano /etc/docker/daemon.json{ "iptables" : false }
- 그 후 docker 재시작 => 그러면 이제 docker 컨테이너 간 통신이 안됨 ^^
- routed를 기본적으로 허용하는
iptables와 달리ufw는 따로 설정해줘야함sudo ufw default allow routed sudo ufw reload
- 이제 도커도 ufw로 사용가능해졌다~!
Docker는 다양한 환경에서 사용할 수 있도록 여러 가지 네트워크 드라이버를 제공 중 입니다. 각 드라이버는 특정한 목적과 사용 사례에 맞게 설계되었습니다.
| 드라이버 | 설명 |
|---|---|
| bridge | 기본 네트워크. 여러 컨테이너를 연결 |
| host | 컨테이너가 호스트 네트워크를 공유 |
| none | 네트워크를 비활성화 (격리) |
| overlay | 여러 호스트에 걸쳐 네트워크 구성 |
| macvlan | 실제 물리 네트워크 인터페이스 사용 |
예를 들어, 컨테이너를 특정 브리지 네트워크에 연결하려면 다음과 같이 실행할 수 있습니다. (docker-compose 사용 시 docker-compose.yml 에서 network: 로 설정 가능)
docker network create my_bridge
docker run -d --name my_container --network my_bridge ubuntu:latest
이제 각 네트워크 드라이버에 대해 알아봅시다.
브리지 네트워크는 기본적으로 컨테이너 간 통신을 가능하게 하는 네트워크 유형입니다.
# 새로운 브리지 네트워크 생성
docker network create my_bridge
# 컨테이너 실행 시 특정 네트워크에 연결
docker run -d --name my_container --network my_bridge ubuntu:latest
브리지 네트워크 내의 컨테이너들은 컨테이너 이름을 이용해 서로 통신할 수 있습니다.
# container2 내부에서 container1에 접근
ping container1
그러나 브리지 네트워크는 기본적으로 외부 네트워크와 연결되지 않기 때문에 외부와의 통신을 위해서는 포트 매핑이 필요합니다.
# 컨테이너 실행 시 포트 매핑 설정
docker run -d -p 8080:80 --network my_bridge nginx
이 설정을 통해 외부에서 컨테이너 내부의 웹 서버(80번 포트)에 8080 포트를 통해 접근 가능해집니다!
호스트 네트워크는 컨테이너가 호스트 시스템의 네트워크를 직접 공유하는 방식으로, 별도의 네트워크 격리 없이 컨테이너가 호스트의 IP와 포트를 그대로 사용합니다.
# 호스트 네트워크 모드로 컨테이너 실행
docker run --network host nginx
이 방식은 네트워크 성능이 중요한 경우에 유리하지만, 컨테이너 간 격리가 없기 때문에 보안에 취약할 수 있습니다
네트워크를 완전히 비활성화하여, 외부 및 다른 컨테이너와의 통신을 차단하는 방식입니다.
# 네트워크가 없는 컨테이너 실행
docker run --network none ubuntu:latest
이 방식은 완전히 격리된 환경에서 실행해야 하는 애플리케이션에 적합합니다. (도커 네트워크의 default는 bridge이기 때문에 네트워크 없는 컨테이너를 위해서는 논 네트워크 사용)
오버레이 네트워크는 여러 개의 Docker 호스트(서버) 간에 컨테이너를 연결할 수 있도록 하는 네트워크입니다. Docker Swarm과 Kubernetes 같은 오케스트레이션 환경에서 사용합니다.
# 새로운 오버레이 네트워크 생성
docker network create -d overlay my_overlay_network
...오케스트레이션 환경은 다음에 다뤄보도록 하겠습니다
Macvlan 네트워크는 컨테이너가 독립적인 MAC 주소를 가지도록 설정해서 실제 네트워크 인터페이스를 사용할 수 있도록 합니다.
# 새로운 macvlan 네트워크 생성
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 my_macvlan_network
이 방식은 컨테이너를 기존 네트워크와 직접 연결해야 하는 경우에 적합합니다.
추가) TLS 인증을 통한 보안
Docker는 기본적으로 암호화되지 않기 때문에, 민감한 데이터 전송 시에는 TLS(Transport Layer Security)를 적용하기도 합니다.
저는certbot으로 적용했으니 그에 대해서만 작성할게요..!
1.certbot설치sudo apt update sudo apt install certbot
- 인증서 발급
sudo certbot certonly --standalone -d domain.com --email 이메일@email.com --agree-tos --no-eff-emaildomain에 대한 인증서 발급,
/etc/letsencrypt/live/domain.com/에 저장됨
3. Docker 컨테이너에 TLS 적용docker run -d \ --name my_secure_container \ -v /etc/letsencrypt/live/domain.com/fullchain.pem:/etc/ssl/certs/fullchain.pem:ro \ -v /etc/letsencrypt/live/domain.com/privkey.pem:/etc/ssl/private/privkey.pem:ro \ -p 443:443 \ nginxnginx 컨테이너가 Let's Encrypt 인증서로 HTTPS 지원
3-1. docker 데몬에서 certbot 인증서 사용 (도커 엔진 자체가 TLS를 사용하게 하고 싶을 때 설정, 인증서 날라가면 난리나니 꼭 필요할 때만 설정합시다.){ "tls": true, "tlscacert": "/etc/letsencrypt/live/yourdomain.com/fullchain.pem", "tlscert": "/etc/letsencrypt/live/yourdomain.com/cert.pem", "tlskey": "/etc/letsencrypt/live/yourdomain.com/privkey.pem", "hosts": ["tcp://0.0.0.0:2376", "unix:///var/run/docker.sock"] }3-2. docker compose에 certbot tls 적용
version: '3' services: web: image: nginx ports: - "443:443" volumes: - /etc/letsencrypt/live/yourdomain.com/fullchain.pem:/etc/ssl/certs/fullchain.pem:ro - /etc/letsencrypt/live/yourdomain.com/privkey.pem:/etc/ssl/private/privkey.pem:ro킹 짱 컴포즈에도 물론 TLS 설정이 가능합니다.
도커는 배울수록 어렵습니다. 리눅스가 익숙한 개발자라면 굉장히 쉽게 배울 것 같은데 저는 학부생 시절에 배운 내용이 전부라 너무나도 어렵네요. 그래도 꾸준히 시리즈 완성해보겠습니다.
그리고 도커는 귀여운 이미지가 너무 많아요 여러분들도 귀여운 그림 보고 가세요 저는 뜬금없는 저 기차가 장어 닮아서 좋습니다.

Docker가 Image Layer를 구성하는 방법 + 테스트
Deep Dive into Docker Containers | Architecture and Features
우분투에서 docker 컨테이너와 방화벽
Docker Network