こんにちは、ちゃりおです。
最近、CDKでEC2にデプロイするCodepipeline作りました。
初めてCDKでCodeシリーズを書いたのですが、Cloudformationと比べてかなり楽に
かけて感動したので記事にします。
概要
以下概要です。
- ソースはgithub
- githubのWebhookをトリガーにCodepipelineを発火
- フローはCodepipeline>Codebuil>CodeDeploy
バージョン
試したときのバージョンです。
- node: v14.5.0
- cdk: 1.60.0
事前準備
以下の事前準備が必要です。
- nodeのインストール
- CDKのインストール
- githubトークンの取得
- Settings>Developper settings>Personal access tokens
- repoのフルアクセスがあればよいはず
CDK
デプロイフロー作成のCDK
最低限だとこんな感じになると思います。
本番で使うなら、環境ごとに作れるようにしたり、セキュアな情報はパラメータストアを使うなどが必要になってくると思います。
import * as cdk from '@aws-cdk/core';
import * as codebuild from '@aws-cdk/aws-codebuild';
import * as codedeploy from '@aws-cdk/aws-codedeploy';
import * as codepipeline_actions from '@aws-cdk/aws-codepipeline-actions';
import * as codepipeline from '@aws-cdk/aws-codepipeline';
export class DeployflowStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string ) {
super(scope, id);
// === CodeBuild ===
const project = new codebuild.PipelineProject(this, 'CodeBuild', {
projectName: 'simple-ec2-deployflow-project',
});
// === CodeDeploy ===
const deploymentGroup = new codedeploy.ServerDeploymentGroup(this, "DeploymentGroup", {
deploymentGroupName: 'simple-ec2-deployflow-group',
ec2InstanceTags: new codedeploy.InstanceTagSet(
{
Deploy: ['simple-ec2-deployflow'],
}
),
deploymentConfig: codedeploy.ServerDeploymentConfig.ALL_AT_ONCE
});
// === Artifact ===
const sourceOutput = new codepipeline.Artifact();
const buildOutput = new codepipeline.Artifact();
// === Code Pipeline Action ===
const sourceAction = new codepipeline_actions.GitHubSourceAction({
actionName: 'Github',
owner: '<github owner>',
repo: '<github repo>',
output: sourceOutput,
// トークンはssmとかで渡したほうが良さそう
oauthToken: cdk.SecretValue.plainText('<github token>'),
branch: 'master',
trigger: codepipeline_actions.GitHubTrigger.WEBHOOK,
});
const buildAction = new codepipeline_actions.CodeBuildAction({
actionName: "CodeBuild",
input: sourceOutput,
project,
outputs: [buildOutput]
});
const deployAction = new codepipeline_actions.CodeDeployServerDeployAction({
actionName: 'CodeDeploy',
input: buildOutput,
deploymentGroup: deploymentGroup,
});
// === Code Pipeline ===
const pipeline = new codepipeline.Pipeline(this, 'CodePipeline', {
pipelineName: 'simple-ec2-deployflow-pipeline',
stages: [
{
stageName: 'Source',
actions: [sourceAction]
},
{
stageName: 'Build',
actions: [buildAction]
},
{
stageName: 'Deploy',
actions: [deployAction]
}
]
});
}
}
注意点
EC2にデプロイする場合、EC2のIAMロールをKMSのアクセスポリシーで許可する必要があります。
許可しない状態でやると、デプロイ時に権限のエラーがでてデプロイできないです。
(デプロイアーティファクトをKMSで復号化できないため)
おまけ: 生成されるCloudformationをみてみる
Cloudformationは、1000行くらいになっていました。
JSONだからというのもあると思いますが、yamlで手動で書いても300行以上になる気がします。
今回のCDKだと80行くらいなので、かなり抑えられています。
直接記述しなくても、IAMロールとかS3バケットの作成とかよしなにやってくれます。
自動生成されるCloudformationを抜粋しつつ見てみます。
「cdk.out/<スタック名>.template.json」が生成されたCloudFormationです。(マネジメントコンソールからも見れます。)
ArtifactBucketの定義です。
CDKでは一行ですが、以下のS3バケットの記述があります。(new codepipeline.Artifact();)
KMSで暗号化しているみたいです。
"CodePipelineArtifactsBucket11111": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketEncryption": {
"ServerSideEncryptionConfiguration": [
{
"ServerSideEncryptionByDefault": {
"KMSMasterKeyID": {
"Fn::GetAtt": [
"CodePipelineArtifactsBucketEncryptionKey11111",
"Arn"
]
},
"SSEAlgorithm": "aws:kms"
}
}
]
},
探してみると、KMSの定義もありました。
"CodePipelineArtifactsBucketEncryptionKey1111": {
"Type": "AWS::KMS::Key",
"Properties": {
"KeyPolicy": {
"Statement": [
{
"Action": [
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
KMSもう少しみてみると、IAMロールに許可を与えているのがわかります。
CodePipelineとCodebuildのIAMロールに復号化などの許可を行っています。
"Action": [
"kms:Decrypt",
"kms:DescribeKey",
"kms:Encrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*"
],
"Effect": "Allow",
"Principal": {
"AWS": {
"Fn::GetAtt": [
"CodePipelineRole1111",
"Arn"
]
}
},
CodepipelineのIAMロール・ポリシーもありました。
CDK側ではなにも指定しませんでしたが、最小限の権限が割り当てられているようです。
"CodePipelineRoleB3A660B4": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "codepipeline.amazonaws.com"
}
}
],
"Version": "2012-10-17"
}
},
"Metadata": {
"aws:cdk:path": "DeployflowStack/CodePipeline/Role/Resource"
}
},
"CodePipelineRoleDefaultPolicy8D520A8D": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": [
"s3:GetObject*",
"s3:GetBucket*",
"s3:List*",
"s3:DeleteObject*",
"s3:PutObject*",
"s3:Abort*"
],
このように、色々自動生成してくれます。
便利な反面どういったリソースが作られるか理解できていないと
共通化できるのに、必要以上にリソースを作ってしまうことがあります。
まとめ
今回は、CDKでCodepipelineのデプロイフローを作ってみました。
Cloudformationで数百行書く必要があったものが、CDK L2 Libraryを使えば百行以下でかけました。
便利な反面、慣れていないととコード上からはどういったリソースが作られているかわかないこともあります。
(KMSが作成されるの見落として、EC2にデプロイするときにハマりました。)
生成されるCloudformationも確認しながら、CDK使っていきたいです。


