Blog

Back to resource

GitOps for Terraform and Helm with Cluster.dev

29 Nov 2023
Articles
Author: VOLODYMYR TSAP, CO-OWNER, CTO OF CLUSTER.DEV
Views: 707

In the realm of DevOps, GitOps has emerged as a powerful methodology to manage infrastructure and applications. This article will illustrate the implementation of a GitOps flow for Terraform modules (for infrastructure provisioning) and Helm charts (for Kubernetes applications) using the Cluster.dev platform.

Cluster.dev offers an intuitive interface and tools designed to simplify the setup, configuration, and maintenance of Kubernetes infrastructures. Its capabilities align well with implementing a GitOps workflow for Terraform modules and Helm charts.

Understanding GitOps

In GitOps, all configuration and infrastructure code reside within Git repositories. Any adjustments made to the configuration stored in the repository trigger a reconciliation process that enacts these modifications.

Utilizing Cluster.dev ensures that your complete configuration remains consistently managed and stored within Git.

Let’s look at an example infrastructure repository: https://github.com/shalb/cdev-aws-eks

Unit Versioning in StackTemplate

A stack template is a yaml file that tells Cluster.dev which units to run and how to do it. It’s an important resource of Cluster.dev, responsible for its flexibility. Stack templates use Go template language which allows users to both select and customize units they want to run.

Here, in the /template.yaml you can find links for each module, whether it’s Terraform or a Helm chart.

 units:
   - name: route53
     type: tfmodule
     source: github.com/shalb/cluster.dev-domain?ref=v0.1.0 # refering git repo of the module with the version


   - name: vpc
     type: tfmodule
     providers: *provider_aws
     source: terraform-aws-modules/vpc/aws  # refering module in terraform registry and its version
     version: "5.1.1"

To update a module in the template, just modify the tag. It’s advisable to test using a development branch.

Versioning the Resulting Infrastructure — The Stack

The next level of versioning is at the Stack level. This object determines which StackTemplate to use and includes all necessary variables for this stack.

Consider the following from https://github.com/shalb/cdev-aws-eks/blob/main/examples/stack-eks.yaml:

 name: cluster
template: "https://github.com/shalb/cdev-aws-eks?ref=main" # The version of StackTemplate pinned to a specific stack
kind: Stack
backend: aws-backend
cliVersion: ">= 0.7.14"
variables:
  region: {{ .project.variables.region }}

Git tags and branches in the stack can be used to manage and update versions of StackTemplates.

Upgrading Your Infrastructure

Suppose you need to update a Terraform module in your production setup.

1. Update the module version in the StackTemplate:

- name: route53
  type: tfmodule
  source: github.com/shalb/cluster.dev-domain?ref=v0.2.0 # Update the module's version here

2. As long as this change affects your infrastructure module, create a new tag for the StackTemplate in Git, then update the tag within the Stack:

 name: cluster
template: "https://github.com/shalb/cdev-aws-eks?ref=1.2.3" # Adjust the StackTemplate's version

And that’s it. Your infrastructure code now has a set pinned layout for infrastructure components, all maintained within Git.

GitOps Reconciliation

The Cluster.dev’s ability to start whole infrastructures makes it ideal for GitOps reconciliation. However, modifications to the infrastructure can have a substantial impact, emphasizing the need to preview planned changes. To address this, we recommend implementing a Pull Request (PR) or Merge Request (MR) process for thorough review and authorization of changes.

Outlined below is the typical process:

  1. An engineer modifies the Stack version, creating a Pull Request for the main branch.
  2. This automatically activates the cluster.dev (cdev plan) command, enabling the user to inspect proposed infrastructure changes.
  3. Once the PR is approved, the merging process triggers a new pipeline, using the cluster.dev (cdev apply) command to effectively apply all changes.

This way Cluster.dev reconciles changes in various components, be they Terraform modules or Helm charts.

GitHub Workflow Example

Let’s assume you are storing your Cluster.dev configurations (stack yamls) inside a Git repository under the .cluster.dev/dev-project/ folder.

For each project (e.g., dev or production infrastructure), create a distinct GitHub workflow file: github/workflows/dev-project.yaml.

 name: Cluster.dev for dev-project

on:
  push:
    branches:
      - 'cluster.dev-*'
      - main
    paths:
      - '.cluster.dev/dev-project/**'
  pull_request:
    branches:
      - main
    paths:
      - '.cluster.dev/dev-project/**'

jobs:
  plan:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    container: clusterdev/cluster.dev:v0.7.18
    steps:
    - name: Check out code
      uses: actions/checkout@v3

    - name: Run ClusterDev Plan
      run: |
        cd .cluster.dev/10-project
        aws s3 mb s3://cdev-state || true # create or reuse state bucket
        cdev plan
      env:
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        AWS_DEFAULT_REGION: eu-central-1
  apply:
    if: github.event_name == 'push' && contains(github.ref, 'refs/heads/main') # Runs only on push to main branch
    runs-on: ubuntu-latest
    container: clusterdev/cluster.dev:v0.7.18
    steps:
    - name: Check out code
      uses: actions/checkout@v3

    - name: Run ClusterDev Apply
      run: |
        cd .cluster.dev/dev-project
        cdev apply --force
      env:
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        AWS_DEFAULT_REGION: eu-central-1

In this example, we employ a Cluster.dev container from DockerHub. The two jobs are:

  • plan: Creates a plan for a PR or a specific branch commit.
  • apply: Actuates the configuration and reconciles changes, with –force enabling non-interactive mode.

This approach is highly adaptable, suitable for various CI/CD systems like GitLab or Jenkins.

Demo

Use this demo link EKS Cluster creation demo to try out the GitOps pipelines that would be generated into your repository.

Best Practices

Using Cluster.dev makes it easier to align with the GitOps best practices for Terraform modules and Helm charts, including:

  • Embracing modular design principles to promote reusability.
  • Employing Helm chart versioning strategies for efficient management of application releases.
  • Regular review and testing changes with automated CI/CD pipelines before applying them.

Summary

Working through this guide we have seen how Cluster.dev can boost the GitOps flow for Terraform modules and Helm charts. This helps organizations optimize their DevOps workflows, including seamless integration of infrastructure components, their versioning, and reconciliation.

Back to resource