목록으로
DevOps

개발자를 위한 Docker 입문

Docker의 기본 개념부터 실전 활용까지. 개발 환경을 컨테이너로 관리하는 방법을 알아봅니다.

Docker는 애플리케이션을 컨테이너로 패키징하고 실행하는 도구입니다. "내 컴퓨터에서는 되는데..."라는 문제를 해결해줍니다.

Docker가 필요한 이유

개발 환경과 프로덕션 환경의 차이로 인한 문제가 많습니다.

  • Node.js 버전이 다름
  • 운영체제가 다름
  • 필요한 라이브러리가 설치되지 않음
  • 환경 변수 설정이 다름

Docker는 애플리케이션과 실행 환경을 함께 패키징합니다. 어디서 실행하든 동일하게 동작합니다.

핵심 개념

이미지(Image)

애플리케이션과 실행 환경을 담은 템플릿입니다. 읽기 전용입니다.

컨테이너(Container)

이미지를 실행한 인스턴스입니다. 이미지를 기반으로 생성되며, 쓰기가 가능합니다.

Dockerfile

이미지를 만드는 설명서입니다. 어떤 베이스 이미지를 사용하고, 어떤 파일을 복사하고, 어떤 명령을 실행할지 정의합니다.

Dockerfile 작성하기

Node.js 애플리케이션용 Dockerfile 예시입니다.

# 베이스 이미지
FROM node:20-alpine

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

# 패키지 파일 복사 (캐싱 활용)
COPY package*.json ./

# 의존성 설치
RUN npm ci

# 소스 코드 복사
COPY . .

# 빌드
RUN npm run build

# 포트 노출
EXPOSE 3000

# 실행 명령
CMD ["npm", "start"]

레이어 캐싱 활용

package.json을 먼저 복사하고 npm install을 실행하면, 소스 코드만 변경되었을 때 의존성 설치를 건너뛸 수 있습니다.

기본 명령어

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

# 컨테이너 실행
docker run -p 3000:3000 my-app

# 백그라운드 실행
docker run -d -p 3000:3000 my-app

# 실행 중인 컨테이너 목록
docker ps

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

# 컨테이너 중지
docker stop <container_id>

# 컨테이너 삭제
docker rm <container_id>

# 이미지 목록
docker images

# 이미지 삭제
docker rmi <image_id>

# 컨테이너 로그 보기
docker logs <container_id>

# 컨테이너 내부 접속
docker exec -it <container_id> /bin/sh

Docker Compose

여러 컨테이너를 함께 관리할 때 사용합니다. 웹 서버, 데이터베이스, 캐시 등을 한 번에 실행할 수 있습니다.

# docker-compose.yml
version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/mydb
      - REDIS_URL=redis://cache:6379
    depends_on:
      - db
      - cache

  db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass
      - POSTGRES_DB=mydb
    volumes:
      - postgres_data:/var/lib/postgresql/data

  cache:
    image: redis:7-alpine

volumes:
  postgres_data:
# 모든 서비스 시작
docker-compose up

# 백그라운드 실행
docker-compose up -d

# 중지
docker-compose down

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

개발 환경에서의 활용

핫 리로드를 위한 볼륨 마운트

services:
  app:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app          # 소스 코드 마운트
      - /app/node_modules  # node_modules는 컨테이너 것 사용
    command: npm run dev

소스 코드 변경이 컨테이너에 바로 반영됩니다.

프로덕션 최적화

멀티 스테이지 빌드

# 빌드 스테이지
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 프로덕션 스테이지
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/server.js"]

빌드에만 필요한 파일을 최종 이미지에서 제외하여 이미지 크기를 줄입니다.

자주 하는 실수

민감한 정보 포함

# 절대 하지 마세요
ENV API_KEY=secret123

환경 변수는 실행 시 전달하거나 시크릿 매니저를 사용합니다.

.dockerignore 미사용

# .dockerignore
node_modules
.git
.env
*.log

불필요한 파일이 이미지에 포함되지 않도록 합니다.

마무리

Docker는 처음에는 낯설 수 있지만, 익숙해지면 개발과 배포가 훨씬 편해집니다.

로컬에서 Docker Compose로 개발 환경을 구성하는 것부터 시작해보세요. 데이터베이스나 캐시를 컨테이너로 실행하면 설치와 관리가 간편해집니다.