CI/CD Pipeline Setup

View .md

Ship on git push. One command — kanject aws pipeline up — provisions an AWS-native CodePipeline that builds, tests, and deploys every stage of your service in order, with a manual approval gate before production.

There are two ways to run Kanject deploys in CI. Pick one; both end in the same kanject aws deploy.

A
AWS-native pipeline
CodePipeline + CodeBuild + CodeStar Connections, scaffolded and provisioned for you by kanject aws pipeline up. This page.
B
Bring your own runner
Already on GitHub Actions, GitLab, or Buildkite? Skip the scaffolding and call kanject aws deploy from your runner.

Before you start

  • A Kanject service with kanject-cli/manifest.json and your stages declared in manifest.aws.stages — the pipeline emits one deploy stage per entry, in order.
  • A CodeStar Connection to GitHub, created and authorized in the AWS console. The one-time OAuth handshake can’t be automated; once authorized, the ARN is stable.
  • A Secrets Manager secret holding a GitHub PAT (used for private repo cloning inside CodeBuild).
  • An S3 artifact bucket and your CodeArtifact domain / owner / repo coordinates.
  • AWS credentials for the target account (--profile defaults to default).

One command: pipeline up

pipeline up is idempotent and manifest-driven: it persists the pipeline config, scaffolds the deploy/ files if they’re missing, and creates or updates the <service>-pipeline CloudFormation stack — all in one run.

bash
# First run: supply the org-constant config once# (persisted to kanject-cli/pipeline.json — later runs reuse it)kanject aws pipeline up \  --connection arn:aws:codeconnections:eu-west-1:111122223333:connection/abcd \  --repo-owner kanject --repo-name kanject-analytics \  --artifact-bucket kanject-pipeline-artifacts \  --codeartifact-domain kanject --codeartifact-owner 111122223333 --codeartifact-repo internal \  --github-pat-secret arn:aws:secretsmanager:eu-west-1:111122223333:secret:kanject/github-pat

Every flag is saved to kanject-cli/pipeline.json, so you pass it once. Both written files are reviewable JSON — commit them and the diff shows exactly what changed. Re-running with no flags is a clean no-op.

bash
# Add a second deploy region to prod — config is already persistedkanject aws pipeline up --stage prod --add-region us-east-1# Reconcile after hand-editing deploy/pipeline.template — no flags neededkanject aws pipeline up

What gets provisioned

  • A CloudFormation stack named <service>-pipeline containing the whole CI surface.
  • A CodePipeline triggered on push to your branch: Source → Build → Deploy<Stage1> → … → Deploy<FinalStage>.
  • A shared Build CodeBuild project (kanject sync + dotnet build + dotnet test) and a shared Deploy project (kanject aws deploy --env $STAGE) — the stage is injected per action, so there’s no per-stage buildspec.
  • A manual approval gate before the final stage (skipped for single-stage services).
  • IAM roles for CodeBuild plus the webhook that starts the pipeline on push.

The Build project runs kanject sync before dotnet build, so cross-repo dependencies resolve on the fresh runner — without it, restore can’t find a sibling repo’s project and the build fails. See Dependency Sources & Resolution.

Prefer explicit steps?

The original two-step flow still works: init writes the deploy/ files, bootstrap deploys the stack. pipeline up simply folds both into one idempotent command.

bash
# 1. Scaffold deploy/ (pipeline.template + the two buildspecs)kanject aws pipeline init# 2. Deploy the pipeline stack (same flags as pipeline up)kanject aws pipeline bootstrap \  --connection <CODESTAR_CONNECTION_ARN> \  --repo-owner kanject --repo-name kanject-analytics \  --artifact-bucket kanject-pipeline-artifacts \  --codeartifact-domain kanject --codeartifact-owner 111122223333 --codeartifact-repo internal \  --github-pat-secret <SECRETS_MANAGER_ARN>

Bring your own runner

On GitHub Actions, GitLab, Buildkite, or Jenkins the recipe is the same everywhere: install the .NET SDK, install Amazon.Lambda.Tools and Kanject.Cli as global tools, authenticate to AWS, then run kanject aws deploy --env <stage> --non-interactive. This disables prompts without silently granting approval.

yaml
name: Deployon:  push:    branches: [main]jobs:  deploy:    runs-on: ubuntu-latest    permissions:      id-token: write   # AWS OIDC      contents: read    steps:      - uses: actions/checkout@v4      - uses: actions/setup-dotnet@v4        with: { dotnet-version: '10.0.x' }      - run: dotnet tool install -g Amazon.Lambda.Tools      - run: dotnet tool install -g Kanject.Cli      - uses: aws-actions/configure-aws-credentials@v4        with:          role-to-assume: arn:aws:iam::123456789012:role/github-deploy          aws-region: eu-west-1      - run: kanject aws deploy --env stage --non-interactive

Gate production with your provider’s native approval mechanism — e.g. a GitHub Environment with required reviewers on the prod job.

Multiple microservices

Pipelines are one per service, not one mega-pipeline per repo. Each service directory owns its manifest, its stack, and its <service>-pipeline — so a broken deploy in one service never blocks the others, and rollback stays per-stack.

bash
contoso-wallet/                       # one git repo├── wallet-api/│   ├── kanject-cli/manifest.json     # service "wallet-api"│   └── deploy/pipeline.template      # stack: wallet-api-pipeline└── wallet-tasks/    ├── kanject-cli/manifest.json     # service "wallet-tasks"    └── deploy/pipeline.template      # stack: wallet-tasks-pipeline

Run kanject aws pipeline up once inside each service directory. A service with several Lambdas doesn’t need several pipelines — all of its entry projects deploy together into one stack. Draw the boundary where release cadence and ownership split.

Was this page helpful?