Skip to content

kubectl on Kestrel

The recommended path for deploying and updating workloads is GitOps — commit to your repo, let ArgoCD reconcile. See Your repo, your workloads for the full picture. This page is for debugging with read-only commands and the narrow mutating escape hatch when you need to step outside GitOps temporarily.

These commands inspect cluster state without changing anything. Use them freely — ArgoCD does not interact with read-only operations, and no policy blocks them. The one exception is kubectl debug (last row): it adds an ephemeral container to the target Pod, so it is technically a mutation and is subject to Pod Security Standards admission. It is grouped here because it is a debugging tool, not a deployment action.

CommandWhat it shows
kubectl get <resource>List resources (Pods, Deployments, Services, etc.) in your namespace.
kubectl describe <resource> <name>Detailed status, events, and conditions for a specific resource. The first place to look when a Pod is stuck.
kubectl logs <pod>Container stdout/stderr. Add -f to follow live, --previous to see the last crashed container’s logs.
kubectl exec -it <pod> -- <command>Run a command inside a running container. Useful for debugging network issues or inspecting the filesystem. Does not change the resource spec.
kubectl port-forward <pod-or-svc> <local>:<remote>Tunnel a local port to a Pod or Service. Handy for reaching a service without an Ingress. Stops when you Ctrl-C.
kubectl auth can-i <verb> <resource>Check whether your RBAC role allows a specific action. Add --list to see everything you can do in the current namespace.
kubectl top podLive CPU and memory usage per Pod (requires metrics-server, which is running on Kestrel).
kubectl debug <pod>Attach an ephemeral debug container to a running Pod. Useful when the main container lacks debugging tools. Not purely read-only — it mutates the Pod by adding an ephemeral container, so the debug container is subject to Pod Security Standards (restricted) admission. A debug image that needs root or extra capabilities will be rejected.

Tenants have admin RBAC inside their own namespaces, so mutating kubectl commands are not blocked at the API level. However, three systems interact with every mutation:

  1. ArgoCD selfHeal — if the resource is managed by an ArgoCD Application with selfHeal: true (the recommended default), ArgoCD reverts your change on the next sync (within ~30 seconds of detection, up to ~3 minutes poll interval).
  2. Kyverno admission policies — the cluster enforces Pod Security Standards at the restricted level. Any Pod spec that violates PSS is rejected at admission, whether it comes from kubectl apply or from ArgoCD.
  3. Capsule tenant boundaries — Capsule constrains what resources you can create (no LoadBalancer Services, no wildcard Ingress hostnames, only uber-user-* priority classes, namespaces must be tenant-prefixed). See Known limitations for the full list.

The table below covers each mutating verb with its policy interactions.

Applies a manifest from a file or stdin.

Terminal window
kubectl apply -f deployment.yaml -n <your-tenant>-prod
DimensionDetail
RBACAllowed — tenants have create and update on workload resources in their namespaces.
KyvernoThe manifest must satisfy PSS restricted. Missing securityContext fields (e.g. runAsNonRoot, seccompProfile, drop: [ALL]) cause an admission rejection — not a silent failure.
CapsuleResources must target a tenant-prefixed namespace. Service type must be ClusterIP (not LoadBalancer, NodePort, or ExternalName). Priority class must be one of the three uber-user-* classes.
ArgoCDIf the resource is managed by an Application with selfHeal: true, your applied state is overwritten on the next sync. Use the escape-hatch workflow to apply changes that persist.

Opens a resource in your editor for live modification.

Terminal window
kubectl edit deployment/my-app -n <your-tenant>-prod
DimensionDetail
RBACAllowed — equivalent to get + update.
KyvernoEdits that break PSS are rejected on save. You will see an admission error in your editor.
CapsuleSame constraints as apply — you cannot edit a Service to type LoadBalancer, for example.
ArgoCDReverted on next selfHeal sync. Use the escape-hatch workflow if the edit must persist long enough to test.

Removes a resource from the cluster.

Terminal window
kubectl delete deployment/my-app -n <your-tenant>-prod
DimensionDetail
RBACAllowed — tenants have delete on workload resources.
KyvernoNo admission check on deletes.
CapsuleNo additional constraint beyond namespace scoping.
ArgoCDIf managed with prune: true, ArgoCD recreates the resource from Git on the next sync. If you actually want the resource gone, delete the manifest from your Git repo instead.

