소개
Pine & Path는 Alder Ridge 방문객 안내서를 다른 방문자 센터에 보내려고 합니다. 현재 이미지는 작동하지만 애플리케이션과 함께 Go 컴파일러, 소스 파일, 빌드 잔여물까지 담고 있습니다. 네 개의 트레일, 난이도 필터, 상세 페이지, 로컬 그래픽, 완전한 GPX 경로 다운로드를 모두 제공하는 경량 런타임 이미지를 전달해 보세요.
간단한 Docker 이미지를 빌드하고 실행할 수 있고 Dockerfile의 FROM, COPY와 포트 공개를 알고 있어야 합니다. 완성된 애플리케이션과 자료가 제공되므로 Go 프로그래밍은 필요하지 않습니다. 이 실습에서는 컴파일, 빌드 단계, 런타임 파일 배치, 셸의 파일 작성 구문을 사용하기 전에 설명합니다. 공원과 경로 데이터는 교육용으로 만든 가상의 자료입니다.
Docker, 빌더 이미지, 제공된 참조 서비스가 준비되어 있습니다. 명령은 Workstation, 정상 작동하는 예제는 Reference Guide, 여러분이 전달할 결과는 Your Guide에서 확인합니다. 이 실습은 챌린지와 독립적입니다. 읽기, 빌드, 일반적인 실수를 포함하여 약 60분을 예상하세요. 이는 저자의 예상 시간입니다.
정상 작동하는 시작 이미지 빌드하기
이 단계에서는 완전한 안내서의 동작을 확인한 다음 제공된 시작 이미지를 빌드합니다. Reference Guide에서 시작하세요. 트레일 네 개가 표시됩니다. Easy를 선택하고 Cedar Loop를 열어 거리와 상승 고도를 읽은 뒤 Download GPX를 사용하세요. GPX는 이름이 있는 트랙과 지리 좌표를 담은 XML이며, 이 다운로드는 실제 경로 파일입니다. Back to trails, Moderate를 차례로 선택하고 Ridge Path를 여세요. 전체 트레일로 돌아갑니다. 텍스트뿐 아니라 스타일시트와 개략 지도도 살펴보세요. 이들 역시 런타임 리소스입니다.

