,

Docker 핵심 개념 — Dockerfile·Image·Container를 Class·인스턴스로 이해하기

한눈에 보기 — 이미 아는 개념으로 Docker 읽기

Docker의 세 개념은 객체지향 프로그래밍의 소스 코드 → 클래스 → 인스턴스 구조와 정확히 대응된다.

[ OOP ]                          [ Docker ]

소스 코드 (Class 정의)           Dockerfile
        ↓  컴파일/빌드                    ↓  docker build
Class (또는 실행파일)            Docker Image
        ↓  new                           ↓  docker run
Object (인스턴스)                Docker Container
OOPDocker특징
소스 코드 (Class 정의)Dockerfile텍스트 파일. 무엇을 담을지 정의만 함
컴파일/빌드docker build정의를 실행 가능한 형태로 굳힘
Class / 실행파일Docker Image불변(immutable). 실행 전 정적 산출물
newdocker run이미지에서 실제 프로세스를 띄움
Object (인스턴스)Docker Container살아있는 프로세스. 상태를 가짐

클래스 하나로 여러 인스턴스를 만들 수 있듯, 이미지 하나로 컨테이너를 여러 개 띄울 수 있다. 이미지 자체는 변하지 않는다.


Docker가 필요한 이유 — “내 컴퓨터에서는 됐는데”

가장 흔한 개발 장애물이다. 로컬에서는 잘 돌아가는데 서버에서는 실패한다. 원인은 대부분 환경 차이다 — Python 버전, 라이브러리 버전, 환경 변수, OS 설정.

Docker는 앱과 그 앱이 실행되기 위한 환경 전체를 하나의 이미지에 묶는다. 이미지를 가져다 실행하면, 어떤 머신에서 돌리든 동일한 환경이 보장된다.

# Docker 없이
개발자 PC:   Python 3.11, requests 2.28 → 잘 됨
서버:        Python 3.8,  requests 2.20 → 오류

# Docker 있으면
개발자 PC:   이미지 실행 → 잘 됨
서버:        동일 이미지 실행 → 동일하게 잘 됨

Dockerfile — 소스 코드

Dockerfile은 이미지를 어떻게 만들지를 서술하는 텍스트 파일이다. 클래스 정의처럼, 실행하기 전까지는 아무것도 하지 않는다.

# Dockerfile 예시 — Go 백엔드 서버

# 1. 베이스 이미지: 어떤 환경 위에서 시작할지
FROM golang:1.22-alpine AS builder

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

# 3. 의존성 먼저 복사 (캐시 최적화)
COPY go.mod go.sum ./
RUN go mod download

# 4. 소스코드 복사 후 빌드
COPY . .
RUN go build -o server ./cmd/server

# 5. 실행 이미지 (빌드 결과물만 가져감 — 경량화)
FROM alpine:3.19
WORKDIR /app
COPY --from=builder /app/server .

# 6. 컨테이너 시작 시 실행할 명령
CMD ["./server"]

각 줄(FROM, RUN, COPY)이 이미지의 레이어가 된다. 변경이 없는 레이어는 캐시되어 재빌드 속도가 빨라진다.

주요 명령어

명령어역할
FROM베이스 이미지 지정 (출발점)FROM python:3.11-slim
WORKDIR작업 디렉토리 설정WORKDIR /app
COPY호스트 파일을 이미지로 복사COPY . .
RUN빌드 시점에 명령 실행 (레이어 생성)RUN pip install -r requirements.txt
ENV환경 변수 설정ENV PORT=8080
EXPOSE컨테이너가 사용할 포트 명시 (문서화 목적)EXPOSE 8080
CMD컨테이너 시작 시 실행할 기본 명령CMD ["python", "app.py"]
ENTRYPOINTCMD와 유사. 덮어쓰기 어렵게 고정할 때ENTRYPOINT ["./server"]

docker build — 컴파일

Dockerfile을 읽어 이미지를 만드는 단계다. 소스코드를 컴파일하는 것과 같다 — 결과물은 실행 가능한 정적 산출물(이미지)이다.

# 기본 빌드
docker build -t my-app:1.0.0 .
#            ↑ 이미지 이름:태그   ↑ Dockerfile 위치 (현재 디렉토리)

# 결과 확인
docker images
# REPOSITORY   TAG       IMAGE ID       SIZE
# my-app       1.0.0     a1b2c3d4e5f6   28MB

빌드된 이미지는 불변(immutable)이다. 클래스 파일처럼, 이미지 자체는 실행해도 변하지 않는다. 컨테이너를 아무리 많이 띄우고 수정해도 원본 이미지는 그대로다.


Docker Image — 클래스

이미지는 컨테이너의 설계도다. OS, 런타임, 라이브러리, 앱 코드, 설정이 모두 담긴 레이어 스택이다.

# 이미지 레이어 구조
Layer 4: COPY . .            ← 앱 소스코드
Layer 3: RUN go mod download ← 의존성
Layer 2: WORKDIR /app        ← 디렉토리 설정
Layer 1: FROM golang:1.22    ← 베이스 OS + Go 런타임

# 변경된 레이어 이후만 재빌드 → 캐시 효율

