お疲れさまです。@naokiurです。
2020年、今年も宜しくお願い致します。
AWS CDKを知ってから、
「これは、AWS CDKだとどうやって作成するんだろう…?」
みたいな考えになることが多いです。
今回は、CI/CD環境の簡単なものを、
AWS CDK(Java)で構築しました。
環境
- MacBook Pro (Retina 13-inch、Early 2015)
- macOS Mojave 10.14.6
- Java 1.8.0_191
- IntelliJ IDEA CE 2019.2.4
CodePipelineの構築
構成図

ソースを取得して、
ZIP化、S3に格納するだけですが、
業務ではGithubを用いているため、
CodeCommitではなく、
Githubをソース取得元にしました。
CodePipeline構築
CodePipelineを構築するためには、
大きくわけて、以下を作成することで、構築することができました。
- Pipelineクラス
- Stagesクラス
- Actionクラス
- Artifactクラス
Pipelineクラス
文字通り、CodePipelineを表現するクラスです。
このクラスを build()
し、
cdk deploy
することで、
AWS上にCodePipelineを構築することができました。
final Pipeline saveToS3Pipeline = Pipeline.Builder
.create(this, "saveSourceToS3")
.pipelineName("saveSourceToS3")
.stages(new ArrayList<>(Arrays.asList(source, build, deploy)))
.build();
これに限らず、
AWSリソースを生成するためには、
hoge.Builder.create(Stackクラス, id).~中略~.build()
で構築できるようになっていることが多いようなので、
わかりやすいなと感じております。
CodePipelineは Stage
を最低2つ必要とするため、
stages()
には少なくとも2つ要素を持つListを指定する必要があります。
指定していない場合、 エラーとなりました。
Stageクラス
CodePipelineに設定するStageのクラスです。
今回は(中身があまりないながら)
Source, Build, Deployの3つのステージをすべて作成しました。
final StageProps source = StageProps.builder()
.stageName("DownloadSourceFromGithub")
.actions(new ArrayList<>(Arrays.asList(github)))
.build();
final StageProps build = StageProps.builder()
.stageName("BuildSource")
.actions(new ArrayList<>(Arrays.asList(codeBuild)))
.build();
final StageProps deploy = StageProps.builder()
.stageName("SaveSourceToS3")
.actions(new ArrayList<>(Arrays.asList(s3)))
.build();
早速 hoge.Builder.create(Stackクラス, id).~中略~.build()
という書き方ではないですね。
Stageは、AWSサービスではなく、CodePipelineの一要素であり、
CloudFormationのスタックの リソース
として出てくるものではないためです。
(※個人の意見です)
Stageには、複数のActionを持つことができるようです。
Actionクラス
Stageで実行するActionのクラスです。
それぞれのStageに対応した、Actionを作成します。
今回は(中身があまりないので)
各Stageにつき、1つずつです。
final Action github = GitHubSourceAction.Builder
.create()
.actionName("DownloadFromGithub")
.oauthToken(githubToken)
.branch(branchName)
.repo(repoName)
.owner(ownerName)
.output(sourceArtifact)
.build();
final Action codeBuild = CodeBuildAction.Builder
.create()
.actionName("BuildSource")
.project(codeBuildProject)
.input(sourceArtifact)
.outputs(new ArrayList<>(Arrays.asList(buildArtifact)))
.build();
final Action s3 = S3DeployAction.Builder
.create()
.bucket(deployBucket)
.actionName("DeploySourceToS3")
.input(buildArtifact)
.build();
codepipeline.actions
パッケージ内に、
実行するActionに応じたクラスがあるので、
必要なクラスを生成します。
(現在、CodePipelineでできることすべてではないようです…)
GitHubSourceActionクラス
GithubをSourceとするためのActionです。
わかりやすいですね。
リポジトリやブランチを設定します。
接続するためのOAuthTokenを指定することもでき、
SecretValueクラスを使用します。
SecretValueクラス
シークレットな情報を取得するためのクラスです。
System ManagerのパラメータストアのSecretから情報を取得したり、
Secret Managerから情報することができるようです。
今回、Secret Managerに予めGithubのTokenを設定しておき、
それを取得するように致しました。
final SecretsManagerSecretOptions secretOptions = SecretsManagerSecretOptions.builder()
.jsonField("github-token")
.build();
final SecretValue githubToken = SecretValue.secretsManager(
"naokiur-secret",
secretOptions
);
CodeBuildActionクラス
CodePipeline用のCodeBuildを構築するクラスです。
今回はリポジトリ内にbuildspec.ymlを作成しました。
S3DeployActionクラス
S3にデプロイするためのクラスです。
Artifactクラス
Actionクラスに出てきたのですが、
CodePipelineでもある、
各ActionのInput/Outputに指定するクラスです。
これで、受け渡しをするイメージを持っています。
以下の2つを作成し、
それぞれのActionのInput/Outputに指定しました。
final Artifact sourceArtifact = Artifact.artifact("Source");
final Artifact buildArtifact = Artifact.artifact("Build");
ハマったところ
- System ManagerのパラメータストアのSecretは、CodePipelineに設定することができない
- 自分が知らなかっただけなのですが、サポートされていない、とのことでした…。
- 最初、SecretManagerではなく、パラメータストアのSecretでやろうとしていたのですが、以下エラーメッセージが出てしまいました…
- SSM Secure reference is not supported in [AWS::CodePipeline::Pipeline/Properties/Stages,AWS::CodePipeline::Webhook/Properties/AuthenticationConfiguration/SecretToken]
- GithubのWebhook時にInvalid credentialsが出る
- SecretValueクラスを生成する際です。
- これも自分が知らなかっただけなのですが、最初、SecretValue生成時は以下でした。
final SecretValue githubToken = SecretValue.secretsManager("naokiur-secret");
- これだと接続ができず、Tokenはあっているはずなのに、なぜだろう…とハマってしまいました。
- 結局、キーの指定方法が誤っていて、取得できておらず、Tokenが空でアクセスしていたようです。
- CodePipeline実行時にエラーとなるまで気づかなかった…
- CloudFormationのファイルを生成できるコマンド、
cdk synthesize
をしたところ、当該項目が以下となっていました。SecretToken: "{{resolve:secretsmanager:naokiur-secret:SecretString:::}}"
- これで、パラメータ不足に気づきました…。