使用 AWS CDK(TypeScript)构建 CodePipeline
发布于
2025年4月27日
更新于
2025年4月27日
25
分钟阅读
AWS
随着微服务和容器化时代的到来,利用 AWS 服务构建一条端到端的持续集成/持续部署(CI/CD)流程已经成为常见需求。本文将以 AWS CDK(TypeScript) 为例,带你一步步搭建一条从 CodeCommit 到 CodeBuild,再到 S3 发布制品的 CodePipeline。
1. 项目结构概览
在开始之前,假设你已经安装好 AWS CDK 并初始化了一个 TypeScript 项目。目录结构示例如下:
my-cdk-project/
├── bin/
│ └── my-cdk-project.ts // CDK 应用入口
├── lib/
│ └── code-pipeline-stack.ts // 我们接下来要编写的 Stack
├── build-spec.yaml // CodeBuild 构建规范
├── package.json
└── tsconfig.json
2. 核心 CDK 代码
import * as cdk from 'aws-cdk-lib';
import { Duration } from 'aws-cdk-lib';
import * as codebuild from 'aws-cdk-lib/aws-codebuild';
import * as codecommit from 'aws-cdk-lib/aws-codecommit';
import * as codepipeline from 'aws-cdk-lib/aws-codepipeline';
import * as 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);
// 1. 引用已有 S3 Bucket 作为制品存储
const artifactBucket = s3.Bucket.fromBucketArn(this, 'ArtifactBucket', 'arn:aws:s3:::your-artifact-bucket');
// 2. 引用已有 IAM 角色,用于 Pipeline 执行权限
const pipelineRole = iam.Role.fromRoleArn(this, 'PipelineRole', 'arn:aws:iam::123456789012:role/CodePipelineRole', {
mutable: false,
});
const eventBridgeRole = iam.Role.fromRoleArn(
this,
'EventBridgeRole',
'arn:aws:iam::123456789012:role/EventBridgeRole',
{ mutable: false },
);
// 3. 创建 CodeCommit 仓库
const repository = new codecommit.Repository(this, 'MyRepo', {
repositoryName: 'my-app-repo',
});
// 4. 定义 CodeBuild 项目
const buildProject = new codebuild.PipelineProject(this, 'BuildProject', {
projectName: 'my-app-build',
role: pipelineRole,
queuedTimeout: Duration.hours(1),
timeout: Duration.hours(1),
buildSpec: codebuild.BuildSpec.fromSourceFilename('build-spec.yaml'),
environment: {
buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_5,
computeType: codebuild.ComputeType.SMALL,
privileged: true,
environmentVariables: {
ENV: {
type: codebuild.BuildEnvironmentVariableType.PLAINTEXT,
value: 'prod',
},
},
},
});
// 5. 定义 Pipeline Artifact
const sourceArtifact = new codepipeline.Artifact('SourceArtifact');
const buildArtifact = new codepipeline.Artifact('BuildArtifact');
// 6. 配置 Source 阶段:监听 CodeCommit 的 prod 分支
const sourceAction = new actions.CodeCommitSourceAction({
actionName: 'Fetch_Source',
repository,
branch: 'prod',
output: sourceArtifact,
role: pipelineRole,
eventRole: eventBridgeRole,
trigger: actions.CodeCommitTrigger.EVENTS,
runOrder: 1,
});
// 7. 配置 Build 阶段:调用 CodeBuild
const buildAction = new actions.CodeBuildAction({
actionName: 'Run_Build',
project: buildProject,
input: sourceArtifact,
outputs: [buildArtifact],
role: pipelineRole,
runOrder: 2,
});
// 8. 创建 Pipeline 并添加各个 Stage
const pipeline = new codepipeline.Pipeline(this, 'CodePipeline', {
pipelineName: 'MyAppPipeline',
artifactBucket,
role: pipelineRole,
});
pipeline.addStage({ stageName: 'Source', actions: [sourceAction] });
pipeline.addStage({ stageName: 'Build', actions: [buildAction] });
}
}
3. 示例 build-spec.yaml
version: 0.2
phases:
install:
runtime-versions:
nodejs: 22
pre_build:
commands:
- npm run lint
- npm run test
build:
commands:
- npm ci
- npm run build
- npx cdk deploy <StackName> --require-approval never
4. 跨账户 CodePipeline
要在 CDK 中使用另一个 AWS 账号(假设为 Account A)里的 CodeCommit 仓库,并在本账号(Account B)中通过 CodePipeline 拉取代码,你需要完成以下几个关键步骤:
4.1. 在 Account A(CodeCommit 所在账号)配置跨账号访问角色
打开 Account A 的 IAM 控制台,创建一个新角色(如 cross-account-access-role),信任策略指定允许 Account B 的根账号或 Pipeline 服务角色来 sts:AssumeRole:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::ACCOUNT_B_ID:root" },
"Action": "sts:AssumeRole"
}
]
}
4.2. 给这个角色附加对目标仓库的只读权限:
- AWS 托管策略
AWSCodeCommitReadOnly; - 如果使用 KMS 加密制品,还要给角色添加
kms:Decrypt、kms:GenerateDataKey*等权限,并在 CMK 的 Key Policy 里允许该角色使用
4.3. 在 Account B(Pipeline 所在账号)引用跨账号资源
在你的 CDK Stack 中,先通过 ARN 导入外部仓库和跨账号角色:
// 从 Account A 导入 CodeCommit 仓库
const externalRepo = codecommit.Repository.fromRepositoryArn(
this,
'ExternalRepo',
'arn:aws:codecommit:ap-northeast-1:ACCOUNT_A_ID:MySharedDemoRepo',
);
// 从 Account A 导入刚才创建的跨账号访问角色
const crossAccountRole = iam.Role.fromRoleArn(
this,
'CrossAccountRole',
'arn:aws:iam::ACCOUNT_A_ID:role/cross-account-access-role',
);
4.4. 在 CDK 中配置 Source 动作使用跨账号角色
将 CodeCommitSourceAction 的 role 属性指向上述跨账号角色。
const sourceArtifact = new codepipeline.Artifact('SourceArtifact');
const crossAccountSource = new codepipeline_actions.CodeCommitSourceAction({
actionName: 'CrossAccount_Source',
repository: externalRepo,
branch: 'main',
output: sourceArtifact,
role: crossAccountRole,
trigger: codepipeline_actions.CodeCommitTrigger.EVENTS,
});
pipeline.addStage({
stageName: 'Source',
actions: [crossAccountSource],
});
这样,CodePipeline 会以你在 Account A 创建的角色身份,从该仓库拉取代码。
5. 使用Github作为Repository
如果代码是存放在Github上的话,CodePipeline还可以从Github上拉取代码。
5.1. 在 GitHub 侧创建 Personal Access Token
- 登录 GitHub → 右上角头像 → Settings → Developer settings → Personal access tokens → Fine-grained personal access tokens → Generate new token
- 选择至少包含
repo(读取私有仓库)或public_repo(只读公开仓库)的权限,生成后复制好这串 Token。
5.2. 将 Token 存到 AWS Secrets Manager
aws secretsmanager create-secret \
--name my-github-token \
--description "GitHub OAuth token for CodePipeline" \
--secret-string "<YOUR_TOKEN_HERE>"
这样,你就可以在 CDK 里通过 Secret 名称来安全地引用它。
5.3. 在 CDK 里引用这个 Secret
import * as cdk from 'aws-cdk-lib';
import * as codebuild from 'aws-cdk-lib/aws-codebuild';
import * as codecommit from 'aws-cdk-lib/aws-codecommit';
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);
// ... other settings
const oauthToken = cdk.SecretValue.secretsManager('my-github-token');
// 配置 GitHubSourceAction
const githubSource = new cpactions.GitHubSourceAction({
actionName: 'Checkout_From_GitHub',
owner: '你的 GitHub 用户名或组织名',
repo: '你的仓库名',
branch: 'main', // 或你想跟踪的分支
oauthToken: oauthToken, // 关键:把 SecretValue 传给这里
output: sourceOutput,
trigger: cpactions.GitHubTrigger.WEBHOOK, // 通过 Webhook 实时触发
});
// 将 Source 阶段加入 Pipeline
pipeline.addStage({
stageName: 'Source',
actions: [githubSource],
});
}
}
6. 小结
本文示范了如何使用 AWS CDK(TypeScript)快速搭建:
- CodeCommit → CodeBuild 的基础流水线
- 跨账号拉取 CodeCommit 仓库
- 从 GitHub 拉取代码并触发构建
你可以在此基础上,灵活添加测试、部署到 Elastic Beanstalk、ECS、Lambda 等更多 Stage,构建严谨而高效的 CI/CD 流程。