AWS CDK 使用 GitHub 集成创建 CodePipeline 示例
介绍
在本文中,我们将探索如何使用 AWS CDK 创建一个 AWS CodePipeline。该 CodePipeline 包括与 GitHub 的源代码集成、使用 CodeBuild 构建应用程序,以及通过 CloudFormation 部署资源。此外,我们还将配置一个自定义的 S3 存储桶用于存储流水线的构建工件。
前置条件
在开始之前,请确保您已完成以下准备工作:
- 已安装并配置 AWS CDK。
- 拥有一个包含应用程序代码和
buildspec.yml文件的 GitHub 仓库。 - 将 GitHub OAuth 令牌存储在 AWS Secrets Manager 中。
- 为 CodePipeline 和 CodeBuild 配置了适当的 IAM 角色。
关键组件
该CodePipeline包含三个阶段:
- 源阶段(Source Stage): 从 GitHub 仓库获取代码。
- 构建阶段(Build Stage): 使用 CodeBuild 构建应用程序。
- 部署阶段(Deploy Stage): 使用 CloudFormation 部署资源。
代码详解
以下是用于创建CodePipeline的 CDK 代码的详细说明。
1. 资源存储桶
创建一个 S3 存储桶用于存储CodePipeline运行中的asset文件。该存储桶配置了生命周期规则,在 7 天后删除文件。
const assetBucket = new s3.Bucket(this, '<construct id>', {
bucketName: '<bucketName>',
lifecycleRules: [
{
id: 'DeleteAfter7Days',
enabled: true,
expiration: cdk.Duration.days(7),
},
],
});
2. IAM 角色
CodePipeline 使用一个通过 ARN 指定的现有 IAM 角色。
const codepipelineRole = iam.Role.fromRoleArn(this, '<construct id>', '<CODE_PIPELINE_ROLE_ARN>', {
mutable: false,
});
3. 构建项目
配置一个 CodeBuild 项目用于构建应用程序。该项目使用 Amazon Linux 2 作为构建环境。
const buildProject = new codebuild.PipelineProject(this, '<construct id>', {
projectName: '<projectName>',
role: codepipelineRole,
queuedTimeout: cdk.Duration.hours(0.5),
timeout: cdk.Duration.hours(0.5),
buildSpec: codebuild.BuildSpec.fromSourceFilename('buildspec.yml'),
environment: {
buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_5,
computeType: codebuild.ComputeType.SMALL,
environmentVariables: {
XX: {
type: codebuild.BuildEnvironmentVariableType.PLAINTEXT,
value: '<value>',
},
},
},
});
这里指定了 buildspec.yml 文件,该文件包含构建命令和 CodeBuild 项目的配置,确保构建过程被定义且可以与应用程序代码一起进行版本控制。
4. Pipeline 定义
配置CodePipeline的三个阶段:源代码、构建和部署,并使用前面定义的 S3 存储桶和 IAM 角色。
const pipeline = new codepipeline.Pipeline(this, '<construct id>', {
pipelineName: '<pipelineName>',
artifactBucket: assetBucket,
role: codepipelineRole,
pipelineType: codepipeline.PipelineType.V1,
});
5. 源代码阶段
源代码阶段通过 Webhook 从 GitHub 仓库拉取代码。GitHub OAuth 令牌通过 AWS Secrets Manager 安全获取。
const sourceAction = new codepipeline_actions.GitHubSourceAction({
actionName: 'GitHubSource',
owner: '<GitHub account user>',
repo: '<GitHub repository>',
branch: '<branch>',
oauthToken: cdk.SecretValue.secretsManager('github-token', {
jsonField: 'oauthToken',
}),
output: sourceOutput,
trigger: codepipeline_actions.GitHubTrigger.WEBHOOK,
runOrder: 1,
});
说明:
cdk.SecretValue.secretsManager: 此方法安全地获取存储在 AWS Secrets Manager 中的密钥。'github-token': Secrets Manager 中密钥的名称。此密钥必须事先存在,并包含必要的 OAuth 令牌。jsonField: 'oauthToken': 在此示例中,OAuth 令牌保存在oauthToken字段里。- 此方法确保敏感凭据(如 OAuth 令牌)不会硬编码在应用程序中,从而提高安全性。
6. 构建阶段
构建阶段执行之前定义的 CodeBuild 项目。
const buildAction = new codepipeline_actions.CodeBuildAction({
actionName: 'Build',
project: buildProject,
input: sourceOutput,
outputs: [buildOutput],
role: codepipelineRole,
runOrder: 2,
});
7. 部署阶段
部署阶段使用 CloudFormation 动作创建或更新堆栈。
const deployAction = new codepipeline_actions.CloudFormationCreateUpdateStackAction({
actionName: 'CloudFormation-CreateUpdateStack',
stackName: '<stackName>',
adminPermissions: true,
templatePath: buildOutput.atPath('cloudformation-template.yaml'),
deploymentRole: codepipelineRole,
replaceOnFailure: true,
role: codepipelineRole,
runOrder: 3,
});
这里指定的 cloudformation-template.yaml 文件在构建阶段中通过执行cdk synth命令来获取的。
8. 添加阶段到CodePipeline
最后,将各阶段添加到CodePipeline中。
pipeline.addStage({
stageName: 'Source',
actions: [sourceAction],
});
pipeline.addStage({
stageName: 'Build',
actions: [buildAction],
});
pipeline.addStage({
stageName: 'Deploy',
actions: [deployAction],
});
完整代码
import * as cdk from 'aws-cdk-lib';
import * as codebuild from 'aws-cdk-lib/aws-codebuild';
import * as codepipeline from 'aws-cdk-lib/aws-codepipeline';
import * as codepipeline_actions from 'aws-cdk-lib/aws-codepipeline-actions';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as s3 from 'aws-cdk-lib/aws-s3';
import type { Construct } from 'constructs';
export class CodePipelineStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
/** asset bucket */
const assetBucket = new s3.Bucket(this, `<construct id>`, {
bucketName: `<bucketName>`,
lifecycleRules: [
{
id: 'DeleteAfter7Days',
enabled: true,
expiration: cdk.Duration.days(7),
},
],
});
const codepipelineRole = iam.Role.fromRoleArn(this, `<construct id>`, '<CODE_PIPELINE_ROLE_ARN>', {
mutable: false,
});
const buildProject = new codebuild.PipelineProject(this, `<construct id>`, {
projectName: `<projectName>`,
role: codepipelineRole,
queuedTimeout: cdk.Duration.hours(0.5),
timeout: cdk.Duration.hours(0.5),
buildSpec: codebuild.BuildSpec.fromSourceFilename('buildspec.yml'),
environment: {
buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_5,
computeType: codebuild.ComputeType.SMALL,
environmentVariables: {
XX: {
type: codebuild.BuildEnvironmentVariableType.PLAINTEXT,
value: '<value>',
},
},
},
});
const pipeline = new codepipeline.Pipeline(this, `<construct id>`, {
pipelineName: `<pipelineName>`,
artifactBucket: assetBucket,
role: codepipelineRole,
pipelineType: codepipeline.PipelineType.V1,
});
const sourceOutput = new codepipeline.Artifact();
const buildOutput = new codepipeline.Artifact();
const sourceAction = new codepipeline_actions.GitHubSourceAction({
actionName: 'GitHubSource',
owner: '<GitHub account user>',
repo: '<GitHub repository>',
branch: '<branch>',
oauthToken: cdk.SecretValue.secretsManager('github-token', {
jsonField: 'oauthToken',
}),
output: sourceOutput,
trigger: codepipeline_actions.GitHubTrigger.WEBHOOK,
runOrder: 1,
});
const buildAction = new codepipeline_actions.CodeBuildAction({
actionName: 'Build',
project: buildProject,
input: sourceOutput,
outputs: [buildOutput],
role: codepipelineRole,
runOrder: 2,
});
const deployAction = new codepipeline_actions.CloudFormationCreateUpdateStackAction({
actionName: 'CloudFormation-CreateUpdateStack',
stackName: `<stackName>`,
adminPermissions: true,
templatePath: buildOutput.atPath(`cloudformation-template.yaml`),
deploymentRole: codepipelineRole,
replaceOnFailure: true,
role: codepipelineRole,
runOrder: 3,
});
pipeline.addStage({
stageName: 'Source',
actions: [sourceAction],
});
pipeline.addStage({
stageName: 'Build',
actions: [buildAction],
});
pipeline.addStage({
stageName: 'Deploy',
actions: [deployAction],
});
}
}
结论
此示例展示了如何使用 AWS CDK 构建一个强大的 CI/CD CodePipeline。通过与 GitHub 集成,可以在每次提交时自动触发CodePipeline,而通过 CloudFormation 部署可以确保您的基础设施始终保持最新。
通过此CodePipeline,您可以简化部署流程,更专注于为应用程序开发新功能。