CdkPipelineが非推奨になったのでCodePipelineに移行してみた

#AWS
#CDK
#Python
#CdkPipeline
#CodePipeline

CDK v1をv2へ移行するにあたり、cdkコマンドを打った際、出力されるwarningに対応することになりました

(*本記事ではまだCDKv1を使用しています)

Pythonのaws_cdk.pipelines.CdkPipelineはdeprecated(非推奨)となっており、aws_cdk.pipelines.CodePipelineに変更します

移行についてのブログやドキュエントなどあさっても良い感じのが見つからず、なんとなくこうだろうで進めて成功したようなので経験則として参考にしてください

  • 1.aws_cdk.pipelines.CdkPipelineで記述されたコードをaws_cdk.pipelines.CodePipelineの書き方へ修正

 

  • 2.CodeCommitへpushしパイプラインを動かし変更を反映

 

流れ的には二段階の単純な工程で終わりますが、1 -> 2の間にハマりポイントがたくさんありました。

$ pip list aws-cdk.aws-codepipeline 1.118.0 aws-cdk.aws-codepipeline-actions 1.118.0 aws-cdk.aws-codecommit 1.118.0 aws-cdk.aws-codestarnotifications 1.118.0 aws-cdk.aws-iam 1.118.0 aws-cdk.pipelines 1.118.0 aws-cdk.core 1.118.0
$ cdk --version 2.23.0 (build 50444aa)
from aws_cdk import ( aws_codepipeline as codepipeline, aws_codepipeline_actions as actions, aws_codecommit as codecommit, aws_codestarnotifications as notifications, aws_iam as iam, pipelines, core ) from pipeline_lib.pipeline_stage import PipelineStage class PipelineDevStack(core.Stack): def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) sourceArtifact = codepipeline.Artifact() cloudAssemblyArtifact = codepipeline.Artifact() pipeline = pipelines.CdkPipeline(self, 'Pipeline', pipeline_name=self.node.try_get_context( 'repository_name') + "-dev-pipeline", cloud_assembly_artifact=cloudAssemblyArtifact, source_action=actions.CodeCommitSourceAction( action_name="CodeCommitgit", repository=codecommit.Repository.from_repository_name( self, 'Repo', repository_name=self.node.try_get_context('repository_name')), output=sourceArtifact, branch="dev" ), synth_action=pipelines.SimpleSynthAction( synth_command="cdk synth", install_commands=[ "echo <docker password> | docker login -u <docker user> --password-stdin", "aws codeartifact login --tool pip --repository <codeartifact repository name> --domain <domain name> --domain-owner <aws account id>", "pip install --upgrade pip", "npm i -g aws-cdk", "pip install -r requirements.txt" ], test_commands=[ "python -m pytest -xx functions/tests/", "bandit -r functions/src" ], source_artifact=sourceArtifact, cloud_assembly_artifact=cloudAssemblyArtifact, environment={ 'privileged': True }, role_policy_statements=[ iam.PolicyStatement( actions=['codeartifact:*'], resources=['*']), iam.PolicyStatement( actions=['sts:GetServiceBearerToken'], resources=['*']) ] ) ) dev = PipelineStage(self, self.node.try_get_context('repository_name') + "-dev", env={ 'region': "ap-northeast-1", 'account': "<aws dev account id>"} ) pipeline.add_application_stage(dev) notifications.CfnNotificationRule(self, 'pipeline-notification', name=self.node.try_get_context( 'repository_name') + "-dev", detail_type="FULL", event_type_ids=[ "codepipeline-pipeline-pipeline-execution-succeeded", "codepipeline-pipeline-pipeline-execution-resumed", "codepipeline-pipeline-pipeline-execution-superseded", "codepipeline-pipeline-pipeline-execution-started", "codepipeline-pipeline-pipeline-execution-canceled", "codepipeline-pipeline-pipeline-execution-failed", "codepipeline-pipeline-manual-approval-succeeded", "codepipeline-pipeline-manual-approval-needed", "codepipeline-pipeline-manual-approval-failed", ], resource=pipeline.code_pipeline.pipeline_arn, targets=[ { "targetAddress": self.node.try_get_context('pipeline-topic-arn'), "targetType": "SNS" } ] )
from aws_cdk import ( aws_codebuild as codebuild, aws_codecommit as codecommit, aws_codestarnotifications as notifications, aws_iam as iam, pipelines, core ) from pipeline_lib.pipeline_stage import PipelineStage class PipelineDevStack(core.Stack): def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) pipeline = pipelines.CodePipeline(self, 'Pipeline', pipeline_name=self.node.try_get_context( 'repository_name') + "-dev-pipeline", synth=pipelines.CodeBuildStep('Synth', build_environment=codebuild.BuildEnvironment( compute_type=codebuild.ComputeType.LARGE, privileged=True), input=pipelines.CodePipelineSource.code_commit( branch="dev", repository=codecommit.Repository.from_repository_name( self, 'Repo', repository_name=self.node.try_get_context('repository_name'))), install_commands=[ "echo <docker password> | docker login -u <docker user> --password-stdin", "aws codeartifact login --tool pip --repository <codeartifact repository name> --domain <domain name> --domain-owner <aws account id>", "pip install --upgrade pip", "npm i -g aws-cdk", "pip install -r requirements.txt" ], commands=[ "python -m pytest -xx functions/tests/", "bandit -r functions/src", "cdk synth" ], role_policy_statements=[ iam.PolicyStatement( actions=['codeartifact:*'], resources=['*']), iam.PolicyStatement( actions=['sts:GetServiceBearerToken'], resources=['*']) ] ), cross_account_keys=True ) dev = PipelineStage(self, self.node.try_get_context('repository_name') + "-dev", env={ 'region': "ap-northeast-1", 'account': "<aws dev account id>"} ) pipeline.add_stage(stage=dev) pipeline.build_pipeline() notifications.CfnNotificationRule(self, 'pipeline-notification', name=self.node.try_get_context( 'repository_name') + "-dev", detail_type="FULL", event_type_ids=[ "codepipeline-pipeline-pipeline-execution-succeeded", "codepipeline-pipeline-pipeline-execution-resumed", "codepipeline-pipeline-pipeline-execution-superseded", "codepipeline-pipeline-pipeline-execution-started", "codepipeline-pipeline-pipeline-execution-canceled", "codepipeline-pipeline-pipeline-execution-failed", "codepipeline-pipeline-manual-approval-succeeded", "codepipeline-pipeline-manual-approval-needed", "codepipeline-pipeline-manual-approval-failed", ], resource=pipeline.pipeline.pipeline_arn, targets=[ { "targetAddress": self.node.try_get_context('pipeline-topic-arn'), "targetType": "SNS" } ] )

