介绍
团队有一个等待交付的小型 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。将地址保存为 shell 变量。$(...) 捕获命令输出,--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 中,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 中保存的镜像;下一次拉取将获取已发布版本:
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 接受了启动请求,但不能证明应用健康。实际请求应用: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 任务定义来选择并运行镜像。



