| | |

GitLab 20 🦊 GitOps Workflows and Kubernetes Cluster Integrations

⏱️ Estimated read: 10 min | |

The previous chapter covered deploying applications to named environments. This chapter covers the mechanism that connects GitLab to a Kubernetes cluster and the workflow that keeps the cluster synchronized with a Git repository. GitLab provides a Kubernetes agent that runs inside the cluster and maintains a bidirectional connection to GitLab. The recommended workflow is GitOps: the cluster pulls its desired state from a Git repository (via Flux), and the agent provides the connection and observability. The exam tests the distinction between the GitOps workflow (pull-based, recommended) and the CI/CD workflow (push-based, weaker security model), the agent registration and installation steps, and the role of Flux as the GitOps operator .

Key point: The GitLab agent runs inside the cluster and communicates with GitLab via the agent server (KAS). The GitOps workflow uses Flux to pull manifests from a Git repository and reconcile the cluster state. The CI/CD workflow uses the agent to run kubectl commands from a pipeline, pushing changes to the cluster. GitLab recommends GitOps for production and considers the CI/CD workflow a migration path with a weaker security model .


Why GitOps and the Kubernetes agent exist

The cluster connection problem. A Kubernetes cluster behind a firewall or NAT cannot accept inbound connections from GitLab. The agent solves this by opening an outbound bidirectional channel to the agent server (KAS). GitLab communicates with the cluster through this channel, and the cluster does not need a public endpoint . The agent also provides real-time API access, event push, and a low-latency cache of Kubernetes objects.

The push versus pull problem. In a CI/CD workflow, the pipeline pushes changes to the cluster. This works, but the pipeline must hold credentials with write access to the cluster, and the security model is weaker because every job has the same access. In a GitOps workflow, the cluster pulls changes from the Git repository. The agent does not need write access from the pipeline; Flux reconciles the state, and the agent provides observability. The GitOps workflow is pull-based, and GitLab actively invests in it as the first-class experience .

The drift problem. A cluster can be modified by kubectl commands, Helm releases, or operators. These changes are not in the Git repository, and the cluster state drifts from the desired state. GitOps with Flux includes automatic drift remediation: Flux compares the cluster state to the Git repository and reapplies the manifests when they diverge. The agent provides the visualization of the cluster state in the GitLab UI .

The agent registration problem. The agent must be registered before it can be installed. The registration creates a record in GitLab and generates an access token. The token is used by the Helm installation to authenticate the agent. The agent configuration file (.gitlab/agents/<agent-name>/config.yaml) is optional but required for authorizing other projects or groups to access the agent .

The trade-off. The GitOps workflow requires Flux to be bootstrapped in the cluster, and it requires the manifests to be structured for Flux reconciliation. The CI/CD workflow is simpler to set up for a single pipeline but has a weaker security model and is not recommended for production .


a. Registering and installing the agent

The agent is registered in a GitLab project. The registration generates an access token, which is used by the Helm installation.

# Register the agent
Operate → Kubernetes clusters → Connect a cluster (agent)
Agent name: my-agent
Register
# Copy the access token.

The agent is installed with Helm. The default installation grants cluster-admin to the agent’s service account, which is not recommended for production. The installation should be customized to use a service account with restricted permissions .

# Install the agent with Helm
helm repo add gitlab https://charts.gitlab.io
helm repo update
helm upgrade --install my-agent gitlab/gitlab-agent \
  --namespace gitlab-agent-my-agent \
  --create-namespace \
  --set image.tag=<current-agent-version> \
  --set config.token=<your-token> \
  --set config.kasAddress=wss://kas.gitlab.com

The config.kasAddress is the agent server address. On GitLab.com, it is wss://kas.gitlab.com. On self-managed instances, it is wss://<gitlab-hostname> or grpcs://<gitlab-hostname> .


b. The GitOps workflow with Flux

The GitOps workflow uses Flux as the GitOps operator. Flux is bootstrapped in the cluster and configured to watch a Git repository (or an OCI registry) for manifests. The agent detects the Flux GitRepository objects and configures a Receiver, which triggers reconciliation when a git push occurs .

# .gitlab/agents/<agent-name>/config.yaml
gitops:
  manifest_projects:
    - id: my-group/my-manifests
      paths:
        - glob: 'manifests/**/*.yaml'

The manifest_projects block tells the agent which GitLab projects contain the Kubernetes manifests. The agent detects changes and notifies Flux. Flux pulls the manifests and applies them to the cluster.

