- Before you begin
- Run commands against your cluster from GitLab CI/CD
- Build a simple manifest into an OCI image and deploy it to the cluster
- Clean up resources
- Next steps
Get started deploying to Kubernetes
This page introduces you to deploying to Kubernetes using methods supported by GitLab. In the end, you will understand:
- How to deploy with Flux
- How to deploy or run commands against your cluster from GitLab CI/CD pipelines
- How to combine Flux and GitLab CI/CD for the best outcome
Before you begin
This tutorial builds on the project you created in Get started connecting a Kubernetes cluster to GitLab. You’ll use the same project you created in that tutorial. However, you can use any project with a connected Kubernetes cluster and a bootstrapped Flux installation.
Run commands against your cluster from GitLab CI/CD
The agent for Kubernetes integrates with GitLab CI/CD pipelines. You can use CI/CD to run commands like kubectl apply
and helm upgrade
against your cluster in a secure and scalable way.
In this section, you’ll use the GitLab pipeline integration to create a secret in the cluster and use it to access the GitLab container registry. The rest of this tutorial will use the deployed secret.
-
Create a deploy token with the
read_registry
scope. - Save your deploy token and username as CI/CD variables called
CONTAINER_REGISTRY_ACCESS_TOKEN
andCONTAINER_REGISTRY_ACCESS_USERNAME
.- For both variables, set the environment to
container-registry-secret*
. - For
CONTAINER_REGISTRY_ACCESS_TOKEN
:
- For both variables, set the environment to
-
Add the following snippet to your
.gitlab-ci.yml
file, and update bothAGENT_KUBECONTEXT
variables to match your project’s path:stages: - setup - deploy - stop create-registry-secret: stage: setup image: "portainer/kubectl-shell:latest" variables: AGENT_KUBECONTEXT: my-group/optional-subgroup/my-repository:testing before_script: # The available agents are automatically injected into the runner environment # We need to select the agent to use - kubectl config use-context $AGENT_KUBECONTEXT script: - kubectl delete secret gitlab-registry-auth -n flux-system --ignore-not-found - kubectl create secret docker-registry gitlab-registry-auth -n flux-system --docker-password="${CONTAINER_REGISTRY_ACCESS_TOKEN}" --docker-username="${CONTAINER_REGISTRY_ACCESS_USERNAME}" --docker-server="${CI_REGISTRY}" environment: name: container-registry-secret on_stop: delete-registry-secret delete-registry-secret: stage: stop image: "" variables: AGENT_KUBECONTEXT: my-group/optional-subgroup/my-repository:testing before_script: # The available agents are automatically injected into the runner environment # We need to select the agent to use - kubectl config use-context $AGENT_KUBECONTEXT script: - kubectl delete secret -n flux-system gitlab-registry-auth environment: name: container-registry-secret action: stop when: manual
Before you continue, consider how you might run other commands with CI/CD.
Build a simple manifest into an OCI image and deploy it to the cluster
For production use cases, it is a best practice to use an OCI repository as a caching layer between the Git repository and FluxCD. FluxCD checks for new images in the OCI repository, while GitLab pipeline builds the Flux-compliant OCI images. To learn more about enterprise best practices, see enterprise considerations.
In this section, you’ll build a simple Kubernetes manifest as an OCI artifact, then deploy it to your cluster.
-
Add the following YAML to
clusters/testing/nginx.yaml
. This lets Flux know to retrieve the specified OCI image and deploy its content.apiVersion: source.toolkit.fluxcd.io/v1beta2 kind: OCIRepository metadata: name: nginx-example namespace: flux-system spec: interval: 1m url: oci://registry.gitlab.example.org/my-group/optional-subgroup/my-repository/nginx-example ref: tag: latest secretRef: name: gitlab-registry-auth --- apiVersion: kustomize.toolkit.fluxcd.io/v1 kind: Kustomization metadata: name: nginx-example namespace: flux-system spec: interval: 1m targetNamespace: default path: "." sourceRef: kind: OCIRepository name: nginx-example prune: true
You can find the container registry URL for your GitLab instance on the left sidebar, under Deploy > Container registry.
-
We’ll deploy NGINX as an example. Add the following YAML to
clusters/applications/nginx/nginx.yaml
:apiVersion: apps/v1 kind: Deployment metadata: name: nginx-example namespace: default spec: replicas: 1 selector: matchLabels: app: nginx-example template: metadata: labels: app: nginx-example spec: containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80 protocol: TCP --- apiVersion: v1 kind: Service metadata: name: nginx-example namespace: default spec: ports: - port: 80 targetPort: 80 protocol: TCP selector: app: nginx-example
-
Now, let’s package the previous YAML into an OCI image. Extend your
.gitlab-ci.yml
file with the following snippet, and again update theAGENT_KUBECONTEXT
variable:nginx-deployment: stage: deploy variables: IMAGE_NAME: nginx-example # Image name to push IMAGE_TAG: latest MANIFEST_PATH: "./clusters/applications/nginx" IMAGE_TITLE: NGINX example # Image title to use in OCI annotation AGENT_KUBECONTEXT: my-group/optional-subgroup/my-repository:testing FLUX_OCI_REPO_NAME: nginx-example # Flux OCIRepository to reconcile NAMESPACE: flux-system # Namespace for the OCIRepository resource # This section configures a GitLab environment for the nginx deployment specifically environment: name: applications/nginx kubernetes: agent: $AGENT_KUBECONTEXT namespace: default flux_resource_path: kustomize.toolkit.fluxcd.io/v1/namespaces/flux-system/kustomizations/nginx-example # We will deploy this resource in the next step image: name: "fluxcd/flux-cli:v2.4.0" entrypoint: [""] before_script: - kubectl config use-context $AGENT_KUBECONTEXT script: # This line builds and pushes the OCI container to the GitLab container registry. # You can read more about this command in https://fluxcd.io/flux/cmd/flux_push_artifact/ - flux push artifact oci://${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${IMAGE_TAG} --source="${CI_REPOSITORY_URL}" --path="${MANIFEST_PATH}" --revision="${CI_COMMIT_SHORT_SHA}" --creds="${CI_REGISTRY_USER}:${CI_REGISTRY_PASSWORD}" --annotations="org.opencontainers.image.url=${CI_PROJECT_URL}" --annotations="org.opencontainers.image.title=${IMAGE_TITLE}" --annotations="com.gitlab.job.id=${CI_JOB_ID}" --annotations="com.gitlab.job.url=${CI_JOB_URL}" # This line triggers an immediate reconciliation of the resource. Otherwise Flux would reconcile following its configured reconciliation period. # You can read more about the various reconcile commands in https://fluxcd.io/flux/cmd/flux_reconcile/ - flux reconcile source oci -n ${NAMESPACE} ${FLUX_OCI_REPO_NAME}
-
On the left sidebar, select Operate > Environments and check the available dashboard for Kubernetes. The
applications/nginx
environment should be healthy.
Secure the GitLab pipeline access
The previously deployed agent is configured using the .gitlab/agents/testing/config.yaml
file.
By default, the configuration enables access to the clusters configured in the project where the GitLab pipelines run.
By default, this access uses the deployed agent’s service account to run commands against the cluster.
This access can be restricted either to a static service account identity or by using the CI/CD job as an identity in the cluster.
Finally, regular Kubernetes RBAC can be used to limit the access of the CI/CD jobs in the cluster.
In this section, we’ll restrict CI/CD access by adding an identity to every CI/CD job, and impersonating the job in the cluster.
-
To configure the CI/CD job impersonation, edit the
.gitlab/agents/testing/config.yaml
file, and add the following snippet to it (replacingpath/to/project
):ci_access: projects: - id: my-group/optional-subgroup/my-repository access_as: ci_job: {}
-
As the CI/CD jobs don’t have any cluster bindings yet, we can not run any Kubernetes commands from GitLab CI/CD. Let’s enable CI/CD jobs to create
Secret
objects in theflux-system
namespace. Create theclusters/testing/gitlab-ci-job-secret-write.yaml
file with the following content:apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: secret-manager namespace: default rules: - apiGroups: [""] resources: ["secrets"] verbs: ["create", "delete"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: gitlab-ci-secrets-binding namespace: default subjects: - kind: Group name: gitlab:ci_job apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: secret-manager apiGroup: rbac.authorization.k8s.io
-
Let’s enable CI/CD jobs to trigger a FluxCD reconciliation too. Create the
clusters/testing/gitlab-ci-job-flux-reconciler.yaml
file with the following content:apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: ci-job-admin roleRef: name: flux-edit-flux-system kind: ClusterRole apiGroup: rbac.authorization.k8s.io subjects: - name: gitlab:ci_job kind: Group --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: ci-job-view roleRef: name: flux-view-flux-system kind: ClusterRole apiGroup: rbac.authorization.k8s.io subjects: - name: gitlab:ci_job kind: Group
For more information about CI/CD access, see Using GitLab CI/CD with a Kubernetes cluster.
Clean up resources
To finish, let’s remove the deployed resources and delete the secret we used to access the container registry:
- Delete the
clusters/testing/nginx.yaml
file. Flux will take care of removing the related resources from the cluster. - Stop the
container-registry-secret
environment. Stopping the environment will trigger itson_stop
job, removing the secret from the cluster.
Next steps
You can use the techniques in this tutorial to scale deployments across projects. The OCI image can be built in a different project, and as long as Flux is pointed at the right registry, Flux will retrieve it. This exercise is left for the reader.
For more practice, try changing the original Flux GitRepository
in /clusters/testing/flux-system/gotk-sync.yaml
to an OCIRepository
.
Finally, see the following resources for more information about Flux and the GitLab integration with Kubernetes:
- Enterprise considerations for the Kubernetes integration
- Use the agent for operational container scanning
- Use the agent to provide remote workspaces for your engineers