CodePipelineに承認アクションを設定する
Codepipelineのステージに承認(Approval)アクションを追加することができます。
パイプラインが承認ステージまで進むと、一度動作が停止し、手動による承認を待機するステータスとなります。
今回は承認ステージになりましたら、SNSでメール通知する構成を目指します。
構築する環境
CodePipelineを構成し、4つのリソースを連携させます。
1つ目はCodeCommitです。
CodeCommitはCodePipelineのソースステージを担当します。
Gitリポジトリとして使用します。
2つ目はCodeBuildです。
CodeBuildはCodePipelineのビルドステージを担当します。
CodeCommitにプッシュされたコードから、Dockerイメージをビルドします。
ビルドしたイメージをECRにプッシュします。
3つ目はSNSです。
SNSはCodePipelineの承認ステージを担当します。
パイプラインが承認ステージになりましたら、一旦パイプラインが停止し、SNSでメール通知します。
メールによる通知を受けたユーザは、パイプラインのページにアクセスし、承認ボタンを押すとパイプラインが再開されます。
4つ目はLambda関数です。
この関数の働きは、ECS(Fargate)サービスのタスク希望数を変更することです。
具体的には希望数を0から1に変更します。
CodePipelineにデプロイステージを作成します。
後述のFargateにデプロイするように設定します。
SSMパラメータストアにDockerHubアカウント情報を保存します。
DockerBuildでイメージを生成する際に、DockerHubにサインインした上でベースイメージをプルするために、これらを使用します。
CodePipelineが開始されるきっかけですが、CodeCommitへのプッシュを条件とします。
具体的には、EventBridgeに上記を満たすルールを用意します。
プライベートサブネットに、FargateタイプのECSを作成します。
EC2インスタンスを作成します。
Fargate上に作成されたコンテナにアクセスするためのクライアントして使用します。
CloudFormationテンプレートファイル
上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。
https://github.com/awstut-an-r/awstut-fa/tree/main/080
テンプレートファイルのポイント解説
本ページはCodepipeline内に承認ステージを作成し、SNSでメール通知する方法を取り上げます。
CodePipelineに関する基本的な事項については、以下のページをご確認ください。
CodePipelineにデプロイステージを作成し、ECS(Fargate)にデプロイする方法については、以下のページをご確認ください。
CodePipeline内でLambda関数を呼び出すアクションを定義し、ECS(Fargate)サービスの希望数を変更する方法については、以下のページをご確認ください。
プライベートサブネットにFargateを構築する方法については、以下のページをご確認ください。
CloudFormationカスタムリソースを使用して、CloudFormationスタック削除時に、自動的にS3バケット内のオブジェクトと、ECRリポジトリ内のイメージを削除します。
詳細につきましては、以下のページをご確認ください。
SNS
Resources:
Topic:
Type: AWS::SNS::Topic
Properties:
Subscription:
- Endpoint: !Ref MailAddress
Protocol: email
TopicName: !Ref Prefix
Code language: YAML (yaml)
SNSトピックを作成します。
通知先にメールを指定します。
詳細については、以下のページをご確認ください。
CodePipeline
Resources:
Pipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
ArtifactStore:
Location: !Ref BucketName
Type: S3
Name: !Ref Prefix
RoleArn: !GetAtt CodePipelineRole.Arn
Stages:
- Actions:
- ActionTypeId:
Category: Source
Owner: AWS
Provider: CodeCommit
Version: 1
Configuration:
BranchName: !Ref BranchName
OutputArtifactFormat: CODE_ZIP
PollForSourceChanges: false
RepositoryName: !GetAtt CodeCommitRepository.Name
Name: Source
OutputArtifacts:
- Name: !Ref PipelineSourceArtifact
Region: !Ref AWS::Region
RunOrder: 1
Name: Source
- Actions:
- ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
Configuration:
ProjectName: !Ref CodeBuildProject
InputArtifacts:
- Name: !Ref PipelineSourceArtifact
Name: Build
OutputArtifacts:
- Name: !Ref PipelineBuildArtifact
Region: !Ref AWS::Region
RunOrder: 1
Name: Build
- Actions:
- ActionTypeId:
Category: Approval
Owner: AWS
Provider: Manual
Version: 1
Configuration:
CustomData: hoge hoge hoge.
ExternalEntityLink: http://example.com
NotificationArn: !Ref TopicArn
InputArtifacts: []
Name: Approval
OutputArtifacts: []
Region: !Ref AWS::Region
RunOrder: 1
Name: Approval
- Actions:
- ActionTypeId:
Category: Deploy
Owner: AWS
Provider: ECS
Version: 1
Configuration:
ClusterName: !Ref ECSClusterName
FileName: !Ref ImageDefinitionFileName
ServiceName: !Ref ECSServiceName
InputArtifacts:
- Name: !Ref PipelineBuildArtifact
Name: Deploy
Region: !Ref AWS::Region
RunOrder: 1
Name: Deploy
- Actions:
- ActionTypeId:
Category: Invoke
Owner: AWS
Provider: Lambda
Version: 1
Configuration:
FunctionName: !Ref ECSFunctionName
InputArtifacts: []
Name: Invoke
OutputArtifacts: []
Region: !Ref AWS::Region
RunOrder: 1
Name: Invoke
Code language: YAML (yaml)
Stagesプロパティに承認ステージを定義します。
Configurationプロパティ内で、承認ステージの詳細設定を行います。特に重要なパラメータはNotificationArnプロパティです。本プロパティに先述のSNSトピックを指定します。
InputArtifactsおよびOutputArtifactsプロパティは空の配列を指定します。今回の挙動では、アーティファクトに対する読み書きは発生しないためです。
以下がCodePipeline用のIAMロールです。
Resources:
CodePipelineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- codepipeline.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: PipelinePolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- lambda:invokeFunction
Resource:
- !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${ECSFunctionName}"
- Effect: Allow
Action:
- codecommit:CancelUploadArchive
- codecommit:GetBranch
- codecommit:GetCommit
- codecommit:GetRepository
- codecommit:GetUploadArchiveStatus
- codecommit:UploadArchive
Resource:
- !GetAtt CodeCommitRepository.Arn
- Effect: Allow
Action:
- codebuild:BatchGetBuilds
- codebuild:StartBuild
- codebuild:BatchGetBuildBatches
- codebuild:StartBuildBatch
Resource:
- !GetAtt CodeBuildProject.Arn
- Effect: Allow
Action:
- s3:PutObject
- s3:GetObject
- s3:GetObjectVersion
- s3:GetBucketAcl
- s3:GetBucketLocation
Resource:
- !Sub "arn:aws:s3:::${BucketName}"
- !Sub "arn:aws:s3:::${BucketName}/*"
- Effect: Allow
Action:
- sns:Publish
Resource:
- !Ref TopicArn
- Effect: Allow
Action:
- ecs:*
Resource: "*"
- Effect: Allow
Action:
- iam:PassRole
Resource: "*"
Condition:
StringLike:
iam:PassedToService:
- ecs-tasks.amazonaws.com
Code language: YAML (yaml)
承認ステージ用の権限を設定します。
SNSトピックに対して、「sns:Publish」を許可します。
(参照)アプリコンテナ
Dockerfile
FROM amazonlinux
RUN yum update -y && yum install python3 python3-pip -y
RUN pip3 install bottle
COPY main.py ./
CMD ["python3", "main.py"]
EXPOSE 8080
Code language: Dockerfile (dockerfile)
アプリコンテナ用のイメージは、Amazon Linux 2をベースとして作成します。
Python製WebフレームワークのBottleを使用します。
ですからPythonおよびpipをインストール後、これをインストールします。
アプリロジックを記載したPythonスクリプト(main.py)をコピーし、これを実行するように設定します。
先述の通り、アプリはtcp/8080でHTTPリクエストを待ち受けますので、このポートを公開します。
main.py
from bottle import route, run
@route('/')
def hello():
return 'Hello CodePipeline.'
if __name__ == '__main__':
run(host='0.0.0.0', port=8080)
Code language: Python (python)
Bottleを使用して、簡易的なWebサーバを構築します。
8080/tcpでHTTPリクエストを待ち受け、「Hello CodePipeline.」を返すという単純な構成です。
環境構築
CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。
CloudFormationスタックを作成し、スタック内のリソースを確認する
CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。
各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。
- ECR:fa-080
- CodeCommit:fa-080
- CodeBuild:fa-080
- CodePipeline:fa-080
- Lambda関数:fa-080-function-ecs
- SNSトピック:fa-080
メールアドレスの認証
SNSトピックのサブスクライバーとしてメールアドレスを指定した場合、そのメールアドレスを認証する必要があります。
詳細につきましては、以下のページをご確認ください。
リソース確認
AWS Management Consoleから各リソースを確認します。
CodePipelineを確認します。
パイプラインの実行に失敗しています。
これはCloudFormationスタック作成時に、CodeCommitが作成されたことがきっかけとして、パイプラインが実行されたためです。
現時点ではCodeCommitにコードをプッシュしていないため、パイプライン実行の過程でエラーが発生しました。
作成されているステージに注目します。
Approvalという名前で、SNSトピックを呼び出すステージが用意されています。
パイプラインがこのステージまで到達すると、一旦停止し、承認を待つことになります。
動作確認
準備が整いましたので、CodeCommitにコードをプッシュします。
まずCodeCommitをプルします。
$ git clone https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/fa-080
Cloning into 'fa-080'...
warning: You appear to have cloned an empty repository.
Code language: Bash (bash)
空のリポジトリがプルされました。
リポジトリにDockerfileおよびmain.pyを加えます。
$ ls -al
total 8
drwxrwxr-x 3 ec2-user ec2-user 51 Aug 20 23:54 .
drwxrwxr-x 3 ec2-user ec2-user 20 Aug 20 23:53 ..
-rw-rw-r-- 1 ec2-user ec2-user 187 Aug 12 11:01 Dockerfile
drwxrwxr-x 7 ec2-user ec2-user 119 Aug 20 23:53 .git
-rw-rw-r-- 1 ec2-user ec2-user 691 Aug 20 11:25 main.py
Code language: Bash (bash)
2ファイルをCodeCommitにプッシュします。
$ git add .
$ git commit -m 'first commit'
[master (root-commit) 6bfe691] first commit
...
2 files changed, 39 insertions(+)
create mode 100644 Dockerfile
create mode 100644 main.py
$ git push
...
* [new branch] master -> master
Code language: Bash (bash)
正常にプッシュできました。
しばらく待機した後、改めてCodePipelineを確認します。
パイプラインが開始されました。
SourceおよびBuildステージは正常に完了し、承認(Approval)ステージに到達しました。
ただしステータスは「Pending」とあり、「Waiting for approval」というメッセージが表示されてます。
つまり権限を持つユーザが承認するまで、この状況は継続されることになります。
SNSトピックから、以下の通りメールが届きます。
このようにメールによって、ユーザに承認を待っていることを知らせることができます。
パイプラインの承認に必要な権限につきましては、AWS公式ページでは、以下の通り示されています。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"codepipeline:ListPipelines"
],
"Resource": [
"*"
]
},
{
"Effect": "Allow",
"Action": [
"codepipeline:GetPipeline",
"codepipeline:GetPipelineState",
"codepipeline:GetPipelineExecution"
],
"Resource": "arn:aws:codepipeline:us-east-2:80398EXAMPLE:MyFirstPipeline"
},
{
"Effect": "Allow",
"Action": [
"codepipeline:PutApprovalResult"
],
"Resource": "arn:aws:codepipeline:us-east-2:80398EXAMPLE:MyFirstPipeline/MyApprovalStage/MyApprovalAction"
}
]
}
Code language: JSON / JSON with Comments (json)
https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/approvals-iam-permissions.html
上記の権限を満たすユーザで承認を進めます。
「Approval」を押下し、承認します。
「Approved」と表示されました。
つまり承認することによって、パイプラインが再開されたということです。
しばらく待機します。
パイプラインの全ステージが完了しました。
Fargateを確認します。
ECS(Fargate)のタスク希望数が1であり、そのタスクのIPアドレスが「10.0.2.4」であることがわかります。
実際にタスク内のコンテナにアクセスします。
% aws ssm start-session --target i-0c41c5926230b480c
Starting session with SessionId: root-0c76e08548a26fec6
sh-4.2$
Code language: Bash (bash)
SSM Session Managerの詳細につきましては、以下のページをご確認ください。
curlコマンドを使って、タスク内のコンテナにアクセスします。
sh-4.2$ curl http://10.0.2.4:8080/
Hello CodePipeline.
Code language: Bash (bash)
コンテナから応答がありました。
確かにBottleアプリで設定した文字列です。
このことから、確かにパイプラインが実行されたということがわかります。
このようにCodePipelineに承認ステージを作成することによって、パイプラインの一時停止、SNSによるメール通知、承認によるパイプラインの再開を実装することができました。
まとめ
CodePipelineに承認ステージを作成し、SNSでメール通知する方法を確認しました。