AWS CloudFormationでECRリポジトリを構築しよう

# はじめに
AWS CloudFormationを利用してVPC構築のテンプレートのサンプルです。

テンプレートの概要が分からない場合は、[はじめてのAWS CloudFormationテンプレートを理解する](https://qiita.com/miyabiz/items/eb7b0fa1675b5199b9b7)を参考にしてください。

コードは[GitHub](https://github.com/miyabiz-room/CloudFormation-Template/tree/ecr-01)にもあります。

今回は、akane というシステムの dev 環境を想定しています。
同じ構成で違う環境を作成する場合は、{環境名}-parameters.jsonを別途作成します。

```text:ディレクトリ構成
    akane (システム)
      └── ecr (スタック)
          ├── dev-parameters.json (dev 環境のパラメータ)
          └── ecr.yml (CFnテンプレート)
```

# AWS リソース構築内容
  1. ECRスタック
    - リポジトリ (タグのイミュータビリティ有効、イメージスキャンの設定有効)
    - ライフサイクルポリシールール (30イメージ以上は削除する)
 
# 実行環境の準備
[AWS CloudFormationを動かすためのAWS CLIの設定](https://qiita.com/miyabiz/items/fed11796f0ea2b7608f4)を参考にしてください。

# AWS リソース構築手順
1. 下記を実行してスタックを作成

    ```
    ./create_stacks.sh
    ```

2. 下記を実行してスタックを削除

    ```
    ./delete_stacks.sh
    ```

# 構築テンプレート
**1. ECRスタック**
 
```yaml:ecr.yml
AWSTemplateFormatVersion: 2010-09-09
Description: ECR For Akane

# Metadata:

Parameters:
  SystemName:
    Type: String
    AllowedPattern: '[a-zA-Z0-9-]*'
  EnvType:
    Description: Environment type.
    Type: String
    AllowedValues: [dev, stg, prod]
    ConstraintDescription: must specify dev, stg or prod.

Mappings: 
  AzMap: 
    ap-northeast-1:
      1st: ap-northeast-1a
      2nd: ap-northeast-1d
      3rd: ap-northeast-1c

# Conditions

# Transform

Resources:
  # ECR Repositoryを作成
  akaneECRRepository:
    Type: AWS::ECR::Repository
    Properties: 
      ImageScanningConfiguration:
        scanOnPush: true
      ImageTagMutability: IMMUTABLE
      LifecyclePolicy: 
        LifecyclePolicyText: '{"rules":[{"rulePriority":1,"description":"Delete more than 30 images","selection":{"tagStatus":"any","countType":"imageCountMoreThan","countNumber":30},"action":{"type":"expire"}}]}'
      RepositoryName: !Sub
        - ${SystemName}-${EnvType}-repo
        - {SystemName: !Ref SystemName, EnvType: !Ref EnvType}
      Tags: 
        - Key: Name
          Value: !Sub
          - ${SystemName}-${EnvType}-repo
          - {SystemName: !Ref SystemName, EnvType: !Ref EnvType}
        - Key: SystemName
          Value: !Ref SystemName
        - Key: EnvType
          Value: !Ref EnvType 

Outputs:
  akaneECRRepository:
    Value: !GetAtt akaneECRRepository.Arn
    Export:
      Name: !Sub
        - ${SystemName}-${EnvType}-repo-arn
        - {SystemName: !Ref SystemName, EnvType: !Ref EnvType}
```

```json:dev-parameters.json
{
    "Parameters": [
        {
            "ParameterKey": "SystemName",
            "ParameterValue": "akane"
        },
        {
            "ParameterKey": "EnvType",
            "ParameterValue": "dev"
        }
    ]
}
```

**2. 実行ファイル**

```sh:create_stacks.sh
#!/bin/sh
SYSTEM_NAME=akane
ENV_TYPE=dev

function create_stack() {
STACK_NAME=$1
aws cloudformation create-stack \
--stack-name ${SYSTEM_NAME}-${ENV_TYPE}-${STACK_NAME} \
--template-body file://./${SYSTEM_NAME}/${STACK_NAME}/${STACK_NAME}.yml \
--cli-input-json file://./${SYSTEM_NAME}/${STACK_NAME}/${ENV_TYPE}-parameters.json

aws cloudformation wait stack-create-complete \
--stack-name ${SYSTEM_NAME}-${ENV_TYPE}-${STACK_NAME}
}

create_stack ecr
```

```sh:delete_stacks.sh
#!/bin/sh
SYSTEM_NAME=akane
ENV_TYPE=dev

function delete_stack() {
STACK_NAME=$1
aws cloudformation delete-stack \
--stack-name ${SYSTEM_NAME}-${ENV_TYPE}-${STACK_NAME}

aws cloudformation wait stack-delete-complete \
--stack-name ${SYSTEM_NAME}-${ENV_TYPE}-${STACK_NAME}
}

delete_stack ecr
```