The oc set, grouped by what you are trying to find out. Every kubectl command works here too — these are the ones that only exist on OpenShift, or that answer an OpenShift question faster.
A Project is a namespace with a template and a lifecycle. oc project switches the active one, which is what most resource not found
confusion comes down to — you are looking in the wrong namespace.
| Command | What it does | Typical use |
|---|---|---|
| oc login -u user --server=URL | Authenticate; writes context into ~/.kube/config | oc login -u kubeadmin --server=https://api.ocp.example.com:6443 |
| oc login --token=... | Log in with a token rather than a password | oc login --token=sha256~xxx --server=https://api.ocp:6443 |
| oc whoami | Which identity is this context using | oc whoami |
| oc whoami -t | Print the current token — for curl against the API | TOKEN=$(oc whoami -t) |
| oc whoami --show-console | The web console URL for this cluster | oc whoami --show-console |
| oc whoami --show-server | The API endpoint you are actually talking to | oc whoami --show-server |
| oc project | Which project is active right now | oc project |
| oc project <name> | Switch the active project | oc project prod |
| oc projects | Every project you can see — never leaks ones you cannot | oc projects |
| oc new-project | Create a project THROUGH the template, with its quota and policy | oc new-project prod --description='Production' |
| oc delete project | Delete a project and everything in it, PVCs included | oc delete project scratch |
| oc status | A readable summary of what is running in this project | oc status -n prod |
| oc config get-contexts | Every cluster/user/namespace combination you have | oc config get-contexts |
| oc config use-context | Switch clusters without logging in again | oc config use-context prod/api-ocp:6443/admin |
S2I builds an image from source without a Dockerfile. An ImageStream is a pointer with history — which is what gives you a rollback target and a redeploy trigger.
| Command | What it does | Typical use |
|---|---|---|
| oc new-app | Create a full application from source, image or template | oc new-app python:3.11~https://github.com/org/app.git |
| oc new-app --name=x --image= | From an existing image rather than source | oc new-app --name=api --image=quay.io/org/api:v2 |
| oc new-app --dry-run -o yaml | See what it WOULD create before it creates it | oc new-app nginx --dry-run -o yaml |
| oc new-app -e KEY=value | Set environment variables at creation | oc new-app mysql -e MYSQL_ROOT_PASSWORD=x |
| oc new-build | A BuildConfig without deploying it | oc new-build --binary --name=api -l app=api |
| oc start-build | Run a build now | oc start-build api |
| oc start-build --from-dir=. --follow | Binary build from a local directory, streaming logs | oc start-build api --from-dir=. --follow |
| oc start-build --from-file= | Build from a single local file | oc start-build api --from-file=app.jar |
| oc logs -f bc/<name> | Follow the latest build's logs | oc logs -f bc/api |
| oc cancel-build | Stop a running build | oc cancel-build api-7 |
| oc get bc,builds | BuildConfigs and the builds they produced | oc get bc,builds -n prod |
| oc get is | Image streams and the tags they expose | oc get is -n prod |
| oc describe is | Tag history — every digest this tag has pointed at | oc describe is/api |
| oc tag src:tag dst:tag | Move or copy a tag; this is how you promote a build | oc tag api:latest api:prod |
| oc tag --scheduled | Re-check an external image periodically. Without it, imported once, never again | oc tag quay.io/org/api:latest api:latest --scheduled |
| oc import-image --confirm | Force an import check right now | oc import-image api:latest --confirm |
| oc rollout latest | Trigger a new deployment from the current image | oc rollout latest deploy/api |
| oc rollout undo | Roll back to the previous revision | oc rollout undo deploy/api |
| oc rollout status | Block until the rollout finishes or fails | oc rollout status deploy/api --timeout=5m |
| oc set image | Change a container image in place | oc set image deploy/api api=quay.io/org/api:v3 |
| oc set env | Add, change or list environment variables | oc set env deploy/api LOG_LEVEL=debug |
| oc set env --from=secret/x | Inject a whole secret as environment variables | oc set env deploy/api --from=secret/db-creds |
A Route is OpenShift's ingress object. Admitted=False is the single most useful field on one — an unadmitted route returns 503 from the router and looks exactly like a broken backend.
| Command | What it does | Typical use |
|---|---|---|
| oc expose svc | Create a Route for a Service | oc expose svc/api |
| oc expose svc --hostname= | Route with a specific host | oc expose svc/api --hostname=api.example.com |
| oc create route edge | TLS terminated at the router, HTTP to the pod | oc create route edge api --service=api |
| oc create route passthrough | Router forwards bytes; the pod terminates TLS | oc create route passthrough api --service=api |
| oc create route reencrypt | Terminate, then re-encrypt to the pod | oc create route reencrypt api --service=api --dest-ca-cert=ca.crt |
| oc get route | Every route and the host it claims | oc get route -n prod |
| oc get route -o jsonpath status | Whether the router admitted it — check this before anything else | oc get route api -o jsonpath='{.status.ingress[*].conditions[*].reason}' |
| oc annotate route timeout | Per-route backend timeout | oc annotate route api haproxy.router.openshift.io/timeout=60s |
| oc annotate route rate-limit | Per-route connection limiting | oc annotate route api haproxy.router.openshift.io/rate-limit-connections=true |
| oc set route-backends | Weighted backends — canary splits at the router | oc set route-backends api api=90 api-next=10 |
| oc -n openshift-ingress get pods | Where the routers actually run | oc -n openshift-ingress get pods -o wide |
| oc -n openshift-ingress rsh ... haproxy.config | What the router configured for real | oc -n openshift-ingress rsh deploy/router-default cat haproxy.config |
SCC decides what a POD may ask for; RBAC decides what a USER may do. Both refuse in writing, and the wording tells you which one it was.
| Command | What it does | Typical use |
|---|---|---|
| oc get scc | Every constraint on the cluster, and what it permits | oc get scc |
| oc describe scc restricted-v2 | The default: no root, dropped capabilities, random UID | oc describe scc restricted-v2 |
| oc get pod -o jsonpath scc | Which SCC actually admitted this pod | oc get pod api-7d9f -o jsonpath='{.metadata.annotations.openshift\.io/scc}' |
| oc adm policy scc-subject-review | Which SCC WOULD admit this workload — before granting anything | oc adm policy scc-subject-review -z api-sa -f deploy.yaml |
| oc adm policy scc-review | Which service accounts could run this pod spec | oc adm policy scc-review -f deploy.yaml |
| oc adm policy add-scc-to-user | Grant an SCC. Prefer a custom SCC over anyuid | oc adm policy add-scc-to-user anyuid -z build-sa |
| oc adm policy remove-scc-from-user | Take it away again | oc adm policy remove-scc-from-user anyuid -z build-sa |
| oc auth can-i | Can this identity do this, resolved rather than guessed | oc auth can-i create deploy -n prod --as=jane |
| oc auth can-i --list | Everything an identity can do in a namespace | oc auth can-i --list -n prod --as=jane |
| oc auth can-i --as=system:serviceaccount: | The service-account form, where this usually bites | oc auth can-i list secrets --as=system:serviceaccount:prod:api-sa |
| oc adm policy who-can | The reverse question — who can do this? | oc adm policy who-can delete pods -n prod |
| oc adm policy add-role-to-user | Grant a namespace role | oc adm policy add-role-to-user edit jane -n prod |
| oc adm policy add-cluster-role-to-user | Grant a cluster role | oc adm policy add-cluster-role-to-user cluster-reader auditor |
| oc adm groups new | Create a group to bind roles to, rather than to users | oc adm groups new platform-team jane bob |
| oc adm policy remove-cluster-role-from-group | Stop everyone self-provisioning projects | oc adm policy remove-cluster-role-from-group self-provisioner system:authenticated:oauth |
The ownership chain is ClusterVersion → ClusterOperator → the operator's workload. Start at the top: a degraded cluster operator names its own problem in a way a pod list never will.
| Command | What it does | Typical use |
|---|---|---|
| oc get clusteroperators | The first command of any OpenShift incident | oc get co |
| oc get co | grep -v 'True.*False.*False' | Only the unhealthy ones | oc get co | grep -v 'True.*False.*False' |
| oc describe co <name> | The Degraded condition names the failing resource | oc describe co/ingress |
| oc get clusterversion | Current version, and what an upgrade is waiting on | oc get clusterversion |
| oc adm upgrade | Which versions are actually on offer | oc adm upgrade |
| oc adm upgrade --to= | Start an upgrade to a specific version | oc adm upgrade --to=4.16.11 |
| oc adm upgrade channel | Change the update channel | oc adm upgrade channel stable-4.16 |
| oc get clusterversion Upgradeable | The cluster's own opinion, before you start | oc get clusterversion -o jsonpath='{.items[0].status.conditions[?(@.type=="Upgradeable")].message}' |
| oc get apirequestcount | Who is still calling a deprecated API | oc get apirequestcount | grep -v ' 0 ' |
| oc get mcp | Whether node config is mid-rollout or wedged | oc get mcp |
| oc get machineconfig | Every node-level config object | oc get mc |
| oc get nodes -o wide | Node state, roles, kernel and runtime versions | oc get nodes -o wide |
| oc adm top nodes | Actual node CPU and memory pressure | oc adm top nodes |
| oc adm cordon / uncordon | Stop or resume scheduling on a node | oc adm cordon worker-04 |
| oc adm drain | Evict everything, respecting PodDisruptionBudgets | oc adm drain worker-04 --ignore-daemonsets --delete-emptydir-data |
| oc get pdb -A | The budget that will block the next drain | oc get pdb -A |
| oc get subscription,installplan,csv -A | OLM operator state, end to end | oc get sub,ip,csv -A |
| oc get installplan -A | The unapproved plan keeping an operator on an old version | oc get installplan -A |
must-gather is the supported dump. Scope it when you already know the area — the full collection runs to several GB and 15+ minutes.
| Command | What it does | Typical use |
|---|---|---|
| oc adm must-gather | The full supported cluster dump | oc adm must-gather --dest-dir=./mg |
| oc adm must-gather -- gather_network_logs | Network only, in a fraction of the time | oc adm must-gather --dest-dir=./mg -- /usr/bin/gather_network_logs |
| oc adm must-gather -- gather_audit_logs | API audit logs only | oc adm must-gather -- /usr/bin/gather_audit_logs |
| oc adm must-gather --image= | One operator's deep state instead of everything | oc adm must-gather --image=registry.redhat.io/openshift-logging/cluster-logging-rhel9-operator:latest |
| oc adm inspect | Everything about one namespace or resource, structured | oc adm inspect ns/openshift-ingress |
| oc debug node/<node> | A root shell on a node without SSH | oc debug node/worker-04 |
| oc debug node/ -- chroot /host | Run a host command directly | oc debug node/worker-04 -- chroot /host journalctl -u kubelet -n 200 |
| oc debug deploy/<name> | A copy of the pod with the entrypoint replaced by a shell | oc debug deploy/api |
| oc debug --as-root | Debug pod as root, when the SCC allows it | oc debug deploy/api --as-root |
| oc adm node-logs --role=master | Journal or file logs from every master | oc adm node-logs --role=master -u kubelet |
| oc adm node-logs --path= | Read a log file off the node, e.g. the audit log | oc adm node-logs --role=master --path=kube-apiserver/audit.log |
| oc get events -A --sort-by= | What the cluster just complained about. Expires in an hour | oc get events -A --sort-by=.lastTimestamp | tail -40 |
| oc logs -f --tail=100 | Follow a pod's logs | oc logs -f deploy/api --tail=100 |
| oc logs -p | The PREVIOUS container — what a CrashLoop actually said | oc logs -p api-7d9f |
| oc rsh | Shell into a running container | oc rsh deploy/api |
| oc port-forward | Reach a pod's port locally without a Route | oc port-forward svc/api 8080:8080 |
| oc cp | Copy a file in or out of a container | oc cp api-7d9f:/tmp/heap.hprof ./heap.hprof |
| oc rsync | Sync a directory in or out | oc rsync ./config api-7d9f:/etc/app/ |
A Pending PVC is either waiting for a consumer, which is correct, or the backend refused — and only describe tells you which.
| Command | What it does | Typical use |
|---|---|---|
| oc get pvc -A --field-selector | Every stuck claim on the cluster | oc get pvc -A --field-selector=status.phase=Pending |
| oc describe pvc | The provisioner's own error message | oc describe pvc data-0 |
| oc get sc | Binding mode, reclaim policy and expansion — check before committing | oc get sc -o custom-columns=NAME:.metadata.name,BIND:.volumeBindingMode,RECLAIM:.reclaimPolicy |
| oc get pv | grep Released | Retained volumes still holding data, waiting to be rebound | oc get pv | grep Released |
| oc get volumeattachment | Whether a volume is attached, and to which node | oc get volumeattachment |
| oc set volume deploy/x --add | Attach a new volume to a workload | oc set volume deploy/api --add --name=data --claim-name=data-0 --mount-path=/data |
| oc set volume deploy/x | What is mounted where, in one line per volume | oc set volume deploy/api |
| oc get quota,limitrange | The project's ceilings — a common cause of Pending | oc get quota,limitrange -n prod |
| oc describe quota | Used versus hard, per resource | oc describe quota -n prod |
| oc adm top pods | Live CPU and memory per pod | oc adm top pods -n prod --sort-by=memory |