AWS ECRのイメージをデプロイ。

# ECRのイメージをデプロイします。

次の2つが参考になりました。
https://dev.classmethod.jp/articles/codepipeline-ecs-codedeploy/
https://aws.amazon.com/jp/blogs/news/build-a-continuous-delivery-pipeline-for-your-container-images-with-amazon-ecr-as-source/

## 前提
VPCが作成されていること
ECRにイメージがアップされていること

### リポジトリ

![ecr.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/53ca9f13-263b-b53e-0e14-5c521ad9a7b5.png)

### イメージ

![ecr_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/a2b887d6-e6d2-c64e-2bd3-8106ec20c27e.png)

「イメージのURIのコピー」をクリックすると「イメージ名：タグ」をコピーできます。

例）xxxxxxxxxxxxxx.ecr.ap-northeast-1.amazonaws.com/php-sample:latest

# デプロイ先

今回は、AmazonECS(ブルー／グリーン）でデプロイします。
本来はVPCでPrivateサブネット2つとロードバランサの構成になると思います。Privateサブネットにデプロイしたときにインストール作業で、インターネットに接続するため、Natゲートウェイが必要になります。Natゲートウェイは料金がかかるため、この記事では、Publicサブネット２つにデプロイすることにします。
デプロイ時のインストールが何をしているかは。。まだ、わかりません。

## ロードバランサ用のセキュリティグループを作成

![セキュリティグループ作成.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/0ff104bf-ebb4-39c6-9d79-152ca3bdd773.png)

<dl>
 <dt>セキュリティグループ名<dt><dd>わかりやすい名称をつけます</dd>
 <dt>VPC<dt><dd>作成済みのVPCを選択</dd>
</dl>

「セキュリティグループを作成」をクリック

「インバウンドルールの編集」をクリック

![セキュリティグループのインバウンド編集.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/8978e8af-f318-2b22-f436-96b419d29fc9.png)

「ルールを追加」をクリック

|項目|設定|
|---|---|
|タイプ| HTTP|
|ソース| 任意の場所 0.0.0.0/0 ::/0|

を設定して「ルールを保存」をクリック

## ロードバランサの作成

EC2 > 「ロードバランサの作成」 > 「HTTP HTTPS」を選んで「作成」

### 手順１
![ロードバランサ作成.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/8c2ca93a-6f00-0555-6efa-4b0eb3276a16.png)


<dl>
 <dt>名前</dt><dd>ロードバランサの名前</dd>
 <dt>リスナーの追加</dt><dd>今回は8080ポートを追加した</dd>
 <dt>アベイラビリティーゾーン</dt><dd>サブネット二つを登録</dd>
</dl>

### 手順２
「次の手順：～」をクリック

### 手順３
![ロードバランサのセキュリティグループ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/149ed912-c58e-1999-e060-210e49651cf9.png)

先に作成したセキュリティグループとdefaultの両方をチェック！

### 手順４
![ロードバランサのルーティング設定.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/1416d7a3-f9c5-898d-e521-27e131b8f845.png)

<dl>
  <dt>名前</dt><dd>後で削除するので適当な名前でOKです。</dd>
</dl>

### 手順５
「次の手順：～」をクリック

### 手順６
「作成」をクリック

### リスナーの削除
リスナーは、Fargateのサービス作成時に同時に作成するのでここで削除しておく

![ロードバランサのリスナー削除.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/b77e69ab-2844-3f65-ca88-18a454594dc4.png)

「リスナー」タブの「リスナー」を選択して「削除」をクリック

### ターゲットグループの削除
ターゲットも、Fargateのサービス作成時に同時に作成するのでここで削除しておく

![ロードバランサのターゲットグループの削除.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/8f346f0c-4b3a-8cd6-6c0f-12d1079750a9.png)

先ほど作成したターゲットグループを選択し、「Action」->「Delete」を選択する

## Fargate
ECSオブジェクトとそれらの関連を示す図
![ECSオブジェクトとそれらの関連を示す図](https://d129ird697a0zf.cloudfront.net/ecs-objects-taskdef-1aba4ac72a5c999e0cb74833a18e6289eb71d32a.png)

この記事での作成順序。サービスを作成実行した後にデプロイされてコンテナが実行されます。


1. CodeDeployが利用するロールの作成
1. クラスタ
1. タスク定義
1. サービス


### CodeDeployが利用するロールの作成

再利用できるロールがある場合はそちらをご利用ください。

1. サービス -> IAM -> ロール -> ロールの作成
1. 「AWSサービス」から「CodeDeploy」を選択
1. 「ユースケースの選択」から「CodeDeploy - ECS」を選択
1. 「次のステップ：～」をクリック
1. 「AWSCodeDeployRoleForECS」があることを確認
1. 「次のステップ：～」をクリック
1. 「次のステップ：～」をクリック
1. ロール名を設定
1. 「ロールの作成」

### クラスタ

1. サービス -> Elastic Container Service　
2. 「クラスターの作成」
3. 「ネットワーキングのみ」を選択 -> 「次のステップ」をクリック
4. 「クラスター名」を設定 -> 「作成」をクリック

VPCは先に作成したものを使用する

### タスク定義

1. サービス -> Elastic Container Service
2. メニューから「タスク定義」をクリック
2. 「新しいタスク定義の作成」をクリック
3. 「FARGATE」を選択 -> 「次のステップ」

![タスク定義１.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/ef48b2c3-2054-47ea-3d7d-fed560a737e4.png)

|項目 | 設定値 |
|-----|-------|
|タスク定義名 | わかりやすい名前 |
|タスクロール|なし|

![タスク定義2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/9e5ff073-1bd5-17f8-c4d8-2cef098048d4.png)

|項目 | 設定値 |
|-----|-------|
|タスクメモリ | 0.5GB |
|タスクCPU|0.25vCPU|

「コンテナの追加」をクリック

![タスク定義コンテナ追加１.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/8718a3e4-94dc-e736-c500-bef54249740e.png)

|項目 | 設定値 |
|-----|-------|
|コンテナ名 | 名前をつけましょ|
|イメージ | ECRのリポジトリ名とタグ名|
|メモリ制限| ソフト制限 128|
|ポートマッピング| 80 |

![タスク定義コンテナ追加2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/81c51bbf-d73b-c398-e46c-079056ac80d3.png)

|項目 | 設定値 |
|-----|-------|
|GPUユニット数 | 256 (1024CPU units = 1Coreらしい。。1/4Core予約だと256)|

「追加」をクリック
「作成」をクリック

### サービス

1. タスク定義の詳細を表示
2. 「アクション」-> 「サービスの作成」を選択

![サービス作成１.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/17a801ba-6572-c74c-de57-5462fe43d2e2.png)

|項目 | 設定値 |
|------|--------|
|起動タイプ | FARGATE |
| リビジョン | 自動設定。テストで同名のタスク定義を作っていたので、３になっています。最初なら１です。|
|プラットフォームバージョン | LATEST |
| クラスター|先に作成したクラスターを選択 |
| サービス名 |名付けてください |
| タスクの数| 今回は1|

![サービス作成2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/d91e1dc6-1719-5edc-df60-51fcf9269b5c.png)

|項目 | 設定値 |
|------|--------|
|デプロイメントタイプ | Blue/Greenデプロイメント |
|codeDeployのサービスロール | 先に作成したサービスロール |

「次のステップ」をクリック

![サービス作成3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/c30487ec-aa92-73f5-7246-c577bc38648a.png)

|項目 | 設定値 |
|------|--------|
|クラスターVPC | 準備しておいたVPC |
|サブネット | サブネットを２つ選択 |
| セキュリティグループ | 「編集」で「default」を選択 |
| パブリックIPの自動割り当て| 今回はPublicのサブネットなので Enabledとした。PrivateならDisabled |

![サービス作成4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/da133c1c-17b7-df35-0078-fa6667722860.png)

|項目 | 設定値 |
|------|--------|
|ロードバランサーの種類 | Application Load Balancer |
| ロードバランサー名|先に作成したロードバランサーを選択 |

「ロードバランサーに追加」をクリック

![サービス作成5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/5e944ed7-6a0d-5995-1a86-17bcb5cd0bc8.png)

|項目 | 設定値 |
|------|--------|
|プロダクションポート| 80|
|テストリスナーポート|8080 |

「次のステップ」をクリック

「Auto Scaling (オプション)」はそのままで「次のステップ」をクリック
「サービスの作成」をクリック

![サービス作成の結果１.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/bf401830-77c8-6b28-770f-0fb7cc339d76.png)

サービスが作成され、タスクが一つ起動していることを確認

![サービス作成ターゲットグループ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/5ef1bce5-f97c-a7bd-edf3-4cfa96688ad5.png)

FARGATEのサービス作成で作ったターゲットグループのどちらかを確認
EC2 -> ターゲットグループの「Targets」タブのStatusがhealthyであること

ロードバランサーのDNS名のURLにアクセスして、アプリケーションが表示されることを確認

## CodePipeline

ECRのリポジトリに新しいイメージがプッシュされたらデプロイするように設定します。

### CodePipelineの設定ファイル

CodePipelineでデプロイするためには次のファイルを準備します。
* appspec.yml
* taskdef.json

今回はCodeCommitに保存します。S3でもイケるはず！

![CodeCommit.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/ecd746bf-0258-912c-6cf8-45a2ee866cc3.png)


appspec.yml

```
version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: "<TASK_DEFINITION>" ## <TASK_DEFINITION>という文字列を置き換えることなくそのまま使用してください。
        LoadBalancerInfo:
            ContainerName: "php-container" ##コンテナ名、適切な名前に置き換えてください
            ContainerPort: "80" ##適切なポート番号に置き換えてください
```

taskdef.json

```
{
  "executionRoleArn": "arn:aws:iam::xxxxxxxxx:role/ecsTaskExecutionRole",
  "containerDefinitions": [
    {
      "name": "php-container",
      "image": "<IMAGE1_NAME>",
      "portMappings": [
        {
          "containerPort": 80,
          "hostPort": 80,
          "protocol": "tcp"
        }
      ],
      "essential": true
    }
  ],
  "requiresCompatibilities": ["FARGATE"],
  "networkMode": "awsvpc",
  "cpu": "256",
  "memory": "512",
  "family": "php-task"
}
```

|項目名|設定値|
|--------|---------|
|executionRoleArn|タスクを実行するロール "arn:aws:iam::xxxxxx:role/ecsTaskExecutionRole"| 
|ContainerDefinitions.name|コンテナ名php-container|
|ContainerDefinitions.image|IMAGE1_NAME は、パイプライン作成時に設定しCodePipeline実行時に置き換えられます。|


### CodePipeline

1. サービス -> CodePipeline を選択
2. 「Pipelineを作成する」をクリック

![codepipeline1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/9b90e2c6-c2b6-3e15-8ec4-3869658795e0.png)

パイプライン名を設定して「次に」をクリック

![codepipeline2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/ca5647b7-0079-4537-c743-5c154996cf11.png)


| 項目 | 設定値　|
|------|---------|
|ソースプロバイダー| Amazon ECR |
|リポジトリ名 |amazon ECR のリポジトリ |
|画像タグ | latest （画像と翻訳されているが Docker Image のImageだと思う）|

「次に」をクリック
「ビルドステージを追加する」でビルドは追加しないのでそのまま「ビルドステージをスキップ」をクリック。確認ダイアログで「スキップ」をクリック

![codepipelineデプロイ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/38aa2f1d-b4bb-1636-e72a-727d7ac2768b.png)

| 項目 | 設定値　|
|------|---------|
|デプロイプロバイダー| Amazon ECS(ブルー/グリーン)を選択|
|AWS CodeDeployアプリケーション| ECSのクラスターで作成したサービス実行時に作成されている。類似名称を探そう！|
|AWS CodeDeploy デプロイグループ|これもサービス実行時に作成されている。類似名称を探す|
|AWS ECS タスク定義| SourceArtifact (後で修正します）|
|AWS ECS AppSpecファイル| SourceArtifact (後で修正します）|
|タスク定義のプレースホルダー文字 |IMAGE1_NAME (taskdef.jsonファイルの image項目に設定した文字列) |

「次に」をクリック
「レビュー」画面で確認し、「パイプラインを作成する」をクリック。

![codepipeline作成直後.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/7445dff0-537d-8350-fcb2-8dcc1fcb06ac.png)


パイプラインが作成され、実行されます。
ここでは、Deployは、設定が足りないので失敗します。

### SourceにCodeCommitを追加

パイプラインのSourceに、appspec.ymlとtaskdef.jsonがあるCodeCommitを追加します。

![codepipelineアクションの追加.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/b43b000c-c835-5fba-eb2c-e0ea6e4801ee.png)

1. パイプラインの詳細画面で「編集する」をクリック
2. 「編集する：Source」の「ステージを編集する」をクリック
3. 「アクションの追加」をクリック

![codepipelineアクションの編集.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/613e1573-921d-ea97-8376-e7901f3f012a.png)

| 項目 | 設定値　|
|------|---------|
|アクション名|名前を付けます|
|アクションプロバイダー | AWS CodeCommit |
|リポジトリ名|　作成済みのリポジトリを選択|
|ブランチ名| ここでは、masterを選択|
|出力アーティファクト|パイプラインの後続のDeployで参照するアーティファクトの名称。ここではCodeFiles|

「完了」をクリック

「編集する：Source」の「完了」をクリック

![codepipelineSource編集後.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/f209bb2e-19ec-92ea-1eef-de60249c2f1a.png)

SourceにAmazonECRとAWS CodeCommitの二つが追加されています。

### Deployの編集

![codepipeline-Deploy編集.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/4c7b1f85-8a10-71ea-3434-bc1b36e695c5.png)


1. 「編集する：Deploy」の「ステージを編集する」をクリック
2. Deployの編集ボタンをクリック。（画像の赤矢印）

![codepipeline-Deploy編集アーティファクト追加.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93066/206add04-a6c2-068f-0150-28adb63a87cf.png)

| 項目 | 設定値　|
|------|---------|
|入力アーティファクト|「追加」し、Sourceプロバイダで追加したアーティファクトを選択|
|Amazon ECS タスク定義|Sourceプロバイダで追加したアーティファクトを選択|
|Amazon CodeDeploy AppSpecファイル|Sourceプロバイダで追加したアーティファクトを選択|
|入力アーティファクト| Amazon ECRの出力アーティファクトを選択|
|タスク定義のプレースホルダー文字 |IMAGE1_NAME (taskdef.jsonファイルの image項目に設定した文字列) |

「完了」をクリック
「編集する：Deploy」の「完了」をクリック
「保存する」をクリック->「保存する」をクリック
「変更をリリースする」をクリック

デプロイされます。失敗する場合はエラー表示やログなどを参照。