Chapter 28Lesson 01~190 minutes

Kubernetes Agent, Cluster Access, GitOps-Oriented Delivery, Kubernetes Deployments, and Environment Integration: Concepts, Architecture, and Mental Model

Connect GitLab delivery evidence to Kubernetes without collapsing agent authorization, cluster context, manifest intent, workload rollout, environment records, and health into one “deployment succeeded” state.

Kubernetes AgentCluster contextGitOpsImage digestRollout evidence

Learning objectives

  • Explain the difference between GitLab Agent authorization, a Kubernetes context, Kubernetes RBAC, a deployment manifest, a GitLab environment record, and workload health.
  • Trace verified image → authorized GitLab job → Agent/context → manifest or Flux reconciliation → workload → environment/deployment record → health evidence.
  • Identify why digest-pinned images and namespaced least privilege are stronger than mutable tags and cluster-wide credentials.
  • Distinguish the push-based CI/CD workflow from GitOps reconciliation and understand GitLab’s current recommendation to use Flux for GitOps.
  • Perform read-only inspection before any cluster mutation.

1. The practical problem: “the deploy job is green” tells you too little

Chapter 27 replaced long-lived provider secrets with explicit workload identity. Kubernetes adds another authorization and state boundary. A GitLab job can succeed while using the wrong cluster context, an Agent can be reachable while Kubernetes RBAC denies the operation, a manifest can apply successfully while Pods never become Ready, and GitLab can record a deployment while the external service remains unhealthy.

The chapter therefore treats Kubernetes delivery as a chain of independently inspectable states. The artifact has an immutable identity. The pipeline has an exact source and compiled configuration. The job is authorized to a specific Agent/context. Kubernetes authorizes only the required namespace operations. The desired manifest names the exact image digest. GitLab records the environment/deployment. Finally, the cluster’s rollout and service behavior are verified independently.

Core rule: never infer Kubernetes health from CI job success. Preserve the job and deployment record, then verify the actual Deployment, Pods, imageID, rollout status and service behavior.

2. Mental model: seven identities cross two control planes

The flow begins with a verified artifact, not “whatever latest means now.” GitLab compiles a job for an exact SHA. Agent authorization exposes one or more named kube contexts to that job. The selected context reaches the cluster, where Kubernetes RBAC independently decides which namespace operations are allowed. The job either applies desired state directly, or a GitOps controller such as Flux reconciles reviewed desired state. GitLab then records an environment/deployment, while Kubernetes runtime state supplies the final health evidence.

flowchart TD A[Verified image @ sha256] --> B[Authorized pipeline/job] B --> C[GitLab Agent + selected context] C --> D[Kubernetes RBAC] D --> E[Manifest apply or Flux reconciliation] E --> F[Deployment / Pods / Service] B --> G[GitLab environment + deployment record] F --> H[Rollout + imageID + endpoint health] G --> I[Operational history] H --> I

The Agent is not a replacement for Kubernetes RBAC, and a GitLab environment is not the Kubernetes controller. These arrows are causal boundaries, not decorative boxes.

3. Name every state before changing any of it

State layer Evidence to capture Why it matters
Source/revision CI_PIPELINE_SOURCE, ref, CI_COMMIT_SHA, pipeline/job IDs The cluster change must be attributable to the exact source hypothesis and job that requested it.
Compiled CI configuration Merged YAML, rules result, environment declaration, agent/context selection Proves which deployment path GitLab actually created—not what a developer remembers writing.
Job/runner Job ID/status, runner/executor/image/tool versions Runner success is only execution evidence; it does not prove cluster authorization or rollout health.
Agent/context authorization Agent identity, configuration project, ci_access project/group/environment scope, selected kube context Defines which jobs can even obtain a usable cluster context.
Kubernetes authorization Namespace, ServiceAccount/impersonated identity, Role/RoleBinding, kubectl auth can-i evidence Agent availability is not equivalent to Kubernetes permission.
Artifact/image identity Registry path plus immutable @sha256: digest and producer SHA/pipeline Prevents a later tag mutation from silently changing deployed bytes.
Manifest/reconciliation Reviewed manifest/Helm/Kustomize/Flux revision and manifest digest Captures desired state separately from runtime state.
GitLab environment/deployment Environment name/tier/URL, deployment/job ID, agent/dashboard metadata GitLab records deployment intent/history; this is not the same as Kubernetes health.
Kubernetes runtime Deployment generation, ReplicaSet, Pod imageID, rollout status, Service/endpoint state Proves what the cluster actually ran.
Governance/cleanup Authorization owner, namespace/resource labels, cleanup evidence, exception record Makes access and resource lifecycle auditable and bounded.

