OpenShift Administrator (EX280) - Fact Sheet¶
Quick Reference¶
Exam Code: EX280 Duration: 3 hours Format: Performance-based hands-on tasks on a live OpenShift 4.x cluster Passing Score: 210/300 (70%) Cost: $500 USD Validity: 3 years Open documentation: oc explain, web console, cluster resources
π Official EX280 page π OpenShift 4.14 Documentation π Latest OpenShift Docs
Cluster components¶
| Component | Purpose |
|---|---|
| Control plane (master) nodes | etcd, kube-apiserver, kube-controller-manager, kube-scheduler, OpenShift API |
| Compute (worker) nodes | Run user workloads |
| Infrastructure nodes | Optional dedicated nodes for routers, registry, monitoring |
| etcd | Cluster state store |
| CRI-O | Container runtime |
| OVN-Kubernetes | Default SDN (replaces older OpenShift SDN) |
| HAProxy router | Default ingress for Routes |
| Image registry | OpenShift internal image registry |
| Operator Lifecycle Manager (OLM) | Manages operator installations |
| Cluster Monitoring Operator | Prometheus + Alertmanager + Grafana |
High-yield oc commands¶
Cluster info¶
oc whoami # current user
oc whoami --show-server # API endpoint
oc whoami --show-token # token (sensitive)
oc cluster-info
oc get clusterversion # current version
oc get nodes
oc get nodes -L node-role.kubernetes.io/worker
oc describe node <name>
oc get co # cluster operators
oc get clusteroperators -o wide
oc adm top nodes # resource usage
oc adm top pods -A
Projects (namespaces)¶
oc projects # list
oc project myproject # switch
oc new-project myapp --description='...' --display-name='My App'
oc delete project myapp
Workloads¶
oc new-app https://github.com/user/repo --name=myapp
oc new-app docker.io/nginx --name=web
oc get all
oc get deployments
oc scale deploy/web --replicas=3
oc rollout status deploy/web
oc rollout undo deploy/web
oc set image deploy/web web=nginx:1.25
oc set env deploy/web FOO=bar
oc set resources deploy/web --limits=cpu=500m,memory=512Mi --requests=cpu=100m,memory=128Mi
oc autoscale deploy/web --min=2 --max=10 --cpu-percent=70
Pods and debugging¶
oc get pods
oc get pods -o wide
oc describe pod <name>
oc logs <pod>
oc logs -f <pod> # follow
oc logs <pod> -c <container> # specific container
oc rsh <pod> # shell into pod
oc exec <pod> -- <command>
oc debug node/<nodename> # debug pod on a node
oc debug deploy/web # debug a deployment
oc port-forward pod/<pod> 8080:80 # forward
Services and routes¶
oc expose deploy/web --port=80 # creates Service
oc expose svc/web # creates Route
oc expose svc/web --hostname=app.example.com
oc create route edge --service=web --hostname=app.example.com # TLS-terminated edge route
oc create route passthrough --service=web # TLS passthrough
oc create route reencrypt --service=web # TLS reencrypt
oc get routes
oc get svc
Storage¶
oc get pv
oc get pvc
oc set volume deploy/web --add --type=pvc --claim-size=1Gi --mount-path=/data
oc set volume deploy/web --remove --name=<volname>
oc get storageclass
oc get sc # alias
Authentication and RBAC¶
oc adm policy add-cluster-role-to-user cluster-admin alice
oc adm policy add-role-to-user admin alice -n myproject
oc adm policy remove-role-from-user admin alice -n myproject
oc get clusterrolebinding | grep alice
oc auth can-i create pods --as=alice -n myproject
oc adm policy who-can create pods -n myproject
Secrets and ConfigMaps¶
oc create secret generic mysecret --from-literal=password=s3cr3t
oc create secret generic mysecret --from-file=./creds.txt
oc create secret docker-registry myreg --docker-server=... --docker-username=... --docker-password=...
oc create secret tls mytls --cert=cert.pem --key=key.pem
oc create configmap myconfig --from-literal=KEY=value
oc create configmap myconfig --from-file=./app.conf
oc set env deploy/web --from=configmap/myconfig
oc set volume deploy/web --add --type=configmap --configmap-name=myconfig --mount-path=/etc/app
Operators¶
oc get csv -A # ClusterServiceVersions
oc get subscription -A
oc get installplan -A
oc get operatorgroup
Must-gather (for support / debug)¶
oc adm must-gather # cluster-wide diagnostic
oc adm must-gather --image=registry.redhat.io/<image> # operator-specific
Resource shapes you should be able to write¶
Deployment¶
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: myproject
spec:
replicas: 3
selector:
matchLabels: { app: web }
template:
metadata:
labels: { app: web }
spec:
containers:
- name: web
image: nginx
resources:
requests: { cpu: 100m, memory: 128Mi }
limits: { cpu: 500m, memory: 512Mi }
ports:
- containerPort: 80
Service¶
apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector: { app: web }
ports:
- port: 80
targetPort: 80
Route¶
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: web
spec:
host: app.example.com
to: { kind: Service, name: web }
tls:
termination: edge # edge | passthrough | reencrypt
insecureEdgeTerminationPolicy: Redirect
PersistentVolumeClaim¶
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data
spec:
accessModes: [ReadWriteOnce]
resources:
requests: { storage: 5Gi }
storageClassName: gp3-csi
ResourceQuota¶
apiVersion: v1
kind: ResourceQuota
metadata:
name: project-quota
spec:
hard:
requests.cpu: '4'
requests.memory: 8Gi
limits.cpu: '8'
limits.memory: 16Gi
persistentvolumeclaims: '10'
pods: '20'
LimitRange (default per-container limits)¶
apiVersion: v1
kind: LimitRange
metadata:
name: project-limits
spec:
limits:
- type: Container
default: # if not set on container
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 128Mi
max:
cpu: '2'
memory: 4Gi
NetworkPolicy¶
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-frontend
spec:
podSelector:
matchLabels: { app: backend }
policyTypes: [Ingress]
ingress:
- from:
- podSelector:
matchLabels: { app: frontend }
ports:
- protocol: TCP
port: 8080
Role + RoleBinding¶
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: myproject
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: alice-pod-reader
namespace: myproject
subjects:
- kind: User
name: alice
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
Subscription (install operator)¶
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: openshift-pipelines-operator
namespace: openshift-operators
spec:
channel: latest
name: openshift-pipelines-operator-rh
source: redhat-operators
sourceNamespace: openshift-marketplace
installPlanApproval: Automatic
Identity providers¶
OpenShift supports multiple identity providers configured via the cluster OAuth resource. Common ones:
- HTPasswd - flat-file user/password (common on the exam)
- LDAP - directory service
- GitHub / GitLab / Google - OAuth integrations
- OpenID Connect - OIDC providers (Keycloak, Okta, etc.)
HTPasswd configuration¶
htpasswd -c -B -b users.htpasswd alice secret
htpasswd -B -b users.htpasswd bob secret2
oc create secret generic htpass-secret \
--from-file=htpasswd=users.htpasswd \
-n openshift-config
oc edit oauth cluster
In the OAuth resource:
spec:
identityProviders:
- name: my_htpasswd
mappingMethod: claim
type: HTPasswd
htpasswd:
fileData:
name: htpass-secret
After save, the cluster reconfigures the OAuth pods. Wait ~30s, then oc login -u alice -p secret.
Security Context Constraints (SCCs)¶
SCCs are OpenShift's mechanism for controlling which pod security features are allowed. Built-in SCCs (most to least restrictive):
| SCC | Notes |
|---|---|
restricted-v2 | Default for non-privileged pods. Most secure. |
restricted | Older default. |
nonroot-v2 | Allows nonroot UIDs |
anyuid | Allows any UID (often needed for legacy images) |
hostnetwork | Use host network |
hostmount-anyuid | Mount host paths |
privileged | Almost no restrictions |
Grant SCC¶
oc adm policy add-scc-to-user anyuid -z <serviceaccount> -n <namespace>
oc adm policy add-scc-to-group privileged system:serviceaccounts:<namespace>
A pod failing with "unable to validate against any security context constraint" is the canonical SCC error.
Storage classes (common)¶
| Cloud | Default StorageClass | Type |
|---|---|---|
| ROSA on AWS | gp3-csi | EBS gp3 |
| ARO on Azure | managed-csi | Azure Disk |
| OpenShift on VMware | thin-csi | VMware vSphere |
| OpenShift on bare metal | varies (LVM Operator, ODF, NFS) | many |
Access modes:
ReadWriteOnce (RWO)- one node mountReadOnlyMany (ROX)- many nodes ROReadWriteMany (RWX)- many nodes RW (requires NFS or similar)ReadWriteOncePod (RWOP)- single podReadWriteManyPod- newer
Monitoring¶
OpenShift ships a Prometheus-based monitoring stack in the openshift-monitoring namespace.
oc -n openshift-monitoring get pods
oc -n openshift-monitoring get routes prometheus-k8s
oc -n openshift-monitoring get routes alertmanager-main
User-defined monitoring (workload metrics) requires enabling:
oc -n openshift-monitoring edit cm cluster-monitoring-config
# Set:
# data:
# config.yaml: |
# enableUserWorkload: true
Common exam triggers¶
- "Allow user alice to admin namespace foo" β
oc adm policy add-role-to-user admin alice -n foo - "Pod can't run because of UID" β SCC issue; grant
anyuidto the SA, or change image to nonroot - "Expose deployment to public DNS name" β
oc expose svc/X --hostname=...(oroc create route edge) - "Limit project to 4 CPUs" β ResourceQuota
- "Default request/limit per container in project" β LimitRange
- "Restrict pod-to-pod traffic" β NetworkPolicy
- "Install operator" β Subscription via OperatorHub or YAML
- "Persistent storage for app" β PVC with appropriate storageClass and accessModes
- "Different ingress termination types" β Edge / Passthrough / Reencrypt
- "Add HTPasswd users" β htpasswd file β secret β OAuth resource
Things candidates commonly forget¶
- After editing
OAuthfor an identity provider, wait 30s for the OAuth pods to roll. Thenoc loginworks. oc expose svccreates a Route by default. To get an Ingress, useoc create -fwith an Ingress YAML.oc adm policy add-scc-to-userrequires-z <sa>for service accounts (not just usernames).- Routes default to HTTP. Use
oc create route edgefor TLS-terminated. oc edit deploy/webopens an in-place editor. Save and exit applies. Useoc apply -f file.yamlfor repeatable changes.oc rollout restart deploy/webis the modern way to restart pods (better thandelete pod).- After changing a ConfigMap or Secret used as env vars, the deployment doesn't auto-reload - use
oc rollout restart.
After-pass next steps¶
| Cert | Why |
|---|---|
| EX288 - OpenShift Application Development | Dev counterpart |
| EX316 - OpenShift Virtualization | VMs on OpenShift |
| EX480 - Advanced Cluster Management | Multi-cluster fleet |
| CKA | Vendor-neutral parallel |
| CKS | Kubernetes security specialist |