CodePipeline、ブランチごとデプロイ
Posted:
基本、下記をなぞる。 が、「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の設定を行い、自動ビルドを回し始める。
手順
- 対応ブランチごとにECRのリポジトリを作成する
https://ap-northeast-1.console.aws.amazon.com/ecs/home?region=ap-northeast-1#/repositories
ECSの管理コンソールにログイン ->[ リポジトリの作成 ]->[ リポジトリ名 ]にレポジトリ名[ api9 ]などを入れる。 このECRのレポジトリ名はGithubのブランチと揃えるようにした。
- 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ビルドするようにしているため。
- ECRのタスク定義を作成する このタスク定義に基いてECRサービスで使うコンテナが起動される。 またここでコンテナの環境変数も設定できる。ソースコードにはAPIキーなどは含めたくないため、 環境変数の形でコンテナに渡すようにする。
このファイルはAPIキーなど重要な情報が入るので、Githubなどのレポジトリに気軽に入れないようにする。
下記のコマンドでタスク定義を作る(更新する)
aws ecs register-task-definition --cli-input-json file://./imagedefinitionsapi9.json
- 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のログ を確認する
- buildspec.yml の用意 ( 追記予定地 )
imagedefinitions.json のフォーマットは https://docs.aws.amazon.com/codepipeline/latest/userguide/pipelines-create.html に詳しい
- 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 ]を追加する
- 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
- 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
の処理で失敗する。
- Githubにpushして自動デプロイ開始