AWSのCodePipeline(コードパイプライン)を使うことで、コード変更後のデプロイを自動化(プロジェクトのCI/CD化)することができます。
ここではそもそもCodePipeline(コードパイプライン)とは何か?使うメリットは何か?についてまとめています。
また、セキュリティを高めるために、すべてのデータをgithubで管理するのではなく、.envファイルやCodePipelineのタスク定義ファイルなど重要なデータは、AWS上のCodeCommitに置くプロジェクトでCodePipelineを実行する方法について実例でまとめています。
- CodePipelineとは何か?
- CodePipelineの処理の流れ
- CodePipelineのメリットは何か?
- CodePipelineの料金イメージ
- CI/CDとは何か?
- CodePipelineを使うときのルール
- CodePipelineの作成手順(実例)
- パイプラインの作成
- ソースステージの追加
- ビルドステージの追加
- デプロイステージの追加
- タスク定義ファイルの指定
- 動的更新のためのIMAGE名を指定する
- レビュー
- タスク定義ファイルの作成
- apspecファイルの作成
- Source名を変更する
- Sourceにステージを追加する
- ステージング用のデプロイアクションの編集
- 認証ステージの追加
- 本番環境のデプロイステージを追加
- 元の環境の保持時間を変更する方法
- 参考リンク
CodePipelineとは何か?
AWSのサービスの一つで、簡単にいうと本番化の自動化です。
AWS上で運用しているサービスで、コード改修など変更があった場合に、変更を自動検知してサービスを自動デプロイ(本番化)することができます。
自動更新を開始するトリガーは自分で設定できます。
例えば、githubでコード変更があった場合や、ECRに新しいイメージがプッシュされた場合などです。
CodePipelineの処理の流れ
CodePipelineは、コード(Source)からイメージをビルド(Build)し、問題ないかテストを行い、ステージング環境に反映し(Staging)確認を行い、問題なければ本番化(Production)する一連の流れをまとめたサービスです。
▼AWSの各種サービスとの関係
CodePipelineの中で行われる処理をAWSの他のサービスと合わせると以下のようになります。
つまり、「CodeCommit」「CodeBuild」「CodeDeploy」の3つのサービスを統合したのが「CodePipeline」ということです。
CodePipelineのメリットは何か?
CodePipelineのメリットは本番かを自動化できることです。
これは、CodePipelineがない場合の本番化を知っておくとCodePipelineのメリットがわかりやすいです。
CodePipelineを使わない場合
CodePipelineを使わない場合に本番かする場での流れは以下のようになります。
コード変更(ローカル)
↓
コードをレポジトリにプッシュ(github, CodeCommit,,,)
↓
イメージのビルド(ローカル)
↓
イメージをプッシュ(ECR)
↓
タスク定義の更新(ECS)
↓
サービスの更新(ECS)
上記をステージとプロダクションのそれぞれで実施。
特にイメージが変更になる度に、タスク定義とサービスの更新作業が発生するのが手間です。
CodePipelineを使う場合
上記の作業をCodePiplineで自動化すると以下のようになります。
コード変更(ローカル)
↓
コードをレポジトリにプッシュ(github, CodeCommit,,,)
これは、Githubの変更をトリガーにした場合です。
AWSがGithubの変更を検知して、イメージの作成、タスク定義やサービスの更新、イメージからコンテナを作成しテスト、本番公開までを自動で進めてくれます。
本番公開する前に、ステージングの段階を設定して、手動承認しなければ本番化できない設定にもできます。
CodePipelineの料金イメージ
CodePipelineで何を監視&動かすかによって料金が変わります。
CodeCommit, CodeBuild, CodeDeployを使う場合は以下のようになります。
コストを安くする方法
CodeBuildでイメージのビルドとテストを実行することもできますが、この作業はローカルでも十分に実行可能です。
AWSでCodeBuildを使ってビルド&テストするよりもローカルで実行した方が早いこともあり、ビルドをCodePipelineに組み込まなければその分コストを抑えることができます。
CI/CDとは何か?
CodePipelineを調べているとよく直面する用語に「CI/CD」があります。
「CI/CD」とは、簡単に言うと本番化を自動するという概念です。
CI/CD(本番化の自動化)ができるサービスの一つにCodePipelineがあります。他にもCircleCiという他社サービスもあります。
CIがデプロイまでの処理の自動化で、CDがデプロイ後の処理の自動化です。
CIとは何か?
CIとは、Continuous Integrationの略です。日本語では、継続的インテグレーションといいます。
プロジェクトの運用では、本番環境のコードを直接いじることは基本的になく、ブランチを切ってmasterに統合(インテグレーション)していきます。
Dockerの場合は、更新後のイメージをビルドし、レポジトリに統合(インテグレーション)します。
このインテグレーションの作業を自動的(継続的)にすることをCIといいます。
CDとは何か?
CDとは、Continuous Deploymentの略です。日本語では、継続的デプロイメントといいます。
運用中のアプリケーションのコードを変更した場合は、その変更内容を反映(デプロイ)する必要があります。
このデプロイの作業を自動的(継続的)にすることをCDといいます。
CodePipelineを使うときのルール
CodePipelineを使うためには以下の3つが必要となります。
ステージとは?
CodePipelineでは監視やデプロイなど個々のアクションをステージと呼びます。ステージは全部で6種類あります。
ステージ名 | 処理内容 | 主な対象 |
---|---|---|
source | 監視対象を選ぶ | S3, ECR, CodeCommit, Github |
build | イメージをビルドする | CodeBuild, Jenkins |
test | イメージのテストを行う | CodeBuild, Jenkins |
deploy | 新しいサービスを始動する | CodeDeploy, S3, ECS |
approval | 手動で承認をすると次のステージに進める | 手動 |
invoke | 呼び出し | Lambda, Step Functions |
CodePipelineでは上記のうちの2つ以上を設定する必要があります。
ソースステージとは?
監視対象を選択するステージをソースステージと呼びます。上記のsourceにあたる部分です。
例えば、ソースステージにCodeCommitを選択すれば、指定のレポジトリのブランチで変更を検知した場合に、設定してある自動化プロセスが発火します。
最少構成
CodePipelineを使うときのルールを満たしたときの、最少構成は以下のようになります。
ソースステージ(固定)
↓
デプロイステージ
CodePipelineの作成手順(実例)
作成するCodePipelineの概要
ここでは参考として、以下のようなCodePipelineを作成する例を紹介します。
1. CodeCommitとECRの変更をトリガーにする
2. イメージの作成はローカルで実施(CodeBuildは使わない)
3. 完全自動デプロイはStagingまで
4. Productionデプロイの前に承認作業を入れる
5. 承認されたらProductionを自動デプロイ
作成後のCodePipelineイメージ
パイプラインの作成
パイプラインの作成
まずは、CodePipelineに入りパイプラインを作成します。
「パイプラインを作成する」ボタンをクリックします。
パイプラインの設定
・パイプライン名
任意(わかりやすいようにプロジェクトに沿った名前をつける)。
なお、指定した名前が、ロール名の末尾に自動で追加されます。(変更可能)
・サービスロール
CodePipelineは様々なAWSサービスにアクセスするため、専用のIAMを作成する必要があります。
「新しいサービスロール」を選べば、入力内容に沿って専用のIAMを自動作成してくれます。
既存のIAMを選択することも可能です。選択できるのはCodePipeline用のIAMのみです。
基本的には、新規作成します。
・ロール名
新しいサービスロールを作成する場合は名前をつける必要があります。
パイプライン名を入力すれば自動で専用の名前が入ります。(変更も可能)
AWSCodePipelineServiceRole-ap-<リージョン>-<パイプライン名>
高度な設定
アーティファクトとは何か?
CodePipelneを設定する中で頻繁に出てくるワードに「アーティファクト」があります。
アーティファクトとはひとまとまりのデータのことです。(オブジェクトに似たイメージ)
コードやイメージなど①受け取ったデータを、必要に応じて処理を施し、②次のステージに渡していくときに、これらのデータにそれぞれアーティファクト名をつけて、どのアーティファクトを渡すか指定します。
各ステージからみて、
①受け取ったアーティファクトを「入力アーティファクト」
②渡すアーティファクトを「出力アーティファクト」
と呼びます。
ステージ1
↓ ステージ1の出力アーティファクト
↓ ステージ2の入力アーティファクト
ステージ2
↓ ステージ2の出力アーティファクト
▼参考例
CodeCommitにプッシュされた変更後のソースコードが一つのアーティファクトになる。(仮に名前を アーティファクトA とする)また、更新後のイメージをECRにプッシュした場合はイメージがアーティファクトとなる。(仮に名前を アーティファクトB とする)
次のデプロイステージに2つのアーティファクトを渡す。その中で、コンテナの起動に使うためのイメージを指定するタブでは、アーティファクトBを入力する。
・アーティファクトストアとは何か?
アーティファクト(入出力データ)の保存場所のことです。
デフォルトはパイプラインと同じリージョンおよびアカウントのS3です。
自分で選ぶことも可能です。
基本的にはデフォルトで問題ありません。
・暗号化キー
パイプラインのアーティファクトの暗号化方法を選択します。
基本的にはデフォルトのAWSマネージド型キー(CMK)で問題ありません。
ソースステージの追加
ソースステージの選択
CodeCommitの変更をトリガーとしてCodePipelineを作動させるため、CodePipelineを選択します。(後から変更・追加も可能です)
選択すると、CodeCommitに登録されているレポジトリとブランチがプルダウンで選択できるようになります。
変更を検知する、リポジトリとブランチ名を選択します。
検出オプションの選択
変更をどのように検知するかを決めます。CloudWatchEventsかCodePipelineを選択できます。
CloudWatchEventsで変更を検知する方法が推奨。
出力アーティファクトの選択
アーティファクトをどのように出力するかを選択します。デフォルトと完全クローンが選択できます。
デフォルトのZip形式で出力を選択します。
なお、完全なクローンを作成する場合は、CodeBuildにクローンで生成されたレポジトリにアクセスするための権限を付与する必要があります。
ビルドステージの追加
ビルドステージはスキップ
今回、ビルドはローカルで行うため、スキップします。
参考として、内容のみ記載しておきます。
ビルドプロジェクトの作り方
イメージ作成とテストをするサービスを選択します。CodeBuildとJankinsが選択できます。
CodeBuildとは何か?
受け取ったソースコードからイメージを作成し、作成したイメージをECRにプッシュするAWSのサービスです。
▼CodeBuildでビルドプロジェクトを作成する場合
中段の「プロジェクトを作成する」から、CodeBuildに飛び、プロジェクトを作成することができます。
↓ CodeBuild
(参考)CodeBuildとは何か?
デプロイステージの追加
デプロイで使用するCodeDeployの設定を行います。
プロバイダーの選択
↓ デプロイの方法を選択します。
今回は、デプロイにBlue/Greenを選択します。
CodeDeployのアプリケーションを選択
既存から選択するか、新規作成することができます。
CodeDeployのプラットフォームはEC2, Lamba, ECSから選択することができます。
ECSでクラスターを作成した場合のCodeDeploy
ECSでクラスターを作成した場合、そのサービス名で自動でCodeDeployのアプリケーションとデプロイグループも自動で作成されます。
今回はECSで作成したアプリケーションを使うため、冒頭にAppECS-
がついています。
タスク定義ファイルの指定
コンテナ定義が書かれた、タスク定義ファイルを指定します。
デフォルトではtaskdef.jsonを使います。任意の名前をつけたい場合は入力します。(今回はtaskdef.stg.jsonを指定)
タスク定義ファイルとは何か?
コンテナ起動のための詳細情報が書かれたjson形式のファイルです。
デフォルトはtaskdef.json
です。
コンテナ名、ポート番号、環境変数などが記載されています。ECSでタスク定義をした際に作成されます。
SourceArtifactとは何か?
前の処理から、CodeDeployに渡されたひとまとまりのデータのことです。
ここでは、CodeCommitのソースコードが渡されています。
つまりここでは、CodeCommitにプッシュされたディレクトリのtaskdef.stg.json
ファイルをコンテナ起動のためのタスク定義ファイルとして使うことを指示しています。
タスク定義ファイルの例
{
"executionRoleArn": "arn:aws:iam::account_ID:role/ecsTaskExecutionRole",
"containerDefinitions": [
{
"name": "sample-website",
"image": "<IMAGE>",
"essential": true,
"portMappings": [
{
"hostPort": 80,
"protocol": "tcp",
"containerPort": 80
}
]
}
],
"requiresCompatibilities": [
"FARGATE"
],
"networkMode": "awsvpc",
"cpu": "256",
"memory": "512",
"family": "ecs-demo"
}
イメージ名をプレースホルダー"image": "<IMAGE>"
で指定しています。
appspecファイルの指定
デプロイ時に使用するappsepcファイルを指定します。
ファイル名はCodeCommitにプッシュしたファイル名と合わせます。
ファイル名拡張子は.yml
でも問題ありません。
appspecファイルとは何か?
appspecファイルとは、各デプロイメントでライフサイクルイベントフックを定義したファイルです。
ECSで作成したCodeDeployの場合は、以下を定義します。
- ECSサービスの名前
- コンテナー名とポート番号(トラフィックを新しいタスクセットに転送する)
- 検証テストとして使用される関数(任意)
appspecファイルの例
version: 0.0
Resources:
- TargetService:
Type: AWS::ECS::Service
Properties:
TaskDefinition: <TASK_DEFINITION>
LoadBalancerInfo:
ContainerName: "sample-website"
ContainerPort: 80
タスク定義名をプレースホルダーTaskDefinition: <TASK_DEFINITION>
で指定しています。
動的更新のためのIMAGE名を指定する
前の処理から渡された、入力アーティファクトでイメージ名を動的に取得するため"image": "<IMAGE>",
としています。
このイメージ名を使うため、プレースホルダーはIMAGEを選択します。
次へをクリック。
レビュー
設定した内容を確認して、問題なければパイプラインを作成します。
タスク定義ファイルの作成
タスク定義ファイルtaskdef.json
(今回はtaskdef.stg.json)を作成し、そこにJSON形式のタスクデータを貼り付けます。
デプロイグループで対象のECSサービス名確認する
デベロッパー用ツール > CodeDeploy > アプリケーション > AppECS(ECSクラスター名) → DgpECS(ECSデプロイグループ名)
で、CodeDeployで設計した内容が表示されます。
「環境設定」で、「クラスター名」と「サービス名」を確認します。
貼り付けるデータの取得
CodeDeployで対象としたECSサービスに移動します。(リンクをクリックすればジャンプします)
タスクタブを選択して、タスク定義をクリックします。
・JSONタブで表示されるデータをすべてコピーします。
ファイルの作成とデータの貼り付け
ローカルでCodeCommitと同期しているルートディレクトリにtaskdef.stg.json
を作成し、先ほどコピーしたタスク定義を貼り付けます。
imageプロパティの編集
デフォルトで指定されている更新用のイメージは、ビルドした時点でのイメージを指しています。(タグがlatestであっても)
このためimageをプレースホルダーで、更新されたデータ(入力アーティファクトから受け取ったデータ)が入るようにします。
▼変更前
"image": "111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/reposirory-name:latest"
↓ 変更後
"image": "<IMAGE>",
他はそのままで問題ありません。
このタスク定義ファイルは環境変数が含まれているため取り扱いに注意が必要です。(なので、githubではなく、ここだけCodeCommit上に置いています)
apspecファイルの作成
ファイルの作成
ローカルでCodeCommitと同期しているルートディレクトリにappspec.yml
を作成します。
データの貼り付け
appspec.ymlを以下のようにします。
version: 0.0
Resources:
- TargetService:
Type: AWS::ECS::Service
Properties:
TaskDefinition: <TASK_DEFINITION>
LoadBalancerInfo:
ContainerName: "sample-website"
ContainerPort: 80
ContainerNameには、対象のコンテナ名を記載します。
CodeCommitにプッシュ
apspecとtaskdefファイルが作成できたら、git add と git commit し、masterにプッシュします。
CodePipelineで確認する
プッシュした内容がパイプラインに反映されているか確認します。
デベロッパー用ツール > CodePipeline > パイプライン > パイプライン名
Source名を変更する
Sourceの中にECRなど他にも追加するアクションがあるため、CodeCommitのアクション名をわかりやすい名前に変更します。
環境変数やtaskdefやappsepcなどデプロイに必要な情報が入っているため、今回は「Deploy-info」にします。
↓ Deploy-info
Sourceにステージを追加する
対象のパイプラインで「編集」ボタンをクリックする。
↓
↓ ステージを編集をクリック
↓ アクションを追加をクリック
・アクション名
パイプラインに表示される名前(任意)
・アクションプロバイダー
ECR (プルダウンの Sourceから選択)
・リポジトリ名
プルダウンから選択
・イメージタグ
デフォルトはlatest。今回はそのままでOK
・出力アーティファクト
次のステージに渡すデータ名(任意)
完了をクリックして追加完了です。
SourceにECRのイメージが追加されました。
ステージング用のデプロイアクションの編集
デプロイアクション名の編集
今回作成しようとしているCodePipelineは、まず、ステージングのデプロイがあり、次にプロダクションのデプロイがくる2本立てになっています。
わかりやすいように、ステージングのデプロイのアクション名を変更します。
↓ STG-Deployに変更
入力アーティファクトの追加
2つのSourceから渡された出力アーティファクトを受け取る設定をします。
▼アクション名と出力アーティファクト名
・Deploy-Info: -DeployInfo
・ECR-IMAGE: ECR–IMAGE
▼プルダウンから選択
タスク定義ファイルとappspecファイルを指定する
taskdef.jsonとappspec.ymlが入っている入力アーティファクトを選び、ファイル名を指定します。
デプロイ用のイメージの指定
コンテナ起動の元となるイメージが入っている、入力アーティファクト名とイメージ名を指定します。
(補足)変数の名前空間
変数の名前空間はデフォルトのままで問題ありません。今回は使用しません。
認証ステージの追加
ステージから本番環境をデプロイする前に、手動の承認を追加します。
ステージを追加するを選択します。
↓ アクション名を入力(任意)
Sourceの中にECRなど他にも追加するアクションがあるため、CodeCommitのアクション名をわかりやすい名前に変更します。
↓ アクションプロバーダーでManual Approval
を選択
承認ステージに入ったときに、承認者が内容の確認をしやすいように、URLやコメントを入れることもできます。
STG-Deployの後に、承認ステージの追加されました。
本番環境のデプロイステージを追加
手動承認が完了したら、本番環境にデプロイが進むようにします。
ステージングと本番環境の違い
今回は、ステージングと本番環境の切り分けをコンテナに渡す環境変数で設定しています。
ステージングの場合は、ステージング用のサイト(https://stg~)
にステージング環境用のAPIトークンで入ってデータを取得します。
本番環境の場合は、本番用のサイト(https://~)
に本番環境用のAPIトークンで入ってデータを取得します。
環境変数はタスク定義ファイルに記述されているため、本番環境用のtaskdef.prd.json
を作成し、入力アーティファクトからそのファイルを選択します。
ここがステージングとの違いです。(逆にいうとここだけしか違わない)
CodeDeoloyのアプリケーション名とデプロイグループを指定
入力アーティファクトを選択
taskdef、appspec, イメージが入ったアーティファクトを指定します。
▼アクション名と出力アーティファクト名
・Deploy-Info: -DeployInfo
・ECR-IMAGE: ECR–IMAGE
▼プルダウンから選択
タスク定義ファイルとappspecファイルを指定
taskdef.jsonとappspec.ymlが入っている入力アーティファクトを選び、ファイル名を指定します。
デプロイ用のイメージの指定
コンテナ起動の元となるイメージが入っている、入力アーティファクト名とイメージ名を指定します。
保存と変更
ステージを追加したら必ず保存してくだsだい。これを忘れるともう一度入力し直しになります。
CodePipelineの変更をリリースする
最後に、変更をリリースして、CodePipelineの設定は完了です。
次に、taskdef.prd.jsonファイルを作成します。
貼り付けるデータの取得
対象のクラスターのサービスに移動します。ECRに入り以下ページに移動します。
クラスター > クラスター名 > サービス: サービス名
・タスクタブを選択して、タスク定義をクリックします。(先ほどはstgでしたが、今回はprdを選択します)
・JSONタブで表示されるデータをすべてコピーします。
ファイルの作成とデータの貼り付け
ローカルでCodeCommitと同期しているルートディレクトリにtaskdef.prd.json
を作成し、先ほどコピーしたタスク定義を貼り付けます。
imageプロパティの編集
デフォルトで指定されている更新用のイメージは、ビルドした時点でのイメージを指しています。(タグがlatestであっても)
このためimageをプレースホルダーで、更新されたデータ(入力アーティファクトから受け取ったデータ)が入るようにします。
"image": "111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/reposirory-name:latest"
↓ 変更
"image": "<IMAGE>",
他はそのままでOKです。
CodeCommitにプッシュ
apspecとtaskdefファイルが作成できたら、git add と git commit し、masterにプッシュします。
CodePipelineで進行状況の確認
プッシュされたことで、CodeCommitの変更内容を検知して、CodePipelineが動き出したか確認します。
デベロッパー用ツール > CodePipeline > パイプライン > パイプライン名
Sourceが進行中になります。
↓ Sourceが完了するとステージングのデプロイに進みます
↓ 詳細リンクをクリック
デベロッパー用ツール > CodeDeploy > デプロイ > デプロイID
ページに移動し、進行状況が確認できます。
↓ デプロイ完了
↓ CodePipelineに戻る
「ステータスが成功しました」になります。
↓ 承認ステージに進みます
↓ 手動承認
↓
元の環境の保持時間を変更する方法
Blue/Greenは、新しい開発環境(Green)を構築したときに、古い環境(Blue)も一定時間残す仕様になっています。
デフォルトでは、Greenに切り替えて1時間問題がなければBlueを削除します。
この削除までの時間は自由に設定することができます。
今回、1時間も待機していないといけないのは長いため、ステージング環境は0分(新しいサーバーが切り替わったら即切り替え完了)、プロダクション環境は30分に設定します。
元の環境の保持時間の変更方法
▼ステージングの元のリビジョンの保持時間を変更
CodeDeployのアプリケーションで、ステージングのアプリケーションの中のアプリケーショングループを選択します。
デベロッパー用ツール > CodeDeploy > アプリケーション > AppECS(ECSクラスター名) → DgpECS(ECSデプロイグループ名)
一番下の「デプロイ設定」の「元のリビジョンの終了」を0時間0分に設定します。
変更が完了したら、「変更の保存」をクリックします。
同様に、プロダクションのアプリケーションを選択肢、「元のリビジョンの終了」を0時間30分に設定します。
変更が完了したら、「変更の保存」をクリックします。
待機中のタスクの強制終了
ステップ1とステップ2が終わっていれば、更新後の環境構築と再ルーティングは終わっています。
ステップ3で指定時間待機中ですが、これをスキップしたい場合は、右上の「元のタスクセットの終了」をクリックします。
↓
ステップ3とステップ4も完了となり、このステージが完了し、次のステージに進めるようになります。