CodePipeline、ブランチごとデプロイ

基本、下記をなぞる。 が、「artifacts として事前準備で作成したタスク定義ファイルを指定します。」という表現だけが違う、気がする。 AWS CodePipelineがECSへのデプロイをサポートしたのでやってみる - Qiita

ECSのタスク定義に使用する( aws ecs register-task-definition –cli-input-json ./imagedefinitions.json で使用する )ファイルのフォーマットと artifactsのフォーマットは異なる。 [ The image definition file image definitions.json contains invalid JSON format ]というエラーが出る。

構成

  • Githubのあるブランチにgit pushすると、CodePipelineが反応する
  • CodePipeline経由で、CodeBuildが起動、DockerイメージをビルドしてECRにdocker push、ECRのタスク定義も更新して新しいイメージが見えるようにする
  • 開発者が見る、URLはALB -> ECSインスタンス -> ECSコンテナ という形でアクセスする
  • ALBはリクエストヘッダ中のホスト名の箇所で特定のターゲットグループに振り分ける設定にする
  • むやみにALBインスタンスを増やさない

作業の流れ

ECRでDockerレポジトリを作成、Dockerイメージをビルドして、Dockerレポジトリに入れる。 Dockerレポジトリにあるイメージを用いて、ECSのタスク定義を行う。

CodePipelineは設定を行えば、定期的にGithubの特定のレポジトリを監視して、 変更があったらDockerイメージをビルドできる。この際、『どのようにビルドするか』を Gitレポジトリのトップディレクトリにある buildspec.yml に従って行う。このbuildspec.ymlを用意しておく。 あらかじめGithubに目的のブランチを作っておく( でないとCodePipelineの設定時に、ターゲットのブランチがプルダウンメニューに現れない ) CodePipelineの設定を行い、自動ビルドを回し始める。

手順

  1. 対応ブランチごとにECRのリポジトリを作成する

https://ap-northeast-1.console.aws.amazon.com/ecs/home?region=ap-northeast-1#/repositories

ECSの管理コンソールにログイン ->[ リポジトリの作成 ]->[ リポジトリ名 ]にレポジトリ名[ api9 ]などを入れる。 このECRのレポジトリ名はGithubのブランチと揃えるようにした。

  1. Dockerイメージを作成する 既にあるDockerの作業環境を流用する。 Dockerイメージをビルドする。 このコマンドは ECRでDockerレポジトリを作成した後、[ プッシュコマンドの表示 ]で確認できるコマンドに沿う。
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com

で表示されたコマンドを実行。Dockerfileがあるディレクトリに移動し

docker build -t api9 .

でDockerイメージをビルド。

docker tag api9:latest 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/api9:latest
docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/api9:latest

でイメージにタグを付け、ECRのレポジトリにイメージをpush 時間はかかるが、ここでDockerイメージをビルドしてpushしておくこと。 というのも、CodeBuildの時間を短縮するためにECRのイメージを利用して差分だけDockerビルドするようにしているため。

  1. ECRのタスク定義を作成する このタスク定義に基いてECRサービスで使うコンテナが起動される。 またここでコンテナの環境変数も設定できる。ソースコードにはAPIキーなどは含めたくないため、 環境変数の形でコンテナに渡すようにする。

このファイルはAPIキーなど重要な情報が入るので、Githubなどのレポジトリに気軽に入れないようにする。

下記のコマンドでタスク定義を作る(更新する)

 aws ecs register-task-definition --cli-input-json file://./imagedefinitionsapi9.json
  1. ECSサービスを作成する 作成した[ サービス定義 ]から[ サービス ]を作成する 既にクラスターがある場合は、それを使い、ない場合は新規に作成する。

『クラスターはどの単位で分離すべきか』は、(2018/01時点の考えとしては) 『コンテナの負荷が影響を与えて良いグループ』と考えている。 基本的にはコンテナのオートスケールを適切に設定できれば、 同じクラスター内に同居を進めた方が集約率を上げられるので、 基本、こちらで考えるが、スケールアウトが間に合わないなどのリスクを考えると 本番系API, WWWは別クラスターという考え方もある ( その他コーポレートサイトと開発、redashなどは同居可能だと思われる )

4.1 クラスター新規作成 https://ap-northeast-1.console.aws.amazon.com/ecs/home?region=ap-northeast-1#/clusters ECSの管理コンソールから[ クラスター ]->[ クラスターの作成 ]->[ EC2 Linux + ネットワーキング ]が選択されていることを確認した上で ->[ 次のステップ ]

下記の内容で作成した

  • クラスター名 : general

  • プロビジョニング : スポット

  • スポットインスタンスの配分戦略 : 分散

  • EC2インスタンスタイプ : c4.large

  • 最大価格 1.26

  • インスタンス数 : 1

  • ストレージ 22GB

  • キーペア : test-aws

  • VPC

  • サブネット : privateの2つ

  • セキュリティグループ

  • コンテナインスタンスのIAMロール : ecsinstanceRole

  • スポット群IAMロール : ecsSpotFleetRole

でgeneralという名前のECSクラスターを作成した。