The source for Flux can be a Git repository or an OCI registry. GitLab recommends using OCI images for source control because they are immutable and can be scanned for security issues. The default Git branch can store cluster state without triggering a sync when OCI is used .

The immediate Git repository reconciliation feature reduces the delay between a git push and the cluster reconciliation. The agent detects the push and triggers the Flux Receiver. The GitRepository.spec.interval should still be set to an acceptable duration because not every push event is guaranteed to be received .


c. The CI/CD workflow: push-based deployment

The CI/CD workflow uses the agent to run kubectl commands from a pipeline. The agent connection provides a kubeconfig context, and the pipeline selects it with kubectl config use-context.

deploy:
  stage: deploy
  image: debian:13-slim
  variables:
    KUBECTL_VERSION: v1.34
  before_script:
    - kubectl config use-context my-group/my-project:my-agent
  script:
    - kubectl apply -f manifests/

The context format is <path/to/agent/project>:<agent-name>. The agent connection is available in every CI/CD job that is authorized to use it. The authorization is configured in the agent configuration file under ci_access .

The CI/CD workflow is considered push-based because GitLab pushes changes to the cluster. The security model is weaker because the pipeline credentials have the same access as the agent’s service account. GitLab recommends this workflow only for pipeline-driven processes or as a migration path, not for production deployments .

The access_as attribute in the agent configuration file can restrict the pipeline’s access. The ci_job: {} setting impersonates the CI/CD job, so the permissions are scoped to the job rather than the agent’s service account .


Complete Example Session

# ============================================
# PART 1: REGISTER THE AGENT
# ============================================

# Operate → Kubernetes clusters → Connect a cluster (agent)
# Agent name: production-agent
# Register
# Copy the access token.
# ============================================
# PART 2: CREATE THE AGENT CONFIG
# ============================================

cat > .gitlab/agents/production-agent/config.yaml <<'EOF'
gitops:
  manifest_projects:
    - id: my-group/k8s-manifests
      paths:
        - glob: 'manifests/**/*.yaml'
EOF

git add .gitlab/agents/production-agent/config.yaml
git commit -m "Add agent configuration"
git push origin main
# ============================================
# PART 3: INSTALL THE AGENT
# ============================================

helm repo add gitlab https://charts.gitlab.io
helm repo update
helm upgrade --install production-agent gitlab/gitlab-agent \
  --namespace gitlab-agent-production \
  --create-namespace \
  --set config.token=<your-token> \
  --set config.kasAddress=wss://kas.gitlab.com
# ============================================
# PART 4: VERIFY THE CONNECTION
# ============================================

# Operate → Kubernetes clusters
# Connection status: Connected
# ============================================
# PART 5: BOOTSTRAP FLUX
# ============================================

flux bootstrap gitlab \
  --owner=my-group \
  --repository=k8s-manifests \
  --branch=main \
  --path=manifests
# ============================================
# PART 6: ADD A MANIFEST
# ============================================

cat > manifests/nginx.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.25
EOF

git add manifests/nginx.yaml
git commit -m "Add nginx deployment"
git push origin main
# ============================================
# PART 7: OBSERVE THE RECONCILIATION
# ============================================

# The agent detects the push and triggers Flux.
# Flux applies the manifest to the cluster.
# Operate → Kubernetes clusters → View
# The nginx deployment appears.
# ============================================
# PART 8: CI/CD WORKFLOW (ALTERNATIVE)
# ============================================

deploy:
  stage: deploy
  image: debian:13-slim
  before_script:
    - kubectl config use-context my-group/k8s-manifests:production-agent
  script:
    - kubectl apply -f manifests/nginx.yaml
# ============================================
# PART 9: VERIFY THE CLUSTER STATE
# ============================================

kubectl get deployments
# NAME    READY   UP-TO-DATE   AVAILABLE
# nginx   1/1     1            1

The nine parts trace the agent lifecycle: registration, configuration, installation, verification, Flux bootstrap, manifest addition, reconciliation observation, CI/CD alternative, and cluster verification.


Quick Reference

Agent Registration

StepLocation
Register agentOperate → Kubernetes clusters
TokenGenerated at registration
Config file.gitlab/agents/<name>/config.yaml

Installation

MethodCommand
Helmhelm upgrade --install <name> gitlab/gitlab-agent
KAS address (GitLab.com)wss://kas.gitlab.com
KAS address (self-managed)wss://<hostname>

Workflows

WorkflowModelRecommended
GitOpsPull (Flux)Yes
CI/CDPush (kubectl)Migration only

