플랫폼, 데브옵스와 클라우드

Docker 기초

meellon 2026. 6. 20. 07:00

학습 목표

Dockerfile로 이미지를 정의할 수 있다.

이미지 레이어빌드 캐시가 속도·크기에 미치는 영향을 설명할 수 있다.

docker build / docker run의 주요 옵션을 사용할 수 있다.

볼륨bind mount로 데이터를 유지할 수 있다.

포트 매핑으로 호스트에서 컨테이너 서비스에 접근할 수 있다.

문제 상황

  • 로컬에선 되는데 서버에 올리면 Python 버전·라이브러리가 다르다
    • "내 머신에선 됐는데"를 줄이려면 이미지로 환경을 고정해야 한다
  • Dockerfile을 고칠 때마다 pip install이 10분씩 돈다
    • 캐시를 왜 못 타는지 모른다
  • 컨테이너를 지우면 DB 데이터가 사라진다
    • 볼륨 없이 실행한 탓이다
  • docker run 했는데 localhost:8080이 안 열린다
    • -p 매핑을 안 했거나 앱이 0.0.0.0이 아닌 127.0.0.1만 listen

컨테이너 개념·VM 비교를 봤다. 이번 편은 Docker CLI로 이미지를 만들고 실행하는 실무 흐름이다.

1. 이미지와 Dockerfile

이미지 — 읽기 전용 레이어 스택 + 메타데이터. 컨테이너는 그 위에 쓰기 가능 레이어를 얹은 실행 인스턴스.

FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
지시어 역할
FROM 베이스 이미지
WORKDIR 이후 명령의 작업 디렉터리
COPY / ADD 파일 복사 (ADD는 URL·tar 자동 해제 — 보통 COPY 선호)
RUN 빌드 시 명령 (레이어 생성)
EXPOSE 문서화용 포트 (실제 publish는 run -p)
CMD / ENTRYPOINT 컨테이너 시작 시 기본 명령
docker build -t my-app:1.0 .
docker images

2. 레이어와 빌드 캐시

각 Dockerfile instruction은 (대부분) 새 레이어를 만든다. 변경되지 않은 상위 레이어는 캐시 재사용.

  • 자주 바뀌는 것(COPY . .)은 아래가 아니라 에 둔다
  • 의존성 설치(requirements.txt + RUN pip)는 소스보다 먼저 — 소스만 바뀌면 pip 캐시 hit
  • .dockerignorenode_modules, .git 제외 — 불필요한 캐시 무효화 방지
# 나쁜 예: 소스 변경마다 pip 전체 재실행
COPY . .
RUN pip install -r requirements.txt

# 좋은 예
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .

3. docker run

docker run -d --name api \
  -p 8080:8000 \
  -v app-data:/var/lib/app \
  -e DATABASE_URL=postgres://... \
  my-app:1.0

옵션 의미
-d detached — 백그라운드
--name 컨테이너 이름
-p host:container 포트 publish
-v name:/path named volume
-v /host/path:/container/path bind mount
-e 환경 변수
--rm 종료 시 컨테이너 삭제
docker ps          # 실행 중
docker logs api    # stdout/stderr
docker exec -it api sh   # 셸 진입
docker stop api && docker rm api

4. 볼륨과 데이터 유지

컨테이너 쓰기 레이어는 컨테이너 삭제 시 사라진다. DB·업로드 파일은 볼륨 또는 bind mount로 분리한다.

방식 특징
Named volume Docker가 경로 관리, 이식·백업 용이
Bind mount 호스트 디렉터리 직접 연결, 개발 시 핫 리로드
tmpfs 메모리 — 영속 불필요·민감 데이터
docker volume create pgdata
docker run -d -v pgdata:/var/lib/postgresql/data postgres:16
  • 프로덕션 DB는 보통 관리형 RDS 등; 컨테이너 볼륨은 개발·CI·stateful 워크로드에 한정
  • 권한: 호스트 UID와 컨테이너 user mismatch 시 쓰기 실패 — USER·chown 조정

5. 포트와 네트워크 기초

  • 컨테이너 내부 EXPOSE 8000만으로는 호스트에서 접근 불가
  • -p 8080:8000 — 호스트 8080 → 컨테이너 8000
  • 앱은 0.0.0.0 에 bind (컨테이너 내부 127.0.0.1만 listen하면 외부에서 unreachable)
  • 기본 bridge 네트워크: 컨테이너끼리는 이름으로 통신하려면 user-defined network + --network
docker network create appnet
docker run -d --network appnet --name db postgres:16
docker run -d --network appnet -p 8080:8000 --name api my-app:1.0
# api → db:5432 (서비스 이름 = DNS)

6. 정리

  • Dockerfile로 재현 가능한 이미지를 만든다
  • 레이어 순서가 빌드 시간을 좌우한다
  • run은 포트·볼륨·환경을 붙여 실행 환경을 완성한다
  • 데이터는 컨테이너 밖(볼륨)에 둔다

다음에 다룰 것

  • 컨테이너 런타임과 보안
  • namespace, cgroup, capabilities, rootless

해당 내용은 Docker 공식 문서(https://docs.docker.com) 및 컨테이너 실무 관행을 기반으로 합니다.

'플랫폼, 데브옵스와 클라우드' 카테고리의 다른 글

Pod와 Deployment  (0) 2026.06.23
Kubernetes 개요  (0) 2026.06.22
컨테이너 런타임과 보안  (0) 2026.06.21
컨테이너란 무엇인가  (0) 2026.06.19
플랫폼 오리엔테이션  (0) 2026.06.18