Video Thumbnail for Lesson
12.4: Kluctl (Single Service)

Kluctl (Single Service)

Overview

In this lesson we'll use Kluctl to deploy a single service to multiple Kubernetes clusters. The full source is available in the course repository.

Project structure

A .kluctl.yaml file defines the environments that Kluctl can deploy to:

targets:
  - name: staging
    args:
      environment: staging
    # Adding a context to .kluctl.yaml helps prevent accidentally deploying to the wrong cluster!
    context: devops-directive-kubernetes-course

  - name: production
    args:
      environment: production
    # Adding a context to .kluctl.yaml helps prevent accidentally deploying to the wrong cluster!
    context: gke_kubernetes-course-424917_us-central1-a_devops-directive-kubernetes-course

args:
  - name: environment

discriminator: kluctl-{{ target.name }}

Each target passes an environment argument and specifies a kubeconfig context. This prevents accidental deployments to the wrong cluster and provides a discriminator so Kluctl can safely manage resources from multiple targets.

The root deployment.yaml pulls in an environment specific config file and references subdeployments:

vars:
  - file: config/{{ args.environment }}.yaml

deployments:
  - path: namespaces
  - barrier: true
  - include: services

commonLabels:
  devopsdirective.com/course: "kubernetes-course"

Here we load shared variables, create the namespace before any services, and apply a common label to all resources.

Service configuration

Within services/api-golang the service deployment.yaml loads a config file for the selected environment:

vars:
  - file: config/{{ args.environment }}.yaml

deployments:
  - path: manifests

An example production configuration looks like:

apiGolang:
  version: 1.0.0 # PRODUCTION_IMAGE_TAG
  replicas: 2

The Deployment manifest uses these variables to set the replica count and image tag:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-golang
  namespace: demo-app
  labels:
    app: api-golang
spec:
  replicas: { { apiGolang.replicas } }
  selector:
    matchLabels:
      app: api-golang
  template:
    metadata:
      labels:

Ingress routing rules reference the shared hostname value:

  namespace: demo-app
spec:
  entryPoints:
    - web
  routes:
    - kind: Rule
      match: Host(`{{ sharedVars.hostName }}`) && PathPrefix(`/api/golang`)
      middlewares:
        - name: strip-api-prefixes
      services:
        - kind: Service

Rendering manifests

Kluctl can render manifests without applying them. To view the production configuration run:

kluctl render -t production | yq

Using -t staging produces the staging manifests with a different hostname, replica count and image tag.