이미지는 Docker Hub, GCR(Google Container Registry), ECR(AWS) 같은 레지스트리에 올려두고 어디서든 당겨서 쓸 수 있다. npm install로 패키지를 가져오듯, docker pull로 이미지를 가져온다.


docker run — new, 컨테이너 생성

이미지에서 실제 프로세스를 띄우는 단계다. new ClassName()으로 인스턴스를 만드는 것과 같다.

# 기본 실행
docker run my-app:1.0.0

# 포트 바인딩 (호스트:컨테이너)
docker run -p 8080:8080 my-app:1.0.0

# 백그라운드 실행 + 이름 지정
docker run -d --name api-server -p 8080:8080 my-app:1.0.0

# 환경 변수 주입
docker run -d   -e DB_HOST=postgres   -e DB_PORT=5432   -p 8080:8080   my-app:1.0.0

# 같은 이미지로 컨테이너 여러 개 (클래스 → 여러 인스턴스)
docker run -d -p 8081:8080 --name api-1 my-app:1.0.0
docker run -d -p 8082:8080 --name api-2 my-app:1.0.0
docker run -d -p 8083:8080 --name api-3 my-app:1.0.0

Docker Container — 인스턴스

컨테이너는 이미지에서 실행된 프로세스다. 자체 파일시스템, 네트워크, 프로세스 공간을 가지며, 호스트 OS와 격리된다.

# 실행 중인 컨테이너 목록
docker ps
# CONTAINER ID  IMAGE          STATUS    PORTS                  NAMES
# a1b2c3d4      my-app:1.0.0   Up 2min   0.0.0.0:8080->8080/tcp api-server

# 컨테이너 내부 접속 (디버깅)
docker exec -it api-server sh

# 로그 확인
docker logs -f api-server

# 중지 / 삭제
docker stop api-server
docker rm   api-server

컨테이너는 기본적으로 임시(ephemeral)다. 컨테이너가 삭제되면 내부에서 쓴 파일도 사라진다. 데이터를 유지하려면 볼륨(Volume)을 마운트한다.

# 볼륨 마운트 — 호스트의 ./data가 컨테이너 /app/data와 연결됨
docker run -d   -v $(pwd)/data:/app/data   my-app:1.0.0

docker-compose — 여러 컨테이너를 한 번에

실제 서비스는 앱 서버 하나만으로 돌아가지 않는다. DB, 캐시, 메시지 큐가 함께 필요하다. docker-compose는 여러 컨테이너를 하나의 파일로 정의하고 한 번에 띄운다.

# docker-compose.yml
version: '3.9'
services:

  api:
    build: .                    # 현재 디렉토리 Dockerfile로 빌드
    ports:
      - "8080:8080"
    environment:
      - DB_HOST=postgres
      - REDIS_HOST=redis
    depends_on:
      - postgres
      - redis

  postgres:
    image: postgres:16-alpine   # 기존 이미지 사용
    environment:
      POSTGRES_DB:       mydb
      POSTGRES_USER:     admin
      POSTGRES_PASSWORD: secret
    volumes:
      - pg_data:/var/lib/postgresql/data   # 데이터 영구 보존

  redis:
    image: redis:7-alpine

volumes:
  pg_data:
# 전체 스택 시작
docker compose up -d

# 전체 종료
docker compose down

# 로그 통합 확인
docker compose logs -f

핵심 개념 정리

개념한 줄 설명OOP 대응
Dockerfile이미지 빌드 명세서 (텍스트)소스 코드 / Class 정의
Image불변 실행 가능 패키지 (레이어 스택)컴파일된 Class / .class 파일
Container이미지에서 실행된 살아있는 프로세스Object (인스턴스)
Registry이미지 저장소 (Docker Hub, GCR 등)패키지 저장소 (npm, Maven)
Volume컨테이너 밖에 데이터를 영구 저장외부 데이터베이스 / 파일시스템
Network컨테이너 간 통신 채널객체 간 메서드 호출 경로
docker-compose여러 컨테이너를 한 파일로 정의·실행여러 클래스를 묶은 애플리케이션 조립

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

# ── 이미지 ──────────────────────────────────────
docker build -t name:tag .        # Dockerfile로 이미지 빌드
docker images                     # 이미지 목록
docker pull nginx:alpine          # 레지스트리에서 이미지 가져오기
docker push name:tag              # 레지스트리에 이미지 올리기
docker rmi name:tag               # 이미지 삭제

# ── 컨테이너 ─────────────────────────────────────
docker run -d -p 8080:8080 name:tag  # 이미지로 컨테이너 실행
docker ps                            # 실행 중인 컨테이너
docker ps -a                         # 전체 컨테이너 (중지 포함)
docker stop                      # 컨테이너 중지
docker rm                        # 컨테이너 삭제
docker logs -f                   # 로그 스트리밍
docker exec -it  sh              # 컨테이너 내부 접속

# ── compose ──────────────────────────────────────
docker compose up -d          # 전체 스택 백그라운드 시작
docker compose down           # 전체 종료 (컨테이너·네트워크 삭제)
docker compose down -v        # 볼륨까지 삭제
docker compose logs -f        # 전체 로그
docker compose ps             # 서비스 상태

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다