View

반응형

Docker란? — 왜 모든 개발자가 Docker를 쓸까

“내 컴퓨터에선 되는데요?”라는 말, 개발자라면 한 번쯤 들어보셨을 겁니다. Docker는 바로 이 문제를 해결하기 위해 탄생한 컨테이너 기반 가상화 플랫폼입니다.

Docker는 애플리케이션과 그 실행에 필요한 모든 환경(라이브러리, 설정 파일, 런타임 등)을 하나의 컨테이너에 패키징합니다. 이 컨테이너는 어떤 환경에서든 동일하게 동작하기 때문에, 개발·테스트·프로덕션 환경 간의 차이로 인한 문제를 원천적으로 차단합니다.

가상머신(VM) vs Docker 컨테이너

Docker를 이해하려면 먼저 기존 가상머신과의 차이를 알아야 합니다.

가상머신과 Docker 컨테이너의 아키텍처 차이를 보여주는 다이어그램
가상머신 vs Docker 컨테이너 아키텍처 비교
구분 가상머신 (VM) Docker 컨테이너
구조 하이퍼바이저 + 게스트 OS Docker Engine (커널 공유)
크기 GB 단위 MB 단위
시작 시간 분 단위 초 단위
리소스 사용 무겁다 (OS 전체 로드) 가볍다 (필요한 것만)
이식성 제한적 뛰어남
Docker는 2013년 등장 이후 현재까지 컨테이너 기술의 표준으로 자리잡았습니다. 2026년 현재 거의 모든 클라우드 서비스와 CI/CD 파이프라인에서 Docker를 사용합니다.

Docker를 써야 하는 이유

1. 환경 일관성 — 개발, 테스트, 프로덕션 환경이 완전히 동일합니다.

2. 빠른 배포 — 이미지를 빌드해두면 어디서든 몇 초 만에 실행할 수 있습니다.

3. 리소스 효율 — VM 대비 훨씬 가볍고, 하나의 서버에 더 많은 서비스를 올릴 수 있습니다.

4. 격리성 — 각 컨테이너는 독립된 환경에서 실행되어 서로 영향을 주지 않습니다.

5. 버전 관리 — 이미지에 태그를 달아 쉽게 롤백하거나 특정 버전을 재현할 수 있습니다.

Docker 핵심 개념 3가지 — 이미지, 컨테이너, 레지스트리

Docker를 사용하기 전에 반드시 알아야 할 3가지 핵심 개념이 있습니다. 이 개념만 이해하면 Docker의 전체 흐름이 한눈에 보입니다.

Dockerfile에서 이미지를 빌드하고 컨테이너로 실행하는 Docker 워크플로우 다이어그램
Docker 워크플로우 — Dockerfile → 이미지 → 컨테이너

1. 이미지 (Image)

Docker 이미지는 컨테이너를 만들기 위한 읽기 전용 템플릿입니다. 애플리케이션 코드, 런타임, 라이브러리, 환경 변수, 설정 파일 등 실행에 필요한 모든 것을 포함합니다.

비유하면, 이미지는 붕어빵 틀과 같습니다. 틀 하나로 여러 개의 붕어빵(컨테이너)을 만들 수 있죠.

2. 컨테이너 (Container)

컨테이너는 이미지를 실행한 인스턴스입니다. 이미지가 설계도라면, 컨테이너는 그 설계도로 지은 실제 건물입니다.

각 컨테이너는 독립된 파일시스템, 네트워크, 프로세스를 가지며 서로 격리되어 실행됩니다.

이미지를 '설계도', 컨테이너를 '실제 건물'로 비유하면 이해하기 쉽습니다. 하나의 설계도(이미지)로 여러 건물(컨테이너)을 지을 수 있습니다.

3. 레지스트리 (Registry)

레지스트리는 Docker 이미지를 저장하고 배포하는 저장소입니다. 가장 대표적인 퍼블릭 레지스트리가 Docker Hub(hub.docker.com)이며, nginx, postgres, node 등 공식 이미지를 무료로 다운로드할 수 있습니다.

기업 환경에서는 프라이빗 레지스트리(AWS ECR, Google GCR, GitHub Container Registry 등)를 사용하여 내부 이미지를 안전하게 관리합니다.

Docker 설치하기 — Windows / Mac / Linux

Docker 설치는 운영체제에 따라 방법이 다릅니다. 가장 쉬운 방법은 Docker Desktop을 사용하는 것이며, Windows와 Mac에서는 이 방법을 권장합니다.

