이미지 빌드 · Dockerfile 문법 · 이론
Dockerfile 은 설정 파일이 아니라 빌드 스크립트다
한 줄 요약
Dockerfile 의 지시어는 두 부류입니다. 레이어를 만드는 것(RUN, COPY, ADD)과
이미지 설정에 값을 새기는 것(ENV, CMD, ENTRYPOINT, USER, LABEL, EXPOSE).
어느 쪽인지 알면 크기 문제와 보안 문제를 절반쯤 미리 피할 수 있습니다.
왜 이게 필요했나
가장 자주 반복되는 사고는 시크릿입니다. ENV NPM_TOKEN=... 로 넣으면
토큰이 이미지 설정에 영구히 남습니다.
docker inspect -f '{{json .Config.Env}}' bad:v1# "NPM_TOKEN=npm_9fA3xQ2LkD8vR1sT6yU0wZ4bN7mC5eJ"ARG 로 받아서 쓰고 rm ~/.npmrc 로 지워도 소용이 없습니다. 파일은
아래 레이어에 그대로 남고, 클래식 빌더에서는 히스토리에도 남습니다.
**레지스트리에 푸시했다면 그 토큰은 이미 유출된 것으로 간주하고 폐기해야
합니다. 이미지를 지우는 것으로는 되돌릴 수 없습니다.**
어떻게 동작하나
몇 가지 지시어는 겉보기와 다르게 동작합니다.
ADD 는 COPY 의 상위 호환이 아닙니다. ADD 는 로컬 tar 를 자동으로
풀고 URL 도 받습니다. 그 추가 동작이 대부분 문제입니다. 아카이브 안에../ 경로가 있으면 의도하지 않은 위치에 파일이 쓰이고, URL 다운로드는
체크섬 검증이 없습니다. 기본값은 COPY 이고, ADD 가 정당한 경우는 로컬
tar 를 의도적으로 풀 때뿐입니다.
COPY --chown 과 RUN chown -R 은 크기가 두 배 차이 납니다.COPY . /app 이 286MB 라면 이어지는 RUN chown -R app:app /app 은 파일
전체를 새 레이어에 다시 쓰므로 286MB 를 한 번 더 씁니다. COPY 에 옵션
하나를 붙이면 레이어가 하나로 끝납니다.
USER 는 반드시 숫자 UID 로 씁니다. 쿠버네티스의 runAsNonRoot 는
이름을 보고는 root 인지 판별하지 못하고 파드를 거부합니다.
Error: container has runAsNonRoot and image has non-numeric user (app),cannot verify user is non-rootHEALTHCHECK 에는 오해가 둘 있습니다. 실패해도 컨테이너가 재시작되지
않고 unhealthy 로 표시만 되며, **쿠버네티스는 이미지의 HEALTHCHECK 를
아예 무시**합니다. 프로브를 따로 정의해야 합니다.
현장에서 만나는 모습
리뷰 체크리스트는 다섯 줄이면 충분합니다.
1. FROM 이 고정되어 있는가 (latest 는 롤백할 대상을 없앤다)
2. USER 가 숫자 UID 인가
3. CMD/ENTRYPOINT 가 JSON 배열(exec 형식)인가
4. 시크릿이 ARG/ENV 로 들어오지 않는가
5. 최종 스테이지에 빌드 도구가 남아 있지 않은가
"태그를 고정하면 보안 패치를 못 받는다"는 반론이 흔한데, 갱신은 사람이
아니라 봇이 PR 을 올리고 CI 가 검증한 뒤 병합하면 됩니다. **자동으로
흘러 들어오는 것과 검증을 거쳐 들어오는 것의 차이**입니다.
다음 실습에서 할 것
지시어를 하나씩 추가하며 태그를 바꿔 빌드하고, 각 지시어가 이미지의 어느
필드에 새겨지는지 inspect 로 확인한 뒤, 마지막에 체크리스트를 통과하는
Dockerfile 을 완성합니다.