Docker

Docker란 무엇인가?

Docker는 애플리케이션을 컨테이너라는 가상 환경에 담아서 실행하는 기술입니다.

🍱 쉬운 비유로 이해하기

  • 일반적인 개발: 집에서 요리할 때마다 재료 사고, 도구 준비하고, 청소하기
  • Docker 사용: 미리 모든 재료와 도구가 들어있는 도시락 상자 → 어디서든 바로 요리 가능!

💡 한 줄 요약

"내 컴퓨터에서 작동하는 프로그램을 다른 어떤 컴퓨터에서도 똑같이 작동하게 해주는 마법의 상자"


왜 Docker를 사용해야 할까?

😩 기존의 문제점

개발자 A: "내 컴퓨터에서는 잘 되는데..."
개발자 B: "내 컴퓨터에서는 안 돼요..."
운영팀: "서버에서는 또 다른 오류가..."

✨ Docker의 해결책

"Docker 컨테이너에서는 모든 컴퓨터에서 똑같이 작동해요!"

🎯 주요 장점

장점설명예시
일관성어디서나 동일하게 실행개발-테스트-운영 환경 통일
격리다른 프로그램과 충돌 없음Node.js 16과 18 동시 사용
이식성쉽게 다른 서버로 이동AWS에서 Google Cloud로 간단 이전
확장성필요에 따라 여러 개 실행트래픽 증가 시 컨테이너 추가

핵심 개념 이해하기

🏗️ Container (컨테이너)

실제 애플리케이션이 실행되는 가상 환경
= 프로그램 + 운영체제 + 라이브러리가 모두 포함된 박스

📋 Image (이미지)

컨테이너를 만들기 위한 설계도/템플릿
= 요리 레시피 같은 것

📝 Dockerfile

이미지를 만들기 위한 명령어들이 적힌 파일
= 상세한 요리 레시피

🔄 관계도

Dockerfile → (빌드) → Image → (실행) → Container

Docker 설치 및 시작

💾 설치 방법

Windows/Mac:
1. Docker Desktop 다운로드
2. 설치 후 고래 아이콘 확인

Ubuntu:

# Docker 설치
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

# 사용자를 docker 그룹에 추가
sudo usermod -aG docker $USER

✅ 설치 확인

docker --version
# Docker version 24.0.x 출력되면 성공!

🎉 첫 번째 명령어

# "Hello World" 컨테이너 실행
docker run hello-world

이 명령어가 하는 일:
1. hello-world 이미지 찾기
2. 없으면 Docker Hub에서 다운로드
3. 컨테이너 생성하고 실행
4. 메시지 출력 후 종료


기본 명령어 마스터하기

🖼️ 이미지 관련 명령어

# 이미지 목록 보기
docker images

# 이미지 다운로드
docker pull nginx
docker pull node:18

# 이미지 삭제
docker rmi nginx

# 이미지 상세 정보
docker inspect nginx

📦 컨테이너 관련 명령어

# 컨테이너 실행
docker run nginx

# 백그라운드로 실행 (-d: detached)
docker run -d nginx

# 포트 매핑해서 실행
docker run -d -p 8080:80 nginx

# 이름 지정해서 실행
docker run -d -p 8080:80 --name my-web nginx

# 실행 중인 컨테이너 보기
docker ps

# 모든 컨테이너 보기 (중지된 것 포함)
docker ps -a

# 컨테이너 중지
docker stop my-web

# 컨테이너 재시작
docker restart my-web

# 컨테이너 삭제
docker rm my-web

# 실행 중인 컨테이너 강제 삭제
docker rm -f my-web

🌐 실습: 웹서버 실행해보기

# Nginx 웹서버 실행
docker run -d -p 3000:80 --name my-website nginx

# 브라우저에서 http://localhost:3000 접속
# Nginx 기본 페이지 확인!

# 로그 확인
docker logs my-website

# 컨테이너 내부 접속
docker exec -it my-website bash

Dockerfile 작성법

📝 기본 구조

# 1. 베이스 이미지 선택
FROM node:18

# 2. 작업 디렉토리 설정
WORKDIR /app

# 3. 파일 복사
COPY package*.json ./

# 4. 명령어 실행
RUN npm install

# 5. 소스 코드 복사
COPY . .

# 6. 포트 노출
EXPOSE 3000

# 7. 컨테이너 시작 명령어
CMD ["npm", "start"]

🎯 주요 명령어 설명