Windows 설치 (Docker Desktop)

사전 요구사항: Windows 10/11 (64비트), WSL 2 활성화 필수

1. 먼저 PowerShell을 관리자 권한으로 열고 WSL 2를 설치합니다.

wsl --install

2. 컴퓨터를 재부팅합니다.

3. Docker Desktop 공식 사이트에서 설치 파일을 다운로드합니다.

Docker Desktop 공식 웹사이트의 다운로드 페이지 스크린샷
Docker Desktop 공식 다운로드 페이지

4. 다운로드한 Docker Desktop Installer.exe를 실행하고 안내에 따라 설치합니다.

5. 설치 완료 후 Docker Desktop을 실행하면, 시스템 트레이에 고래 아이콘이 나타납니다.

Windows에서는 WSL 2가 필수입니다. Docker Desktop 설치 전에 WSL 2를 먼저 활성화해주세요. PowerShell(관리자)에서 wsl --install 명령어를 실행하면 됩니다.

Mac 설치 (Docker Desktop)

1. Docker Desktop 공식 사이트에서 Mac용 설치 파일(.dmg)을 다운로드합니다.

2. Apple Silicon(M1~M5)과 Intel 칩 중 본인의 Mac에 맞는 버전을 선택하세요.

3. .dmg 파일을 열고 Docker 아이콘을 Applications 폴더로 드래그합니다.

4. Applications에서 Docker를 실행합니다.

Linux 설치 (Docker Engine)

Linux에서는 Docker Engine을 직접 설치하는 방법이 일반적입니다. Ubuntu/Debian 기준으로 설명합니다.

# Ubuntu/Debian에 Docker Engine 설치
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# 저장소 추가
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo \"${UBUNTU_CODENAME:-$VERSION_CODENAME}\") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

설치 확인

설치가 완료되면 터미널(또는 명령 프롬프트)에서 다음 명령어를 입력하여 정상 설치를 확인합니다.

# 설치 확인
docker --version
docker compose version

# 테스트 실행
docker run hello-world

docker run hello-world 명령어를 실행하면 Docker Hub에서 hello-world 이미지를 자동으로 다운로드하고, "Hello from Docker!" 메시지가 출력됩니다. 이 메시지가 보이면 Docker가 정상적으로 설치된 것입니다.

Docker 기본 명령어 총정리 — 이것만 알면 시작할 수 있다

Docker 설치가 끝났다면, 이제 핵심 명령어를 익혀보겠습니다. Docker를 처음 접하는 분들은 아래 명령어만 먼저 익히면 충분합니다.

이미지 관련 명령어

# 이미지 관련 명령어
docker pull nginx              # 이미지 다운로드
docker images                  # 이미지 목록 확인
docker rmi nginx               # 이미지 삭제
docker image prune             # 사용하지 않는 이미지 정리

컨테이너 실행 및 관리

# 컨테이너 실행
docker run -d --name my-nginx -p 8080:80 nginx
# -d: 백그라운드 실행
# --name: 컨테이너 이름 지정
# -p 8080:80: 호스트 8080 포트를 컨테이너 80 포트에 연결

# 컨테이너 관리
docker ps                      # 실행 중인 컨테이너 목록
docker ps -a                   # 모든 컨테이너 목록 (중지 포함)
docker stop my-nginx           # 컨테이너 중지
docker start my-nginx          # 컨테이너 시작
docker restart my-nginx        # 컨테이너 재시작
docker rm my-nginx             # 컨테이너 삭제

위 예제에서 docker run -d --name my-nginx -p 8080:80 nginx를 실행하면, Nginx 웹 서버가 백그라운드에서 실행됩니다. 브라우저에서 http://localhost:8080에 접속하면 Nginx 기본 페이지를 확인할 수 있습니다.

docker run은 pull + create + start를 한 번에 실행합니다. 이미지가 로컬에 없으면 자동으로 Docker Hub에서 다운로드합니다.

디버깅 명령어

# 컨테이너 내부 접속
docker exec -it my-nginx bash
# -i: 표준 입력 유지
# -t: 터미널 할당

# 로그 확인
docker logs my-nginx           # 전체 로그
docker logs -f my-nginx        # 실시간 로그 (tail -f와 유사)

