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.
Read-only commands (always safe)
Section titled “Read-only commands (always safe)”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.
| Command | What 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 pod | Live 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. |
Mutating commands
Section titled “Mutating commands”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:
- ArgoCD
selfHeal— if the resource is managed by an ArgoCD Application withselfHeal: true(the recommended default), ArgoCD reverts your change on the next sync (within ~30 seconds of detection, up to ~3 minutes poll interval). - Kyverno admission policies — the cluster enforces Pod Security Standards at the
restrictedlevel. Any Pod spec that violates PSS is rejected at admission, whether it comes fromkubectl applyor from ArgoCD. - Capsule tenant boundaries — Capsule constrains what resources you can create (no
LoadBalancerServices, no wildcard Ingress hostnames, onlyuber-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.
Per-verb breakdown
Section titled “Per-verb breakdown”kubectl apply
Section titled “kubectl apply”Applies a manifest from a file or stdin.
kubectl apply -f deployment.yaml -n <your-tenant>-prod| Dimension | Detail |
|---|---|
| RBAC | Allowed — tenants have create and update on workload resources in their namespaces. |
| Kyverno | The manifest must satisfy PSS restricted. Missing securityContext fields (e.g. runAsNonRoot, seccompProfile, drop: [ALL]) cause an admission rejection — not a silent failure. |
| Capsule | Resources 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. |
| ArgoCD | If 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. |
kubectl edit
Section titled “kubectl edit”Opens a resource in your editor for live modification.
kubectl edit deployment/my-app -n <your-tenant>-prod| Dimension | Detail |
|---|---|
| RBAC | Allowed — equivalent to get + update. |
| Kyverno | Edits that break PSS are rejected on save. You will see an admission error in your editor. |
| Capsule | Same constraints as apply — you cannot edit a Service to type LoadBalancer, for example. |
| ArgoCD | Reverted on next selfHeal sync. Use the escape-hatch workflow if the edit must persist long enough to test. |
kubectl delete
Section titled “kubectl delete”Removes a resource from the cluster.
kubectl delete deployment/my-app -n <your-tenant>-prod| Dimension | Detail |
|---|---|
| RBAC | Allowed — tenants have delete on workload resources. |
| Kyverno | No admission check on deletes. |
| Capsule | No additional constraint beyond namespace scoping. |
| ArgoCD | If 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. |
kubectl patch
Section titled “kubectl patch”Applies a strategic-merge or JSON patch to a resource.
kubectl patch deployment/my-app -n <your-tenant>-prod \ -p '{"spec":{"replicas":3}}'| Dimension | Detail |
|---|---|
| RBAC | Allowed — equivalent to update. |
| Kyverno | If the patch changes Pod-template fields, the resulting spec must still satisfy PSS restricted. |
| Capsule | Same constraints as apply. |
| ArgoCD | Reverted on next selfHeal sync. |
kubectl scale
Section titled “kubectl scale”Adjusts replica count on a Deployment, StatefulSet, or ReplicaSet.
kubectl scale deployment/my-app --replicas=5 -n <your-tenant>-prod| Dimension | Detail |
|---|---|
| RBAC | Allowed. |
| Kyverno | No admission check — scaling does not change the Pod template. |
| Capsule | Subject to namespace quota. If the new replica count exceeds your CPU or memory quota, the new Pods stay Pending. |
| ArgoCD | Reverted to the manifest’s replicas value on next selfHeal sync. To scale permanently, update replicas in your Git repo. |
kubectl rollout
Section titled “kubectl rollout”Manages rollout state — restart, undo, pause, resume, status.
kubectl rollout restart deployment/my-app -n <your-tenant>-prodkubectl rollout undo deployment/my-app -n <your-tenant>-prod| Dimension | Detail |
|---|---|
| RBAC | Allowed. |
| Kyverno | rollout 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. |
| Capsule | No additional constraint. |
| ArgoCD | rollout 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. |
kubectl set image
Section titled “kubectl set image”Updates the container image on a Deployment or StatefulSet.
kubectl set image deployment/my-app my-app=myimage:v2 -n <your-tenant>-prod| Dimension | Detail |
|---|---|
| RBAC | Allowed — equivalent to patch on the Pod template. |
| Kyverno | The new image must not trigger a PSS violation (unlikely unless the new image’s entrypoint changes security-sensitive fields at the container level). |
| Capsule | No additional constraint. |
| ArgoCD | Reverted on next selfHeal sync. To change the image permanently, update the manifest in your Git repo. |
Platform-admin-only verbs
Section titled “Platform-admin-only verbs”The following commands require cluster-scoped permissions that tenants do not have:
| Command | Why 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.
Escape hatch
Section titled “Escape hatch”When you need to make a temporary kubectl mutation that survives long enough to test — without ArgoCD reverting it within seconds — use this workflow:
1. Pause the ArgoCD Application
Section titled “1. Pause the ArgoCD Application”In the ArgoCD UI, open your Application and click the three-dot menu → Disable Auto-Sync. This stops ArgoCD from polling your Git repo and reverting drift.
Alternatively, patch the Application directly:
kubectl patch application/<your-tenant>-my-service -n argo-cd \ --type merge \ -p '{"spec":{"syncPolicy":{"automated":null}}}'2. Make your mutation
Section titled “2. Make your mutation”Now your kubectl changes stick until you re-enable auto-sync:
kubectl apply -f experimental-deployment.yaml -n <your-tenant>-prod# orkubectl scale deployment/my-app --replicas=5 -n <your-tenant>-prod# orkubectl set image deployment/my-app my-app=myimage:v2-beta -n <your-tenant>-prod3. Verify
Section titled “3. Verify”Test whatever you needed to test. The mutation persists because ArgoCD is paused.
4. Revert or capture
Section titled “4. Revert or capture”You have two exit paths:
Revert — re-enable auto-sync and ArgoCD reverts the cluster to match Git:
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.
5. Unpause
Section titled “5. Unpause”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.