Skip to main content

Using Klotho with GitHub Actions

Overview

This tutorial will show how to integrate Klotho with GitHub actions to produce a rapid and iterative CI/CD process.

Why?

Continuous integration and delivery are DevOps practices that aim to speed the software delivery without compromising on quality. Through automating as many steps in the release process as possible, CI/CD shortens the time it takes to release software to users.

Getting started with GitHub actions

Within the GitHub repository, there is a tab labeled Actions. This tab allows you create development workflows local to your repository.

Setting Your Klotho Token

As of the v0.6.3 release of Klotho-Pro. You are required to pass authentication and authorization in order to compile your application. Since the klotho --login command is not able to be used within CI/CD environments, you must set the KLOTHO_ID_TOKEN environment variable.

When you log in on your Klotho CLI, you can retrieve the IdToken field from your ~/.klotho/credentials.json file.

Set the Github Actions environment secret for KLOTHO_CREDS_ID_TOKEN (or the equivalent of the environment name specified in the Klotho compile step below). This will allow klotho to authorize your user based on the ID token provided.

The ID token is currently valid for a year and will need to be replaced within the Github Actions secrets accordingly.

Creating a Github Action

We will define a GitHub action to compile our TypeScript code and run Klotho against that compiled code each time there is a push to the branch main. Once Klotho-compiled, the action will deploy the contents in ./compiled to AWS.

This GitHub Action can be further expanded upon to add testing against local code or the deployed application.

To reference how to properly configure your pulumi deploy step, refer to the Pulumi documentation.

klotho_deploy.yaml
name: Klotho
on:
push:
branches: [main]

env:
# Set this to your preferred AWS region, like us-east-1
AWS_REGION: <region>
# Set your application name. Changing this will orphan the previous
# deployment and proceed with a new one.
# Change with caution, if you have already deployed.
APP_NAME: <app name>
# Set this to the email you used to register with Klotho
KLOTHO_EMAIL: <email>

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Input checks
run: |
function err() { echo "::error title=Missing workflow configuration ::$@" ; touch FAIL ; }
[[ "$AWS_REGION" != '<region>' ]] || err 'Please set your region in the workflows tab.'
[[ "$APP_NAME" != '<app name>' ]] || err 'Please set your app name in the workflows tab.'
[[ "$KLOTHO_EMAIL" != '<email>' ]] || err 'Please set your email in the workflows tab.'
[[ -n "${{ secrets.AWS_ACCESS_KEY_ID }}" ]] || err 'Please add an AWS_ACCESS_KEY_ID secret to your repository.'
[[ -n "${{ secrets.AWS_SECRET_ACCESS_KEY }}" ]] || err 'Please add an AWS_SECRET_ACCESS_KEY secret to your repository.'
[[ -n "${{ secrets.PULUMI_ACCESS_TOKEN }}" ]] || err 'Please add an PULUMI_ACCESS_TOKEN secret to your repository.'
if [[ -f FAIL ]] ; then exit 1 ; fi
- uses: actions/checkout@v2
- name: Use Node.js 16.x
uses: actions/setup-node@v2
with:
node-version: 16.x
cache: "npm"
cache-dependency-path: package-lock.json
- name: Build
run: |
npm ci
npx tsc
- name: Install Klotho
run: |
curl -fsSL http://srv.klo.dev/update/latest/linux/amd64 -o "$RUNNER_TEMP/klotho"
chmod +x "$RUNNER_TEMP/klotho"
"$RUNNER_TEMP/klotho" --local
- name: Klotho compile
run: |
"$RUNNER_TEMP/klotho" . --app "$APP_NAME" --provider aws
env:
KLOTHO_ID_TOKEN: ${{ secrets.KLOTHO_CREDS_ID_TOKEN }}
- name: Install compiled dependencies
run: npm install
working-directory: ./compiled
- name: Pulumi deploy
run: |
pulumi -C compiled -s "$APP_NAME" stack select --create
pulumi -C compiled -s "$APP_NAME" config set aws:region "${AWS_REGION}"
pulumi -C compiled -s "$APP_NAME" refresh --yes
pulumi -C compiled -s "$APP_NAME" up --yes

pulumi_out="$(pulumi -C compiled -s "$APP_NAME" stack output --json)"
for key in $(echo "$pulumi_out" | jq -r '. | keys[]') ; do
echo "$pulumi_out" | jq -r '.[$key]' --arg key "$key" | sed "s/^/::notice title=$key::/"
done
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
PULUMI_CONFIG_PASSPHRASE: ""