TestForge | Aidevops | 📊 Plogger ✍️ Blog 📚 Docs
plogger

AI DevOps Korea

AI 서비스 개발, 운영, 성능개선을 하나의 루프로 연결합니다

aidevops.kr에서 LLMOps, RAG, AI Agent, 관측성, 평가, 비용-성능 최적화를 실전 운영 관점으로 정리합니다.

Docker 기초부터 실전까지

· 수정 4월 16일
Docker 기초부터 실전까지 다이어그램
이 글에서 다루는 핵심 흐름, 아키텍처 구조, 주요 판단 포인트를 한눈에 이해할 수 있도록 정리한 그림입니다.
Docker는 개발 환경을 통일해주는 도구이기도 하지만, 더 본질적으로는 애플리케이션 실행 단위를 표준화하는 기술입니다. 실무에서 중요한 것은 `docker run` 명령을 외우는 것보다 이미지가 어떻게 만들어지고, 어떤 상태를 컨테이너 안에 두면 안 되는지 이해하는 것입니다.

컨테이너는 가상머신이 아니다

컨테이너는 운영체제를 통째로 가상화하는 것이 아니라, 커널을 공유하면서 프로세스를 격리해 실행합니다. 그래서 가볍고 빠르지만, 그만큼 파일 시스템과 네트워크, 볼륨, 프로세스 수명에 대한 이해가 중요합니다.

이미지 설계가 곧 운영 품질이다

FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:22-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/package*.json ./
RUN npm ci --omit=dev
CMD ["node", "dist/server.js"]

좋은 Dockerfile은 단순히 동작하는 파일이 아니라 아래 목표를 만족해야 합니다.

  • 이미지 크기를 불필요하게 키우지 않기
  • 빌드 캐시를 잘 활용하기
  • 실행 환경과 빌드 환경을 분리하기
  • 비밀값을 이미지 안에 굳히지 않기

멀티 스테이지 빌드는 이런 목적에 가장 자주 쓰이는 기본 패턴입니다.

자주 쓰는 명령보다 더 중요한 관점

docker build -t my-app .
docker run -p 3000:3000 my-app
docker ps
docker logs <container-id>
docker exec -it <container-id> sh

이 명령들을 아는 것은 출발점일 뿐입니다. 실제로는 다음 질문이 더 중요합니다.

  • 로그는 컨테이너 밖에서 수집되는가
  • 설정은 환경 변수로 주입되는가
  • 데이터는 볼륨에 저장되는가
  • 종료 신호를 받았을 때 애플리케이션이 정상 종료되는가

상태는 컨테이너 밖에 둬야 한다

컨테이너는 교체 가능한 실행 단위로 보는 편이 맞습니다. 그래서 업로드 파일, DB 데이터, 세션 파일처럼 유지되어야 하는 상태를 컨테이너 내부 파일 시스템에 두면 운영 중 교체와 스케일링이 어려워집니다.

  • 영속 데이터: 볼륨이나 외부 스토리지
  • 설정값: 환경 변수나 시크릿 관리
  • 로그: 표준 출력 기반 수집

개발과 운영 이미지의 목표는 다르다

개발 환경에서는 빠른 rebuild와 핫 리로드가 중요하고, 운영 환경에서는 작고 예측 가능한 이미지가 중요합니다. 하나의 Dockerfile로 두 목적을 모두 만족시키려 하지 말고, 필요하면 docker-compose나 별도 stage로 역할을 나누는 편이 좋습니다.

운영에서 자주 보는 문제

  • latest 태그만 사용해 어떤 이미지가 배포됐는지 추적이 안 되는 상황
  • health check 없이 컨테이너가 떠 있기만 하면 정상이라고 간주하는 구조
  • root 사용자로 그대로 실행하는 이미지
  • 이미지에 .env나 키 파일을 COPY하는 실수
  • 빌드 컨텍스트가 커서 CI 시간이 과도하게 길어지는 문제

추천하는 실무 습관

  • 버전 태그와 git sha를 함께 남기기
  • .dockerignore를 적극적으로 관리하기
  • health check와 readiness 관점을 분리하기
  • 이미지 스캔과 기본 보안 점검을 CI에 넣기
  • 로컬 실행 편의성과 운영 이미지 최적화를 따로 보기

정리

Docker의 핵심은 명령어가 아니라 실행 단위를 표준화하는 사고방식입니다. 이미지, 설정, 데이터, 로그, 종료 신호의 경계를 명확히 두기 시작하면 Docker는 단순한 개발 도구가 아니라 배포와 운영 안정성을 높이는 기반이 됩니다.

운영 환경에서 어려워지는 지점

  • Docker 기본기는 컨테이너 동작이 빌드 재현성, 런타임 격리, 배포 신뢰도까지 바꾸기 때문에 중요하다.
  • 초기 실수는 문법보다 이미지 크기, secret 처리, 무엇이 컨테이너 안에 있어야 하는지에 대한 오해에서 더 자주 나온다.
  • 컨테이너화는 좋은 경계를 강화하고 나쁜 경계를 드러낸다.

중요한 아키텍처 결정

  • 기본적으로 multi-stage build와 작은 runtime 이미지를 사용한다.
  • 설정은 외부화하고 빌드 결과물은 immutable하게 유지한다.
  • 컨테이너는 하나의 명확한 프로세스 책임 중심으로 설계한다.

실무 예시

실용적인 빌드는 앞단 stage에서 의존성을 해결하고 runtime에는 필요한 결과물만 싣는다.

FROM node:20 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist

피해야 할 안티패턴

  • 컨테이너를 디버그 도구와 가변 상태가 가득한 미니 가상머신처럼 쓰는 것.
  • secret과 환경별 값을 이미지에 굽는 것.
  • CI에서 layer cache와 rebuild 비용을 무시하는 것.

운영 체크리스트

  • 이미지 크기와 취약점 기준선을 정기적으로 점검한다.
  • 컨테이너 시작 시간과 readiness 동작을 검증한다.
  • Dockerfile을 리뷰 가능하고 결정론적으로 유지한다.
  • CI에서 이미지 재현성을 테스트한다.

최종 판단

Docker는 CLI 수준에서는 단순하지만 경계 설계에서는 냉정하다. 이미지를 편한 포장물이 아니라 immutable 배포 단위로 다룰 때 가장 큰 이익이 나온다.

Continue Reading

다음으로 읽기 좋은 글

다음 탐색

이 주제를 시스템 관점으로 더 이어서 보기