ECRのライフサイクルの設定メモ

## これはなに？

AWSのECSを使う前提で、ECRを利用しています。
こちらはDockerイメージのリポジトリで、CIやパイプラインで定期的にビルドしたイメージをpush & 登録する設定を試しています。

ここでは、ECSについてはまだ触れません。
(ECSを起動すると思いがけず課金が発生するので、個人枠では慎重に進めています....)

## やりたいこと

さて、ECRもAWSの1年間の無償枠の中の1つとして利用ができます。
ただし、サイズ制限があり、**リポジトリの利用サイズが0.5GBを越えてしまうと、課金対象**になってしまいます。

今実験しているDockerのイメージは、サイズが450MB程度...。
CIでの定期的なpushは実施できそうなので、更新した単位でイメージの登録はできますが、2世代分は保持はできません。

ということで、やりたいのはこちら。

- 最新の1つを残して、うまく削除できるようにしたい

### 注意点

スクリーンショットや設定方法は変更される可能性があります。
また、実際にちゃんと消えているか、課金状況はどうかというのは、こまめに確認することをお勧めします...。

## 方法: ライフサイクルの設定

設定にあたっては、こちらの記事を参考にさせていただきました。

- [Amazon ECR ライフサイクルポリシー / ライフサイクルポリシーの作成
](https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/lp_creation.html) (AWS公式)
- [ECRのライフサイクルポリシー設定によるリポジトリ容量の節約](https://dev.classmethod.jp/cloud/aws/ecr-lifecycle/) (Classmethod DevelopersIO)

### 設定画面

「最新の1つを残して」を条件にしたので、「次の数値を超えるイメージ数」に1を設定。さらに、タグ付けの有無は問わずに指定しています。

<img width="464" alt="lifecycle-config.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27976/5b35376f-f661-3186-c4b7-744430ff3729.png">

### 適用の結果

リポジトリに複数イメージが溜まった状態で、テストのポリシーを実行すると、該当するイメージがあれば以下のように表示されます。

<img width="450" alt="lifecycle-policy-at-console.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27976/50586c46-7657-d567-840e-9f0396685334.png">


実際には、新しいイメージがプッシュされた**直後に削除が発生するのではなく**、削除フラグ的なものが設定された上で、2〜3時間くらい経ってから削除になっています。

## Terraformで設定する

コンソールでの設定がうまく行ったので、設定をTerraform側に落とし込んでみます。
ECR作成やライフサイクルポリシーの設定も、リソースとして定義ができるので、terraform importをしてから、以下のような形で書き出しています。

- ECRのリポジトリ名は akiko/redmine_banner
  - メンテナ＆イメージ名的に / が使えるので、あえてこうしてみる
- ECRのリポジトリ作成後に、``aws_ecr_lifecycle_policy`` で、ポリシーを設定
 - 対象は ``repository = `` で設定します

```hcl
resource "aws_ecr_repository" "akiko_redmine_banner" {
  name = "akiko/redmine_banner"
}

resource "aws_ecr_lifecycle_policy" "akiko_redmine_banner_policy" {
  policy = jsonencode(
    {
      rules = [
        {
          action = {
            type = "expire"
          }
          description  = "最新の1つを残してイメージを削除する"
          rulePriority = 1
          selection = {
            countNumber = 1
            countType   = "imageCountMoreThan"
            tagStatus   = "any"
          }
        },
      ]
    }
  )
  repository = "${aws_ecr_repository.akiko_redmine_banner.name}"
}
```

## 補足：AWSからのアラート

課金のアラームを設定しているので、ECRに関しても警告メッセージが届きました。抜粋ですがこんな感じ。

<img width="400" alt="ecr-limit.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27976/934f7be4-7672-e841-da4b-1656d8bede31.png">

## 補足：CircleCIからのイメージのビルドと登録

以下は抜粋ですが、CircleCIからaws-cliを使ってイメージのビルドとECRへの登録を行う部分です。

- CircleCIのAWS ECR用のOrbsを使ってみています
- 基本的にはjobsのところで細かいスクリプト処理を記載したりするのですが、Orbsを使っている場合は、環境変数と呼び出したい処理の名前を記載するぐらいでOK
- 以下の例だとbuildではソースのチェックアウトしかしてません

個人的には、CodePipelone & CodeBuildで同じ処理をするよりは、手元でcliを操作する感覚に近いので、こちらのほうが好きかも...です。

```yaml

orbs:
  aws-ecr: circleci/aws-ecr@6.2.0

version: 2.1

jobs:
  build:
    docker:
      # specify the version you desire here (ruby 2.4.x)
      - image: circleci/ruby:2.5-browsers-legacy
    steps:
      - checkout

workflows:
  build_test_push:
    jobs:
      - build:
          filters:
            branches:
              ignore:
                - /ignore-build-.*/
                - master
      - aws-ecr/build-and-push-image:
          account-url: AWS_ECR_ACCOUNT_URL
          aws-access-key-id: AWS_ACCESS_KEY_ID
          aws-secret-access-key: AWS_SECRET_ACCESS_KEY
          create-repo: true
          dockerfile: Dockerfile
          path: .
          region: AWS_REGION
          repo: akiko/redmine_banner
          extra-build-args: '--build-arg COMMIT=$CIRCLE_SHA1 --build-arg=BRANCH=$CIRCLE_BRANCH'
          requires:
            - build
          filters:
            branches:
              only:
                - ecs-trial
```