docker exec -it는 실행 중인 컨테이너 안에 들어가서 직접 명령어를 실행할 수 있는 매우 유용한 명령어입니다. 문제 해결이나 설정 확인 시 자주 사용합니다.

자주 쓰는 명령어 한눈에 보기

명령어 설명
docker pull 이미지 다운로드
docker run 컨테이너 생성 및 실행
docker ps 실행 중 컨테이너 목록
docker stop / start 컨테이너 중지 / 시작
docker exec -it 컨테이너 내부 접속
docker logs 로그 확인
docker rm / rmi 컨테이너 / 이미지 삭제

Dockerfile 작성법 — 나만의 Docker 이미지 만들기

Docker Hub에 있는 공식 이미지를 그대로 사용할 수도 있지만, 대부분의 경우 자신의 애플리케이션을 담은 커스텀 이미지를 만들어야 합니다. 이때 사용하는 것이 Dockerfile입니다.

Dockerfile이란?

Dockerfile은 Docker 이미지를 만들기 위한 설정 파일입니다. 어떤 베이스 이미지를 사용하고, 어떤 파일을 복사하고, 어떤 명령어를 실행할지를 순서대로 기술합니다.

Dockerfile 명령어가 이미지 레이어를 쌓아가는 구조를 보여주는 다이어그램
Dockerfile의 레이어 구조 — 각 명령어가 하나의 레이어를 생성합니다

위 다이어그램에서 보듯이, Dockerfile의 각 명령어는 하나의 레이어(Layer)를 생성합니다. Docker는 이 레이어를 캐시하여 빌드 속도를 최적화합니다.

주요 Dockerfile 명령어

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

실전 Dockerfile 예제 (Node.js)

# Node.js 애플리케이션 Dockerfile 예제
FROM node:20-alpine

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

# 의존성 파일 먼저 복사 (캐시 활용)
COPY package*.json ./
RUN npm install --production

# 소스 코드 복사
COPY . .

# 포트 노출
EXPOSE 3000

# 실행 명령
CMD ["node", "server.js"]
package*.json을 먼저 복사하고 npm install을 실행하는 이유는 Docker의 레이어 캐시를 활용하기 위해서입니다. 소스 코드만 변경되면 npm install 레이어는 캐시에서 재사용됩니다.

빌드 및 실행

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

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

# 브라우저에서 http://localhost:3000 접속하여 확인

docker build -t my-node-app .에서 마지막 점(.)은 현재 디렉토리를 빌드 컨텍스트로 사용하겠다는 의미입니다. Dockerfile이 현재 디렉토리에 있어야 합니다.

Docker Compose — 여러 컨테이너를 한 번에 관리하기

실제 프로젝트에서는 웹 서버, 앱 서버, DB, 캐시 등 여러 서비스가 함께 동작합니다. 이때 각각 docker run으로 실행하면 관리가 매우 복잡해집니다.

Docker Compose는 여러 컨테이너를 하나의 YAML 파일로 정의하고, 한 번의 명령으로 전체를 관리할 수 있게 해주는 도구입니다.

Docker Compose로 Nginx, Node.js, PostgreSQL, Redis를 연결한 멀티 컨테이너 구성도
Docker Compose 멀티 컨테이너 아키텍처 예시

docker-compose.yml 작성하기

아래는 Node.js 앱 + PostgreSQL + Redis로 구성된 실전 예제입니다.

# docker-compose.yml (compose.yml도 가능)
services:
  # 웹 애플리케이션
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/mydb
      - REDIS_URL=redis://cache:6379
    depends_on:
      - db
      - cache
    volumes:
      - .:/app
      - /app/node_modules

  # PostgreSQL 데이터베이스
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - db-data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

  # Redis 캐시
  cache:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  db-data:
Docker Compose V2부터는 docker-compose 대신 docker compose (하이픈 없이)를 사용합니다. Docker Desktop에 기본 포함되어 있어 별도 설치가 필요 없습니다.

핵심 속성 설명

build — Dockerfile이 있는 경로를 지정합니다. .이면 현재 디렉토리입니다.

image — Docker Hub의 공식 이미지를 사용할 때 지정합니다.

ports호스트:컨테이너 형식으로 포트를 매핑합니다.

environment — 환경 변수를 설정합니다.

depends_on — 서비스 간 의존성을 정의합니다. db가 먼저 시작된 후 app이 시작됩니다.

volumes — 데이터를 영구적으로 보존하거나, 호스트와 파일을 공유합니다.

