はじめに
チームが小さな 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 に、イメージ数ゼロの 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"
最後に 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 が起動要求を受け付けたことを示しますが、正常動作の証拠ではありません。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 公式ドキュメントを参照してください:レジストリ認証とイメージのプッシュ; イメージタグの上書きを防ぐ。



