본문 바로가기

운영체제 및 플랫폼/Docker(도커)

도커, Dockerfile, 도커파일작성법, 도커빌드, 빌드캐시, dockerignore, CMD ENTRYPOINT 차이, 도커이미지, 컨테이너, DevOps

728x90
반응형

한 줄 요약

Dockerfile은 도커 이미지를 만드는 순서를 적은 설계도예요. 명령어의 역할과 빌드 캐시 규칙을 알면 빌드가 빨라지고 결과도 예측하기 쉬워져요.

Dockerfile 빌드 캐시


1. 핵심 개념

1.1 Dockerfile이란

Dockerfile은 이미지를 만들기 위한 명령을 순서대로 적은 텍스트 파일이에요. docker build 명령이 이 파일을 위에서부터 읽어 이미지를 만들어요.

빌드 컨텍스트: docker build를 실행할 때 도커에 함께 전달되는 파일 묶음이에요. 보통 명령을 실행한 폴더 전체예요.

 

이미지와 레이어의 기본 개념은 도커 개념 정리 글에서 다뤘어요. 이 글은 Dockerfile을 어떻게 작성하는지에 집중해요.

1.2 왜 중요한가

  • Dockerfile은 이미지를 다시 만들 수 있는 근거예요. 같은 파일로 빌드하면 같은 절차를 거쳐요.
  • 명령어 순서에 따라 빌드 캐시 재사용 여부가 달라져요. 그래서 빌드 시간에 직접 영향을 줘요.

2. 쉽게 이해하기

Dockerfile은 요리 레시피와 같아요.

  • 레시피의 각 단계가 Dockerfile의 명령 한 줄이에요.
  • 이전에 만들어 둔 단계 결과를 다시 쓰는 것이 빌드 캐시예요.
  • 레시피 3단계를 바꾸면, 3단계 이후 과정은 전부 다시 해야 해요. 앞 단계가 바뀌었으니 뒤 결과도 달라지기 때문이에요.

그래서 잘 바뀌지 않는 단계를 앞에, 자주 바뀌는 단계를 뒤에 두는 것이 핵심이에요.


3. 자주 쓰는 Dockerfile 명령어

명령어 역할
FROM 시작점이 될 베이스 이미지를 지정해요
WORKDIR 이후 명령이 실행될 작업 폴더를 지정해요
COPY 빌드 컨텍스트의 파일을 이미지 안으로 복사해요
ADD COPY 기능에 더해 원격 URL, 로컬 tar 파일 자동 압축 해제를 지원해요
RUN 빌드 중에 명령을 실행해요 (패키지 설치 등)
ENV 환경 변수를 설정해요. 실행 중인 컨테이너에도 남아요
ARG 빌드할 때만 쓰는 변수를 설정해요
EXPOSE 앱이 사용하는 포트를 문서로 표시해요
CMD 컨테이너 시작 시 기본 실행 명령을 지정해요
ENTRYPOINT 컨테이너 시작 시 항상 실행할 프로그램을 지정해요

 

3.1 헷갈리기 쉬운 명령어

COPY vs ADD
공식 모범 사례는 로컬 파일 복사에 COPY를 권장해요. ADD는 원격 파일이나 tar 압축 해제가 필요할 때 사용해요.

CMD vs ENTRYPOINT

  • CMD는 docker run 이미지 <명령>처럼 인자를 주면 덮어써져요.
  • ENTRYPOINT를 함께 쓰면, CMD 값은 ENTRYPOINT에 전달되는 기본 인자가 돼요.

EXPOSE는 포트를 열지 않아요
EXPOSE는 "이 앱은 이 포트를 써요"라는 표시일 뿐이에요. 실제로 외부에 공개하려면 실행할 때 -p 옵션이 필요해요.

 

3.2 exec 형식으로 작성하기

CMD와 ENTRYPOINT는 두 가지 형식으로 쓸 수 있어요.

# exec 형식 (JSON 배열)
ENTRYPOINT ["java", "-jar", "app.jar"]

# shell 형식
ENTRYPOINT java -jar app.jar

shell 형식은 /bin/sh -c를 거쳐 실행돼요. 이 경우 docker stop이 보내는 종료 신호가 앱에 바로 전달되지 않아요. 그래서 공식 문서는 exec 형식을 권장해요.


4. 빌드 캐시가 동작하는 방식

공식 문서가 설명하는 기본 규칙은 이래요.

  • 명령을 하나씩 확인하며, 이전 빌드 결과와 정확히 일치하면 캐시를 재사용해요.
  • RUN은 명령 문자열만 비교해요. 실행 결과 파일은 확인하지 않아요.
  • COPY, ADD는 복사하는 파일의 메타데이터로 변경 여부를 판단해요. 파일 수정 시각(mtime)만 바뀐 경우는 제외돼요.
  • 한 단계의 캐시가 무효화되면 그 뒤 단계는 모두 다시 실행돼요.

 

4.1 순서에 따른 차이

비효율적인 순서

FROM eclipse-temurin:21-jdk
WORKDIR /app
COPY . .
RUN ./gradlew bootJar --no-daemon

소스 코드 한 줄만 바꿔도 COPY . .부터 전부 다시 실행돼요.

 

캐시를 활용하는 순서

FROM eclipse-temurin:21-jdk
WORKDIR /app

# 1) 잘 바뀌지 않는 빌드 설정 파일을 먼저 복사
COPY gradlew .
COPY gradle gradle
COPY build.gradle settings.gradle ./
RUN ./gradlew dependencies --no-daemon

# 2) 자주 바뀌는 소스 코드는 나중에 복사
COPY src src
RUN ./gradlew bootJar --no-daemon

소스 코드만 바뀌면 COPY src src 단계부터 다시 실행돼요. 앞의 빌드 설정 단계는 캐시를 재사용해요.

 

4.2 RUN 캐시 주의점

RUN apt-get update 같은 명령은 문자열이 같으면 캐시가 그대로 쓰여요. 공식 문서에 따르면 일주일 뒤에 다시 빌드해도 이전과 같은 패키지가 들어갈 수 있어요. 최신 패키지가 필요하면 캐시 없이 빌드해야 해요.

docker build --no-cache -t myapp:1.0 .

5. .dockerignore로 불필요한 파일 제외하기

.dockerignore는 빌드 컨텍스트에서 제외할 파일을 적는 파일이에요. Dockerfile과 같은 위치에 둬요.

.git
build/
*.log
.env
  • 빌드에 필요 없는 파일이 전달되지 않아요.
  • .env 같은 비밀 정보가 실수로 이미지에 복사되는 것을 막을 수 있어요.

6. 핵심 정리

  • Dockerfile은 이미지를 만드는 명령을 순서대로 적은 파일이에요.
  • EXPOSE는 포트를 열지 않아요. 실제 공개는 docker run -p로 해요.
  • CMD, ENTRYPOINT는 exec 형식(JSON 배열)으로 쓰는 것이 공식 권장이에요.
  • 캐시는 한 단계가 바뀌면 이후 단계가 전부 다시 실행돼요. 자주 바뀌는 파일은 뒤쪽에 복사해요.
  • .dockerignore로 불필요한 파일과 비밀 정보를 빌드에서 제외해요.

7. 추가 정보

주의사항

  • 베이스 이미지에 latest 태그만 쓰면 빌드 시점마다 다른 이미지를 받을 수 있어요. 버전 태그를 명시하는 편이 재현에 유리해요.
  • 빌드 캐시로 줄어드는 시간은 프로젝트 구조에 따라 달라서, 공식 문서에 확정 수치가 제시되어 있지 않아요.
반응형