4時間かけてECRにイメージを1万個プッシュしほんとにエラーが出るか確かめてみた

ECRのリポジトリ数とリポジトリあたりのイメージ数の上限が、それぞれ1万に引き上げられました!祭りです!
2019.07.29

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

みんな大好き、Amazon ECRですが、先日のアップデートでリポジトリとイメージの制限が引き上げられました。

Amazon ECR で、リポジトリとイメージの制限の引き上げをサポート

これで、ECRのイメージ数上限に引っかかって夜中に叩き起こされるインフラ担当の方が少しでも減ることをハマコーは祈っております。

(祭) ∧ ∧
 Y  ( ゚Д゚)
 Φ[_ソ__y_l〉     ECRマツリダワッショイ
    |_|_|
    し'´J

ECRのリポジトリ数とイメージ数のデフォルト上限緩和

今回のアップデートで、従来は1リージョンあたりのリポジトリ数、および1リポジトリあたりのイメージ数のデフォルト上限値が1000だったものが、両方とも10000に引き上げられ従来の10倍に制限緩和されました。以下の公式ドキュメントに記載があります。

従来、リポジトリ数の上限1000に引っかかることはあまりないと思いますが、1リポジトリあたりのイメージ上限数1000は、頻繁に変更がありイメージビルドが自動化された環境だと制限にひっかかったのは聞いたことがあります。この場合、CI/CDパイプラインが止まってしまうので致命的。

この上限が10000に引き上げられたことで、そういった事故もある程度は未然に防ぐことができるのではないでしょうか。

1リポジトリにイメージを1万個プッシュしてみた

というわけで、実際に上限が1万になっているか確認してみます。実施環境は以下の通り。

$ aws --version
aws-cli/1.16.207 Python/3.6.4 Darwin/18.6.0 botocore/1.12.197

ECRリポジトリの作成

イメージ制限テスト用のECRを作成します。名前は、test-image-limit-repoで作成。

$ aws ecr create-repository --repository-name test-image-limit-repo
{
    "repository": {
        "repositoryArn": "arn:aws:ecr:ap-northeast-1:123456789012:repository/test-image-limit-repo",
        "registryId": "123456789012",
        "repositoryName": "test-image-limit-repo",
        "repositoryUri": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-image-limit-repo",
        "createdAt": 1564186279.0,
        "imageTagMutability": "MUTABLE"
    }
}

事前に1万個イメージをプッシュしたときの料金を試算

1万個イメージをプッシュする時、料金がどれぐらいかかるかは気になるので、事前に調査。

  • 料金 - Amazon ECR | AWS

  • ストレージコストは1ヶ月あたりGB単位で0.1USD

  • すべてのデータ転送受信(イン)は無料

今回プッシュするイメージは、以下のscratchを利用したダミーファイル。これだと、作成したイメージのサイズは0になります。

Dockerfile

FROM scratch
MAINTAINER hamako1

実際にECRにプッシュしてみます。ECRにログイン。

$ $(aws ecr get-login --no-include-email --region ap-northeast-1)

Dockerfileは以下で用意します。

Dockerfile

FROM scratch
MAINTAINER hamako

DockerbuildしてECRにプッシュします。

docker build -t 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-image-limit-repo:1 .
docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-image-limit-repo:1
The push refers to repository [123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-image-limit-repo]
1: digest: sha256:fef734996a075033ea83ccce717e3e6c8db2ea8c3c1e7d9ce7723aa6818f9687 size: 617

プッシュ後、イメージサイズを確認すると、ImageSizeInBytesが、32Bytesになっていました。イメージの内容自体は0Byteでもメタ情報をもつのか、ECR上ではサイズが増えました。ただ、料金は気にしなくて良さそうです。

$ aws ecr describe-images --repository-name test-image-limit-repo
{
    "imageDetails": [
        {
            "registryId": "123456789012",
            "repositoryName": "test-image-limit-repo",
            "imageDigest": "sha256:fef734996a075033ea83ccce717e3e6c8db2ea8c3c1e7d9ce7723aa6818f9687",
            "imageTags": [
                "1"
            ],
            "imageSizeInBytes": 32,
            "imagePushedAt": 1564212305.0
        }
    ]
}

実際に1万個イメージを作ってプッシュする

以下のシェルスクリプトを用意しました。

push-10000images.sh

#! /bin/bash

REPOSITORY_URI=123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-image-limit-repo
$(aws ecr get-login --no-include-email --region ap-northeast-1)

for count in {1..10000};do

# write Dockerfile
cat << EOS > Dockerfile
FROM scratch
MAINTAINER hamako${count}
EOS

# docker build and push
docker build -t ${REPOSITORY_URI}:${count} .
docker push ${REPOSITORY_URI}:${count}

done

最初は、同じイメージを1万回タグを変えてプッシュすれば良いかと思ったのですが、同じハッシュイメージの場合ダイジェストが同じとなり、リポジトリ上では同一イメージとして判定されイメージ数が増えませんでした。そのため、1万回のループの中で、Dockerfileを都度書き換えてイメージのハッシュ値を変更してビルドしてプッシュしています。これにより、リポジトリ中のイメージ数を増やすことができます。

後は、このシェルスクリプトを実行して、1万イメージアップされるのを待ちます。実際やってみるとわかるのですが、都度Dockerbuildしてアップロードしているので、1メージあたり3秒程度かかります。そんなの1万個も待ってられないので、実際は10シェルに分けて並列アップロードしました。

ついに1万個プッシュされ、その時が!!

徐々に増えるイメージ数… あとちょっとやで…(この画面はWebコンソールのリポジトリを選択したときの数字。イメージ数をカウントするAPIがどこにあるのかわかりません!)

よーやく、1万個イメージがあがりました!!

ターミナルをみると、無事、エラーが表示されました!!やっほい!!

さらにアップ!!

エラー内容としては以下の通り。

denied: The repository with name 'test-image-limit-repo' in registry with id '123456789012' already has the maximum allowed number of images which is '10000'

もう満足やで。ターミナルで並列実行してたけど、途中でECRのログインセッションがきれたり、assume-roleが切れたりして、なんだかんだ4時間ほどかかりました。

イメージ数が限界になる前にやるべきライフサイクルポリシーの設定

今回、むりやりイメージを1万個入れてみましたが、実際問題1万個もイメージが必要となる機会も無いでしょうし、イメージサイズによりもちろんECRのストレージ料金もかかります。

実際にはECRのライフサイクルポリシーを設定して、古くなったイメージは自動的に削除するのが良いでしょう。こちらを記事を参考に事前の設定をオススメします。

ECRのライフサイクルポリシー設定によるリポジトリ容量の節約

地味だけど進化を止めないECRがよござんす

ECRはDocker Hubのようにパブリックにイメージを公開することはできませんが、AWSのコンテナワークロード(ECS、 Fargate、 EKS、 Batch、 実はElastic Beanstalkにも!)を運用する上では無くてはならないサービスです。地味に進化しているので、これからもECRのアップデート情報、追い続けていきます。

それでは、今日はこのへんで。濱田(@hamako9999)でした。