Workstation으로 전환하세요. 시작 디렉터리는 /home/labex/project/trail-guide입니다. pwd는 현재 디렉터리를 출력하고 ls는 항목을 나열합니다. 프로젝트를 벗어났다면 다음 cd로 돌아올 수 있습니다.
cd /home/labex/project/trail-guide
ls
제공된 파일 배치는 다음과 같습니다.
| 소스 경로 | 런타임에서의 용도 |
|---|---|
app/main.go |
컴파일할 Go 프로그램으로, 런타임에 소스는 필요하지 않음 |
content/trails.json |
네 트레일 전체와 그 관계 |
content/routes/ |
GPX 다운로드 네 개 |
public/ |
스타일시트와 직접 제작한 개략 그래픽 |
author-notes/, build-cache/ |
런타임 리소스가 아닌 초안과 잔여물 |
제공된 자료와 참조 서비스를 변경하지 마세요. 수정할 대상은 Dockerfile이며, .dockerignore를 추가하고 이 과정의 이미지와 컨테이너를 생성합니다. Dockerfile.incomplete는 다음 단계에서 사용할 실패 예제입니다.
cat은 텍스트 파일을 표시합니다. 기존 Dockerfile을 읽어 보세요.
cat Dockerfile
준비된 Go 컴파일러 이미지인 dk02-go-builder:1에서 시작합니다. WORKDIR /guide는 이미지 내부의 작업 디렉터리를 선택합니다. COPY . .는 최종 애플리케이션에 필요하지 않은 파일을 포함하여 현재 빌드 컨텍스트를 그 디렉터리에 복사합니다. 마지막 ENTRYPOINT는 컴파일된 프로그램을 직접 시작하는 JSON 배열입니다.
빌드 명령은 해당 명령에 CGO_ENABLED=0을 설정하여 Go 표준 라이브러리만 사용하는 이 예제가 C 라이브러리를 필요로 하지 않게 합니다. go build는 제공된 프로그램을 컴파일합니다. -trimpath는 실행 파일에서 로컬 소스 디렉터리 정보를 제거하며, -o /guide/guide는 실행 파일의 이름을 지정합니다. 이 특정 프로그램은 그 덕분에 빈 런타임 베이스에 적합합니다. 다른 프로그램에는 공유 라이브러리, 인증서, 기타 데이터가 필요할 수 있으므로 빈 베이스가 만능 해결책은 아닙니다.
먼저 컴파일러 버전을 읽어 보세요. docker run --rm은 임시 컨테이너를 생성하고 명령 완료 후 제거합니다. 이미지 이름 뒤의 단어는 실행할 명령을 선택합니다.
docker run --rm dk02-go-builder:1 go version
출력에는 Linux의 Go 1.26이 표시됩니다. 컴파일러는 Workstation이 아닌 컨테이너에서 실행됩니다.
시작 이미지를 빌드하세요. docker build는 Dockerfile을 읽고, -t는 결과에 태그를 부여하며, 마지막 .은 현재 디렉터리를 빌드 컨텍스트로 선택합니다.
docker build -t trail-guide:sample .
빌드가 성공했다는 결과가 나올 때까지 기다리세요. 태그는 실행 중인 컨테이너가 아닌 이미지를 식별합니다. 크기를 바이트 단위로 확인하려면 docker image inspect로 메타데이터를 읽고 --format으로 필드 하나를 선택합니다. 작은따옴표는 템플릿을 그대로 전달합니다.
docker image inspect trail-guide:sample --format '{{.Size}}'
숫자는 준비된 컴파일러 이미지에 따라 달라집니다. 시작 이미지는 작동하지만 컴파일러와 소스가 여전히 들어 있습니다. 작은 크기만으로는 대체 이미지가 완전하다고 입증할 수 없습니다.
빌드 파일과 런타임 파일 분리하기
이 단계에서는 한 단계에서 프로그램을 빌드하고 다른 단계에서 실행 파일과 런타임 리소스만 전달합니다. 같은 프로젝트 디렉터리의 Workstation에서 시작하세요. 단계는 FROM 명령어에서 시작합니다. AS build로 이름을 지정하면 뒤의 COPY --from=build가 컴파일러나 이전 파일시스템 레이어를 상속하지 않고 결과를 가져올 수 있습니다.
먼저 실제로 불완전한 전달물을 살펴보세요. 제공된 Dockerfile.incomplete는 프로그램을 컴파일하고 공개 그래픽을 복사하지만 트레일 데이터는 빠뜨립니다.
cat Dockerfile.incomplete
-f 옵션으로 이 대체 Dockerfile을 선택합니다.
docker build -f Dockerfile.incomplete -t trail-guide:incomplete .
컴파일은 트레일 컬렉션을 읽지 않으므로 빌드가 성공합니다. 다음 실행은 의도적으로 종료 상태 1로 실패할 것으로 예상됩니다.
docker run --rm trail-guide:incomplete
오류 open content/trails.json: no such file or directory를 읽어 보세요. 실행 파일은 있지만 런타임 데이터가 없습니다. 빌드 성공과 완전한 애플리케이션은 서로 다른 결과입니다. 실패한 임시 컨테이너는 제거되었습니다. 그 컨테이너를 고치거나 애플리케이션을 변경하지 말고 일반 Dockerfile을 수정하세요.
히어 도큐먼트는 텍스트 블록 전체를 저장합니다. 아래에서 cat은 줄을 제공하고, >는 Dockerfile에 쓰며, <<'DOCKERFILE'은 DOCKERFILE만 있는 줄에서 끝나는 리터럴 블록을 표시합니다. 시작 표시에 따옴표를 붙이면 저장할 때 셸 확장이 일어나지 않습니다. 수정 가능한 Dockerfile만 교체하세요.
cat > Dockerfile <<'DOCKERFILE'
FROM dk02-go-builder:1 AS build
WORKDIR /src
COPY app/main.go ./main.go
RUN CGO_ENABLED=0 go build -trimpath -o /out/guide main.go
FROM scratch
WORKDIR /guide
COPY --from=build /out/guide ./guide
COPY content/ ./content/
COPY public/ ./public/
ENTRYPOINT ["/guide/guide"]
DOCKERFILE
파일을 따라가 보세요. 첫 단계는 소스를 /out/guide로 컴파일합니다. 두 번째 FROM은 첫 단계를 상속하지 않고 Docker의 빈 파일시스템 베이스인 scratch에서 시작합니다. 실행 파일은 /guide/guide가 되고, 트레일 데이터와 GPX 파일은 content 배치를, 스타일과 그래픽은 public 배치를 유지합니다. 프로그램은 작업 디렉터리를 기준으로 이 상대 경로들을 읽습니다. 실행 파일만 복사해서는 충분하지 않았던 이유입니다.
최종 이미지에는 셸과 컴파일러가 없습니다. 여기서는 예상된 상태입니다. 내부에서 셸을 실행하려 하지 말고 애플리케이션을 확인하세요.
빌드 컨텍스트는 별개의 문제입니다. .dockerignore는 빌더에 보내기 전에 일치하는 컨텍스트 경로를 제외합니다. 맨 앞의 점은 숨김 파일 이름을 나타냅니다. 다음 규칙은 애플리케이션과 런타임 리소스를 제외하지 않고 초안과 오래된 캐시를 뺍니다.
cat > .dockerignore <<'IGNORE'
author-notes/
build-cache/
IGNORE
두 단계 Dockerfile은 런타임 파일을 명시적으로 선택하며, ignore 파일은 불필요한 자료의 전송도 막습니다. 컨텍스트 파일을 제외해도 상속한 레이어에 이미 저장된 바이트를 제거할 수는 없습니다. 빌드 레이어를 남겨 두고 떠나는 역할은 별도 런타임 단계가 합니다.
전달할 이미지를 빌드하세요.
docker build -t trail-guide:lean .
docker image inspect trail-guide:lean --format '{{.Size}}'
예제 이미지의 숫자와 비교하세요. 유용한 결과는 가능한 한 작은 숫자가 아니라, 완전한 안내서를 제공하는 더 작은 런타임입니다. COPY가 실패하면 누락된 소스 경로를 읽고 파일 배치 표 및 현재 디렉터리와 비교하세요. Dockerfile이나 ignore 규칙을 수정한 뒤 다시 빌드합니다. 불완전한 이미지를 감추려고 대체 데이터를 만들거나 소스 폴더를 마운트하지 마세요.
전달한 안내서 실행 및 재생성하기
이 단계에서는 소스 폴더와 독립적으로 이미지를 실행하고 안내서 전체를 사용합니다. Workstation에서 시작하세요. 프로그램은 컨테이너 포트 8080에서 수신합니다. 8090:8080을 공개하면 Workstation의 포트 8090에서 접근할 수 있으며, Your Guide가 이를 표시합니다. -d는 서버를 백그라운드에 두고, --name은 이 과정 컨테이너의 이름을 지정합니다. 마운트를 추가하지 마세요. 이미지는 자체 리소스를 포함해야 합니다.
docker run -d --name trail-guide -p 8090:8080 trail-guide:lean
출력은 컨테이너 ID입니다. 이 컨테이너는 안내서를 제공하기 위해 계속 실행됩니다. docker logs는 프로그램의 출력을 읽고, --tail 5는 마지막 다섯 줄로 제한합니다.
docker logs --tail 5 trail-guide
Guide listening on :8080이 예상됩니다. 공개된 호스트 포트가 아니라 컨테이너 포트입니다. 이전 시도로 컨테이너 이름이 이미 사용 중이면 아래의 과정 범위 제거 명령을 사용한 다음 시작 명령을 다시 실행하세요. 리소스 누락 오류가 있으면 먼저 Dockerfile을 수정하고 다시 빌드해야 합니다.
Your Guide로 전환하여 새로고침하세요. 네 트레일이 모두 나타나야 합니다. Easy를 선택하면 Cedar Loop와 River Walk만 표시됩니다. Cedar Loop를 열어 정보와 지도를 확인하고 GPX를 다운로드하세요. Back to trails로 돌아가 Moderate를 선택하고 Ridge Path를 열어 그 경로도 다운로드합니다. 전체 트레일로 돌아가세요. 로컬 그래픽과 스타일이 로드되어야 하며, 트랙은 선택한 트레일의 것이어야 합니다. Reference Guide도 독립적으로 계속 사용할 수 있어야 합니다.

