소개
팀이 작은 HTTP 애플리케이션을 배포하려 합니다. 제공된 코드를 컨테이너 이미지로 패키징하여 Amazon Elastic Container Registry(ECR)에 저장하고, 저장한 정확한 릴리스가 시작되어 요청에 응답하는지 확인하세요. 별도의 참조 리포지토리는 유지하고 자신이 만든 리소스는 마지막에 삭제합니다.
먼저 AWS Foundations와 IAM 자격 증명 기반 정책의 기초를 학습하세요. Docker 개념은 여기서 설명하며, 앱 코드를 작성하거나 개인 AWS 계정을 준비할 필요가 없습니다. 독립 VM에 설정된 AWS CLI, Docker, Dockerfile 및 소스가 제공됩니다. 위쪽 AWS View에서 리포지토리를 관찰하고 앱을 테스트하며, 아래쪽 Terminal에서 명령을 실행합니다. 두 영역은 같은 리소스 상태를 읽습니다.
자격증 관련 내용
| 자격증 | 시험 작업 | 실습 내용 |
|---|---|---|
| Developer – Associate (DVA-C02) | 작업 3.1, 기술 3.1.1 | 애플리케이션 코드와 런타임을 배포용 컨테이너 이미지로 패키징합니다. |
실습 개요

