気がつけば猫も杓子もDockerと言いますかコンテナな世界になってしまいましたねw DockerイメージをAWSの各種サービスと連携させるためには「ECR」と呼ばれるレジストリサービスへ登録しておく必要があります。
今回はローカルでビルドしたDockerイメージをECRへ登録するまではまとめておきます。
AWS App Runnerが使いたかったのですが、GitHubとの連携で苦戦したためECRにDockerイメージを登録する方法を採用することにしたというのが経緯だったりします。
事前準備
コマンドが最新版か確認
コマンドラインからawsとdockerの各コマンドが最新版か確認します。もし古い物が入っている場合は何らかのエラーでハマる可能性があるのでこのタイミングで更新を。
$ aws --version aws-cli/2.4.29 Python/3.9.12 Darwin/19.6.0 source/x86_64 prompt/off $ docker --version Docker version 20.10.14, build a224086
IAMを準備
ECRが利用できる権限を持ったIAMを作成しアクセスキーとシークレットを保存します。aws configure
コマンドを実行するか、~/.aws/credentials
を直接編集してください。
$ cat ~/.aws/credentials [default] aws_access_key_id = AKXXXXXXXXXXXXXXXXXXXXX aws_secret_access_key = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
ECRにリポジトリを作成する
手順
AWSのマネジメントコンソールなどからDockerイメージを保存するリポジトリを作成します。
「ECS」のページの左メニューに「Amazon ECR」があるのでその下の「リポジトリ」をクリック。
「リポジトリを作成」ボタンをクリック。プライベートかパブリックかは次の画面で選択できます。
リポジトリの作成内容を入力します。
ここでは「プライベート」、名前は「test」としました。この下にプッシュ時に自動的にスキャンするか、暗号化するかの設問があるのでご希望の設定を入力し、一番下にある「リポジトリを作成」ボタンをクリック。
以上でリポジトリの作成は完了です。めっちゃ簡単ですね。
プッシュ方法のチートシート
先ほど作成したリポジトリの詳細画面の右上にある「プッシュコマンドの表示」ボタンをクリックすると、このあと実行するコマンドを表示してくれます。
ご覧の通り、アカウントIDやリポジトリ名などが置き換わった状態のコマンドが表示されます。あとはこれをコピペしてTerminalなどで実行するだけ。めっちゃ便利!
Dockerイメージをプッシュ
基本的には前述の「チートシート」で表示されたコマンドをそのまま実行するだけです。
ログイン情報を保存
ECRにイメージをアップするための認証情報(トークン)をAWSから取得し、dockerコマンドに渡すことで認証情報がローカルに保存されます。
$ aws ecr get-login-password --region 【リージョン】 | docker login --username AWS --password-stdin 【アカウントID】.dkr.ecr.ap-northeast-1.amazonaws.com WARNING! Your password will be stored unencrypted in /Users/katsube/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded
なおこの認証情報の有効期限は12時間のため、このコマンドは定期的に実行する必要があります。
- アカウントIDはAWSの物です。
~/.aws/credentials
に複数のアカウントが登録されており、default以外を利用する場合はaws ecr get-login-password
コマンドに--profile (プロファイル名)
オプションを追加して実行してください。
Dockerイメージをビルド
これは通常通りビルドするだけです。「test」の部分は任意の文字列を指定します。
$ docker build -t test .
Dockerイメージにタグ付け
testイメージにlatestという名前のタグを付けています。タグはバージョン番号のようなもので任意の文字列(v1
やdevelop
など)が指定できます。
$ docker tag test:latest 【アカウントID】.dkr.ecr.ap-northeast-1.amazonaws.com/【リポジトリ名】:latest
ECRへプッシュする
最後にECRへアップします。冒頭のIAMの設定やログイン情報がうまく保存されていればスルッとあがります。
$ docker push 【アカウントID】.dkr.ecr.ap-northeast-1.amazonaws.com/test:latest The push refers to repository [111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test] ce669cbeacc7: Pushed 14435cf07f8c: Pushed adc5e96f5fe1: Pushed b0fc75156d6d: Pushed 7f30cde3f699: Pushed fe810f5902cc: Pushed dfd8c046c602: Pushed 4fc242d58285: Pushed latest: digest: sha256:7977c86c130882643910db1ae3a55865bf5a7cdfaaa8ba11d28b3a1caf86084a size: 1997
マネジメントコンソールなどで確認
ECRのリポジトリを確認し、先ほどプッシュした内容が反映されていれば成功です!
コマンドラインからも確認できます。imageDigestのSHA256のハッシュ値がプッシュ完了後に表示されたものと同一であれば無事にアップされていますね。
$ aws ecr list-images --region ap-northeast-1 --repository-name test { "imageIds": [ { "imageDigest": "sha256:7977c86c130882643910db1ae3a55865bf5a7cdfaaa8ba11d28b3a1caf86084a", "imageTag": "latest" } ] }
~/.aws/credentials
に複数のアカウントが登録されており、default以外を利用する場合は--profile (プロファイル名)
オプションを追加して実行してください。
既存のDockerイメージを更新する
先ほどECRへプッシュしたDockerイメージを更新するには、再度タグをつけてプッシュするだけです。
ソースコードや設定などを変更したらこれもいつも通りビルドしてタグ付け、プッシュします。
$ docker build -t test . $ docker tag test:latest 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test:latest $ docker push 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test:latest
実際にマネジメントコンソールなどでリポジトリの「プッシュされた日時」の時間が更新されていれば成功です。ちなみにタグをつけ忘れると永遠に更新されません。ハマって一晩ほど頭を抱えていましたw
トラブルシューティング
Error saving credentials: error storing credentials
ログイン時にクレデンシャルエラーとなった場合はDockerの設定を変更します。
Error saving credentials: error storing credentials - err: exit status 1, out: `Post "http://ipc/registry/credstore-updated"
~/.docker/config.json
内にある"credsStore":"desktop",
の部分を削除し保存しなおします。
$ cp ~/.docker/config.json ~/.docker/config.json.back $ vi ~/.docker/config.json {"auths":{"https://index.docker.io/v1/":{}},"credsStore":"desktop","experimental":"disabled","stackOrchestrator":"swarm"} ↓ {"auths":{"https://index.docker.io/v1/":{}},"experimental":"disabled","stackOrchestrator":"swarm"}
認証情報の保存先を指定しているようなのですが、これが原因でエラーとなってしまうようです。
no basic auth credentials
ECRへDockerイメージをプッシュする際にno basic auth credentials
と表示された場合は、AWSの認証情報が正しく利用されているか確認してください。
$ docker push 【アカウントID】.dkr.ecr.ap-northeast-1.amazonaws.com/test:latest The push refers to repository [111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test] ce669cbeacc7: Preparing 14435cf07f8c: Preparing adc5e96f5fe1: Preparing b0fc75156d6d: Preparing 7f30cde3f699: Preparing fe810f5902cc: Waiting dfd8c046c602: Waiting 4fc242d58285: Waiting no basic auth credentials
私の場合は~/.aws/credentials
に複数のアカウントが登録されており、default以外を利用したかったのにその指定をしていなかったため発生しました。そのため--profile
オプションを指定することで解決しました。
$ aws ecr get-login-password --region 【リージョン】--profile (プロファイル名) | \ docker login --username AWS --password-stdin 【アカウントID】.dkr.ecr.ap-northeast-1.amazonaws.com
denied: Your authorization token has expired
ECRへDockerイメージをプッシュする際にexpiredと言われた場合、AWSから取得した認証情報の有効期限が切れています。
$ docker push 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test:latest The push refers to repository [111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test] ce669cbeacc7: Preparing (中略) denied: Your authorization token has expired. Reauthenticate and try again.
もう一度ログインしたのち再度プッシュすれば解決します。
$ aws ecr get-login-password --region ap-northeast-1 | \ docker login --username AWS --password-stdin 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com $ docker push 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test:latest