Docker를 활용한 웹 개발 완전 가이드¶
📚 목차¶
Docker 기초 개념¶
Docker란?¶
Docker는 컨테이너라는 작은 상자에 애플리케이션을 담아서 어디서든 똑같이 실행할 수 있게 해주는 도구입니다. 마치 이사할 때 짐을 정리된 박스에 담아서 옮기는 것과 비슷해요!
graph TB
A[개발자 컴퓨터] -->|Docker Image| B[Docker Hub]
B -->|Pull Image| C[운영 서버]
B -->|Pull Image| D[테스트 서버]
B -->|Pull Image| E[동료 컴퓨터]
C --> C1[동일한 환경]
D --> D1[동일한 환경]
E --> E1[동일한 환경]
기본 구조 이해¶
graph LR
A[Dockerfile] -->|빌드| B[Docker Image]
B -->|실행| C[Docker Container]
subgraph "실제 예시"
D[레시피] -->|요리| E[완성된 음식]
E -->|접시에 담기| F[서빙된 요리]
end
Nginx와 Django 연동¶
왜 Nginx를 사용할까?¶
graph TB
A[사용자 요청] --> B[Nginx 웹서버]
B -->|정적 파일| C[이미지, CSS, JS 파일]
B -->|동적 요청| D[Django 애플리케이션]
style B fill:#f9f,stroke:#333,stroke-width:2px
style D fill:#bbf,stroke:#333,stroke-width:2px
Nginx의 역할: - 🚀 빠른 정적 파일 서비스 (이미지, CSS 등) - 🔄 로드 밸런싱 (여러 서버로 요청 분산) - 🛡️ 보안 기능 (DDoS 방어 등)
실습: Django 컨테이너 생성¶
1단계: Django 프로젝트 준비¶
# 작업 디렉토리 만들기 (집을 짓기 전 땅을 정하는 것)
mkdir -p $HOME/work/ch05/ex03
cd $HOME/work/ch05/ex03
2단계: requirements.txt 작성¶
# 필요한 파이썬 라이브러리 목록 (재료 목록 같은 것)
django==4.2.7 # Django 웹 프레임워크
3단계: Dockerfile 작성¶
# 기본 이미지 선택 (요리의 기본 재료)
FROM python:3.11.9
# 컨테이너 내부 작업 폴더 설정
WORKDIR /usr/src/app
# 라이브러리 목록 파일 복사
COPY requirements.txt .
# 파이썬 업데이트 및 라이브러리 설치
RUN python -m pip install --upgrade pip \ # pip 업데이트
&& pip install -r requirements.txt # 필요한 라이브러리 설치
# 프로젝트 파일들 복사
COPY . .
# Django 프로젝트 폴더로 이동
WORKDIR /usr/src/app/myapp
# 개발용 서버 실행 명령어
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
# 포트 8000번 열기 (방문객이 들어올 문)
EXPOSE 8000
4단계: 이미지 빌드 및 실행¶
# Docker 이미지 만들기 (요리 완성)
docker image build . -t myweb01
# 컨테이너 실행하기 (음식을 접시에 담아 서빙)
docker container run -p 8000:8000 -d myweb01
Gunicorn을 사용한 운영환경 구성¶
Gunicorn이란? Django 애플리케이션을 더 안정적으로 실행해주는 도구입니다.
graph LR
A[사용자] --> B[Nginx]
B --> C[Gunicorn]
C --> D[Django App]
subgraph "개발환경 vs 운영환경"
E[개발용: Django runserver]
F[운영용: Nginx + Gunicorn + Django]
end
style F fill:#9f9,stroke:#333,stroke-width:2px
requirements.txt 업데이트¶
django==4.2.7
gunicorn==20.1.0 # 운영용 서버 추가
Dockerfile 수정¶
FROM python:3.11.9
WORKDIR /usr/src/app
COPY requirements.txt .
RUN python -m pip install --upgrade pip \
&& pip install -r requirements.txt
COPY . .
WORKDIR /usr/src/app/myapp
# Gunicorn으로 실행 (운영환경용)
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "myapp.wsgi:application"]
EXPOSE 8000
Nginx 설정¶
default.conf 파일¶
# 백엔드 서버 그룹 정의
upstream myweb{
server djangotest:8000; # Django 컨테이너 이름:포트
}
# 웹서버 설정
server{
listen 80; # 80번 포트에서 대기
server_name localhost; # 서버 이름
location /{
proxy_pass http://myweb; # 모든 요청을 Django로 전달
}
}
Nginx Dockerfile¶
FROM nginx:1.25.3
# 기본 설정 파일 삭제
RUN rm /etc/nginx/conf.d/default.conf
# 우리가 만든 설정 파일 복사
COPY default.conf /etc/nginx/conf.d/
# Nginx 실행
CMD ["nginx", "-g", "daemon off;"]
네트워크로 컨테이너 연결¶
graph TB
subgraph "Docker Network: mynetwork02"
A[Nginx Container<br/>:80]
B[Django Container<br/>:8000]
end
C[외부 사용자<br/>:80] --> A
A -->|proxy_pass| B
style A fill:#f96,stroke:#333,stroke-width:2px
style B fill:#69f,stroke:#333,stroke-width:2px
# 네트워크 생성 (컨테이너들이 대화할 수 있는 통로)
docker network create mynetwork02
# Django 컨테이너 실행
docker container run -d --name djangotest --network mynetwork02 myweb02
# Nginx 컨테이너 실행 (외부 포트 80으로 연결)
docker container run -d --name nginxtest --network mynetwork02 -p 80:80 mynginx02
PostgreSQL과 연동¶
3-Tier Architecture 구현¶
graph TB
subgraph "Presentation Tier"
A[Nginx<br/>웹서버]
end
subgraph "Application Tier"
B[Django<br/>애플리케이션]
end
subgraph "Data Tier"
C[PostgreSQL<br/>데이터베이스]
end
A --> B
B --> C
style A fill:#ff9999
style B fill:#99ccff
style C fill:#99ff99
Django에서 PostgreSQL 설정¶
requirements.txt에 추가¶
django==4.2.7
gunicorn==20.1.0
psycopg2==2.9.9 # PostgreSQL 연결 라이브러리
settings.py 설정¶
# 데이터베이스 연결 설정
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql', # PostgreSQL 사용
'NAME': 'postgres', # 데이터베이스 이름
'USER': 'postgres', # 사용자 이름
'PASSWORD': 'mypass', # 비밀번호
'HOST': 'postgrestest', # 컨테이너 이름 (네트워크 내부)
'PORT': 5432, # PostgreSQL 기본 포트
}
}
전체 연동 실행¶
# 네트워크 생성
docker network create mynetwork03
# PostgreSQL 컨테이너 실행
docker container run --name postgrestest \
--network mynetwork03 \
-e POSTGRES_PASSWORD=mypass \
--mount type=volume,source=myvolume03,target=/var/lib/postgresql/data \
-d mypostgres03
# Django 컨테이너 실행
docker container run -d --name djangotest --network mynetwork03 myweb03
# Nginx 컨테이너 실행
docker container run -d --name nginxtest \
--network mynetwork03 \
-p 8000:80 \
mynginx03
로컬 PostgreSQL과 연동¶
때로는 데이터베이스를 로컬(호스트 컴퓨터)에 설치하고 컨테이너에서 접근해야 할 때가 있습니다.
graph TB
subgraph "Host Machine (실제 컴퓨터)"
A[PostgreSQL<br/>172.17.0.1:5432]
end
subgraph "Docker Network"
B[Django Container]
C[Nginx Container]
end
B -->|172.17.0.1:5432| A
C --> B
style A fill:#ffcc99
Docker0 네트워크 주소 확인¶
# Docker가 만드는 기본 네트워크 주소 확인
ifconfig docker0
# 결과 예시: inet 172.17.0.1
Django 설정 수정¶
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'postgres',
'USER': 'postgres',
'PASSWORD': 'mypass',
'HOST': '172.17.0.1', # Docker0 네트워크 주소
'PORT': '5432',
}
}
Docker Compose 활용¶
Docker Compose란?¶
여러 컨테이너를 한 번에 관리할 수 있는 도구입니다. 마치 오케스트라 지휘자처럼 여러 악기(컨테이너)를 조화롭게 연주시킵니다.
graph TB
A[docker-compose.yml<br/>설정 파일] --> B[한 번에 여러 컨테이너 실행]
B --> C[Nginx Container]
B --> D[Django Container]
B --> E[PostgreSQL Container]
B --> F[Network 생성]
B --> G[Volume 생성]
style A fill:#ff6b6b
style B fill:#4ecdc4
docker-compose.yml 파일 작성¶
# Docker Compose 버전
version: "3"
# 서비스(컨테이너) 정의
services:
# Django 서비스
djangotest:
build: ./myDjango03 # 빌드할 폴더
networks:
- composenet01 # 사용할 네트워크
depends_on: # 실행 순서 (PostgreSQL 먼저)
- postgrestest
restart: always # 문제 생기면 자동 재시작
# Nginx 서비스
nginxtest:
build: ./myNginx03
networks:
- composenet01
ports:
- "80:80" # 포트 연결
depends_on: # Django 먼저 실행 후
- djangotest
restart: always
# PostgreSQL 서비스
postgrestest:
build: ./myPostgres03
networks:
- composenet01
environment: # 환경 변수 설정
POSTGRES_USER: postgres
POSTGRES_PASSWORD: mypass
POSTGRES_DB: postgres
volumes: # 데이터 저장 공간
- composevol01:/var/lib/postgresql/data
restart: always
# 네트워크 정의
networks:
composenet01:
# 볼륨 정의
volumes:
composevol01:
실행 및 관리¶
# 모든 서비스 빌드하고 백그라운드 실행
docker compose up -d --build
# 실행 상태 확인
docker compose ps
# 로그 확인
docker compose logs
# 모든 서비스 정지 및 삭제
docker compose down
# 정지만 (삭제 안함)
docker compose stop
Docker Compose 장점: - ✅ 복잡한 명령어를 파일로 관리 - ✅ 개발환경을 쉽게 공유 - ✅ 한 번에 전체 시스템 실행/종료 - ✅ 서비스 간 의존성 관리
Flask 개발환경¶
Django vs Flask 비교¶
graph TB
subgraph "Django (무거운 프레임워크)"
A1[ORM 내장]
A2[Admin 패널]
A3[보안 기능]
A4[인증 시스템]
A5[템플릿 엔진]
end
subgraph "Flask (가벼운 프레임워크)"
B1[라우팅만]
B2[필요한 기능만 추가]
B3[높은 자유도]
end
style A1 fill:#ff9999
style B1 fill:#99ff99
| 구분 | Django | Flask |
|---|---|---|
| 성격 | 풀스택 (모든 기능 포함) | 마이크로 (최소 기능) |
| 장점 | 빠른 개발, 보안 기본 제공 | 가볍고 자유로움 |
| 사용처 | 대규모 웹사이트, 기업용 | API 서버, 작은 프로젝트 |
| 학습 난이도 | 중간 | 쉬움 |
Flask 애플리케이션 생성¶
main.py 파일¶
# Flask 라이브러리 가져오기
from flask import Flask
# Flask 애플리케이션 생성
app = Flask(__name__)
# 루트 경로(/) 접속시 실행할 함수
@app.route('/')
def hello_world():
return 'hello world!' # 브라우저에 출력할 내용
# 이 파일을 직접 실행했을 때만 서버 시작
if __name__ == '__main__':
# 모든 IP에서 접속 허용, 8001번 포트 사용
app.run(host='0.0.0.0', port=8001)
requirements.txt¶
flask==3.0.0 # Flask 웹 프레임워크
gunicorn==20.1.0 # 운영용 서버
Dockerfile¶
FROM python:3.11.6
WORKDIR /usr/src/app
COPY . .
# 파이썬 패키지 업데이트 및 설치
RUN python -m pip install --upgrade pip
RUN pip install -r requirements.txt
# Flask 앱이 있는 폴더로 이동
WORKDIR ./myapp
# Gunicorn으로 Flask 앱 실행
# main:app은 main.py 파일의 app 변수를 의미
CMD gunicorn --bind 0.0.0.0:8001 main:app
EXPOSE 8001
Nginx와 Flask 연동¶
Nginx 설정 (default.conf)¶
upstream myweb {
server flasktest:8001; # Flask 컨테이너:포트
}
server {
listen 81; # 81번 포트 사용
server_name localhost;
location / {
proxy_pass http://myweb;
}
}
현업 활용법¶
현업에서 많이 사용하는 구성¶
graph TB
subgraph "Production Environment"
A[Load Balancer<br/>ALB/ELB] --> B[Nginx Containers]
B --> C[Django/Flask App Containers]
C --> D[RDS PostgreSQL]
E[Redis Cache] --> C
F[S3 Static Files] --> B
end
style A fill:#ff6b6b
style D fill:#4ecdc4
style E fill:#45b7d1
style F fill:#96ceb4
1. 현업 표준 구성¶
웹 서버: - ✅ Nginx (90% 이상 사용) - Alternatives: Apache, Caddy
애플리케이션 서버: - ✅ Django + Gunicorn (대규모 프로젝트) - ✅ Flask + Gunicorn (API 서버) - FastAPI + Uvicorn (최신 트렌드)
데이터베이스: - ✅ PostgreSQL (80% 이상) - MySQL (레거시 시스템) - Redis (캐시/세션)
컨테이너 관리: - ✅ Docker + Docker Compose (개발환경) - ✅ Kubernetes (운영환경)
2. 현업 개발 워크플로우¶
graph LR
A[개발자<br/>로컬 개발] --> B[Git Push]
B --> C[CI/CD Pipeline<br/>Jenkins/GitHub Actions]
C --> D[Docker Build]
D --> E[테스트 환경 배포]
E --> F[운영 환경 배포]
style C fill:#ff9999
style F fill:#99ff99
3. 환경별 설정 관리¶
# 개발환경
docker-compose.dev.yml
# 테스트환경
docker-compose.test.yml
# 운영환경
docker-compose.prod.yml
4. 현업 꿀팁들¶
성능 최적화:
# Nginx 설정 최적화
worker_processes auto;
keepalive_timeout 65;
# 정적 파일 캐싱
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
보안 설정:
# docker-compose.yml
environment:
- DEBUG=False # Django 디버그 모드 끄기
- ALLOWED_HOSTS=yourdomain.com # 허용 도메인만 설정
- SECRET_KEY=${SECRET_KEY} # 환경변수로 비밀키 관리
모니터링:
# 헬스체크 추가
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health/"]
interval: 30s
timeout: 10s
retries: 3
AWS 클라우드 적용¶
AWS 서비스 매핑¶
graph TB
subgraph "로컬 환경"
A1[Docker Container]
A2[로컬 PostgreSQL]
A3[로컬 Storage]
end
subgraph "AWS 클라우드"
B1[ECS/EKS<br/>컨테이너 서비스]
B2[RDS<br/>관리형 데이터베이스]
B3[S3<br/>오브젝트 스토리지]
end
A1 -->|마이그레이션| B1
A2 -->|마이그레이션| B2
A3 -->|마이그레이션| B3
style B1 fill:#ff9999
style B2 fill:#99ccff
style B3 fill:#99ff99
1. AWS ECS를 이용한 컨테이너 배포¶
Task Definition (작업 정의)¶
{
"family": "django-app",
"taskRoleArn": "arn:aws:iam::account:role/ecsTaskRole",
"networkMode": "awsvpc",
"containerDefinitions": [
{
"name": "django-container",
"image": "your-account.dkr.ecr.region.amazonaws.com/django-app:latest",
"memory": 512,
"cpu": 256,
"essential": true,
"portMappings": [
{
"containerPort": 8000,
"protocol": "tcp"
}
],
"environment": [
{
"name": "DEBUG",
"value": "False"
},
{
"name": "DATABASE_URL",
"value": "postgresql://user:pass@rds-endpoint:5432/dbname"
}
]
}
]
}
2. AWS 아키텍처 예시¶
graph TB
subgraph "Internet"
A[Users]
end
subgraph "AWS Public Subnet"
B[Application Load Balancer<br/>ALB]
C[NAT Gateway]
end
subgraph "AWS Private Subnet"
D[ECS Fargate<br/>Django Containers]
E[RDS PostgreSQL<br/>Multi-AZ]
end
subgraph "AWS Services"
F[S3 Bucket<br/>Static Files]
G[CloudFront CDN]
H[ElastiCache Redis]
end
A --> B
B --> D
D --> E
D --> H
G --> F
B --> G
style B fill:#ff6b6b
style D fill:#4ecdc4
style E fill:#45b7d1
style F fill:#96ceb4
3. Docker 이미지를 ECR에 푸시¶
# AWS ECR 로그인
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com
# Docker 이미지 태그 설정
docker tag django-app:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/django-app:latest
# ECR에 푸시
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/django-app:latest
4. RDS PostgreSQL 연결¶
Django settings.py (AWS용)¶
import os
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME', 'myapp'),
'USER': os.environ.get('DB_USER', 'postgres'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': os.environ.get('DB_HOST'), # RDS 엔드포인트
'PORT': os.environ.get('DB_PORT', '5432'),
'OPTIONS': {
'sslmode': 'require', # AWS RDS는 SSL 필수
},
}
}
# AWS S3 정적 파일 설정
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = 'your-s3-bucket'
AWS_S3_REGION_NAME = 'us-east-1'
# 정적 파일을 S3에 저장
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATICFILES_STORAGE = 'storages.backends.s3boto3.StaticS3Boto3Storage'
5. Infrastructure as Code (Terraform)¶
# main.tf
resource "aws_ecs_cluster" "main" {
name = "django-cluster"
}
resource "aws_ecs_service" "django" {
name = "django-service"
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.django.arn
desired_count = 2
load_balancer {
target_group_arn = aws_lb_target_group.django.arn
container_name = "django-container"
container_port = 8000
}
}
resource "aws_db_instance" "postgres" {
identifier = "django-postgres"
engine = "postgres"
engine_version = "13.7"
instance_class = "db.t3.micro"
allocated_storage = 20
db_name = "myapp"
username = "postgres"
password = var.db_password
backup_retention_period = 7
multi_az = true
publicly_accessible = false
vpc_security_group_ids = [aws_security_group.rds.id]
db_subnet_group_name = aws_db_subnet_group.main.name
skip_final_snapshot = true
}
6. AWS 비용 최적화 팁¶
ECS Fargate vs EC2:
graph LR
A[소규모 프로젝트] --> B[ECS Fargate<br/>관리 편함, 비용 높음]
C[대규모 프로젝트] --> D[ECS on EC2<br/>관리 복잡, 비용 낮음]
style B fill:#ff9999
style D fill:#99ff99
RDS 인스턴스 선택:
- 개발환경: db.t3.micro (무료 티어)
- 운영환경: db.t3.small ~ db.r5.large
오토 스케일링 설정:
# ECS 서비스 오토 스케일링
min_capacity: 2
max_capacity: 10
target_cpu_utilization: 70%
정리 및 다음 단계¶
학습한 내용 요약¶
- Docker 기초: 컨테이너 개념과 이미지 빌드
- 웹 서버 연동: Nginx + Django/Flask 구성
- 데이터베이스: PostgreSQL 연동 방법
- Docker Compose: 여러 컨테이너 통합 관리
- 현업 활용: 실제 개발 환경 구성
- 클라우드 배포: AWS 서비스 활용
다음 학습 추천 순서¶
graph TD
A[현재 위치<br/>Docker + 웹개발] --> B[Kubernetes 기초]
B --> C[CI/CD 파이프라인]
C --> D[모니터링 & 로깅]
D --> E[보안 & 성능 최적화]
style A fill:#4ecdc4
style B fill:#45b7d1
- Kubernetes 학습 (컨테이너 오케스트레이션)
- CI/CD 파이프라인 구축 (Jenkins, GitHub Actions)
- 모니터링 시스템 (Prometheus, Grafana)
- 보안 강화 (HTTPS, 방화벽, 접근 제어)
추가 실습 프로젝트¶
프로젝트 1: Java 개발환경 구성¶
현업에서 많이 사용하는 Java + Spring Boot 환경을 Docker로 구성해보세요.
Java Dockerfile 예시¶
# Java 17 기반 이미지
FROM openjdk:17-jdk-slim
# 작업 디렉토리 설정
WORKDIR /app
# Maven Wrapper 복사
COPY mvnw .
COPY .mvn .mvn
# pom.xml 먼저 복사 (의존성 캐싱을 위해)
COPY pom.xml .
# 의존성 다운로드
RUN ./mvnw dependency:go-offline -B
# 소스 코드 복사
COPY src src
# 애플리케이션 빌드
RUN ./mvnw clean package -DskipTests
# 포트 노출
EXPOSE 8080
# 애플리케이션 실행
CMD ["java", "-jar", "target/myapp-1.0.0.jar"]
docker-compose.yml (Java + PostgreSQL)¶
version: "3"
services:
java-app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=docker
- SPRING_DATASOURCE_URL=jdbc:postgresql://postgres:5432/mydb
- SPRING_DATASOURCE_USERNAME=postgres
- SPRING_DATASOURCE_PASSWORD=password
depends_on:
- postgres
networks:
- java-network
postgres:
image: postgres:13
environment:
POSTGRES_DB: mydb
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- java-network
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- java-app
networks:
- java-network
networks:
java-network:
driver: bridge
volumes:
postgres-data:
프로젝트 2: 마이크로서비스 아키텍처¶
graph TB
subgraph "API Gateway"
A[Nginx/Kong]
end
subgraph "서비스들"
B[User Service<br/>Flask/Django]
C[Product Service<br/>Flask/Django]
D[Order Service<br/>Flask/Django]
end
subgraph "데이터베이스"
E[User DB<br/>PostgreSQL]
F[Product DB<br/>PostgreSQL]
G[Order DB<br/>PostgreSQL]
end
subgraph "공유 서비스"
H[Redis Cache]
I[Message Queue<br/>RabbitMQ]
end
A --> B
A --> C
A --> D
B --> E
C --> F
D --> G
B --> H
C --> H
D --> H
B --> I
C --> I
D --> I
트러블슈팅 가이드¶
자주 발생하는 문제들¶
1. 포트 충돌 문제¶
# 문제: 포트가 이미 사용 중
Error: Port 8000 is already in use
# 해결: 사용 중인 프로세스 확인 및 종료
lsof -i :8000 # 포트 사용 프로세스 확인
kill -9 [PID] # 프로세스 종료
# 또는 다른 포트 사용
docker run -p 8001:8000 myapp
2. 컨테이너 간 통신 문제¶
# 문제: 컨테이너끼리 연결이 안됨
django.db.utils.OperationalError: could not connect to server
# 해결: 네트워크 확인
docker network ls # 네트워크 목록 확인
docker network inspect mynetwork # 네트워크 상세 정보
docker container inspect [컨테이너명] # 컨테이너 네트워크 설정 확인
3. 볼륨 마운트 문제¶
# 문제: 데이터가 저장되지 않음
# 해결: 볼륨 경로 확인
docker volume ls # 볼륨 목록
docker volume inspect myvolume # 볼륨 상세 정보
# 올바른 마운트 방법
docker run -v myvolume:/data myapp # 볼륨 마운트
docker run -v /host/path:/container/path myapp # 바인드 마운트
4. 이미지 빌드 실패¶
# 문제: 패키지 설치 실패
E: Unable to locate package
# 해결: 베이스 이미지 업데이트
FROM python:3.11-slim
RUN apt-get update && apt-get install -y \
build-essential \
&& rm -rf /var/lib/apt/lists/* # 캐시 정리로 이미지 크기 감소
성능 최적화 팁¶
1. 도커 이미지 최적화¶
# 멀티 스테이지 빌드 사용
FROM node:16 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:16-alpine AS production
WORKDIR /app
COPY --from=build /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
2. .dockerignore 활용¶
# .dockerignore 파일
node_modules
.git
.gitignore
README.md
.env
.nyc_output
coverage
.cache
3. 레이어 캐싱 최적화¶
# 나쁜 예: 매번 전체 다시 빌드
FROM python:3.11
WORKDIR /app
COPY . . # 소스가 바뀔 때마다 재빌드
RUN pip install -r requirements.txt
# 좋은 예: 의존성 캐싱 활용
FROM python:3.11
WORKDIR /app
COPY requirements.txt . # requirements.txt만 먼저 복사
RUN pip install -r requirements.txt # 의존성 캐시됨
COPY . . # 소스 코드는 나중에 복사
보안 고려사항¶
1. 컨테이너 보안¶
최소 권한 원칙¶
# 루트 사용자 대신 일반 사용자 생성
FROM python:3.11-slim
# 일반 사용자 생성
RUN useradd --create-home --shell /bin/bash app
# 사용자 변경
USER app
WORKDIR /home/app
# 애플리케이션 실행
CMD ["python", "app.py"]
민감 정보 관리¶
# docker-compose.yml
services:
web:
environment:
# 환경 변수 파일 사용
- DB_PASSWORD_FILE=/run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
2. 네트워크 보안¶
방화벽 설정¶
# UFW를 이용한 방화벽 설정
sudo ufw enable
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw deny 8000/tcp # 직접 접근 차단
HTTPS 설정 (Let's Encrypt)¶
# nginx.conf
server {
listen 80;
server_name yourdomain.com;
return 301 https://$server_name$request_uri; # HTTP를 HTTPS로 리다이렉트
}
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
location / {
proxy_pass http://django;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
실전 면접 대비¶
Docker 관련 예상 질문¶
1. "Docker를 사용하는 이유는 무엇인가요?"¶
답변 포인트: - 환경 일관성 보장 ("내 컴퓨터에서는 되는데?" 문제 해결) - 쉬운 배포 및 확장 - 리소스 효율성 (VM보다 가벼움) - 마이크로서비스 아키텍처 구현 용이
2. "Docker와 VM의 차이점은?"¶
graph TB
subgraph "Virtual Machine"
A1[Guest OS 1]
A2[Guest OS 2]
A3[Hypervisor]
A4[Host OS]
A5[Physical Hardware]
end
subgraph "Docker Container"
B1[Container 1]
B2[Container 2]
B3[Docker Engine]
B4[Host OS]
B5[Physical Hardware]
end
답변: - Docker는 OS 레벨 가상화, VM은 하드웨어 레벨 가상화 - Docker가 더 가볍고 빠름 - VM은 완전한 격리, Docker는 프로세스 레벨 격리
3. "Docker Compose와 Kubernetes의 차이점은?"¶
답변: - Docker Compose: 단일 호스트, 개발/테스트 환경 - Kubernetes: 다중 호스트, 운영 환경, 자동 스케일링
실무 시나리오 문제¶
"운영 중인 Django 앱의 성능이 느려졌습니다. Docker 환경에서 어떻게 해결하시겠습니까?"¶
단계별 접근: 1. 모니터링 확인
# 컨테이너 리소스 사용량 확인
docker stats
# 로그 확인
docker logs [container-id]
-
데이터베이스 최적화
# Django settings.py DATABASES = { 'default': { # 연결 풀링 설정 'CONN_MAX_AGE': 60, 'OPTIONS': { 'MAX_CONNS': 20, } } } -
캐싱 적용
# docker-compose.yml에 Redis 추가 redis: image: redis:alpine ports: - "6379:6379" -
수평 확장
web: image: django-app deploy: replicas: 3 # 3개 인스턴스로 확장
학습 자료 및 참고 링크¶
공식 문서¶
추천 학습 순서¶
- 기초 → 중급 → 고급 순서로 학습
- 이론 학습 후 반드시 실습 진행
- 작은 프로젝트부터 시작해서 점진적 확장
- 커뮤니티 참여 (Stack Overflow, Reddit 등)
실습 프로젝트 아이디어¶
- 개인 블로그 (Django + PostgreSQL + Nginx)
- REST API 서버 (Flask + Redis + Docker Compose)
- 마이크로서비스 (여러 서비스 + API Gateway)
- CI/CD 파이프라인 (GitHub Actions + Docker + AWS)
마무리¶
이 가이드를 통해 Docker를 활용한 웹 개발의 전체 그림을 이해하셨을 것입니다. 중학생 수준에서 시작해서 현업 수준까지의 내용을 다뤘으니, 단계적으로 학습하시기 바랍니다.
기억할 점:
- 이론보다는 직접 실습이 중요합니다
- 에러를 두려워하지 마세요 - 문제 해결 과정에서 더 많이 배웁니다
- 현업 코드를 많이 보세요 - GitHub의 오픈소스 프로젝트들을 참고하세요
- 꾸준한 학습이 가장 중요합니다
성공적인 개발자가 되시길 응원합니다! 🚀