Devin.KR

이미지와 컨테이너의 수명

80분 안팎

학습 목표

빌드 산출물과 실행 상태를 구분합니다.

개념

실행을 복제하기 전에 산출물을 정합니다

안내판 서비스를 다른 컴퓨터에 옮길 때 소스만 전달하면 Java 설치, 라이브러리, 시작 명령이 달라질 수 있습니다. 이미지는 실행에 필요한 파일과 기본 설정을 묶은 산출물입니다. 컨테이너는 그 이미지를 바탕으로 만든 실행 인스턴스입니다. 이번 목표는 같은 이미지로 두 인스턴스를 만들고 공통 파일과 개별 상태를 구분하는 것입니다. 서비스가 정상 응답한다는 사실과 같은 빌드 산출물을 사용한다는 사실을 각각 확인합니다.

이번 모듈의 개인 실습 환경을 준비합니다

모든 레슨은 개인 Docker 환경의 로컬 실습입니다. Bash, Python 3, JDK 17, Docker CLI와 동작 중인 daemon을 준비합니다. Maven은 내려받은 zip의 mvnw와 .mvn/wrapper를 사용하며 시스템 Maven 설치를 요구하지 않습니다. 처음 ./mvnw test로 의존성을 준비하고 캐시가 갖춰진 작성자 환경에서는 오프라인으로 확인합니다. Docker 실행이 제한된 샌드박스는 external 검증 대기로 표시하며 실제 성공 출력으로 간주하지 않습니다.

이전 프로젝트를 출발점으로 삼습니다

실습 zip은 m02 미션 solution의 Java 소스, 요청 ID 필터, 진단 기록, workspace와 scripts, 테스트를 포함합니다. 그대로 시작하되 /identity 응답과 파일을 읽는 /notices를 추가했습니다. /health의 UP 계약과 오류 fixture는 유지합니다. 개인의 이전 산출물을 합칠 때는 README의 비교 절차를 따릅니다. 기존 데이터와 비밀 파일을 통째로 덮어쓰지 않고 변경한 소스의 목적과 이전 테스트 결과를 확인합니다.

이미지가 담는 것과 담지 않는 것을 나눕니다

이미지는 Java 실행 환경, 안내판 JAR, 기본 시작 명령을 담습니다. 실행 뒤 생긴 PID, 현재 메모리, 열린 연결은 이미지 파일에 들어 있지 않습니다. 같은 이미지를 사용해도 요청량과 환경 설정이 다르면 프로세스 상태는 달라집니다. 컨테이너는 가상 머신 전체를 복제한 것이 아니며 실행 환경의 커널에 의존합니다. macOS의 Docker 환경에서는 Linux 가상 환경을 통해 Linux 컨테이너를 실행합니다.

컨테이너 ID와 이미지 ID를 대조합니다

docker inspect에서 컨테이너의 Id는 그 인스턴스의 식별자이고 Image는 사용한 이미지의 로컬 ID입니다. 두 컨테이너의 Id가 다르고 Image가 같으면 독립된 인스턴스가 같은 산출물을 이용했다는 근거가 됩니다. 컨테이너 이름은 사람이 붙이는 별칭이라 이름만 비교해서 버전을 판단하지 않습니다. 실제 식별값은 실행 환경마다 달라지므로 예제에서 임의의 64자리 값을 성공 증거로 제공하지 않습니다.

쓰기 계층에서 생긴 차이를 봅니다

이미지의 공통 파일 위에 각 컨테이너의 쓰기 계층이 생깁니다. 한 인스턴스의 /tmp에 만든 표식은 다른 인스턴스의 같은 경로에 자동으로 나타나지 않습니다. 이미지를 수정한 것도 아닙니다. 실습 검사는 한 컨테이너에서 표식을 만들고 다른 컨테이너에는 없는지 확인합니다. 두 곳에 공유 볼륨을 연결한 경로에서는 다른 결과가 나올 수 있으므로 표식은 데이터 마운트 밖인 /tmp에 둡니다.

중지와 제거의 차이를 읽습니다

중지는 실행 프로세스를 끝내는 동작이고 컨테이너 객체와 쓰기 계층은 남을 수 있습니다. 제거하면 해당 컨테이너의 쓰기 계층을 잃습니다. 같은 이미지에서 다시 생성해도 그 계층의 파일이 복구되지는 않습니다. 이름 붙인 볼륨은 별도 객체이므로 컨테이너 재생성과 다른 수명을 가집니다. 이 구분은 안내판 데이터를 어디에 보관해야 하는지 판단하는 출발점이며 다음 설정 레슨에서 실제 재생성으로 확인합니다.

태그의 이름과 내용 식별을 구분합니다

notice-m03:practice 같은 태그는 이미지 내용을 가리키는 이름입니다. 이후 같은 이름으로 다른 이미지를 빌드하면 이름이 가리키는 대상이 바뀔 수 있습니다. 이번 starter의 release-template.json은 mutable-tag 정책을 요구하므로 마지막 검사가 실패합니다. imagePolicy를 image-id로 바꾸면 검사기는 실제 image inspect의 Id를 읽고 두 컨테이너를 그 값으로 실행합니다. 문자열 이름이 같다는 주장보다 사용한 내용 식별값을 남깁니다.

