Amazon ECR に Windows コンテナの Docker イメージを保存する前に考慮したいこと

普通に docker push すると ECR と MCR から Docker イメージの Pull が発生します。仕様と対処方法、注意事項について紹介します。
2022.01.22

Windows コンテナの実行基盤としてAWSでは Amazon ECS(ECS on EC2)と、AWS Fargate の2つが提供されています。共に Windows コンテナのイメージは Amazon ECR で管理することが多いかと思います。

意外に気付かない点なのですが、Windows コンテナ実行(タスク起動)するときに ECR から Docker イメージを Pull すると同時に Microsoft Container Registry(MCR) からも Pull します。

Icons made by Freepik from www.flaticon.com

Windows OS イメージの仕様と ECR だけで完結させるにはどうすればよいのか紹介します。

どうしてこうなった?

ECR のドキュメントに理由について以下の記載があります。

要はライセンスの都合で Windows の全イメージレイヤーを ECR に Push できません。

Images based on the Windows operating system include artifacts that are restricted by license from being distributed. By default, when you push Windows images to an Amazon ECR repository, the layers that include these artifacts are not pushed as they are considered foreign layers. When the artifacts are provided by Microsoft, the foreign layers are retrieved from Microsoft Azure infrastructure.

ECR 外にイメージがあると困るケース

配布制限のあるレイヤーを外部の Microsoft Container Registry(MCR) から取得するためにインターネットアクセスが発生します。パブリックアクセスが禁止されていたり、制限されているネットワーク環境下ですとインターネット経由で必要なレイヤーを取得できません。

例として NAT Gateway がなくプライベートサブネットからのインターネットアクセスはできなく、ECR へは VPCエンドポイントを設置することで通信経路を確保したとしましょう。これだと Windows コンテナは起動できません。Microsoft Container Registry(MCR) へアクセスするインターネットへの経路がなくコンテナ起動に至りません。

Icons made by Freepik from www.flaticon.com

対処

同じく ECR のドキュメントに対処方法と、注意事項について記載があります。

対処方法

Dockerデーモンに--allow-nondistributable-artifactsフラグをセットすることで、本来 Microsoft Container Registry(MCR)に保存されている配布制限のあるレイヤーも含めてすべて ECR へ Psuhできます。これで必要なアクセス経路を ECR のみで完結させることができます。

It is possible to override this behavior when pushing Windows images to Amazon ECR by using the --allow-nondistributable-artifacts flag in the Docker daemon. When enabled, this flag will push the licensed layers to Amazon ECR which enables these images to be pulled from Amazon ECR via the VPC endpoint without additional access to Azure being required.

Dockerデーモンにフラグをセットする方法は動作検証の項で紹介します。

Icons made by Freepik from www.flaticon.com

注意事項

ECR に全レイヤーを保存することはできますがあくまでも自分の環境内での使用のみ許可されています。ライセンスを守らなくてよいとは言っていなく、パブリックでの配布や、再配布をしてはいけないと記載があります。

Using the --allow-nondistributable-artifacts flag does not preclude your obligation to comply with the terms of the Windows container base image license; you cannot post Windows content for public or third-party redistribution. Usage within your own environment is allowed.

検証環境

Windows の Fargte 環境です。

Product Version
OS Famliy Windows Server 2019 Full
Fargate platform 1.0.0

Dockerイメージ

IIS のイメージに自前のindex.htmlに入れ替えます。

Dockerfile

FROM mcr.microsoft.com/windows/servercore/iis

RUN powershell -NoProfile -Command Remove-Item -Recurse C:\inetpub\wwwroot\*

WORKDIR /inetpub/wwwroot

COPY content/ .

index.htmlの内容はただのテストページです。

content/index.html

<html>

<head>
	<title>AWS Fargate Sample Windows App</title>
	<style>
		body {
			margin-top: 40px;
			background-color: rgb(42, 6, 173);
		}
	</style>
</head>

<body>
	<div style=color:white;text-align:center>
		<h1>AWS Fargate Sample Windows App</h1>
		<p>Your application is now running on a container in AWS Fargate.</p>⏎

動作検証してみた

Windows の Fargate と ECR の組み合わせで Windows コンテナを実行した際の挙動を確認します。

VPCエンドポイントあり構成と、ECR に全レイヤー格納してVPCエンドポイントあり構成の紹介が本編です。

インターネットアクセス許可構成

NAT Gateway を配置しプライベートサブネットからインターネットアクセスを許可した構成です。

項目 設定値
NAT Gateway あり
VPCエンドポイント なし
Docker イメージ Dockerデーモンのフラグ未設定
タスク起動結果 成功

Icons made by Freepik from www.flaticon.com

Let's Try

docker buildコマンドで Docker イメージを作成します。

docker build -t sample-windows-iis .

作成した Docker イメージに ECR のリポジトリ名でlatestタグを付けます。

docker tag sample-windows-iis:latest 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/sample-windows-iis:latest

普通に docker pushコマンドで ECR へ Docker イメージを Push しました。

docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/sample-windows-iis:latest

