Terraform is a great tool for automating infrastructure configuration. As your configuration and environment grow larger, and additional team members come in to help manage infrastructure, a better model needs to be in place to help run your Terraform code in a collaborative manner.
Many solutions exist in both the open source (Atlantis, tf-controller) and commercial (Terraform Cloud, Env0, Spacelift) space. A solution that came to my attention recently is Digger.
Throughout this tutorial, we'll explore Digger, an open-source tool designed to run Terraform processes within your CI pipeline, leveraging your existing CI infrastructure.
What is Digger?
Digger is an open-source tool that allows you to run all Terraform processes using the same CI infrastructure you already use. It reuses your CI infrastructure with jobs, logs, compute, orchestration, etc., so you can benefit from your existing software deployment methodology.
Prerequisites
Before getting started with this tutorial, you will need to have a Civo account. Then, to launch a Civo Kubernetes cluster using Digger.dev, you can follow these steps:
- In your Civo account, obtain an API token by going to Settings -> Profile and clicking the Security tab.
- Create a new GitHub Repository.
- In the new GitHub repository, go to Settings -> Secrets and Variables -> Actions. Create a
CIVO_TOKEN
secret with the API key above. - In the New Repository, ensure you enable GitHub Actions, as well as grant the pipeline read and write permissions.
Configuring the Civo Provider in Terraform
In the repository, create the following files (links provided with example code):
Step 1: Specify required provider as maintained by Civo
terraform {
required_providers {
civo = {
source = "civo/civo"
}
}
}
Step 2: Configure the Civo Provider
CIVO_TOKEN
secret is set in your GitHub Actions pipeline to authenticate Terraform with Civo.
provider "civo" {
region = "LON1"
}
Step 3: Query xsmall instance size
data "civo_size" "xsmall" {
filter {
key = "type"
values = ["kubernetes"]
}
sort {
key = "ram"
direction = "asc"
}
}
data "civo_size" "small" {
filter {
key = "type"
values = ["kubernetes"]
}
filter {
key = "name"
values = ["g4s.kube.small"]
match_by = "re"
}
}
Step 4: Create a firewall
resource "civo_firewall" "core-firewall" {
name = "core"
create_default_rules = false
ingress_rule {
label = "k8s"
protocol = "tcp"
port_range = "6443"
cidr = ["0.0.0.0/0"]
action = "allow"
}
ingress_rule {
label = "k8s"
protocol = "tcp"
port_range = "80"
cidr = ["0.0.0.0/0"]
action = "allow"
}
ingress_rule {
label = "k8s"
protocol = "tcp"
port_range = "443"
cidr = ["0.0.0.0/0"]
action = "allow"
}
}
Step 5: Create a cluster without specific cluster type by default is K3s
resource "civo_kubernetes_cluster" "core-cluster" {
name = "core"
firewall_id = civo_firewall.core-firewall.id
applications = "cert-manager,traefik2-nodeport"
pools {
size = element(data.civo_size.small.sizes, 0).name
node_count = 3
}
}
Setting Up the GitHub Actions Pipeline
The next step is to Sketch out the GitHub Actions pipeline and core Digger configurations. The main branch configuration needed for this is:
name: CI
on:
pull_request:
branches: [ "main" ]
types: [ closed, opened, synchronize, reopened ]
issue_comment:
types: [created]
if: contains(github.event.comment.body, 'digger')
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
# Based on https://github.com/diggerhq/digger/issues/395#issuecomment-1601257947
permissions: write-all
steps:
- name: digger run
uses: diggerhq/digger@v0.2.0
with:
# All current locking mechanisms require large-cloud resources
disable-locking: true
# AWS Setup Below
# setup-aws: true
# aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
# aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
# aws-region: us-east-1
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CIVO_TOKEN: ${{ secrets.CIVO_TOKEN }}
How to Configure Digger
auto_merge: false
projects:
- name: "core-cluster"
dir: core-cluster
Testing the Pipeline
Once everything has been committed to the main branch, you'll need to make a PR to actually test the pipeline. Create a new branch, initial-commit. Make a minor change to any of the Terraform in the core-cluster directory. Push up that branch, then create a new PR.
In that PR, write a new comment to trigger a terraform
plan to see the actions the Terraform code will perform.
Review the output of the terraform plan
output. This will let you and any peer reviewers see what infrastructure changes will occur.
Ensure all resources being created or modified are expected, then write a comment of digger apply
.
On the PR, you will see the results of the Terraform apply.
Once the apply is complete, merge your PR into the main branch.
Once the pipeline has been completed successfully, you can log in to your Civo account and verify that the Kubernetes cluster has been created.
Now we have completed our first cluster, provisioned completely from Digger!
While this configuration will get you far, in Part 2, we will explore hardening our pipeline with better state and lock management, all within the Civo architecture!
Summary
Now that we have finished this tutorial, you should be able to use Digger to automate Terraform processes within a Civo Kubernetes cluster using GitHub Actions. You can read part 2, “Hardening our Infrastructure as Code Pipeline with Digger,” here.
If you are interested in learning more about the topics discussed in this tutorial, check out some of these resources:
- More tutorials on Infrastructure as Code can be found here.
- How to choose an Infrastructure as Code Solution talk from Lee Briggs.