Dockerfile 기본 구축 원리와 주요 명령어 활용법

Dockerfile 와 컨테이너화 전략

Dockerfile 은 Docker 이미지를 생성하기 위한 텍스트 기반의 스크립트 파일입니다. 이는 개별적인 설치 과정을 일일이 실행하고 docker commit을 사용하여 수동으로 저장을 반복하는 방식에서 벗어날 수 있게 합니다. commit 방식은 간단한 테스트에는 유용할 수 있으나, 환경 변화가 잦거나 복잡한 요구사항이 있는 상황에서는 재현성과 유지보수 측면에서 비효율적입니다. Dockerfile 을 사용하면 인프라의 상태를 코드로 관리하여 일관된 이미지 생성이 가능해집니다.

1. 이미지 빌드 워크플로우

일반적인 Docker 이미지 생성 과정은 다음과 같은 세 단계로 나뉩니다.

  • 빌드 정의 파일 (Dockerfile) 작성
  • 빌드 컨텍스트를 이용한 이미지 컴파일 (docker build)
  • 생성된 이미지를 기반으로 런타임 인스턴스 실행 (docker run)

소프트웨어 개발 생명주기의 관점에서 해석하면 다음과 같습니다.

  • Dockerfile: 애플리케이션을 구성하는 소스 코드 및 설정 자료원
  • Image: 배포 가능한 최종 아티팩트
  • Container: 실행 중인 애플리케이션 상태

Docker 는 지정된 Dockerfile 의 각 명령어를 순차적으로 처리합니다. 내부적으로는 각 단계마다 임시 컨테이너를 생성하고 수정한 내용을 커밋하여 레이어 (Layer) 를 쌓아 올린 뒤, 그 결과물을 기반으로 다음 단계의 컨테이너를 실행합니다. 모든 명령어가 완료되면 최종 이미지가 완성됩니다.

2. 핵심 지시문 (Instruction) 해설

Dockerfile 은 여러 가지 예약된 지시문을 통해 이미지의 행동을 제어합니다. 각 지시문은 대문자로 시작해야 하며, 실행되는 순서에 따라 이미지가 구성됩니다.

FROM: 베이스 이미지 정의

새로운 이미지의 기반이 될 기존 이미지를 지정합니다. 일반적으로 Dockerfile 의 첫 줄에 위치하며, 예를 들어 최소화된 OS 를 선택하거나 특정 언어의 런타임을 포함하는 이미지를 사용할 수 있습니다.

LABEL 과 MAINTAINER: 메타데이터 관리

이미지에 대한 정보를 태그할 때 사용됩니다. 과거에는 MAINTAINER가 주로 사용되었으나, 현재는 더 유연한 LABEL 지시문이 권장됩니다. 라벨을 통해 작성자 정보뿐만 아니라 다양한 커스텀 속성을 추가할 수 있습니다.

LABEL maintainer="dev-team@company.com"

RUN: 빌드 타임 명령어 실행

이미지 빌드 도중 shell 명령어를 실행하여 패키지를 설치하거나 환경을 설정합니다. 두 가지 형식을 지원합니다.

  • Shell Form: RUN apt-get update와 같이 쉘을 통장 실행
  • Exec Form: RUN ["apt-get", "update"]와 같이 JSON 배열 형태로 직접 실행 (쉘 인터프리터를 거치지 않음)

WORKDIR: 작업 디렉토리 설정

컨테이너 내부에서의 현재 작업 경로를 지정합니다. 만약 해당 경로가 없다면 자동으로 생성되며, 이후의 COPYRUN 명령은 이 경로를 기준으로 상대적 경로로 처리될 수 있습니다.

ENV: 환경 변수 선언

이미지 내부와 컨테이너 실행 시에 사용할 환경 변수를 정의합니다. 이렇게 설정된 변수는 후속 명령어에서도 참조할 수 있습니다.

COPY 와 ADD: 파일 전송

호스트 머신의 파일을 이미지 내부로 복사합니다. COPY는 단순 파일 이동을 담당하는 반면, ADD는 압축 파일 자동 추출이나 원격 URL 다운로드 기능을 추가로 제공합니다. 단순 파일 이동이 목적이라면 가독성 측면에서 COPY를 우선 사용하는 것이 좋습니다.

VOLUME: 데이터 볼륨 마운팅

데이터 영구화를 위해 호스트나 다른 저장소와 연결할 디렉토리를 미리 지정합니다.

