1. Docker란?
Docker는 애플리케이션을 컨테이너라는 표준화된 단위로 패키징하고 실행하기 위한 오픈 소스 플랫폼입니다. 컨테이너는 코드, 런타임, 시스템 도구, 시스템 라이브러리 등 소프트웨어 실행에 필요한 모든 것을 포함하는 경량화된 실행 환경입니다.
📦 표준화된 패키징
"어디서나 동일하게 실행"을 보장합니다. 개발, 스테이징, 프로덕션 환경 간의 차이로 인한 문제("내 로컬에서는 되는데...")를 해결합니다.
⚡ 경량화 & 고밀도
가상 머신(VM)과 달리 게스트 OS를 포함하지 않아 훨씬 가볍고 빠르게 시작됩니다. 호스트 머신의 자원을 효율적으로 활용할 수 있습니다.
🔁 생명주기 관리
빌드, 배포, 실행, 모니터링, 로깅까지 컨테이너의 전 생명주기를 관리하는 도구와 생태계를 제공합니다.
2. 왜 써야 하는가? (기존 대안과 비교)
| 방식 | 장점 | 단점 | Docker의 차별점 |
|---|---|---|---|
| 베어메탈 / 직접 설치 | 최대 성능, 완전한 제어 | 환경 구성 복잡, 확장/이전 어려움, 의존성 지옥 | 환경 구성의 코드화, 빠른 배포와 롤백 |
| 전통적 가상머신(VM) | 강한 격리, 완전한 OS 제어 | 무거움(GB 단위), 느린 시작, 오버헤드 큼 | 경량(MB 단위), 빠른 시작/중지, 높은 밀도 |
| 클라우드 PaaS | 관리 부담 감소, 빠른 출시 | 벤더 종속, 제어권 제한, 비용 증가 가능성 | 멀티 클라우드/하이브리드 호환성, 환경 일관성 |
3. 핵심 개념
Docker는 클라이언트-서버 아키텍처로 동작합니다. 주요 구성 요소와 흐름을 이해해야 합니다.
이미지 (Image)
컨테이너를 생성하기 위한 읽기 전용 템플릿. 여러 개의 레이어로 구성되며, Dockerfile로 빌드됩니다.
ubuntu:22.04, python:3.11-slim
컨테이너 (Container)
이미지를 실행한 상태. 쓰기 가능한 레이어가 추가되어 생성되며, 격리된 프로세스로 동작합니다.
docker run -it python:3.11 bash
Dockerfile
이미지를 빌드하기 위한 단계별 명령어 스크립트. 재현 가능한 빌드를 정의합니다.
볼륨 (Volume)
컨테이너의 데이터를 호스트에 유지하는 메커니즘. 컨테이너 삭제 후에도 데이터 보존.
4. 퀵스타트: 설치 → 설정 → 첫 예제
Step 1: 설치 (Ubuntu 기준)
# 기존 패키지 제거 (선택사항)
sudo apt-get remove docker docker-engine docker.io containerd runc
# 저장소 설정 및 패키지 설치
sudo apt-get update
sudo apt-get install -y \
ca-certificates \
curl \
gnupg \
lsb-release
# Docker 공식 GPG 키 추가
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# 저장소 설정
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Docker Engine 설치
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 현재 사용자를 docker 그룹에 추가 (sudo 없이 실행)
sudo usermod -aG docker $USER
# **로그아웃 후 재로그인 필요**
Step 2: 기본 설정 확인
# Docker 데몬 상태 확인
sudo systemctl status docker
# Docker 데몬 시작 및 부팅 시 자동 실행 설정
sudo systemctl start docker
sudo systemctl enable docker
# 간단한 테스트: Hello World 컨테이너 실행
docker run hello-world
Step 3: 첫 번째 Python 애플리케이션 컨테이너화
간단한 Flask 앱을 Dockerize 해봅니다.
from flask import Flask
import os
app = Flask(__name__)
@app.route('/')
def hello():
hostname = os.environ.get('HOSTNAME', 'unknown')
return f"Hello from Docker Container! Hostname: {hostname}"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
# 베이스 이미지 선택 (경량 Python)
FROM python:3.11-slim
# 작업 디렉토리 설정
WORKDIR /app
# 의존성 파일 복사 및 설치
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 애플리케이션 소스 복사
COPY app.py .
# 환경 변수 설정 (선택)
ENV HOSTNAME=my-first-container
# 컨테이너가 사용할 포트 노출
EXPOSE 5000
# 컨테이너 실행 시 실행할 명령
CMD ["python", "app.py"]
# requirements.txt 생성
echo "Flask==3.0.0" > requirements.txt
# Docker 이미지 빌드 (태그 지정)
docker build -t my-python-app:1.0 .
# 빌드된 이미지 확인
docker images
# 컨테이너 실행 (포트 매핑, 백그라운드 실행)
docker run -d -p 8080:5000 --name my-app my-python-app:1.0
# 실행 중인 컨테이너 확인
docker ps
# 로그 확인
docker logs my-app
# 브라우저에서 http://localhost:8080 접속 테스트
# 컨테이너 중지 및 삭제
docker stop my-app
docker rm my-app
5. 핵심 설정 레퍼런스 (Dockerfile & docker run)
| 구분 | 지시어 / 옵션 | 설명 | 예시 |
|---|---|---|---|
| Dockerfile | FROM |
베이스 이미지 지정 | FROM ubuntu:22.04 |
COPY / ADD |
파일 복사 (ADD는 URL/압축 해제 추가) | COPY ./src /app |
|
RUN |
이미지 빌드 중 명령 실행 | RUN apt-get update && apt-get install -y python3 |
|
ENV |
환경 변수 설정 | ENV PYTHONUNBUFFERED=1 |
|
EXPOSE |
사용 포트 정보 제공 (실제 개방X) | EXPOSE 8080 |
|
CMD / ENTRYPOINT |
컨테이너 기본 실행 명령 | CMD ["python", "app.py"] |
|
| docker run | -d |
데몬 모드 (백그라운드 실행) | docker run -d nginx |
-p |
포트 매핑 (호스트:컨테이너) | -p 80:8080 |
|
-v |
볼륨 마운트 (호스트:컨테이너) | -v /data:/app/data |
|
--env / -e |
환경 변수 설정 | -e DB_HOST=localhost |
|
--name |
컨테이너 이름 지정 | --name my-nginx |
|
--restart |
재시작 정책 (always, unless-stopped) | --restart unless-stopped |
6. 실무 팁 & 트러블슈팅
Dockerfile에서 자주 변경되지 않는 부분(의존성 설치)을 앞쪽에, 자주 변경되는 부분(소스코드 복사)을 뒤쪽에 배치하여 빌드 캐시를 최대한 활용하세요.
# 좋은 예: 패키지 설치가 먼저
COPY requirements.txt .
RUN pip install -r requirements.txt # 캐시 활용
COPY app.py . # 변경 시 여기부터 재빌드
불필요한 파일(로그, 가상환경, 빌드 캐시, .git)이 이미지에 포함되는 것을 방지하여 이미지 크기를 줄이고 보안을 강화합니다.
# .dockerignore 예시
.git
__pycache__
*.log
.env
Dockerfile
README.md
venv/
*.pyc
원인: 컨테이너 내부의 메인 프로세스가 종료되었기 때문입니다. (예: 단순히 echo "hello"를 실행하는 경우)
해결: 장기 실행 프로세스(웹 서버, 데이터베이스)를 포그라운드에서 실행하거나, tail -f /dev/null과 같은 명령으로 프로세스를 유지합니다.
# 잘못된 예: 바로 종료
docker run ubuntu echo "hello"
# 해결 1: 인터랙티브 모드로 쉘 유지
docker run -it ubuntu bash
# 해결 2: 웹 서버 실행 (메인 프로세스가 지속됨)
docker run -d -p 80:80 nginx
원인: 호스트에서 마운트된 볼륨 내 파일의 소유자/권한이 컨테이너 내부의 사용자(보통 root가 아닌 UID 1000 등)와 맞지 않을 때 발생합니다.
해결: Dockerfile에서 적절한 사용자 생성 및 전환을 하거나, 호스트와 컨테이너의 UID/GID를 맞춥니다.
# Dockerfile 내에서
RUN groupadd -r appuser && useradd -r -g appuser appuser
USER appuser
WORKDIR /home/appuser
# 이후 COPY/RUN 명령은 appuser 권한으로 실행
# 실행 중인 컨테이너 내부 쉘 접근
docker exec -it [container_name] /bin/bash
# 컨테이너 로그 실시간 확인
docker logs -f [container_name]
# 컨테이너 상세 정보 (IP, 마운트, 네트워크 등)
docker inspect [container_name]
# 시스템 자원 사용량 확인
docker stats
# 사용하지 않는 이미지, 컨테이너, 볼륨 일괄 정리
docker system prune -a --volumes
7. 참고 자료
- 📘 Docker 공식 문서 - 가장 정확하고 최신의 정보원
- 🐋 Docker Hub - 공식 및 커뮤니티 이미지 레지스트리
- 📝 Dockerfile 레퍼런스 - 모든 지시어 상세 설명
- 🚀 Awesome Compose - 다양한 애플리케이션의 Docker Compose 예제 모음
- 다음 단계 학습 추천: Docker Compose (다중 컨테이너 관리), Docker Swarm / Kubernetes (오케스트레이션), 컨테이너 보안 모범 사례