명령어설명예시
FROM베이스 이미지 지정FROM node:18-alpine
WORKDIR작업 디렉토리 설정WORKDIR /app
COPY파일 복사COPY . .
RUN빌드 시 명령어 실행RUN npm install
EXPOSE포트 노출EXPOSE 3000
CMD컨테이너 시작 명령어CMD ["npm", "start"]
ENV환경변수 설정ENV NODE_ENV=production

🏗️ 이미지 빌드 및 실행

# Dockerfile로 이미지 빌드
docker build -t my-app .

# 태그와 함께 빌드
docker build -t my-app:v1.0 .

# 빌드한 이미지로 컨테이너 실행
docker run -d -p 3000:3000 my-app

실전 예제 - React 앱 Docker화

📁 프로젝트 구조

my-react-app/
├── src/
├── public/
├── package.json
├── Dockerfile
└── .dockerignore

🚀 단계별 Dockerfile 작성

1단계: 개발용 Dockerfile

FROM node:18-alpine

# 작업 디렉토리 설정
WORKDIR /app

# package.json 복사 및 의존성 설치
COPY package*.json ./
RUN npm install

# 소스 코드 복사
COPY . .

# 개발 서버 포트 노출
EXPOSE 3000

# 개발 서버 시작
CMD ["npm", "start"]

2단계: 프로덕션용 멀티스테이지 Dockerfile

# 빌드 스테이지
FROM node:18-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY . .
RUN npm run build

# 프로덕션 스테이지
FROM nginx:alpine

# 빌드된 파일을 nginx로 복사
COPY --from=builder /app/build /usr/share/nginx/html

# nginx 설정 파일 복사 (선택사항)
COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

📄 .dockerignore 파일

node_modules
npm-debug.log
.git
.gitignore
README.md
.env
coverage
.nyc_output

🎯 빌드 및 실행

# 개발용 이미지 빌드
docker build -f Dockerfile.dev -t my-react-app:dev .

# 프로덕션용 이미지 빌드
docker build -t my-react-app:prod .

# 개발 서버 실행
docker run -d -p 3000:3000 -v $(pwd)/src:/app/src my-react-app:dev

# 프로덕션 서버 실행
docker run -d -p 8080:80 my-react-app:prod

Docker Compose로 멀티 컨테이너 관리

🤝 Docker Compose란?

여러 개의 Docker 컨테이너를 하나의 애플리케이션으로 정의하고 관리하는 도구

📋 docker-compose.yml 예시

풀스택 애플리케이션 구성

version: '3.8'

services:
  # 프론트엔드 (React)
  frontend:
    build: ./frontend
    ports:
      - "3000:3000"
    volumes:
      - ./frontend/src:/app/src
    environment:
      - REACT_APP_API_URL=http://localhost:5000
    depends_on:
      - backend

  # 백엔드 (Node.js)
  backend:
    build: ./backend
    ports:
      - "5000:5000"
    environment:
      - NODE_ENV=development
      - DB_HOST=database
      - DB_PORT=5432
      - DB_NAME=myapp
      - DB_USER=postgres
      - DB_PASSWORD=password
      - REDIS_URL=redis://redis:6379
    depends_on:
      - database
      - redis
    volumes:
      - ./backend:/app
      - /app/node_modules

  # 데이터베이스 (PostgreSQL)
  database:
    image: postgres:15
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "5432:5432"

  # 캐시 (Redis)
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data

  # 웹서버 (Nginx)
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/nginx/ssl
    depends_on:
      - frontend
      - backend

volumes:
  postgres_data:
  redis_data:

🎮 Docker Compose 명령어

# 모든 서비스 시작 (백그라운드)
docker-compose up -d

# 특정 서비스만 시작
docker-compose up frontend backend

# 서비스 재빌드 후 시작
docker-compose up --build

# 로그 확인
docker-compose logs

# 특정 서비스 로그 확인
docker-compose logs backend

# 실시간 로그 보기
docker-compose logs -f

# 실행 중인 서비스 확인
docker-compose ps

# 서비스 스케일링
docker-compose up --scale backend=3

# 모든 서비스 중지
docker-compose stop

# 모든 서비스 중지 및 삭제
docker-compose down

# 볼륨까지 삭제
docker-compose down -v

실무 워크플로우

🔄 개발 단계별 Docker 활용

1️⃣ 로컬 개발 환경

# 개발용 compose 파일
docker-compose -f docker-compose.dev.yml up -d

