Amazon ECRにプライベートリポジトリを作成してイメージのpush/pullを実行する


1. はじめに

AWS re:Invent 2020で発表されましたが、Amazon ECRでパブリックレジストリが利用できるようになりました。
しかし、今回はそれとは関係なく、プライベートレジストリを使用します。
これまでECRを触ってこなかったので、使ってみたという内容です。

2. 構成

2台のLinuxサーバを使用します。1台目からイメージをpushし、2台目はイメージをpullします。
ECRはリージョンサービスで、VPCエンドポイントも利用できます。(今回は使用しません)

3. ECRの設定

リポジトリの作成

ECRのリポジトリを以下の設定で作成します。
可視性設定:プライベート
リポジトリ名:test-app-repo
タグのイミュータビリティ:無効
プッシュ時にスキャン:有効
KMS暗号化:有効

4. EC2(1台目)からのpush

まず、ECRレジストリに対してDockerを認証します。「Login Succeeded」と表示されたことを確認します。
WARNINGが出ていますが、そのまま進めます。これについては本記事の「8. 警告&エラー集」で説明します。

$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com
WARNING! Your password will be stored unencrypted in /home/ec2-user/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

今回は「test-app」というイメージをpushしたいと思います。

$ docker images
REPOSITORY      TAG                 IMAGE ID            CREATED             SIZE
test-app        v1.0                72b199328340        10 days ago         461MB

docker tagコマンドでpushする対象にタグを設定します。
指定する形式は、「AWSアカウントID.dkr.ecr.リージョン.amazonaws.com/リポジトリ名:タグ」です。
タグを省略した場合は、自動でlatestのタグが付きます。

$ docker tag test-app:v1.0 \
> 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo:v1.0

タグ付けした結果を確認します。

$ docker images
REPOSITORY                                                        TAG                 IMAGE ID            CREATED             SIZE
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo   v1.0                72b199328340        10 days ago         461MB
test-app                                                          v1.0                72b199328340        10 days ago         461MB

では、イメージをpushします。

$ docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo:v1.0

コンソールから確認すると、イメージタグにv1.0が追加されたことが確認できます。

5. EC2(2台目)からのpull

5-1. IAMポリシーの作成とアタッチ

2台目のEC2はaws configureで認証情報(アクセスキー、シークレットアクセスキー)を渡していないので、
そのままではECRにアクセスできません。
以下のIAMポリシーを作成してEC2のIAMロールにアタッチし、ECRにアクセスできるようにします。
IAMポリシー名:AmazonECRFullAccess

json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:*"
            ],
            "Resource": "*"
        }
    ]
}

5-2. EC2からのpull

まずは、1台目と同じようにECRレジストリに対してDockerを認証します。

$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com

イメージをpullします。

$ docker pull 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo:v1.0

結果を確認します。2台目のLinuxサーバがECRからイメージをpullすることができました。

$ docker images
REPOSITORY                                                        TAG                 IMAGE ID            CREATED             SIZE
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo   v1.0                72b199328340        10 days ago         461MB

6. v2.0をpushする

次に、タグ「v2.0」を付けたイメージもpushしてみたいと思います。

$ docker images
REPOSITORY                                                        TAG                 IMAGE ID            CREATED             SIZE
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo   v1.0                72b199328340        10 days ago         461MB
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo   v2.0                72b199328340        10 days ago         461MB

イメージをpushします。

$ docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo:v2.0

コンソールから確認すると、v2.0が追加されています。

7. イメージタグを削除する

v2.0が不要になったと仮定して、イメージタグを削除したいと思います。
(aws configureでregionを指定してある場合は、コマンドでは指定不要です)

$ aws ecr batch-delete-image --repository-name test-app-repo --image-ids imageTag=v2.0 --region ap-northeast-1
{
    "failures": [],
    "imageIds": [
        {
            "imageTag": "v2.0",
            "imageDigest": "sha256:58d3c26bee377e039c0ce5c2ef92ed2ce10b956bf3dc0cf5dba4b4d6f56aaf94"
        }
    ]
}

再度コンソールから確認すると、v2.0が削除されています。

イメージを削除する場合は、イメージのダイジェストを指定すれば削除できます。
参考:https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/delete_image.html

8. 警告&エラー集

警告①

$ aws ecr get-login --region ap-northeast-1 --no-include-email
$ docker login -u AWS -p {認証トークン} https://123456789012.dkr.ecr.ap-northeast-1.amazonaws.com
WARNING! Using --password via the CLI is insecure. Use --password-stdin.

→AWS CLI バージョン 1.17.10 より前のバージョンを使用している場合はget-loginコマンドで認証しますが、
セキュリティリスクがあり非推奨です。AWS CLIのバージョンを上げて、get-login-passwordを使用することが推奨されます。
参考:https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/Registries.html

警告②

$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com
WARNING! Your password will be stored unencrypted in /home/ec2-user/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

→Dockerのデフォルトの動作として、ログインパスワードを暗号化せずにconfig.jsonに保存します。
外部のクレデンシャルストアに保存する方がより安全という警告です。
参考:https://docs.docker.com/engine/reference/commandline/login/#credentials-store

エラー①

$ docker pull 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo:v1.0
Error response from daemon: Get https://123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/v2/test-app-repo/manifests/v1.0: no basic auth credentials

→ECRレジストリに対してDockerを認証していないと出るエラーです。

エラー②

$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com
An error occurred (AccessDeniedException) when calling the GetAuthorizationToken operation: User: arn:aws:sts::123456789012:assumed-role/IAMロール名/インスタンスID is not authorized to perform: ecr:GetAuthorizationToken on resource: *
Error: Cannot perform an interactive login from a non TTY device

→aws configureで認証情報を指定していない、あるいはEC2のIAMロールにECRへのアクセスに必要な
IAMポリシー(本記事ではAmazonECRFullAccess)がアタッチされていない場合に出るエラーです。