EXPOSE: 포트 노출

애플리케이션이 수신 대기 중인 네트워크 포트를 문서화합니다. 이는 실제 포트 매핑 (-p) 을 강제하는 것은 아니며, 사용자에게 어떤 포트를 열어두어야 하는지 알려주는 역할입니다.

CMD 와 ENTRYPOINT: 컨테이너 진입점

두 지시문 모두 컨테이너가 시작될 때 실행할 기본 명령어를 정의하지만, 동작 방식에서 차이가 있습니다.

  • CMD: docker run 시 사용자가 명시한 명령어로 쉽게 대체될 수 있습니다. 여러 개를 기재할 경우 마지막 하나만 적용됩니다.
  • ENTRYPOINT: 컨테이너의 주 로직을 고정할 때 사용합니다. docker run 뒤에 추가된 인자는 여기 지정된 프로그램의 파라미터로 전달됩니다.

세련된 Dockerfile 구조에서는 ENTRYPOINT에 실행 가능한 바이너리를, CMD에 해당 바이너리에 전달될 기본 옵션을 각각 배치하여 유연성을 확보합니다.

3. 실습: Node.js 애플리케이션 이미지 구축

다음은 기존의 시스템 기반 설치가 아닌 현대적인 웹 애플리케이션 배포를 위해 Node.js 환경 이미지를 생성하는 사례입니다. 변수 이름과 경로, 설치되는 패키지 등을 변경하여 고유한 구조를 갖습니다.

프로젝트 구조 설계

다음은 프로젝트 루트에 존재하는 Dockerfile의 내용입니다. CentOS 대신 Alpine 기반 이미지를 사용하여 크기를 최적화하고, JDK 대신 NPM 의존성 관리 방식을 도입했습니다.

# 베이스 이미지 정의 (Alpine 기반 Node 18 LTS)
FROM node:18-alpine

# 메타데이터 등록
LABEL maintainer="platform-eng@example.com" \
      description="Node.js Microservice Environment"

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

# 환경 변수 정의 (변경 가능한 값들)
ENV SERVICE_PORT=3000
ENV LOG_LEVEL=info

# 의존성 파일 먼저 복사 (캐싱 효율화)
COPY package*.json ./

# 의존성 패키지 설치
RUN npm install --production

# 애플리케이션 소스 코드 복사
COPY . .

# 보안 강화를 위한 사용자 전환 (root 가 아닌 일반 사용자)
USER node

# 외부 포트 정의
EXPOSE ${SERVICE_PORT}

# 시작 스크립트 정의 (ENTRYPOINT 와 CMD 병행)
ENTRYPOINT ["node"]
CMD ["server.js"]

이미지 생성 및 검증

위 내용을 바탕으로 빌드 명령어를 실행합니다. 타겟 태그와 레이블을 명시하여 버전 관리를 준비합니다.

$ docker build -t my-service:v1.2 .
Sending build context to Docker daemon  5.2MB
Step 1/8 : FROM node:18-alpine
...
Successfully built a8b3c4d5e6f7
Successfully tagged my-service:v1.2

실행 및 포트 매핑

생성된 이미지를 실행할 때 호스트 포트 8080 을 컨테이너의 3000 포트로 매핑합니다.

$ docker run -d -p 8080:3000 --name node-app-test my-service:v1.2
$ docker logs node-app-test
Server listening on port 3000

디버그 모드 진입 및 명령어 오버라이드

기본적으로 서버가 시작되도록 설정되어 있지만, 컨테이너 내부로 접근하여 확인 작업을 수행하려면 CMD를 덮어써야 합니다.

$ docker run -it my-service:v1.2 /bin/sh
/app/service $ ls
server.js
package.json
/app/service $ echo $LOG_LEVEL
info

또는 이미지를 업그레이드하여 파이썬 유틸리티를 함께 구비하는 경우, 새로운 버전을 정의할 때 이전 이미지를 계승점으로 삼아 레이어를 효율적으로 재사용할 수 있습니다.

FROM my-service:v1.2
RUN apk add --no-cache python3
CMD ["python3"]

이러한 방식으로 Dockerfile 을 점진적으로 확장하면, 초기 빌드 시간을 단축하면서도 기능 확장이 용이한 인프라를 구축할 수 있습니다.

태그: docker Dockerfile container image-building linux

8월 2일 23:09에 게시됨