4. What the GitLab Agent changes—and what it does not

The Agent opens an outbound connection from the cluster to GitLab’s Kubernetes Agent Server (KAS). In the CI/CD workflow, an authorized project’s jobs receive a kubeconfig containing contexts for Agent connections they may use. Runners do not need to run inside the target cluster.

Authorization is configured in the Agent project, for example:

# .gitlab/agents/staging-agent/config.yaml
ci_access:
  projects:
    - id: platform/example-app
      environments:
        - staging
        - review/*

This authorizes the project/environment combinations to receive the Agent context. Kubernetes permissions still come from the Agent service account or, where configured, impersonation plus RBAC.

Tier boundary: environment-restricted ci_access is available on all tiers. CI-job impersonation via access_as: ci_job is Premium/Ultimate. On Free, do not describe impersonation as available; constrain the Agent service account with Kubernetes RBAC instead.

5. Read-only inspection first

Before a deployment, establish the pipeline identity and the contexts visible to the job without dumping kubeconfig contents or credentials.

printf 'source=%s sha=%s pipeline=%s job=%s\n'   "$CI_PIPELINE_SOURCE" "$CI_COMMIT_SHA" "$CI_PIPELINE_ID" "$CI_JOB_ID"
kubectl config get-contexts -o name
kubectl config current-context
kubectl auth can-i get deployments -n glci-ch28
kubectl auth can-i create deployments -n glci-ch28
kubectl get namespace glci-ch28 --ignore-not-found
kubectl -n glci-ch28 get deployment,service,pod --ignore-not-found

Do not print $KUBECONFIG or its file contents. The safe evidence is the selected context name, authorization answers, cluster/namespace identity and resource metadata.

6. Context identity is part of deployment identity

With the Agent CI/CD workflow, the context name identifies the Agent configuration project and Agent. A production pipeline should select it explicitly rather than rely on whichever context happens to be current.

deploy_staging:
  stage: deploy
  variables:
    KUBE_CONTEXT: platform/cluster-agents:staging-agent
  before_script:
    - kubectl config use-context "$KUBE_CONTEXT"
  script:
    - kubectl auth can-i patch deployments -n app-staging
    - kubectl apply -f k8s/staging.yaml
    - kubectl rollout status deployment/example -n app-staging --timeout=180s

A context selection is evidence of where the request was sent. It is not evidence that RBAC allowed the change or that the rollout became healthy.

7. Least privilege lives in Kubernetes too

A common mistake is to install the Agent with a service account that can administer the whole cluster and then rely only on GitLab project authorization. That leaves one control plane doing work that should be shared with Kubernetes. Prefer namespace-scoped Roles and RoleBindings that permit only the API groups/resources/verbs the deployment job requires.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: glci-deployer
  namespace: app-staging
rules:
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
  - apiGroups: [""]
    resources: ["pods", "services"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]

Deletion rights, Secret access and cluster-scoped resources should be added only when a concrete workflow requires them.

8. Promote bytes, not a mutable tag

A Kubernetes manifest that says image: registry.example/app:latest does not uniquely identify deployed bytes. A release promotion should carry forward the already-tested digest:

spec:
  template:
    spec:
      containers:
        - name: app
          image: registry.example.test/platform/app@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef

The digest links Chapters 23–26 to Kubernetes runtime state. After rollout, capture the Pod imageID and compare its digest to the intended manifest digest. A tag may still be retained as human-readable metadata, but it must not be the only production identity.

9. Push-based CI/CD and GitOps solve different control problems

Model Who changes the cluster? Primary desired-state evidence Security/operations consequence
CI/CD push Pipeline job sends Kubernetes API requests Compiled job + manifest used by that job Fast and direct, but GitLab documents this as a weaker security model and advises against it for production deployments.
Flux GitOps In-cluster Flux controller reconciles repository/OCI desired state Versioned Git/OCI revision and Flux reconciliation state Cluster pulls/reconciles reviewed desired state; credentials and reconciliation remain cluster-side.

GitLab’s legacy built-in Agent pull-based GitOps functionality is gone; current GitLab guidance is to use Flux for GitOps. The Agent remains valuable for connectivity, dashboard visibility and other integration features.

10. Environment integration records intent; the dashboard adds observation

A deployment job can associate the environment with an Agent and Kubernetes namespace using current YAML:

deploy_staging:
  stage: deploy
  script:
    - ./deploy-staging.sh
  environment:
    name: staging
    url: https://staging.example.test
    kubernetes:
      agent: platform/cluster-agents:staging-agent
      dashboard:
        namespace: app-staging

The environment/deployment record is GitLab-owned state. The Kubernetes dashboard can surface cluster resources, but operational acceptance still needs workload-specific health evidence. The older form with namespace directly under kubernetes: is deprecated; use dashboard: namespace:.

11. Rollout health is independent evidence

kubectl -n app-staging rollout status deployment/example --timeout=180s
kubectl -n app-staging get deployment/example -o json
kubectl -n app-staging get pods -l app=example   -o jsonpath='{range .items[*]}{.metadata.name}{"  "}{.status.phase}{"  "}{.status.containerStatuses[0].imageID}{"\n"}{end}'
kubectl -n app-staging get service/example -o json

“Deployment available replicas equal desired replicas,” “Pod Ready,” “container imageID matches the intended digest,” and “the service answers its health endpoint” are different observations. Preserve whichever are required by the service SLO.

12. Avoid deprecated connection mental models

Certificate-based cluster integration was deprecated in GitLab 14.5. Do not build new labs around project/group/instance certificate clusters or legacy “GitLab-managed cluster” assumptions. For current connectivity, use the Agent. For GitOps, use Flux. For a purely local lab, use a disposable kubeconfig only inside the local machine and clearly label it as a simulation—not as the recommended GitLab production pattern.

13. A read-only evidence checklist

Question Read-only proof
Which source asked to deploy? Pipeline source/ref/SHA and IDs; merged CI configuration.
Which Agent/context is selected? Context name and Agent project/name; never kubeconfig credential contents.
May this identity touch the namespace? kubectl auth can-i for exact verbs/resources/namespace.
Which bytes are intended? Manifest image @sha256: reference and producer metadata.
What did GitLab record? Environment/deployment name, job/deployment ID, URL/tier/Agent metadata.
What is actually running? Deployment/ReplicaSet/Pod UID, generation, Ready state and runtime imageID.
Is external behavior healthy? Service endpoint/health check independent of the deploy script exit code.

Knowledge check

A job can see an Agent context. Does that prove it can patch a Deployment?

Why is a digest stronger deployment identity than a tag?

What currently replaces the Agent’s legacy built-in pull-based GitOps feature?

If GitLab shows a successful deployment record but the Pods are CrashLoopBackOff, which state is wrong?

Why should you not print the kubeconfig during diagnosis?

Next lesson

Continue to the guided workflow

Lesson 2 builds the model on a disposable local cluster, including real namespace-scoped ServiceAccount RBAC, a digest-pinned image, rollout evidence and a faithful mapping to GitLab Agent/environment state.

Version and compatibility note

GitLab and GitLab Runner evolve continuously. Treat version-sensitive YAML, runner/executor behavior, APIs, security features, policy controls, tiers, and deprecations as assumptions to verify against the current official GitLab documentation before production use. Preserve the exact project/ref/SHA, compiled configuration, pipeline/job IDs, runner/tool versions, and external target evidence used for any reproducible lab or incident record.

Official references and version notes

Documentation verification date: 2026-09-12. Current GitLab documentation lists the Agent CI/CD workflow as Free, Premium, and Ultimate on GitLab.com, Self-Managed, and Dedicated. Authorized CI/CD jobs receive a KUBECONFIG containing contexts for authorized agent connections; the context identifies the agent configuration project and agent name. ci_access can authorize projects/groups and can restrict access to named environment patterns. The current per-agent authorization limit is 500 projects and 500 groups. CI-job impersonation with access_as: ci_job is Premium/Ultimate; the mandatory lab therefore demonstrates true Kubernetes namespace-scoped ServiceAccount RBAC locally instead of pretending that paid impersonation is Free. GitLab recommends Flux for GitOps; the Agent’s legacy built-in pull-based GitOps functionality was removed in GitLab 17.0. Certificate-based cluster integration was deprecated in GitLab 14.5. The Kubernetes dashboard is currently Beta and available on all tiers. For environment:kubernetes, dashboard namespace/Flux resource settings belong under dashboard:; the older direct namespace/flux_resource_path form is deprecated. Current GitLab Agent docs also note that authorization changes can take a short period to propagate. Preserve the before/after authorization evidence instead of blindly rerunning a denied deployment.

Current assumptions used in this chapter: Version-sensitive YAML, Runner/executor behavior, APIs, security features, policy controls, tiers, and deprecations must be verified against the exact GitLab, GitLab Runner, tool, and external-system versions used in production. Preserve the exact project/ref/SHA, compiled configuration, pipeline/job IDs, runner/tool versions, and external target evidence used for reproducible work.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.