불변 이미지 리포지토리 만들기
이 단계에서는 애플리케이션 릴리스를 저장할 리포지토리를 만듭니다.
이미지는 앱 파일과 런타임을 패키징합니다. 컨테이너는 이미지의 실행 인스턴스입니다. 레지스트리는 이미지를 저장하고 배포하며, ECR 리포지토리는 한 앱의 이미지를 묶습니다. 이미지 저장만으로 앱이 시작되지는 않습니다.
제공된 작업 디렉터리로 이동하여 Dockerfile을 확인하세요. cat은 텍스트 파일을 출력합니다:
cd /home/labex/project
cat application/Dockerfile
FROM은 Python 기반 이미지를, COPY는 앱 파일 추가를, USER는 권한이 낮은 사용자를, CMD는 시작 명령을 지정합니다. 기반 이미지의 sha256 참조는 그 내용만 고정하며, 새로 만드는 앱 이미지의 참조가 아닙니다.
ct-demo를 만드세요. 태그는 release-1처럼 읽기 쉬운 이름입니다. IMMUTABLE은 기존 태그를 다른 내용으로 대체하지 못하게 하여 릴리스 이름을 신뢰할 수 있게 합니다:
aws ecr create-repository \
--repository-name ct-demo \
--image-tag-mutability IMMUTABLE
응답에는 Docker가 사용하는 주소인 repositoryUri와 imageTagMutability: IMMUTABLE이 포함됩니다. URI를 셸 변수에 저장하세요. $(...)는 명령 출력을 캡처하고, --query는 필드를 선택하며, --output text는 JSON 따옴표를 제거합니다:
REPOSITORY_URI=$(aws ecr describe-repositories \
--repository-names ct-demo \
--query 'repositories[0].repositoryUri' \
--output text)
echo "$REPOSITORY_URI"
변수를 유지하도록 이 Terminal 세션을 열어 두세요. 위쪽 AWS View에서 이미지가 0개인 ct-demo가 ct-reference 옆에 나타나야 합니다. 참조 리포지토리는 다른 앱 소유이므로 정리 대상이 아닙니다.
릴리스 빌드 및 게시하기
이 단계에서는 제공된 앱을 빌드하여 이미지를 ECR로 푸시합니다.
푸시하려면 Docker가 먼저 레지스트리에 로그인해야 합니다. 레지스트리 주소는 URI의 첫 번째 슬래시 앞부분입니다. ${REPOSITORY_URI%%/*}는 해당 슬래시와 이후 부분을 제거합니다:
REGISTRY=${REPOSITORY_URI%%/*}
echo "$REGISTRY"
AWS CLI로 단기 ECR 로그인 암호를 받아 Docker로 직접 전달하세요. 파이프 |는 출력을 다음 명령에 전달하며, --password-stdin은 암호가 인수나 Terminal 출력에 노출되지 않게 합니다. 직접 출력하거나 별도로 저장하지 마세요:
aws ecr get-login-password | docker login \
--username AWS \
--password-stdin "$REGISTRY"
Docker는 Login Succeeded를 표시합니다. 현재 자격 증명에 허용된 작업만 가능하며 모든 리포지토리에 접근할 수 있는 것은 아닙니다.
application 디렉터리에서 빌드하세요. -t는 결과 이미지에 URI와 릴리스 태그를 붙입니다. 마지막 인수는 COPY가 사용할 수 있는 파일이 들어 있는 빌드 컨텍스트입니다:
docker build -t "${REPOSITORY_URI}:release-1" application
이미지를 푸시하세요. Docker가 파일 시스템 계층과 내용을 설명하는 manifest를 업로드합니다:
docker push "${REPOSITORY_URI}:release-1"
완료되면 Docker가 sha256:... 다이제스트를 출력합니다. 다이제스트는 정확한 내용을 식별하고 태그는 이름을 식별합니다. 태그 변경을 허용하는 리포지토리에서도 다이제스트는 원래 내용과 연결됩니다.
ECR을 조회하여 저장된 릴리스를 확인하세요:
aws ecr describe-images \
--repository-name ct-demo \
--image-ids imageTag=release-1 \
--query 'imageDetails[0].{Tags:imageTags,Digest:imageDigest}'
다이제스트도 변수에 저장하세요:
IMAGE_DIGEST=$(aws ecr describe-images \
--repository-name ct-demo \
--image-ids imageTag=release-1 \
--query 'imageDetails[0].imageDigest' \
--output text)
ECR 다이제스트는 docker push의 출력과 같아야 합니다. 위쪽 AWS View에서 ct-demo에 release-1과 다이제스트가 나타나야 합니다. 앱은 아직 실행되지 않으며 다음 단계에서 시작합니다.
게시한 정확한 이미지 실행하기
이 단계에서는 다이제스트로 이미지를 가져와 실제 앱 컨테이너를 테스트합니다.
먼저 로컬 빌드 이미지를 삭제하세요. docker image rm은 로컬 참조를 지우며 ECR의 이미지는 삭제하지 않습니다. 다음 pull로 게시된 릴리스를 가져옵니다:
docker image rm "${REPOSITORY_URI}:release-1"
URI와 다이제스트를 @로 연결하여 정확한 내용을 선택하세요:
docker pull "${REPOSITORY_URI}@${IMAGE_DIGEST}"
Docker가 동일한 다이제스트와 다운로드 성공을 표시해야 합니다. 이를 ct01-app으로 시작하세요. --detach는 백그라운드 실행이며, --publish 127.0.0.1:8081:8000은 호스트 8081 포트를 앱의 8000 포트에 연결합니다. 루프백 주소는 직접 접근을 이 VM 내부로 제한합니다. 이미지는 이미 권한이 낮은 사용자를 선택합니다. --read-only는 루트 파일 시스템을 읽기 전용으로, --cap-drop ALL은 Linux capabilities 제거를, no-new-privileges는 추가 권한 획득 방지를 설정합니다:
docker run --detach \
--name ct01-app \
--read-only \
--cap-drop ALL \
--security-opt no-new-privileges \
--memory 256m \
--publish 127.0.0.1:8081:8000 \
"${REPOSITORY_URI}@${IMAGE_DIGEST}"
컨테이너 ID는 Docker가 시작 요청을 수락했다는 뜻이지 앱이 정상이라는 증거는 아닙니다. HTTP를 테스트하세요. curl --fail은 HTTP 오류에서 실패하고 --retry-all-errors는 짧은 연결 재설정을 포함한 시작 시 연결 오류를 재시도합니다:
curl --fail --silent --show-error \
--retry 5 --retry-all-errors --retry-delay 1 \
http://127.0.0.1:8081/
"release": "release-1"과 컨테이너 호스트 이름을 포함하는 JSON을 기대할 수 있습니다. 로그에서 실제 요청을 확인하세요:
docker logs ct01-app
served application request가 나타나야 합니다. 호스트 이름과 타임스탬프는 달라집니다. 위쪽 AWS View에서 Request application을 선택하세요. 응답도 release-1이어야 합니다. 이 버튼은 실제 컨테이너로 HTTP 요청을 보냅니다.

애플리케이션 리소스 정리하기
이 단계에서는 참조 리포지토리를 유지하면서 앱을 중지하고 로컬 이미지와 ECR 리포지토리를 삭제합니다.
먼저 컨테이너를 중지하세요:
docker stop ct01-app
그다음 컨테이너를 삭제하세요. 컨테이너 삭제는 이미지 삭제와 별개입니다:
docker rm ct01-app
이 이미지를 사용하는 실행 중 컨테이너가 없으므로 로컬 다이제스트 참조를 삭제하세요:
docker image rm "${REPOSITORY_URI}@${IMAGE_DIGEST}"
다이제스트로 ECR 이미지를 삭제하세요. imageDigest는 태그에 의존하지 않고 정확한 내용을 선택합니다:
aws ecr batch-delete-image \
--repository-name ct-demo \
--image-ids imageDigest="$IMAGE_DIGEST"
응답의 imageIds에 삭제된 이미지가 표시되고 failures는 비어 있어야 합니다. 이제 비어 있는 앱 리포지토리를 삭제하세요:
aws ecr delete-repository --repository-name ct-demo
참조 리포지토리가 남아 있는지 확인하세요:
aws ecr describe-repositories \
--query 'repositories[].repositoryName'
ct-reference만 표시되어야 합니다. 마지막으로 Docker가 저장한 레지스트리 로그인 정보를 지우세요:
docker logout "$REGISTRY"
위쪽 AWS View에서 ct-demo와 앱 컨테이너가 사라지고 참조 리포지토리는 남아야 합니다. HTTP 오류만으로 정리를 증명할 수 없으므로 리소스 목록도 확인하고 실제 컨테이너와 이미지도 삭제했습니다.
요약
불변 ECR 리포지토리를 만들고 앱 이미지를 빌드 및 게시하여 다이제스트를 확인한 뒤 정확한 릴리스를 실행했습니다. 실제 HTTP 응답과 로그를 테스트했으며 다른 앱의 리포지토리를 유지하면서 자신의 컨테이너, 로컬 이미지와 ECR 리포지토리를 삭제했습니다. 다음 실습에서는 ECS 작업 정의로 이미지를 선택하고 실행합니다.
자세한 내용은 AWS 공식 문서를 참고하세요: 레지스트리 인증 및 이미지 푸시; 이미지 태그 덮어쓰기 방지.