이제 같은 이미지로 대체 컨테이너를 만들어 보세요. Workstation으로 전환합니다. docker rm -f는 이름으로 지정한 과정 컨테이너만 중지하고 제거하며, 이미지는 제거하지 않습니다. dk02-reference는 계속 실행해 두세요.
docker rm -f trail-guide
마운트 없이 새 인스턴스를 생성하세요.
docker run -d --name trail-guide -p 8090:8080 trail-guide:lean
Your Guide로 전환하여 새로고침한 뒤 Easy/Cedar Loop 및 Moderate/Ridge Path 방문과 다운로드를 반복합니다. 이 새 컨테이너는 워크스테이션 소스 폴더를 받은 적이 없습니다. 런타임은 이미지에서 왔습니다.
컨테이너를 실행 상태로 두세요. 나중에 Dockerfile을 변경한 후 태그를 다시 빌드해도 기존 컨테이너가 갱신되지는 않습니다. 새 이미지를 실행하려면 본인의 과정 컨테이너만 제거하고 다시 생성해야 합니다. 서비스 중지나 연결 실패는 알 수 없는 경로에 대해 안내서 자체가 표시하는 Trail not found 페이지와 다릅니다.
요약
컴파일러 단계와 빈 런타임 단계를 분리하고, 애플리케이션에 실제로 필요한 리소스를 복사했으며, 초안을 빌드 컨텍스트에서 제외했습니다. 경량 이미지는 워크스테이션 마운트 없이 전체 컬렉션, 필터, 상세 정보, 그래픽, GPX 다운로드를 제공합니다. 컨테이너를 다시 생성하여 이 이미지가 소스 폴더를 빌려 쓰는 프로세스가 아니라 재사용할 수 있는 전달물임을 확인했습니다.