# 핫 리로드 가능한 개발 서버
docker-compose exec backend npm run dev

2️⃣ 테스트 단계

# 테스트 환경 구성
docker-compose -f docker-compose.test.yml up -d

# 단위 테스트 실행
docker-compose exec backend npm test

# 통합 테스트 실행
docker-compose exec backend npm run test:integration

3️⃣ CI/CD 파이프라인

# .github/workflows/docker.yml
name: Docker Build and Deploy

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Build Docker image
        run: |
          docker build -t myapp:$GITHUB_SHA .
          docker tag myapp:$GITHUB_SHA myapp:latest
      
      - name: Run tests
        run: |
          docker run --rm myapp:latest npm test
      
      - name: Push to registry
        run: |
          echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
          docker push myapp:$GITHUB_SHA
          docker push myapp:latest

4️⃣ 프로덕션 배포

# 프로덕션 서버에서
docker pull myapp:latest
docker-compose -f docker-compose.prod.yml up -d

# 무중단 배포 (Blue-Green)
docker-compose -f docker-compose.prod.yml up -d --scale app=2

유용한 팁과 트릭

🔍 디버깅 및 모니터링

# 컨테이너 내부 접근
docker exec -it <container-name> bash
docker exec -it <container-name> sh  # alpine 기반

# 컨테이너 리소스 사용량 확인
docker stats

# 컨테이너 상세 정보
docker inspect <container-name>

# 실시간 로그 보기
docker logs -f <container-name>

# 컨테이너에서 프로세스 확인
docker exec <container-name> ps aux

🧹 정리 명령어

# 중지된 컨테이너 삭제
docker container prune

# 사용하지 않는 이미지 삭제
docker image prune

# 사용하지 않는 볼륨 삭제
docker volume prune

# 사용하지 않는 네트워크 삭제
docker network prune

# 모든 것 정리 (주의!)
docker system prune -a

# 특정 기간 이전 이미지 삭제
docker image prune -a --filter "until=24h"

⚡ 성능 최적화

Dockerfile 최적화

# 좋은 예: 캐시 활용
FROM node:18-alpine
WORKDIR /app

# package.json을 먼저 복사 (의존성 변경이 없으면 캐시 사용)
COPY package*.json ./
RUN npm ci --only=production

# 소스 코드는 나중에 복사
COPY . .
RUN npm run build

# 나쁜 예: 매번 전체 재빌드
FROM node:18-alpine
WORKDIR /app
COPY . .  # 소스 변경 시마다 전체 재빌드
RUN npm install && npm run build

멀티스테이지 빌드로 이미지 크기 줄이기

# 빌드 스테이지 (큰 이미지)
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# 런타임 스테이지 (작은 이미지)
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html

🔒 보안 모범 사례

# 1. 루트 사용자 피하기
FROM node:18-alpine
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
USER nextjs

# 2. 최소한의 권한으로 실행
COPY --chown=nextjs:nodejs . .

# 3. .dockerignore 활용
# .dockerignore 파일에서 민감한 정보 제외
.env
.env.local
.git
node_modules
*.log

📊 Docker vs 가상머신 비교

특성Docker 컨테이너가상머신
크기가볍다 (수십 MB)무겁다 (수 GB)
시작 속도빠르다 (초 단위)느리다 (분 단위)
자원 사용효율적많은 오버헤드
격리 수준프로세스 격리완전한 OS 격리
이식성매우 높음상대적으로 낮음
사용 사례마이크로서비스, CI/CD레거시 앱, 완전 격리 필요시

결론

🎯 Docker를 사용해야 하는 이유

  1. 개발 환경 일관성: "내 컴퓨터에서는 잘 되는데" 문제 해결
  2. 빠른 배포: 클라우드 네이티브 애플리케이션의 핵심
  3. 효율적인 자원 사용: 가상머신 대비 월등한 성능
  4. 마이크로서비스 아키텍처: 현대적인 애플리케이션 개발의 필수
  5. DevOps 문화: CI/CD 파이프라인의 핵심 기술

🚀 다음 단계

  1. Kubernetes 학습: 컨테이너 오케스트레이션
  2. Docker Swarm: Docker 네이티브 클러스터링
  3. 보안 강화: 컨테이너 보안 모범 사례
  4. 모니터링: Prometheus, Grafana와 연동
  5. 서비스 메시: Istio, Linkerd 등 고급 기술

📚 추가 학습 자료

0개의 댓글