Agent Configuration

KeyPurpose
gitops.manifest_projectsProjects with manifests
ci_access.projectsProjects authorized for CI/CD
access_asImpersonation mode

Context Format

WorkflowContext
GitOpsNot needed (Flux handles)
CI/CD<path/to/agent/project>:<agent-name>

Best Practices

✅ Do This:

gitops:
  manifest_projects:
    - id: my-group/k8s-manifests
<!-- Configure GitOps for the agent -->               # ✅
kubectl config use-context my-group/my-project:my-agent
<!-- Select the agent context in CI/CD -->            # ✅
# Use OCI registry for Flux source
<!-- Immutable and scannable -->                     # ✅

❌ Don’t Do This:

# Grant cluster-admin to the agent in production
<!-- Overly broad permissions -->                    # ❌
# Use CI/CD workflow for production deployments
<!-- Weaker security model -->                       # ❌
# Skip Flux bootstrap for GitOps
<!-- Flux is the reconciler -->                      # ❌

Common Pitfalls

PitfallWhy It HappensFix
Agent not connectingWrong KAS addressUse wss://kas.gitlab.com
GitOps not reconcilingFlux not bootstrappedRun flux bootstrap
CI/CD context not foundAgent not authorizedCheck ci_access in config
Manifests not appliedWrong path in manifest_projectsVerify glob pattern
Drift not remediatedFlux not runningCheck Flux pods

Real-World Examples

1. Register Agent

Operate → Kubernetes clusters → Connect a cluster

2. Agent Config

gitops:
  manifest_projects:
    - id: my-group/manifests

3. Install with Helm

helm upgrade --install my-agent gitlab/gitlab-agent --set config.token=...

4. Verify Connection

Operate → Kubernetes clusters → Connected

5. Flux Bootstrap

flux bootstrap gitlab --owner=my-group --repository=manifests

6. Add Manifest

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx

7. CI/CD Context

before_script:
  - kubectl config use-context my-group/project:my-agent

8. CI/CD Deploy

script:
  - kubectl apply -f manifests/

9. Check Cluster

kubectl get deployments

10. View in GitLab

Operate → Kubernetes clusters → View

Visual

GitOps Workflow

┌──────────────────────────────────────────────┐
│  GitLab project (manifests)                  │
└──────────────────┬───────────────────────────┘
                   │ git push
                   ▼
┌──────────────────────────────────────────────┐
│  Agent detects push                          │
│  Triggers Flux Receiver                      │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Flux pulls manifests                        │
│  Applies to cluster                          │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Cluster state reconciled                    │
│  Agent reports to GitLab UI                  │
└──────────────────────────────────────────────┘

CI/CD Workflow

┌──────────────────────────────────────────────┐
│  GitLab pipeline                             │
└──────────────────┬───────────────────────────┘
                   │ kubectl apply
                   ▼
┌──────────────────────────────────────────────┐
│  Agent connection (KAS)                      │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Kubernetes cluster                          │
│  (push-based)                                │
└──────────────────────────────────────────────┘

Summary

ItemValue
Agent purposeCluster connection and observability
Agent serverKAS (wss://kas.gitlab.com on GitLab.com)
Recommended workflowGitOps with Flux
GitOps modelPull-based
CI/CD modelPush-based
Flux bootstrapflux bootstrap gitlab
Agent config.gitlab/agents/<name>/config.yaml
CI/CD context<path/to/agent/project>:<agent-name>

Key takeaways:

  • The agent connects the cluster to GitLab. It runs inside the cluster and opens an outbound channel to KAS. It does not require a public endpoint on the cluster .
  • The GitOps workflow is recommended. Flux pulls manifests from a Git repository or OCI registry and reconciles the cluster state. The agent provides the connection and the GitLab UI visualization .
  • The CI/CD workflow is push-based. The pipeline runs kubectl commands through the agent connection. It is simpler for pipeline-driven processes but has a weaker security model and is not recommended for production .
  • Flux is the GitOps operator. It must be bootstrapped in the cluster. The agent detects Flux GitRepository objects and triggers reconciliation on push .
  • The agent configuration file is optional but required for authorization. The gitops.manifest_projects block tells the agent which projects contain manifests. The ci_access block authorizes projects to use the agent from CI/CD .

Remember: The agent is the connection. The GitOps workflow is the pull. The CI/CD workflow is the push. Flux is the reconciler. The agent configuration is the authorization. The exam tests the distinction between the two workflows and the components that make each work.

Was this helpful?


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!