76.45 MBの軽量な Docker イメージを ECR から確認できました。

Windows の Fargate で 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/sample-windows-iis:latestの Docker イメージを指定してタスクを起動しました。ちなみに ELB のバックエンドで起動する IIS の Windowsコンテナです。

ELB の DNS 名に Web ブラウザからアクセスして Dockerfile で指定した content/index.html の内容を確認できます。

MCR と ECR から Pull したのかは確認できませんが問題なくタスク起動に成功しました。

インターネットアクセス不可構成

NAT Gateway をなくしプライベートサブネットからインターネットアクセスを禁止した構成です。

項目 設定値
NAT Gateway なし
VPCエンドポイント なし
Docker イメージ Dockerデーモンのフラグ未設定
タスク起動結果 失敗

Icons made by Freepik from www.flaticon.com

Let's Try

新しいタスクを起動しようとすると、ECR へもアクセスできないため Pull できずにタスクの起動に失敗します。

停止理由 ResourceInitializationError: unable to pull secrets or registry auth: pull command failed: : exit status 1

ここまでは想像通りだったと思います次からが本編です。

VPCエンドポイントあり構成

NAT Gateway をなくしたまま、ECR への VPCエンドポイントを用意しました。依然としてプライベートサブネットからインターネットアクセスを禁止した構成です。いよいよ核心に迫ります。

項目 設定値
NAT Gateway なし
VPCエンドポイント あり
Docker イメージ Dockerデーモンのフラグ未設定
タスク起動結果 失敗

Icons made by Freepik from www.flaticon.com

Let's Try

インターネットアクセス不可構成とはエラーメッセージが変わり、https://mcr.microsoft.com/v2/windows/servercore/blobs/...へアクセスしようとしているのが確認できます。ECR へは VPCエンドポイント経由でアクセスできますが、Microsoft Container Registry(MCR)へはインターネット経由のアクセスが必要になり失敗しています。

停止理由 CannotPullContainerError: ref pull has been retried 5 time(s): failed to copy: httpReadSeeker: failed open: failed to do request: Get https://mcr.microsoft.com/v2/windows/servercore/blobs/sha256:567fd00846e9a9f44eea5925b497356dda00fe89b8335d2a3b2a8b9d8...

必要なレイヤーが揃わないのでタスク起動に失敗しました。

ECR に全レイヤー格納してVPCエンドポイントあり構成

VPCエンドポイントはありますが依然としてプライベートサブネットからインターネットアクセスを禁止した構成です。Docker デーモンにフラグをセットして ECR へ Docker イメージを Push し直してから試します。

項目 設定値
NAT Gateway なし
VPCエンドポイント あり
Docker イメージ Dockerデーモンのフラグあり
タスク起動結果 成功

Icons made by Freepik from www.flaticon.com

以下を参考にDockerデーモンのコンフィグファイルを編集します。

C:\ProgramData\docker\configフォルダを開きdaemon.jsonファイルを新規作成しました。内容は以下の様にご自身のAWSアカウントを指定して入力してください。

C:/ProgramData/docker/config/daemon.json

{
    "allow-nondistributable-artifacts": [
        "123456789012".dkr.ecr.ap-northeast-1.amazonaws.com"
    ]
}

当初ProgramDataフォルダの存在がわからずに困りました。隠しフォルダになっているのでエクスプローラーの設定からHidden itemsにチェックを入れて表示してください。

Docker デーモンを再起動すると設定が反映されます。Windows のデーモン再起動方法がわからなかったので OS 再起動しました。

ビルド済みのsample-windows-iis:latestに新たにflagタグを付けました。

docker tag sample-windows-iis:latest 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/sample-windows-iis:flag

flagタグを付けた Docker イメージを Push します。Docker デーモンの設定により全イメージレイヤーを ECR へ Push するため時間がかかります。

docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/sample-windows-iis:flag

2.8 GBにもなる巨大な Docker イメージを ECR から確認できました。

Let's Try

タスク定義を編集しflagタグのイメージを利用するようにしてタスクを起動します。

インターネットアクセスは禁止されていても、ECR へのアクセス経路を VPCをエンドポイントで確保すれば Windows コンテナの起動に成功できることを確認できました。

Web ブラウザからテストページを確認できました。

Docker イメージの Push 方法の違いによる挙動の違いを確認できました。

ネットワーク構成によっては Push 方法を検討しないとタスク起動できないことや、知らないところでパブリックアクセスが発生しているかもしれません。

以上Windows コンテナの Docker イメージを ECR へ Pushしたときに気をつけて欲しいポイントでした。

おわりに

ECR のドキュメントに書いてあるから読めばわかる話なのですが、ECS の Windows コンテナのドキュメントしか知らなく、ECR のドキュメントに Windows コンテナの記述があることに気づきませんでした。ですので、本記事で共有できればなと思います。

その他、スケールアウト・インが多く見込まれており、NAT Gateway経由でインターネットアクセスする場合は、通信量によっては ECR にすべて格納して VPCエンドポイント設置する方が安く上がることも考えられます。環境に適したネットワーク構成をご検討ください。

参考