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にイメージがアップされていること

リポジトリ

イメージ

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

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

デプロイ先

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

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

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

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

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

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

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

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

ロードバランサの作成

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

手順1

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

手順2

「次の手順:~」をクリック

手順3

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

手順4

名前
後で削除するので適当な名前でOKです。

手順5

「次の手順:~」をクリック

手順6

「作成」をクリック

リスナーの削除

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

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

ターゲットグループの削除

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

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

Fargate

ECSオブジェクトとそれらの関連を示す図

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

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

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

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

  1. サービス -> IAM -> ロール -> ロールの作成
  2. 「AWSサービス」から「CodeDeploy」を選択
  3. 「ユースケースの選択」から「CodeDeploy - ECS」を選択
  4. 「次のステップ:~」をクリック
  5. 「AWSCodeDeployRoleForECS」があることを確認
  6. 「次のステップ:~」をクリック
  7. 「次のステップ:~」をクリック
  8. ロール名を設定
  9. 「ロールの作成」

クラスタ

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

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

タスク定義

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

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

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

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

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

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

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

サービス

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

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

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

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

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

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

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

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

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

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

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

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

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

CodePipeline

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

CodePipelineの設定ファイル

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

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

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を作成する」をクリック

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

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

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

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

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

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

SourceにCodeCommitを追加

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

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

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

「完了」をクリック

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

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

Deployの編集

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

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

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

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