Projen Pipelines に入門してみた
はじめに
こんばんは。Penetrator プロダクト開発部で主にインフラを担当している遠藤です。
みなさん元気に CI/CD やっていますか??
先日の AWS Summit Japan 2025 のセッションで Projen Pipelines なるものが紹介されていたので、今回こちらに入門してみました。
パッと調べた限りあまり情報がなさそうでしたので (特に日本語のものは)、興味がある方はぜひ参考にしてみてください!
Projen Pipelines とは?
Projen Pipelinesは、AWS CDK の開発者によって作られたプロジェクト設定ツール「Projen」を利用し、CI/CD パイプラインの自動生成を実現するオープンソースプロジェクトです。アプリケーション向けの継続的デリバリー (CD) パイプラインを高レベルで抽象化して定義できます。
- 特徴
- CI/CD パイプラインのコード生成を自動化
- GitHub Actions や GitLab CI など複数の CI/CD プラットフォームをサポート
- パイプライン設定における実績のあるデフォルト設定を標準搭載
- パイプライン設定を書き換えずにプラットフォーム間の切り替えが容易
- 複雑なデプロイシナリオを少ないコードで扱える
- 導入メリット
- パイプライン設定の記述や保守における反復作業を削減
- 実績のあるデフォルト設定によりプロジェクト間での一貫性を確保
- パイプライン定義の抽象化により、GitHub から GitLab などプラットフォーム移行を円滑化
これにより、開発チームは CI/CD パイプラインの構築・管理を効率的かつ標準化された形で実施できるようになります。
※ 公式 GitHub Repository
CI/CD パイプラインの作成・実行手順
今回は AWS CDK 用の CI/CD パイプラインを作成し、実際に Deploy してみます。
※ 手順内の Construct ID 等の命名は適当です。最小権限の原則も気にせず進めています。あしからず。
-
AWS CDK プロジェクトの作成
まず、今回の検証を実施する AWS CDK プロジェクトを作成します。Terminalmkdir projen-pipelines && \ cd projen-pipelines && \ npx projen new awscdk-app-ts
上記のコマンドを実行すると、下記のようなディレクトリやファイルが生成されます。
projen-pipelines/ ├── .github/ │ ├── workflows/ │ │ ├── build.yml │ │ ├── pull-request-lint.yml │ │ └── upgrade.yml │ └── pull_request_template.md ├── .projen/ │ ├── deps.json │ ├── files.json │ └── tasks.json ├── node_modules/ ├── src/ │ └── main.ts ├── test/ │ └── main.test.ts ├── .eslintrc.json ├── .gitattributes ├── .gitignore ├── .mergify.yml ├── .npmignore ├── .projenrc.ts ├── cdk.json ├── LICENSE ├── package.json ├── README.md ├── tsconfig.dev.json ├── tsconfig.json └── yarn.lock
cdk init
コマンドで AWS CDK プロジェクトを初期化する場合と少し構造が異なりますが、src/main.ts
が CDK のエントリポイントです。src/main.tsimport { App, Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; export class MyStack extends Stack { constructor(scope: Construct, id: string, props: StackProps = {}) { super(scope, id, props); // define resources here... } } // for development, use account/region from cdk cli const devEnv = { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION, }; const app = new App(); new MyStack(app, 'projen-pipelines-dev', { env: devEnv }); // new MyStack(app, 'projen-pipelines-prod', { env: prodEnv }); app.synth();
-
projen-pipelines のインストール
続いて、projen-pipelines を依存関係に追加します。.projenrc.tsimport { awscdk } from 'projen'; const project = new awscdk.AwsCdkTypeScriptApp({ cdkVersion: '2.1.0', defaultReleaseBranch: 'main', name: 'projen-pipelines', projenrcTs: true, devDeps: ['projen-pipelines'], // 追加 }); project.synth();
設定の変更を適用します。
Terminalnpx projen
上記のコマンドを実行すると、ライブラリのインストールと同時に package.json や tasks.json 等の設定ファイルにも変更が適用されます。
-
IAM Role の作成
続いて、CI/CD パイプラインで使用する IAM Role を定義します。src/main.tsimport { App, CfnOutput, RemovalPolicies, Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as iam from 'aws-cdk-lib/aws-iam'; export class MyStack extends Stack { constructor(scope: Construct, id: string, props: StackProps = {}) { super(scope, id, props); const githubRepository = '<Org>/<Repository>'; // 自身の環境に合わせて修正 const githubProvider = new iam.OpenIdConnectProvider(this, 'GitHubProvider', { url: 'https://token.actions.githubusercontent.com', clientIds: ['sts.amazonaws.com'], thumbprints: ['6938fd4d98bab03faadb97b34396831e3780aea1'], }); const githubActionsPolicy = new iam.ManagedPolicy(this, 'GitHubActionsPolicy', { statements: [ new iam.PolicyStatement({ actions: ['*'], resources: ['*'], }), ], }); const githubActionsRole = new iam.Role(this, 'GitHubActionsRole', { assumedBy: new iam.FederatedPrincipal( githubProvider.openIdConnectProviderArn, { "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" }, "StringLike": { "token.actions.githubusercontent.com:sub": `repo:${githubRepository}:*` }, }, "sts:AssumeRoleWithWebIdentity", ), managedPolicies: [githubActionsPolicy], }); new CfnOutput(this, 'GitHubActionsRoleArn', { value: githubActionsRole.roleArn, exportName: 'GitHubActionsRoleArn', }); } } // for development, use account/region from cdk cli const devEnv = { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION, }; const app = new App(); const myStack = new MyStack(app, 'MyStack', { env: devEnv }); RemovalPolicies.of(myStack).destroy() // new MyStack(app, 'projen-pipelines-prod', { env: prodEnv }); app.synth();
こちらは手動で作成します。
※ profile の設定をしている場合は適宜オプションを使用して実行してください。Terminalcdk deploy MyStack
-
CI/CD パイプラインの作成
いよいよ、CI/CD パイプラインを作成していきます。
※ 今回は GitHub Actions を利用する想定で定義していきます。.projenrc.tsimport { awscdk } from 'projen'; import { GithubCDKPipeline } from 'projen-pipelines'; const project = new awscdk.AwsCdkTypeScriptApp({ cdkVersion: '2.1.0', defaultReleaseBranch: 'main', name: 'projen-pipelines', projenrcTs: true, devDeps: ['projen-pipelines'], }); new GithubCDKPipeline(project, { iamRoleArns: { default: 'arn:aws:iam::<AccountId>:role/MyStack-GitHubActionsRolexxxxxxxxxxxxxxxx', // 手順 3 で作成した Role の ARN }, stages: [ { name: 'dev', env: { account: '<AccountId>', region: 'ap-northeast-1' }, // dev 環境として Deploy したい AWS Account ID/Region }, ], }); project.synth();
定義ができたら、再度変更を適用します。
Terminalnpx projen
上記のコマンドを実行すると、GitHub Actions Workflow ファイルを含む各種ファイルが生成・更新されます。
.github/workflows/deploy.yml# ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen". name: deploy on: push: branches: - main workflow_dispatch: {} jobs: synth: name: Synth CDK application needs: [] runs-on: ubuntu-latest permissions: contents: read env: CI: "true" steps: - uses: actions/setup-node@v4 with: node-version: "20" - name: Checkout uses: actions/checkout@v4 - run: npx projen install:ci - run: npx projen build - name: Upload Artifact uses: actions/upload-artifact@v4.3.6 with: name: cloud-assembly path: cdk.out/ assetUpload: name: Publish assets to AWS needs: synth runs-on: ubuntu-latest permissions: id-token: write contents: read env: CI: "true" steps: - uses: actions/setup-node@v4 with: node-version: "20" - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - run: git config --global user.name "github-actions" && git config --global user.email "github-actions@github.com" - name: Download Artifact uses: actions/download-artifact@v4 with: name: cloud-assembly path: cdk.out/ - run: npx projen install:ci - name: AWS Credentials uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::<AccountId>:role/MyStack-GitHubActionsRolexxxxxxxxxxxxxxxx role-session-name: GitHubAction aws-region: us-east-1 - run: npx projen publish:assets deploy-dev: name: Deploy stage dev to AWS needs: assetUpload runs-on: ubuntu-latest permissions: contents: read id-token: write concurrency: group: deploy-dev cancel-in-progress: false env: CI: "true" steps: - uses: actions/setup-node@v4 with: node-version: "20" - name: Checkout uses: actions/checkout@v4 - name: Download Artifact uses: actions/download-artifact@v4 with: name: cloud-assembly path: cdk.out/ - run: npx projen install:ci - name: AWS Credentials uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::<AccountId>:role/MyStack-GitHubActionsRolexxxxxxxxxxxxxxxx role-session-name: GitHubAction aws-region: ap-northeast-1 - run: npx projen deploy:dev - name: Upload Artifact uses: actions/upload-artifact@v4.3.6 with: name: cdk-outputs-dev path: cdk-outputs-dev.json
-
サンプルリソースの作成
ここでは、CI/CD パイプラインを通して Deploy するためのサンプルリソースを作成します。
今回は簡単な S3 Bucket を定義します。src/stack.tsimport { Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as s3 from 'aws-cdk-lib/aws-s3'; export class BackendStack extends Stack { constructor(scope: Construct, id: string, props: StackProps = {}) { super(scope, id, props); new s3.Bucket(this, 'MyBucket'); } }
-
Deploy 設定の適用と Deploy 実行
次に、手順 5 で作成したサンプル Stack を CI/CD パイプラインに載せて Deploy するよう設定します。src/main.tsimport { App, CfnOutput, RemovalPolicies, Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as iam from 'aws-cdk-lib/aws-iam'; import { PipelineApp } from './app' import { BackendStack } from './stack' export class MyStack extends Stack { constructor(scope: Construct, id: string, props: StackProps = {}) { super(scope, id, props); ... 省略 ... // for development, use account/region from cdk cli const devEnv = { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION, }; // Deploy 設定適用 const app = new PipelineApp({ provideDevStack: (scope, id, props) => { return new BackendStack(scope, id, props); }, }); new MyStack(app, 'MyStack', { env: devEnv }); // app 全体に RemovalPolicy を設定 RemovalPolicies.of(app).destroy() app.synth();
最後に、これまでのコード変更を Commit し、GitHub に Push します。
※ Commit コマンドは記載していないので、各自実行してください。Terminalgit remote add origin https://github.com/<Org>/<Repository>.git && \ git push origin main
以上で作業は完了です。
今回は main branch への Push をトリガーに workflow が起動する定義になっているため、GitHub の Repositoy 画面で、
deploy
の Workflow が正常に実行され、AWS 環境に S3 Bucket が Deploy されている事を確認できれば成功です!
まとめ
本記事では、Projen Pipelines を利用した CI/CD パイプラインの構築・実行方法 を紹介しました。
かなり少ないコードで workflow を定義できて、使いこなせればかなり便利かもしれないと思います。
CI/CD パイプラインの構築方法に迷っている方、Projen Pipelines に興味がある方の参考になれば嬉しいです。
もっと良い方法があれば、ぜひコメント等で教えてください!
※ 今回の検証コード
最後に
株式会社 Penetrator はシリーズ A ラウンドにおいて総額 5.5 億円の資金調達を実施し、不動産テック業界における更なる成長を目指して、採用活動を一層強化しています。エンジニア、デザイナー、カスタマーサクセス、BizDev、営業、マーケティングなど、事業拡大を支える多様なポジションで共に挑戦していただける方を待っています!
▽ 会社のカルチャーを知りたい方はこちら
▽ 募集職種を知りたい方はこちら
Discussion