Docker Compose 주요 명령어

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

# 로그 확인
docker compose logs -f

# 특정 서비스만 재시작
docker compose restart app

# 전체 서비스 중지 및 삭제
docker compose down

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

docker compose up -d 한 번이면 앱, DB, 캐시 서버가 한꺼번에 올라갑니다. 개발 환경을 누구나 동일하게 구축할 수 있어 팀 협업에 매우 유리합니다.

멀티 스테이지 빌드 — Docker 이미지 크기를 10배 줄이는 방법

일반적인 방법으로 Docker 이미지를 빌드하면, 빌드 도구와 의존성까지 모두 포함되어 이미지 크기가 1GB가 넘는 경우가 흔합니다. 이를 해결하는 것이 멀티 스테이지 빌드입니다.

멀티 스테이지 빌드란?

하나의 Dockerfile 안에서 여러 개의 FROM 문을 사용하여, 빌드 단계와 실행 단계를 분리하는 기법입니다. 빌드 결과물(artifact)만 최종 이미지에 복사하므로, 불필요한 빌드 도구와 소스 코드를 제거할 수 있습니다.

멀티 스테이지 빌드에서 Build Stage와 Production Stage를 분리하는 과정 다이어그램
멀티 스테이지 빌드 — 빌드 단계의 결과물만 프로덕션 이미지에 복사

실전 예제: React 앱 멀티 스테이지 빌드

# ---- Build Stage ----
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# ---- Production Stage ----
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Build Stage에서는 Node.js 환경에서 앱을 빌드합니다. Production Stage에서는 경량 Nginx 이미지에 빌드 결과물(dist/)만 복사합니다. 빌드에 사용된 Node.js, node_modules, 소스 코드는 최종 이미지에 포함되지 않습니다.

이미지 크기 비교

$ docker images
REPOSITORY          TAG       SIZE
my-app-normal       latest    1.2GB    # 일반 빌드
my-app-optimized    latest    80MB     # 멀티 스테이지 빌드

같은 애플리케이션인데 이미지 크기가 약 15배 차이납니다. 이미지가 작을수록 배포 속도가 빨라지고, 보안 공격 표면도 줄어듭니다.

프로덕션 배포 시에는 반드시 멀티 스테이지 빌드를 사용하세요. 이미지 크기가 작을수록 배포 속도가 빨라지고, 보안 취약점도 줄어듭니다.

실전 예제 — Spring Boot + React 앱 컨테이너화

이제 실제 프로젝트에서 Docker를 어떻게 활용하는지 전체 예제를 통해 살펴보겠습니다. React 프론트엔드 + Spring Boot 백엔드 + PostgreSQL 구성을 Docker로 컨테이너화합니다.

프로젝트 구조

React 프론트엔드와 Spring Boot 백엔드를 Docker로 구성한 프로젝트 디렉토리 구조
프론트엔드 + 백엔드 Docker 프로젝트 구조

백엔드 Dockerfile (Spring Boot)

# backend/Dockerfile (Spring Boot)
FROM eclipse-temurin:21-jdk-alpine AS build
WORKDIR /app
COPY build.gradle settings.gradle ./
COPY gradle/ gradle/
COPY gradlew ./
RUN chmod +x gradlew && ./gradlew dependencies --no-daemon
COPY src/ src/
RUN ./gradlew bootJar --no-daemon

FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=build /app/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

Spring Boot도 멀티 스테이지 빌드를 적용했습니다. Build Stage에서는 JDK로 빌드하고, Production Stage에서는 더 가벼운 JRE만 사용합니다. 의존성을 먼저 다운로드하여 캐시를 활용하는 것이 포인트입니다.

Docker Compose로 전체 연결

# docker-compose.yml
services:
  frontend:
    build: ./frontend
    ports:
      - "80:80"
    depends_on:
      - backend

  backend:
    build: ./backend
    ports:
      - "8080:8080"
    environment:
      - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/mydb
      - SPRING_DATASOURCE_USERNAME=user
      - SPRING_DATASOURCE_PASSWORD=pass
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:
실제 프로덕션에서는 환경 변수를 .env 파일로 분리하고, 비밀번호는 Docker Secrets를 사용하는 것을 권장합니다.

실행하기

# 전체 프로젝트 한 번에 빌드 및 실행
docker compose up -d --build

# 프론트엔드: http://localhost
# 백엔드 API: http://localhost:8080
# 로그 확인: docker compose logs -f

