ローカル環境を汚さずにECRにプッシュする方法

# はじめに

ローカル環境を汚さずに手軽にDockerイメージをECRにプッシュしたい...

本記事では、[AWS CLIの公式Dockerイメージ](https://hub.docker.com/r/amazon/aws-cli)を用いて、自作したDockerイメージをECRにプッシュする方法をご紹介します。

[ECR(Elastic Container Registry)](https://aws.amazon.com/jp/ecr/)とは、AWSが提供しているDockerイメージの保存場所です。プライベートリポジトリ、パブリックリポジトリ、Dockerイメージの脆弱性スキャンを利用できます。

# 前提条件

- AWSアカウントを持っている
- Dockerがインストールされている
    - Windowsの場合: [Docker Desktop for Windows](https://docs.docker.jp/docker-for-windows/install.html) 
    - Macの場合: [Docker Desktop for Mac](https://docs.docker.jp/docker-for-mac/install.html)
- 「[Dockerコンテナ上でTerraformとAWS CLIを実行する方法](https://qiita.com/pmt-hkiho/items/5595d95e04ae23b5e48f)」を参考にして、TerraformとAWS CLIを実行する環境が作成済みである(本記事では、このファイル構成を利用して作業を行います)

https://qiita.com/pmt-hkiho/items/5595d95e04ae23b5e48f

# ECRリポジトリを作成

今回は、[Terraform](https://www.terraform.io/)を利用してAWS上にECRのプライベートリポジトリを作成します。
リージョンは「ap-northeast-1」を利用します。

下記のTerraformファイルを作成します。

```terraform:/terraform/ecr/main.tf
# プロバイダ
provider "aws" {
    region = "ap-northeast-1"
}

# ECR
resource "aws_ecr_repository" "test-app" {

    # リポジトリ名
    name = "test-app"

    # イメージタグの変更不可(上書き禁止)
    image_tag_mutability = "IMMUTABLE"

    image_scanning_configuration {
        # プッシュ時に脆弱性スキャンを実行
        scan_on_push = true
    }
}
```

下記のコマンドを実行します。
今回はサンプルとして`test-app`のリポジトリ名でプライベートリポジトリを作成します。

```text
> docker-compose up -d
> docker-compose exec terraform sh
# cd /terraform/ecr/
# terraform init  (Terraformの初期化を行う。初回に1回だけ実行)
# terraform plan  (AWSの変更内容を確認します。まだAWSには反映されません)
# terraform apply  (実際にAWS上にtest-appのECRリポジトリを作成します。
「Enter a value:」と表示されるので「yes」を入力します)
# exit
```

AWSの[ECRリポジトリ画面](https://ap-northeast-1.console.aws.amazon.com/ecr/repositories?region=ap-northeast-1)から、`test-app`のリポジトリが追加されていることを確認します。

# DockerからECRリポジトリにログイン

下記のコマンドを実行して、DockerからECRリポジトリを使えるようにログインを行います。
下記のコマンドに含まれる「{AWSアカウントID}」を、現在利用しているAWSアカウントID(12桁の数値、AWSの[アカウント設定画面](https://console.aws.amazon.com/billing/home?#/account)に表示されているアカウントID)に書き換えてから実行します。

```text
> docker-compose up -d
> docker-compose exec aws-cli aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin {AWSアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com
(Login Succeededと表示されればログイン成功)
(実行例: docker-compose exec aws-cli aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com)
```

「aws ecr get-login-password --region ap-northeast-1」コマンドで、DockerからECRにログインする際に利用するパスワードを標準出力として返します。

https://docs.aws.amazon.com/cli/latest/reference/ecr/get-login-password.html

「docker login --username AWS --password-stdin {AWSアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com」コマンドで、「ユーザ名: AWS」、「パスワード: 標準入力(aws ecr get-login-passwordの標準出力をパイプで渡す)」、「Dockerレジストリサーバ: {AWSアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com」を設定し、DockerからECRを利用できるようにします。

https://docs.docker.jp/engine/reference/commandline/login.html

パスワードの有効期限は12時間となっています。
Dockerイメージをプッシュやプルした際に認証エラーになる場合は、もう一度、上記のログインを行います。

# DockerイメージをECRリポジトリにプッシュ

下記の構成でテスト用Dockerファイルを作成します。「test app」が表示されるWebサーバとなっています。

```dockerfile:/docker/test-app/Dockerfile
FROM  nginx:1.21.3-alpine
ADD ./index.html /usr/share/nginx/html
```

```html:/docker/test-app/index.html
<html>
<body>
<h1>test app</h1>
version 1.0.0
</body>
</html>
```

下記のコマンドを実行して、DockerのビルドとECRリポジトリにプッシュ(アップロード)します。
下記のコマンドに含まれる「{AWSアカウントID}」をAWSアカウントIDに書き換えてから実行します。

```text
> cd docker/test-app/
> docker build -t {AWSアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/test-app:1.0.0 .
> docker push {AWSアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/test-app:1.0.0
```
イメージタグの名前を「1.0.0」で作成しました。イメージタグの名前を変更したい場合は、上記のコマンドに含まれる「1.0.0」を任意の名前に変更します。

AWSの[ECRリポジトリ画面](https://ap-northeast-1.console.aws.amazon.com/ecr/repositories?region=ap-northeast-1)にある`test-app`のリポジトリをクリックすると、プッシュしたDockerイメージを確認することができます。

# ECRリポジトリからDockerイメージをプル

他の環境で今回ビルドしたDockerイメージを利用する場合は、下記のコマンドを実行して、ECRリポジトリからDockerイメージをプル(ダウンロード)します。
下記のコマンドに含まれる「{AWSアカウントID}」をAWSアカウントIDに書き換えてから実行します。

```text
> docker pull {AWSアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/test-app:1.0.0
```

# ECRリポジトリを削除

下記のコマンドを実行すると、ECRリポジトリを削除することができます。

```text
> docker-compose up -d
> docker-compose exec terraform sh
# cd /terraform/ecr/
# terraform destroy  (AWS上のtest-appのECRリポジトリを削除します。
「Enter a value:」と表示されるので「yes」を入力します)
# exit
> docker-compose down
```

AWSの[ECRリポジトリ画面](https://ap-northeast-1.console.aws.amazon.com/ecr/repositories?region=ap-northeast-1)から、`test-app`のリポジトリが削除されていることを確認します。

# まとめ

Dockerコンテナ上のAWS CLIを使うことにより、ローカル環境を汚さずに手軽にDockerイメージをECRにプッシュできました。

ローカル環境で複数のAWSアカウントを利用している場合、Dockerコンテナ内でAWSの操作をしているため、誤って別のAWS環境を壊してしまう事故を減らせます。
(AWSアカウントごとに、`docker-compose.yml`とフォルダを分ける)

今回は、イメージタグの変更不可(上書き禁止)と、ECRにプッシュすると自動でDockerイメージの脆弱性スキャンを実行する設定にしてあります。将来、[AWS CodePipeline](https://aws.amazon.com/jp/codepipeline/)や[AWS CodeDeploy](https://aws.amazon.com/jp/codedeploy/)等でリリースの自動化する際に役立ちます。

ECRは無料利用枠があります。それを超えるとリポジトリに保存されたDockerイメージのサイズと転送量によって料金が発生します。もう利用しないDockerイメージがある場合は、AWSの[ECRリポジトリ画面](https://ap-northeast-1.console.aws.amazon.com/ecr/repositories?region=ap-northeast-1)からイメージを削除するようにします。
ECRの料金の詳細は下記をご覧ください。

https://aws.amazon.com/jp/ecr/pricing/