Dockerfileを一行ずつ積む
한국어 원문으로 표시합니다.
이 실습은 진짜 VM 에서 돕니다
이 상자는 파드가 아니라 KubeVirt 가 띄운 가상머신입니다. 리눅스 커널이
따로 돌고 systemd 가 실제로 서비스를 관리하며, docker 는 흉내가 아니라
진짜 도커 엔진입니다. docker run 으로 띄운 컨테이너는 실제로 프로세스가
되고 docker exec 도 docker logs 도 그대로 동작합니다.
예전에는 이 실습이 파드 안에서 돌았습니다. 커널 권한을 전부 내려놓은 상자라 컨테이너를 띄우는 단계가 막혀 있었고, 그래서 이미지 아카이브를 직접 풀어 보는 우회로 배웠습니다. 이제 우회가 필요 없습니다.
알아 둘 것이 둘 있습니다.
- 처음 뜨는 데 1분 남짓 걸립니다. VM 이 부팅하고 도커를 설치하기 때문입니다. 파드 실습(보통 40초)보다 느립니다.
- 브라우저 미리보기가 없습니다. VM 으로 들어오는 연결은 채점 포트
하나만 열려 있습니다. 웹 서버를 띄웠다면 VM 안에서
curl로 확인하세요.
목표
Dockerfile 지시어를 하나씩 추가하면서 각각이 이미지의 어느 부분을 바꾸는지 inspect 로 확인하고, 마지막에 리뷰 체크리스트를 통과하는 파일을 만듭니다.
왜 중요한가
Dockerfile 은 설정 파일처럼 생겼지만 실제로는 순서가 의미를 가지는 빌드 스크립트입니다. 같은 지시어라도 위치에 따라 레이어가 늘고, 캐시가 깨지고, 시크릿이 박제됩니다. 이 실습은 지시어를 외우는 것이 아니라 "이 줄이 레이어를 만드는가, 설정을 새기는가"를 매번 구분하는 습관을 들이는 것이 목적입니다. 그 구분 하나로 크기 문제와 보안 문제의 대부분이 예방됩니다.
단계
각 단계마다 새 태그로 빌드해서 앞 단계의 결과도 남겨 둡니다.
/root/build1을 만들고/root/build1/Dockerfile의 첫 줄을FROM alpine:3.20으로 작성합니다.labhub/app:v1로 빌드합니다./root/build1/app.sh를 만들어app-running을 출력하게 하고, Dockerfile 에WORKDIR /app과COPY app.sh /app/을 추가해labhub/app:v2로 빌드합니다.CMD를 JSON 배열 형식으로 추가해app.sh가 실행되게 하고labhub/app:v3로 빌드합니다. 실행하면app-running이 나와야 합니다.ENV APP_ENV=prod와ARG VERSION을 추가하고, ARG 로 받은 값을LABEL app.version에 새깁니다.--build-arg VERSION=2.1.0으로labhub/app:v4를 빌드합니다.ENTRYPOINT를 배열 형식으로 두고CMD ["default-arg"]를 기본값으로 두어, 인자 없이 실행하면default-arg가,override-arg를 주면override-arg가 출력되게 한 뒤labhub/app:v5로 빌드합니다.LABEL org.opencontainers.image.title=labhub-app과EXPOSE 8080을 추가해labhub/app:v6로 빌드합니다.- 최종
/root/build1/Dockerfile이 아래 다섯 항목을 모두 만족하게 다듬고labhub/app:v7로 빌드합니다.FROM에 태그가 고정되어 있고latest가 아니다WORKDIR이 첫COPY보다 앞에 있다ENTRYPOINT또는CMD가 JSON 배열이다ENV/ARG이름에 TOKEN·SECRET·PASSWORD·API_KEY 가 들어가지 않는다
참고
docker image inspect labhub/app:v4 | jq '.[0].Config'로 설정 필드를 한눈에 볼 수 있습니다.docker build --build-arg VERSION=2.1.0 -t labhub/app:v4 /root/build1형태로 인자를 넘깁니다.- 흔한 실수 1:
CMD app.sh처럼 셸 형식으로 쓰면 배열이 아니라 문자열 하나가 됩니다. - 흔한 실수 2: 5단계에서 ARG 값을 ENV 로 넘기면 이미지에 그대로 남습니다. LABEL 로 새기세요.
베이스 이미지 고정하기
/root/build1 을 만들고 /root/build1/Dockerfile 의 첫 줄을 FROM alpine:3.20 으로 작성합니다.
FROM 에 태그를 명시하세요. latest 는 어제 빌드와 오늘 빌드가 달라지게 만듭니다.
첫 빌드
labhub/app:v1 로 빌드합니다.
빌드 컨텍스트는 Dockerfile 이 있는 디렉터리를 지정합니다. -t 로 이름을 붙이지 않으면 나중에 찾기 어렵습니다.
작업 디렉터리와 파일 복사
/root/build1/app.sh 를 만들어 app-running 을 출력하게 하고, Dockerfile 에 WORKDIR /app 과 COPY app.sh /app/ 을 추가해 labhub/app:v2 로 빌드합니다.
WORKDIR 은 이미지 설정(Config.WorkingDir)에 새겨지고, COPY 는 레이어를 만듭니다. 두 지시어의 순서가 상대 경로의 의미를 정합니다.
기본 명령 지정하기
CMD 를 JSON 배열 형식으로 추가해 app.sh 가 실행되게 하고 labhub/app:v3 로 빌드합니다. 실행하면 app-running 이 나와야 합니다.
셸 형식으로 쓰면 /bin/sh -c 로 감싸져 PID 1 이 셸이 됩니다. 배열 형식이 왜 필요한지는 앞 코스에서 봤습니다.
빌드 인자와 환경변수의 차이
ENV APP_ENV=prod 와 ARG VERSION 을 추가하고, ARG 로 받은 값을 LABEL app.version 에 새깁니다. --build-arg VERSION=2.1.0 으로 labhub/app:v4 를 빌드합니다.
ARG 는 빌드하는 동안만 살고 ENV 는 이미지에 남습니다. 빌드 인자로 받은 값을 이미지에 남기려면 LABEL 로 새기세요.
ENTRYPOINT 와 CMD 조합
ENTRYPOINT 를 배열 형식으로 두고 CMD ["default-arg"] 를 기본값으로 두어, 인자 없이 실행하면 default-arg 가, override-arg 를 주면 override-arg 가 출력되게 한 뒤 labhub/app:v5 로 빌드합니다.
ENTRYPOINT 는 고정되고 CMD 는 실행 시 인자로 교체됩니다. 둘 다 배열 형식으로 쓰세요.
표준 라벨과 포트 선언
LABEL org.opencontainers.image.title=labhub-app 과 EXPOSE 8080 을 추가해 labhub/app:v6 로 빌드합니다.
OCI 표준 라벨 키는 org.opencontainers.image. 로 시작합니다. EXPOSE 는 포트를 여는 것이 아니라 문서화하는 지시어입니다.
리뷰 체크리스트 통과시키기
최종 /root/build1/Dockerfile 이 아래 다섯 항목을 모두 만족하게 다듬고 labhub/app:v7 로 빌드합니다.
FROM에 태그가 고정되어 있고latest가 아니다WORKDIR이 첫COPY보다 앞에 있다ENTRYPOINT또는CMD가 JSON 배열이다ENV/ARG이름에 TOKEN·SECRET·PASSWORD·API_KEY 가 들어가지 않는다
지금까지의 Dockerfile 을 다섯 항목에 맞춰 다듬으세요. 채점은 파일 내용과 빌드 결과를 함께 봅니다.