docker compose up -d --build 명령 하나로 프론트엔드, 백엔드, DB가 모두 올라갑니다. 새 팀원이 합류했을 때, Git clone 후 이 명령 하나만 실행하면 전체 개발 환경이 세팅됩니다.

Docker 실무 꿀팁 5가지

Docker를 실무에서 사용하다 보면 알아두면 유용한 팁들이 있습니다. 아래 5가지만 기억하면 Docker를 훨씬 효율적으로 사용할 수 있습니다.

팁 1. 미사용 리소스 정리

Docker를 오래 사용하면 중지된 컨테이너, 미사용 이미지, 네트워크가 쌓여 디스크를 차지합니다.

# 사용하지 않는 리소스 한 번에 정리
docker system prune -a

# 디스크 사용량 확인
docker system df
docker system prune -a는 모든 미사용 이미지를 삭제합니다. 프로덕션 서버에서는 신중하게 사용하세요.

팁 2. 컨테이너 모니터링

# 컨테이너 리소스 실시간 모니터링
docker stats

CPU, 메모리, 네트워크 I/O를 실시간으로 확인할 수 있습니다. 성능 이슈가 발생했을 때 가장 먼저 확인하세요.

팁 3. 이미지 레이어 분석

# 이미지 히스토리 확인 (각 레이어 크기)
docker history my-app

어떤 레이어가 이미지 크기를 키우는지 한눈에 파악할 수 있어, 이미지 최적화에 유용합니다.

팁 4. .dockerignore 활용

.gitignore처럼 빌드 컨텍스트에서 제외할 파일을 지정합니다. 불필요한 파일이 포함되면 빌드 속도가 느려지고 이미지 크기가 커집니다.

node_modules
.git
.env
*.md
dist
build
.DS_Store
*.log

팁 5. 볼륨으로 데이터 영구 보존

컨테이너를 삭제하면 내부 데이터도 함께 사라집니다. DB처럼 데이터를 유지해야 하는 서비스에는 반드시 볼륨(Volume)을 사용하세요.

# 볼륨 생성
docker volume create my-data

# 볼륨 마운트하여 컨테이너 실행
docker run -d -v my-data:/var/lib/postgresql/data postgres:16-alpine

# 볼륨 목록 확인
docker volume ls

볼륨은 컨테이너가 삭제되어도 데이터가 유지되며, 여러 컨테이너에서 공유할 수도 있습니다.

자주 묻는 질문 (FAQ)

Q. Docker Desktop은 무료인가요?

개인 사용, 교육, 소규모 기업(직원 250명 미만, 연 매출 1천만 달러 미만), 오픈소스 프로젝트에서는 무료입니다. 그 외 기업 환경에서는 Pro, Team, Business 유료 플랜을 사용해야 합니다.

Q. Docker와 가상머신(VM)의 차이는 무엇인가요?

VM은 하이퍼바이저 위에 전체 게스트 OS를 설치하므로 무겁고 느립니다. 반면 Docker 컨테이너는 호스트 OS의 커널을 공유하므로 훨씬 가볍고(MB 단위), 시작 시간도 초 단위로 빠릅니다.

Q. Docker Compose와 Kubernetes의 차이는 무엇인가요?

Docker Compose는 단일 서버에서 여러 컨테이너를 관리하는 도구이고, Kubernetes(K8s)는 여러 서버에 걸쳐 컨테이너를 오케스트레이션하는 플랫폼입니다. 개발/테스트 환경에서는 Compose, 대규모 프로덕션에서는 K8s를 사용합니다.

Q. Docker 이미지와 컨테이너의 차이가 뭔가요?

이미지는 애플리케이션 실행에 필요한 모든 것(코드, 런타임, 라이브러리)을 담은 '읽기 전용 템플릿'이고, 컨테이너는 이 이미지를 실행한 '인스턴스'입니다. 하나의 이미지로 여러 컨테이너를 만들 수 있습니다.

Q. Windows에서 Docker가 느린데 어떻게 해야 하나요?

WSL 2 백엔드를 사용하고 있는지 확인하세요. Docker Desktop 설정에서 'Use the WSL 2 based engine'을 체크하세요. 또한 프로젝트 파일을 WSL 파일시스템(\\wsl$\Ubuntu\home)에 두면 I/O 성능이 크게 향상됩니다.

728x90
반응형
Share Link
reply
«   2026/03   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31