콘텐츠로 이동

Docker를 활용한 웹 개발 완전 가이드

📚 목차

  1. Docker 기초 개념
  2. Nginx와 Django 연동
  3. PostgreSQL과 연동
  4. Docker Compose 활용
  5. Flask 개발환경
  6. 현업 활용법
  7. AWS 클라우드 적용

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%


정리 및 다음 단계

학습한 내용 요약

  1. Docker 기초: 컨테이너 개념과 이미지 빌드
  2. 웹 서버 연동: Nginx + Django/Flask 구성
  3. 데이터베이스: PostgreSQL 연동 방법
  4. Docker Compose: 여러 컨테이너 통합 관리
  5. 현업 활용: 실제 개발 환경 구성
  6. 클라우드 배포: AWS 서비스 활용

다음 학습 추천 순서

graph TD
    A[현재 위치<br/>Docker + 웹개발] --> B[Kubernetes 기초]
    B --> C[CI/CD 파이프라인]
    C --> D[모니터링 & 로깅]
    D --> E[보안 & 성능 최적화]

    style A fill:#4ecdc4
    style B fill:#45b7d1
  1. Kubernetes 학습 (컨테이너 오케스트레이션)
  2. CI/CD 파이프라인 구축 (Jenkins, GitHub Actions)
  3. 모니터링 시스템 (Prometheus, Grafana)
  4. 보안 강화 (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]

  1. 데이터베이스 최적화

    # Django settings.py
    DATABASES = {
        'default': {
            # 연결 풀링 설정
            'CONN_MAX_AGE': 60,
            'OPTIONS': {
                'MAX_CONNS': 20,
            }
        }
    }
    

  2. 캐싱 적용

    # docker-compose.yml에 Redis 추가
    redis:
      image: redis:alpine
      ports:
        - "6379:6379"
    

  3. 수평 확장

    web:
      image: django-app
      deploy:
        replicas: 3  # 3개 인스턴스로 확장
    


학습 자료 및 참고 링크

공식 문서

추천 학습 순서

  1. 기초 → 중급 → 고급 순서로 학습
  2. 이론 학습 후 반드시 실습 진행
  3. 작은 프로젝트부터 시작해서 점진적 확장
  4. 커뮤니티 참여 (Stack Overflow, Reddit 등)

실습 프로젝트 아이디어

  1. 개인 블로그 (Django + PostgreSQL + Nginx)
  2. REST API 서버 (Flask + Redis + Docker Compose)
  3. 마이크로서비스 (여러 서비스 + API Gateway)
  4. CI/CD 파이프라인 (GitHub Actions + Docker + AWS)

마무리

이 가이드를 통해 Docker를 활용한 웹 개발의 전체 그림을 이해하셨을 것입니다. 중학생 수준에서 시작해서 현업 수준까지의 내용을 다뤘으니, 단계적으로 학습하시기 바랍니다.

기억할 점: - 이론보다는 직접 실습이 중요합니다 - 에러를 두려워하지 마세요 - 문제 해결 과정에서 더 많이 배웁니다
- 현업 코드를 많이 보세요 - GitHub의 오픈소스 프로젝트들을 참고하세요 - 꾸준한 학습이 가장 중요합니다

성공적인 개발자가 되시길 응원합니다! 🚀