8장: Dockerfile을 통한 이미지 자동 빌드
이 장에서는 Docker 이미지를 자동으로 빌드하기 위한 표준 도구인 Dockerfile을 다룹니다. 앞서 7장까지는 이미지를 수동으로 생성하는 과정을 경험하면서, 이미지와 레이어, 메타데이터의 개념을 익혔습니다. 이제는 수동 단계를 자동화하고, 코드로 관리할 수 있는 Dockerfile을 통해 더 쉽게, 더 일관성 있게, 그리고 더 유지 보수 가능하게 이미지를 빌드하는 방법을 배우게 됩니다.
Dockerfile 빌드의 기본 개념
Dockerfile은 텍스트 기반의 스크립트 파일로, 이미지를 빌드하기 위해 수행해야 할 커맨드와 설정을 단계별로 정의합니다. 빌더는 Dockerfile에 적힌 명령을 위에서부터 아래로 순서대로 실행하며, 각 명령은 새로운 레이어를 형성합니다. 파일 시스템 변경, 환경 변수 설정, 디폴트 실행 명령, 파일 복사 등 대부분의 작업을 Dockerfile 명령으로 선언할 수 있습니다.
Dockerfile을 사용하면 다음과 같은 장점이 있습니다.
- 재현성: Dockerfile에 정의된 명령을 기반으로 동일한 이미지를 언제든 다시 빌드할 수 있어, 결과가 예측 가능하고 일관됩니다.
- 버전 관리 용이성: Dockerfile은 텍스트 파일이므로 Git 같은 버전 관리 시스템으로 변경 사항 추적, 리뷰, 협업이 가능합니다.
- 캐시 활용: Docker 빌드는 이전 빌드 단계의 결과를 캐시하여, 변경 사항이 없는 단계는 재실행하지 않고 빠르게 빌드할 수 있습니다.
- 협업 및 배포 용이성: 팀원들과 Dockerfile을 공유하면, 누구나 같은 환경에서 동일한 이미지를 빌드할 수 있으며, 이미지 배포나 업데이트 과정이 단순해집니다.
Git 설치 예제로 본 Dockerfile 활용
7장에서 Git을 ubuntu 기반 이미지에 설치하기 위해 직접 컨테이너를 띄우고 apt-get으로 설치한 뒤 commit으로 이미지를 생성했습니다. 이제 동일한 작업을 Dockerfile로 자동화할 수 있습니다.
# Dockerfile
FROM ubuntu:latest
LABEL maintainer="dia@allingeek.com"
RUN apt-get update && apt-get install -y git
ENTRYPOINT ["git"]
이 Dockerfile은 다음과 같은 의미를 갖습니다.
- FROM ubuntu:latest: 최신 Ubuntu 이미지를 베이스로 사용합니다.
- LABEL maintainer: 이미지 유지 관리자를 표시하는 메타데이터를 추가합니다.
- RUN apt-get ...: 컨테이너 내부에서 apt-get 명령을 실행하여 git 패키지를 설치합니다.
- ENTRYPOINT ["git"]: 컨테이너가 시작될 때 git 명령을 기본 진입점으로 사용합니다.
이제 docker image build --tag ubuntu-git:auto .
명령으로 이미지를 빌드하면, 빌더가 Dockerfile에 정의된 명령을 순차적으로 실행하여 이미지가 생성됩니다. 결과 이미지를 실행하면 git 명령이 곧바로 실행되는 컨테이너를 얻을 수 있습니다.
Dockerfile의 주요 명령들
Dockerfile에서 자주 사용하는 명령을 간략히 살펴보겠습니다.
- FROM: 베이스 이미지 지정. 모든 Dockerfile은 반드시 FROM으로 시작해야 합니다.
- RUN: 컨테이너 내부에서 명령을 실행하고, 그 결과를 레이어로 커밋합니다.
- CMD: 컨테이너 실행 시 기본으로 실행할 명령이나 아규먼트를 지정합니다. ENTRYPOINT와 결합하여 실행 방식을 정의합니다.
- ENTRYPOINT: 컨테이너 시작 시 항상 실행할 명령을 지정합니다.
- ENV: 환경 변수를 설정합니다.
- LABEL: 이미지에 메타데이터(키-값 쌍)를 추가합니다.
- ADD / COPY: 로컬 파일이나 원격 URL, 또는 tar 아카이브를 이미지에 추가합니다. COPY는 로컬 파일을 단순히 복사하고, ADD는 URL에서 가져오거나 tar 아카이브를 해제하는 등의 추가 기능이 있습니다.
- WORKDIR: 작업 디렉토리를 설정합니다.
- EXPOSE: 컨테이너가 사용할 포트를 선언(실질적 포트 개방 아님, 메타데이터용).
- USER: 디폴트 사용자/그룹을 설정하여 root 아닌 사용자로 프로세스를 실행할 수 있게 합니다.
- VOLUME: 컨테이너에서 볼륨으로 사용할 디렉토리 경로를 선언합니다.
- ONBUILD: 해당 이미지를 베이스로 다른 Dockerfile 빌드 시 실행할 트리거를 정의합니다.
ARG와 멀티스테이지 빌드를 통한 유지 보수성 개선
- ARG: 빌드 시점 변수로, --build-arg로 값을 주입할 수 있습니다. 이를 통해 버전 정보나 환경에 따라 달라지는 값을 하드코딩하지 않고 유연하게 관리할 수 있습니다.
FROM debian:stable
ARG VERSION=0.6
ENV APP_VERSION=${VERSION}
LABEL base.version="${APP_VERSION}"
빌드 시 docker image build --build-arg VERSION=1.0 ...
로 다른 버전을 쉽게 설정할 수 있습니다.
- 멀티스테이지 빌드(Multistage Build): 하나의 Dockerfile 내에서 여러 FROM을 사용해 빌드 단계를 나누는 기법입니다. 빌드용 이미지(빌더 단계)에서 컴파일한 바이너리를 추출해, 최종 런타임 이미지에 최소한의 파일만 포함하는 방식으로 이미지 크기를 줄이고 보안을 강화할 수 있습니다.
예를 들어, Go 애플리케이션을 빌드하는 이미지는 빌더 단계에서는 go, gcc 등의 빌드 도구를 사용하지만, 런타임 단계에서는 빌드된 바이너리만 포함한 깔끔한 minimal 이미지를 사용합니다.
Startup 스크립트, init, Health Check로 향상된 사용자 경험
- Startup 스크립트: 컨테이너 시작 시 환경 변수가 설정되었는지, 종속 서비스가 접근 가능한지 등 선행 조건을 검사하고 실패 시 빠르게 종료하여 문제를 명확히 드러낼 수 있습니다.
- init 프로세스: 여러 프로세스를 실행하거나 고아 프로세스를 정리하려면 컨테이너 내 init(예: tini, runit)을 사용할 수 있습니다. 이렇게 하면 다중 프로세스를 효율적으로 관리하고 신뢰성을 향상시킬 수 있습니다.
- HEALTHCHECK: 컨테이너 내부에서 특정 명령(예:
curl localhost:8080/health
)을 주기적으로 실행해 애플리케이션 상태를 확인하고,docker ps
에서 (healthy)/(unhealthy) 상태를 표시할 수 있습니다. 이는 오케스트레이션 도구나 모니터링 시스템과 통합되어 자동화된 대응을 가능하게 합니다.
이미지 강화(Best Practices)
- CAIID (Content-Addressable Image ID): FROM에 태그 대신 다이제스트를 사용하면, 베이스 이미지가 변하지 않았음을 보장하여 예측 가능성을 높일 수 있습니다.
- 사용자 권한 최소화: USER 명령을 통해 root가 아닌 특정 사용자로 프로세스를 실행하면, 보안 사고 발생 시 피해를 최소화할 수 있습니다.
- SUID/SGID 제거: 이미지 빌드 과정에서 SUID, SGID 비트를 제거하여 권한 상승 취약점을 줄입니다. 예:
chmod ug-s /usr/bin/ping
이러한 강화 기법을 통해 공격 표면을 줄이고, 신뢰할 수 있는 컨테이너 이미지를 만들 수 있습니다.
정리
이 장에서는 Dockerfile을 사용한 이미지 빌드 자동화 방식과 다양한 모범 사례를 다루었습니다. Dockerfile 명령을 통해 파일 시스템 변경, 환경 변수 설정, 실행 엔트리포인트 지정 등의 작업을 간결하게 정의할 수 있고, ARG, 멀티스테이지 빌드, HEALTHCHECK, init 프로세스, 사용자 권한 최소화 등의 기법을 통해 유지보수성과 신뢰성을 크게 향상시킬 수 있습니다. 이러한 기법은 실제 서비스 운영 환경에서 이미지 배포, 업데이트, 문제 해결을 효율적으로 만들며, 컨테이너 기반 애플리케이션 개발 및 운영 파이프라인을 자동화하는 핵심 기술을 제공합니다.
'Docker' 카테고리의 다른 글
Spring Boot 애플리케이션 Docker로 빌드 및 실행하기 (0) | 2024.12.10 |
---|---|
Docker in Action Chapter 7 (0) | 2024.12.09 |
Docker in Action Chapter 6 (0) | 2024.12.09 |
Docker in Action Chapter 5 (0) | 2024.12.09 |
Docker in Action Chapter 4 (0) | 2024.12.09 |