4.2 ECSサービスを追加する ECS管理コンソール ->[ クラスター ]->[ general ]->[ サービス ]のタブ->[ 作成 ] 下記のタスク定義を用いてサービスを作成した

  • タスク定義 : api9:1 ( これは私がいろいろタスク定義をやり直しているので )

  • クラスター : general

  • サービス名 : api9

  • タスクの数 : 1

  • 最小ヘルス率 : 50 (これはデプロイ時、「全体のコンテナ数の何割まで下げる事を挙動するのか」という数値。デフォルト50

  • 最大率 : 200 ( これはデプロイ時、冗長化のため、どれだけコンテナを増やしてよいか )デフォルト200

  • 配置テンプレート : AZバランススプレッド

  • ELBタイプ : Application Load Balancer( ALB )

  • ELB名 : ecs( このALBは事前に作成しておいた。作成してなければ、作成して、隣の再読込ボタンを押す )

  • 負荷分散用のコンテナ : これは「ALBからどのコンテナにアクセスを振り分けるか」で、タスク定義に定義されているコンテナがリストアップされる。 [ api8:0:10081 ]を選択し、[ ELBに追加 ]をクリック

  • リスナーポート : 443:HTTPS

  • ターゲットグループ名 : 新規作成 api9

  • ターゲットグループのプロトコル : HTTP

  • あと他の[ パスパターン ]や評価順などは、この管理画面からでは設定しきれないので『あとでALBの管理画面で変更する』ようにする( 具体的にはリクエストヘッダのホスト名に応じて、負荷分散用のコンテナを振り分けたいが、2018/01時点では、できない )

  • Auto scaling : 開発用途なのでオートスケールは設定しない。コーポレート、サービス用に展開する際には検証して実施する

4.3 サービス作ったら動作確認する コンテナが度々作られ、殺され、再起動を繰り返す、という症状があり得る…

作成したクラスターの

  • [ サービス ]タブで、状況が[ ACTIVE ]になっていることを確認

  • 実行中のタスクが 1以上であること

  • ECS管理コンソール->[ クラスター ]->[ 作成したクラスター ]->[ イベント ] で、このクラスターのイベントを見ることができる。

  • 該当のURLを確認して見えることを確認

  • 上手く行ってなかったらECSインスタンス( このIPアドレスはEC2管理コンソールから確認できる )にsshでログインして、docker exec -t -i コンテナ /bin/bash などでコンテナに入って確認する

  • alpineは apk add git curl でパッケージを追加できる

  • 上手く行かなければ「そもそもローカルでbuildしたイメージは動作するのか」「ECRにpushしたイメージをローカルにpullして、動作するのか」を確認する

  • ECSコンテナのログは、nginxログは設定として /dev/{stdout,stderr}にエイリアスしており、更にECSタスク定義で、ログドライバーをawslogsにしているので、CloudWatch Logsにログが転送される 問題が起きた時は

  • コンテナ内部のログ

  • CloudWatch Logsのログ を確認する

  1. buildspec.yml の用意 ( 追記予定地 )

imagedefinitions.json のフォーマットは https://docs.aws.amazon.com/codepipeline/latest/userguide/pipelines-create.html に詳しい

  1. Github側にCI予定のブランチを作成する 目的のブランチを作成する。私は( masterではなかったので )開発用ブランチから更に

git checkout -b api9 などとして、更にブランチを作成し、下記でGithubにpushした ❯ git push origin (basename (git symbolic-ref HEAD 2> /dev/null))

変更後、Github側で[ api8 ]のブランチのラベルに[ work in progress ]を追加する

  1. CodePipelineの設定 https://ap-northeast-1.console.aws.amazon.com/codepipeline/home?region=ap-northeast-1#/dashboard CodePipelineの管理コンソールにログイン
  • [ パイプラインの作成 ]->パイプライン名[ api9 ]

  • [ ソースプロバイダ ]->[ GitHub ]

  • [ GitHubに接続 ]

  • リポジトリ :

  • ブランチ : api9

  • ビルドプロバイダ : AWS CodeBuild

  • 新しいビルドプロジェクトを作成( なぜ「新しいビルドプロジェクト」を作成する必要があるか? というとビルドプロジェクトごとにCodeBuildの『環境変数』を設定する必要があるため

  • 環境イメージ : AWS CodeBuildマネージド型

  • OS : Ubuntu

  • ランタイム : Docker

  • バージョン : aws/codebuild/docker:17.09.0

  • ビルド仕様 : ソースコードのルートディレクトリのbuildspec.ymlを使用

  • CodeBuildサービスロール : アカウントで新しいロールを作成します。 ロール名 code-build-api9-service-role

  • VPC : 非VPC

  • 環境変数

  • AWS_ACCOUNT_ID :

  • AWS_DEFAULT_REGION : ap-northeast-1

  • IMAGE_NAME : api9

  • GITHUB_OAUTH :

  • デプロイプロバイダ : ECS

  • クラスター名 : general

  • サービス名 : api9

  • イメージのファイル名 : imagedefinitions.json

  • AWSサービスロール : AWS-CodePipeline-Service

  1. CodeBuildの使用するIAMロールに権限を追加 IAMで[ api8 ]とかで検索すると[ code-build-api8-service-role ]などが出てくる。

AmazonEC2ContainerRegistryPowerUser を追加する。この権限が足りないと

aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com

の処理で失敗する。

  1. Githubにpushして自動デプロイ開始
User
CloudFront
ALB
EC2
RDS