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.
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.
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.
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.
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?
No. Agent/project authorization exposes a context; Kubernetes RBAC independently decides whether that identity may patch the Deployment in the namespace.
Why is a digest stronger deployment identity than a tag?
A digest addresses immutable content. A tag can later move to different content, so a tag-only manifest cannot prove which bytes were deployed.
What currently replaces the Agent’s legacy built-in pull-based GitOps feature?
Flux. GitLab removed the legacy pull-based feature in GitLab 17.0 and recommends Flux for GitOps reconciliation.
If GitLab shows a successful deployment record but the Pods are CrashLoopBackOff, which state is wrong?
The GitLab deployment job/record may be successful, but Kubernetes runtime health is not. Diagnose workload/cluster state rather than rewriting pipeline history.
Why should you not print the kubeconfig during diagnosis?
It can contain credentials or credential references. Record context names and authorization results instead of exposing authentication material.
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.
- Using GitLab CI/CD with a Kubernetes cluster — official reference.
- GitLab Agent for Kubernetes — official reference.
- Get started connecting a Kubernetes cluster — official reference.
- Install the Agent for Kubernetes — official reference.
- Migrate legacy Agent GitOps to Flux — official reference.
- Dashboard for Kubernetes — official reference.
- CI/CD YAML syntax — environment:kubernetes — official reference.
- Deprecated CI/CD keywords — official reference.
- Migrate from certificate-based Kubernetes integration — official reference.
- GitLab-managed Kubernetes resources — official reference.
- Kubernetes RBAC authorization — official reference.
- Kubernetes Deployments — official reference.
- kind quick start — official reference.
- Flux documentation — official reference.
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.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.