CDKのステージの中にDocker起動が必要なLambdaの設定があり、以下のprivileged=Trueの設定をしていないとdockerへアクセス出来ず失敗しました

build_environment=codebuild.BuildEnvironment(privileged=True)

 

CfnNotificationRuleを使用する際、resourceにpipelineのarnを設定する必要があるところ、そのままpipeline.pipeline.pipeline_arnを設定するだけでは失敗してしまいます

 

CodePipelineのdocumentを確認すると、Attributesのpipelineでは、

 

The CodePipeline pipeline that deploys the CDK app.

Only available after the pipeline has been built.

 

となっておりbuild済ませておく必要があるそうで、最初は意味が分からなかったのですが、

以下のようにpipelineを呼び出す前にbuild_pipeline()を実行すれば良いようです

pipeline.build_pipeline()

CodeBuildStepのcross_account_keys=True、この設定がないと失敗しました ドキュメントによると、

 

Create KMS keys for the artifact buckets, allowing cross-account deployments.

The artifact buckets have to be encrypted to support deploying CDK apps to another account,

so if you want to do that or want to have your artifact buckets encrypted,

be sure to set this value to true. Be aware there is a cost associated with maintaining the KMS keys.

Default: false

 

となっており、設定するとクロスアカウントのバケットへの暗号化など行ってくれるようです

担当して案件ではmanageアカウントからdevアカウントへクロスアカウントにリソースを操作するため、必要な設定でした

testが多く、メモリが足りないと途中で中断して失敗してしまいます

compute_typeを指定することでメモリを調整できるようです

build_environment=codebuild.BuildEnvironment( compute_type=codebuild.ComputeType.LARGE, privileged=True),

buildspecなどの設定を変更してpushしてもすぐにCodeBuildに反映されず、前回の設定でPipelineが動いてからbuildspecの内容などが反映されます

 

なので、buildの段階で落ちている場合はコンソールに入り、手動でCodeBuildの編集などを行ってからパイプラインを動かす必要があります

最初の一回だけ実行が必要なbootstrapというコマンドを実行する必要があります

実行することでcdk実行のための周辺リソースが作成されるようです

$ cdk bootstrap \ --profile <CodepipeLineを管理するアカウントのprofile> \ --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess \ aws://<CodepipeLineを管理するアカウントID>/ap-northeast-1 $ cdk bootstrap \ --profile <リソースをデプロイしたい先アカウントのprofile> \ --trust <CodepipeLineを管理するアカウントのID> \ --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess \ aws://<リソースをデプロイしたい先アカウントID>/ap-northeast-1

 

CodePipelineのリソース自体を作成するために最初の一回はCLIからデプロイします

$ cdk deploy "*" --profile <CodepipeLineを管理するアカウントのprofile>

CodePipelineのドキュメント => https://docs.aws.amazon.com/cdk/api/v1/python/aws_cdk.pipelines/CodePipeline.html

CodeBuildStepのドキュメント => https://docs.aws.amazon.com/cdk/api/v1/python/aws_cdk.pipelines/CodeBuildStep.html