실행과 관측의 경계를 읽습니다

docker ps는 실행 중인 컨테이너를 보여 주며 docker ps -a는 종료된 객체도 포함합니다. 목록에 없다고 이미지까지 없어진 것으로 판단하지 않습니다. docker image inspect는 이미지, docker inspect는 특정 컨테이너의 상태를 확인하는 데 사용합니다. 출력의 Running은 프로세스 실행 여부라 HTTP 성공과 같지 않습니다. 이번 검사는 컨테이너 실행 상태를 먼저 보고 실제 /health 응답을 기다려 두 근거를 함께 확인합니다.

접속 실패를 상태 오류와 구별합니다

Cannot connect to the Docker daemon은 앱의 HTTP 오류보다 앞선 실행 환경 문제입니다. daemon 동작과 현재 Docker context를 확인합니다. 이름 충돌 오류는 기존 객체의 이름이 남아 있다는 의미이므로 무작정 삭제하지 말고 소유자를 먼저 확인합니다. 실행 직후 Exited이면 docker logs와 inspect의 상태를 읽습니다. JAR 경로, 시작 인자, 수신 주소를 대조하며 프로세스가 살아 있는 것만으로 성공을 기록하지 않습니다.

검사기가 만든 자원만 다룹니다

check.sh는 UUID 접두어와 bootcamp.owner 라벨로 두 컨테이너, 두 볼륨, 빌드 태그를 구분합니다. 호스트의 사용 가능한 임의 포트를 루프백에 할당해 다른 레슨과의 충돌을 줄입니다. 끝나면 그 소유 라벨의 자원만 정상 종료하고 제거합니다. 공유 daemon에서 전체 prune을 실행하는 과제는 아닙니다. 데이터 보존 관찰은 검사 중 재생성 사이의 결과이고 종료 뒤 검사 볼륨이 정리된다는 점을 함께 기록합니다.

완료 기준을 증거로 설명합니다

Java 단위 검사만 통과했다고 이 레슨을 마쳤다고 하지 않습니다. 개인 Docker 환경에서 bash check.sh로 같은 이미지 ID, 다른 컨테이너 ID, 개별 쓰기 상태를 확인해야 합니다. 이어 환경별 응답과 재생성까지 통합 검사가 진행됩니다. 지금의 결함은 이미지 선택 정책이며 다른 레슨의 준비 코드는 제공되어 있습니다. 제출에는 실제 두 ID의 관계와 /tmp 표식이 공유되지 않은 이유를 자신의 말로 적습니다.

팀 동료가 같은 이미지라면 상태도 같아야 한다고 말하면 어떤 상태를 비교했는지 되묻습니다. JAR 파일은 같을 수 있지만 메모리와 요청 로그는 실행마다 달라집니다. 환경 변수도 실행 시점 입력이라 이미지 동일성과 별도로 남깁니다. 서재의 빌드·배포 장에서는 Maven 산출물의 배경을 더 읽고, 여기서는 공통 산출물과 독립된 실행 상태를 관측하는 데 집중합니다.

Docker 이미지 개념과 식별값은 공식 image pull 문서에서 확인할 수 있습니다. 본문 명세의 값은 문서 예제가 아니라 개인 실습에서 관측한 값으로 채웁니다.

따라하기

이미지 준비

zip 루트에서 실행합니다. Java 테스트 성공 뒤 이미지가 생성되는지 확인합니다. Docker를 실행하지 못한 환경이므로 출력은 비웁니다.

./mvnw package
mkdir -p build-context
cp target/notice-board-1.0.0.jar build-context/app.jar
cp Dockerfile .dockerignore build-context/
docker build -t notice-m03:practice build-context

이미지와 실행 식별

실제 sha256 ID를 기록합니다. 컨테이너 Id와 Image 비교는 통합 검사의 independent container IDs와 identical image ID 항목에서 확인합니다.

docker image inspect notice-m03:practice --format '{{.Id}}'

시작 정책 수정

imagePolicy를 image-id로 수정하고 JSON 파싱 성공을 확인합니다. 표시한 명령은 수정 결과를 읽는 명령입니다.

python3 -m json.tool release-template.json

독립 상태 검사

PASS로 표시한 ID 비교와 /tmp 쓰기 계층 격리 항목을 확인합니다. 최종 RESULT의 실패 수가 0인지 보고, 수동 빌드 태그는 README 절차로 정리합니다.

bash check.sh

확인 문제

실습

release-template.json의 mutable-tag 정책을 image-id로 고치고 같은 이미지·다른 컨테이너·독립 쓰기 상태를 확인합니다. 검사 코드와 기대값은 수정하지 않습니다. bash check.sh가 해당 결함을 거부하고 solution은 전체 HTTP·데이터·명세 검사를 통과해야 합니다. 실행 도구가 없는 환경에서는 external 검증 대기로 남깁니다.

시작 코드·테스트 내려받기

실행 명령

bash check.sh

기대 결과

개인 Docker 환경에서 모든 PASS 항목과 RESULT: 0 failure(s). 실제 imageDigest를 기록한 release.json 생성.

모범 답안모범 답안 내려받기

더 읽기

면접 질문

  • 컨테이너 이미지와 실행 중 컨테이너의 차이를 설명합니다.