Applies a strategic-merge or JSON patch to a resource.

Terminal window
kubectl patch deployment/my-app -n <your-tenant>-prod \
-p '{"spec":{"replicas":3}}'
DimensionDetail
RBACAllowed — equivalent to update.
KyvernoIf the patch changes Pod-template fields, the resulting spec must still satisfy PSS restricted.
CapsuleSame constraints as apply.
ArgoCDReverted on next selfHeal sync.

Adjusts replica count on a Deployment, StatefulSet, or ReplicaSet.

Terminal window
kubectl scale deployment/my-app --replicas=5 -n <your-tenant>-prod
DimensionDetail
RBACAllowed.
KyvernoNo admission check — scaling does not change the Pod template.
CapsuleSubject to namespace quota. If the new replica count exceeds your CPU or memory quota, the new Pods stay Pending.
ArgoCDReverted to the manifest’s replicas value on next selfHeal sync. To scale permanently, update replicas in your Git repo.

Manages rollout state — restart, undo, pause, resume, status.

Terminal window
kubectl rollout restart deployment/my-app -n <your-tenant>-prod
kubectl rollout undo deployment/my-app -n <your-tenant>-prod
DimensionDetail
RBACAllowed.
Kyvernorollout restart adds a restart annotation to the Pod template — no PSS violation. rollout undo reverts to a previous ReplicaSet — the previous spec must still satisfy current Kyverno policies.
CapsuleNo additional constraint.
ArgoCDrollout restart triggers a new rollout, but ArgoCD detects the annotation drift and may revert it on next sync. rollout undo similarly gets overwritten. For a permanent rollback, revert the commit in your Git repo.

Updates the container image on a Deployment or StatefulSet.

Terminal window
kubectl set image deployment/my-app my-app=myimage:v2 -n <your-tenant>-prod
DimensionDetail
RBACAllowed — equivalent to patch on the Pod template.
KyvernoThe new image must not trigger a PSS violation (unlikely unless the new image’s entrypoint changes security-sensitive fields at the container level).
CapsuleNo additional constraint.
ArgoCDReverted on next selfHeal sync. To change the image permanently, update the manifest in your Git repo.

The following commands require cluster-scoped permissions that tenants do not have:

CommandWhy it is blocked
kubectl drain <node>Drains workloads from a node — a cluster-wide operation that affects all tenants.
kubectl cordon <node>Marks a node as unschedulable — cluster-wide effect.
kubectl taint <node>Modifies node scheduling constraints — cluster-wide effect.

If you need a node drained or cordoned (e.g. for maintenance of a node running your workload), open a ticket with RCS.

When you need to make a temporary kubectl mutation that survives long enough to test — without ArgoCD reverting it within seconds — use this workflow:

In the ArgoCD UI, open your Application and click the three-dot menuDisable Auto-Sync. This stops ArgoCD from polling your Git repo and reverting drift.

Alternatively, patch the Application directly:

Terminal window
kubectl patch application/<your-tenant>-my-service -n argo-cd \
--type merge \
-p '{"spec":{"syncPolicy":{"automated":null}}}'

Now your kubectl changes stick until you re-enable auto-sync:

Terminal window
kubectl apply -f experimental-deployment.yaml -n <your-tenant>-prod
# or
kubectl scale deployment/my-app --replicas=5 -n <your-tenant>-prod
# or
kubectl set image deployment/my-app my-app=myimage:v2-beta -n <your-tenant>-prod

Test whatever you needed to test. The mutation persists because ArgoCD is paused.

You have two exit paths:

Revert — re-enable auto-sync and ArgoCD reverts the cluster to match Git:

Terminal window
kubectl patch application/<your-tenant>-my-service -n argo-cd \
--type merge \
-p '{"spec":{"syncPolicy":{"automated":{"prune":true,"selfHeal":true}}}}'

Or click Enable Auto-Sync in the ArgoCD UI.

Capture — if the experiment worked and you want to keep it, commit the new state to your Git repo first, then re-enable auto-sync. ArgoCD syncs and sees no drift because Git now matches the cluster.

Whichever exit path you took, confirm auto-sync is back on. Check the Application in the ArgoCD UI — it should show Synced and Auto-Sync: Enabled.