Kustomize with GitLab CICD
Kustomize is a convenient tool when it comes to deploying applications to multiple environments, where each has its own minor differences.
This article presents an approach to leverage Kustomize in a GitLab CICD pipeline.
Throughout this article, git tags deploy to the prod environment while the staging branch deploys to the eponymous environment.
Repository structure
Here is an example repository structure for an application that would have both staging and production environments to deploy to:
my-app/
├── kustomize/
│ ├── base/
│ │ ├── deployment.yml
│ │ └── kustomization.yml
│ └── overlays/
│ ├── staging/
│ │ └── kustomization.yml
│ └── prod/
│ └── kustomization.yml
├── ...
└── .gitlab-ci.yml
Kustomize
In such a scenario, Kustomize would be used as follows.
Base
In this example, a simple deployment manifest is applied by kubectl.
# kustomize/base/deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: my-app
template:
metadata:
labels:
app.kubernetes.io/name: my-app
spec:
containers:
- name: my-app
image: my-registry/my-app:${IMAGE_TAG}
Note that here, the image tag is written as a shell variable (${IMAGE_TAG}) as it will be inferred from CICD and substituted with envsubst.
The base also needs its own kustomization.yml listing the resources the overlays will build on:
# kustomize/base/kustomization.yml
resources:
- deployment.yml
Overlays
To each deployment environment corresponds an overlay. In this case, prod simply applies the base manifest.
# kustomize/overlays/prod/kustomization.yml
resources:
- ../../base
# kustomize/overlays/staging/kustomization.yml
resources:
- ../../base
nameSuffix: -staging
labels:
- pairs:
app.kubernetes.io/name: my-app-staging
includeSelectors: true
Because includeSelectors: true rewrites the Deployment’s spec.selector, apply this overlay to a fresh Deployment: selector labels are immutable, so adding it to an already-deployed workload requires deleting and recreating it.
CICD configuration
By leveraging .gitlab-ci.yml’s rules field, one can define per-branch - and thus per environment - variables.
This can be used to not only select the appropriate overlay, but also set the container image tag, which is substituted using envsubst.
In this example, prod uses the git tag as image tag while staging simply uses the commit sha. However, more environments can easily be added by creating dedicated branches and overlays, and adding an if statement to the rules.
# .gitlab-ci.yml
deploy-job:
stage: deploy
variables:
TARGET_ENV: $CI_COMMIT_BRANCH
IMAGE_TAG: $CI_COMMIT_SHORT_SHA
rules:
- if: $CI_COMMIT_TAG
variables:
TARGET_ENV: prod
IMAGE_TAG: $CI_COMMIT_TAG
- if: $CI_COMMIT_BRANCH == "staging"
script:
- >
kubectl kustomize kustomize/overlays/${TARGET_ENV}
| envsubst
| kubectl apply -f -
The job image must provide both kubectl and envsubst (the latter ships with the gettext package). Cluster access is handled by the GitLab agent for Kubernetes.