Advanced Deployment Workshop: Setup Requirements
This page is for the instructor or cluster administrator who prepares the lab. It lists everything the exercises rely on, derived from the commands and manifests in the modules. It has two audiences: the administrator preparing the cluster (cluster, operators, accounts and roles, image access), and each attendee preparing a workstation (CLI tools). The Verification Checklist at the end lets both confirm the environment is ready before the workshop starts.
Only Module 2 (Exercises) and Module 3 (Exercises) have hands-on steps. Module 1 and Module 4 are reading content; their commands are examples, and the Module 4 commands (oc debug node/…, oc get kubeletconfig, mirror sets, Image Puller) need cluster administrator privileges, as does reading the scheduler logs in the Module 2 (content) troubleshooting example.
Cluster
-
OpenShift version: OpenShift 4.16 or later (Kubernetes 1.29 or later). The content was last tested on OpenShift 4.22.16.
-
Nodes: at least two schedulable worker nodes; three is better. The content was tested on a two-node cluster.
-
Module 2, Exercise 2 (taints): the instructor taints one node. While it is tainted, every attendee’s new pods must fit on the remaining nodes.
-
Module 2, Exercises 3 and 4 (pod anti-affinity, topology spread): with one node, all replicas land on it and there is nothing to observe. The Module 2 text describes a three-node 2-2-2 spread.
-
Module 3, Exercise 3 (Descheduler): the descheduler needs at least two ready nodes. On a single-node cluster it skips every cycle and evicts nothing.
-
Single-node OpenShift is therefore not suitable. A compact three-node cluster with schedulable control-plane nodes also works. On clusters with tainted control-plane nodes, Exercise 4 uses
nodeTaintsPolicy: Honorso that those nodes do not count in the spread.
-
-
CPU architecture: x86_64 (
amd64) worker nodes, and at least one with AVX. Module 2, Exercise 1 requireskubernetes.io/arch=amd64, and Exercise 5 requiresfeature.node.kubernetes.io/cpu-cpuid.AVX=true; on other nodes those pods stayPending. -
Capacity: the exercises' resource requests peak at about 0.75 vCPU and 0.9 GiB of memory per attendee (Module 2, Exercise 6), plus up to ten small NGINX pods without requests (Module 2, Exercise 4). Size worker nodes for that times the number of attendees, on top of the platform’s own usage.
-
Pod slots: each attendee runs up to about 11 pods at once (Module 2, Exercise 4 scales to 10 replicas). Every node has a pod limit (
maxPods, 250 by default), and the operators below add about 10 pods of their own. Check the free slots before the workshop: allow about 11 per attendee plus 10 for the operators. A node that runs out of pod slots leaves new podsPending, including platform pods.oc get nodes \ -o custom-columns=NODE:.metadata.name,MAXPODS:.status.allocatable.podsoc get pods -A \ --field-selector=status.phase=Running \ -o custom-columns=NODE:.spec.nodeName \ --no-headers | sort | uniq -c -
Metrics API (
metrics.k8s.io):oc adm top nodes(Module 2, Exercise 6) and the CPU-based Horizontal Pod Autoscaler (Module 3, Exercise 1) read resource metrics. OpenShift’s built-in platform monitoring provides this API; do not disable it. User workload monitoring is not needed: no exercise uses custom or external metrics. -
No restrictive quotas: do not put a
ResourceQuotaor aLimitRangewith maximums on attendee projects. Module 2, Exercise 6, Step 4 creates a pod that requests 1000 CPUs and 1000Gi and expects it to stayPending; a quota or limit range rejects it at creation instead.
Operators and Cluster Components
| Component | Install source | Namespace | Configuration needed | Used by |
|---|---|---|---|---|
Kube Descheduler Operator |
OperatorHub, Red Hat catalog ( |
|
Create a |
Module 3, Exercise 3 (required) |
Vertical Pod Autoscaler Operator |
OperatorHub, Red Hat catalog ( |
|
None beyond the install; the operator runs the recommender, updater and admission controller. The install also adds VPA permissions to the default project |
Module 3, Exercise 2 (required) |
Node Feature Discovery Operator |
OperatorHub, Red Hat catalog ( |
|
Create a |
Module 2, Exercise 5 (required) |
Metrics API (platform monitoring) |
Built in |
|
None; must stay enabled. |
Module 2, Exercise 6; Module 3, Exercise 1 |
Secondary Scheduler Operator |
OperatorHub, Red Hat catalog ( |
|
Optional. Module 2, Exercise 7 works without it: the pod that names |
Module 1 (reading); Module 2, Exercise 7 Step 1 (instructor demo) |
Kubernetes Image Puller Operator |
OperatorHub, community catalog ( |
|
Optional; no attendee step uses it. Install only to demonstrate the Module 4 |
Module 4 (reading, instructor demo) |
Installing the operators
Each of the three required operators installs into its own namespace with an OperatorGroup that targets only that namespace (OwnNamespace install mode). Install them from OperatorHub in the web console, or from the CLI by creating the namespace, operator group and subscription for each one:
for op in \
openshift-kube-descheduler-operator:cluster-kube-descheduler-operator \
openshift-vertical-pod-autoscaler:vertical-pod-autoscaler \
openshift-nfd:nfd
do
ns=${op%%:*}
pkg=${op##*:}
cat <<EOF | oc apply -f -
apiVersion: v1
kind: Namespace
metadata:
name: ${ns}
---
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
name: ${ns}
namespace: ${ns}
spec:
targetNamespaces:
- ${ns}
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: ${pkg}
namespace: ${ns}
spec:
channel: stable
name: ${pkg}
source: redhat-operators
sourceNamespace: openshift-marketplace
EOF
done
Wait until each operator’s CSV shows Succeeded (see the Verification Checklist), then create the NodeFeatureDiscovery instance and the KubeDescheduler below.
To create the NodeFeatureDiscovery instance from the CLI, apply the default example that the NFD operator ships in its CSV (the same one OperatorHub shows):
oc get csv \
-n openshift-nfd \
-o json |
jq '.items[]
| select(.metadata.name | startswith("nfd"))
| .metadata.annotations["alm-examples"]
| fromjson
| .[]
| select(.kind == "NodeFeatureDiscovery")' |
oc apply \
-n openshift-nfd \
-f -
The nodes get their feature.node.kubernetes.io/… labels within about two minutes.
Descheduler configuration
The Module 3 exercise reads kubedescheduler/cluster in openshift-kube-descheduler-operator (profiles, deschedulingIntervalSeconds, mode, evictionLimits), so the object must exist. The Step 7 example of that exercise is a working starting point (without its do-not-deploy annotation, which only marks the example):
cat <<'EOF' | oc apply -f -
apiVersion: operator.openshift.io/v1
kind: KubeDescheduler
metadata:
name: cluster
namespace: openshift-kube-descheduler-operator
spec:
managementState: Managed
deschedulingIntervalSeconds: 3600
profiles:
- AffinityAndTaints
- TopologyAndDuplicates
mode: Automatic
evictionLimits:
total: 10
node: 5
EOF
Use mode: Automatic if attendees should see eviction events in Module 3, Exercise 3, Step 6; with Predictive the descheduler only logs what it would evict. In Automatic mode with AffinityAndTaints, a descheduling cycle that runs while a node carries the Module 2 taint evicts attendee pods that do not tolerate it; keep the interval long, or taint and untaint promptly.
Attendee Accounts, Projects and Roles
Accounts and projects
Each attendee needs an OpenShift user and one project of their own. The exercises run every command in the current project (no -n flags except for the read-only Descheduler steps), so the project name does not matter. Either let attendees create their own project (the default self-provisioner role allows it):
oc new-project <name>
Or create the projects in advance:
oc adm new-project <user>-deploy --admin=<user>
When the instructor creates the project, attendees must select it after logging in; otherwise oc stays in no project (or default), and the checks below fail with no and Forbidden answers that look like missing permissions:
oc project <user>-deploy
The default project admin role (or edit) covers everything attendees do in their project: creating pods, deployments, HPAs and VPAs, oc exec into pods, oc scale, oc edit and reading events.
Cluster-wide read access
Several steps read cluster-scoped objects (oc get nodes, oc describe node, oc adm top nodes, oc get priorityclasses) and the Descheduler Operator’s namespace, which a project user is Forbidden from seeing. The manifest workshops/deploy/provisioning/attendee-rbac.yaml grants read-only access to just those objects:
-
Install the Kube Descheduler Operator first (the manifest’s
RoleBindinglives in its namespace). -
Apply the manifest from the workshop source repository:
oc apply \ --filename workshops/deploy/provisioning/attendee-rbac.yamlIt creates two read-only cluster roles and binds them to the
workshop-attendeesgroup:workshop-attendee-node-reader(nodes, node metrics, priority classes and pods, cluster-wide) andworkshop-attendee-descheduler-reader(theKubeDeschedulerresource, deployments, pods, events and pod logs inopenshift-kube-descheduler-operatoronly). -
Add every attendee to the group:
oc adm groups new workshop-attendees <user1> <user2> # or, if the group already exists oc adm groups add-users workshop-attendees <user3>To bind the roles to individual users instead of the group:
oc adm policy add-cluster-role-to-user \ workshop-attendee-node-reader <user> oc adm policy add-role-to-user \ workshop-attendee-descheduler-reader <user> \ -n openshift-kube-descheduler-operator
The roles grant no write access. Reading pods in every namespace lets oc describe node show its Allocated resources section, but also shows attendees other projects' pod specs, so use these roles on lab clusters only.
Instructor-only steps
These steps need cluster administrator privileges and stay with the instructor; the exercises mark them:
-
Module 2, Exercise 2: adding and removing the
special-workload=true:NoScheduletaint on a node. -
Module 2, Exercise 7, Step 1: reading the config maps in the
openshift-kube-schedulerandopenshift-secondary-scheduler-operatornamespaces (the attendee role already lets attendees list the pods there). -
Module 3, Exercise 3: creating or changing the
KubeDescheduler. -
Module 4:
oc debug node/…,oc get kubeletconfig, mirror sets and Image Puller resources.
Attendee Workstation
| Tool | Version | Where it is used |
|---|---|---|
|
Matching the cluster’s minor version (tested with OpenShift 4.22.16) |
Every exercise. |
|
Any 1.6 or later (no specific minimum tested) |
Module 3, Exercise 3, Step 2 (pipes |
A POSIX shell with job control, plus |
Any (bash tested) |
Module 2, Exercise 4 counts pods per node with |
Attendees need two terminals for Module 3, Exercise 1 (one generates load while the other watches the HPA). A web terminal or tools pod works if it provides the tools above; when this workshop is built inside the OpenShift 102 Showroom, its shared CLI tools page describes that container. No local container engine (podman, docker) is needed: the Module 4 Dockerfile is an example to read, not to build.
Network and Image Access
Container images the exercises pull (all attendee steps):
| Image | Used by |
|---|---|
|
Module 2, Exercises 1-7; Module 3, Exercises 1-3 |
|
Module 2, Exercise 3 (cache pod) |
Both images come from Quay.io, run as a non-root arbitrary UID under the default restricted-v2 security context constraint, and avoid Docker Hub pull rate limits. Images named in the reading content (myapp:latest, critical-app:latest, nvidia/cuda:latest, registry.k8s.io/pause:3.1, alpine:latest, registry.example.com/…) are illustrations; no exercise pulls them.
No exercise fetches external URLs; the links in the content are documentation for reading.
For disconnected or restricted-egress clusters:
-
Mirror the two Quay.io images above, and add an
ImageTagMirrorSetforquay.io/nginxandquay.io/sclorg, since the exercises pull by tag. -
Mirror the operator catalogs and bundles for the Kube Descheduler, Vertical Pod Autoscaler and Node Feature Discovery operators (and the Secondary Scheduler and Image Puller operators if you demonstrate them), including the operand images they deploy, such as the NFD worker image and the secondary scheduler image.
-
Attendee workstations need to reach only the cluster API (and the console, if they use a web terminal).
Verification Checklist
Run as a cluster administrator:
# At least two Ready worker nodes, amd64
oc get nodes -L kubernetes.io/arch
# At least one node labelled by NFD with AVX (Module 2, Exercise 5)
oc get nodes -l feature.node.kubernetes.io/cpu-cpuid.AVX=true
# Operators installed: each CSV shows PHASE Succeeded
# (grep hides the copied CSVs of operators installed
# for all namespaces)
oc get csv -n openshift-kube-descheduler-operator |
grep -i descheduler
oc get csv -n openshift-vertical-pod-autoscaler | grep -i vertical
oc get csv -n openshift-nfd | grep -i nfd
# Descheduler configured (Module 3, Exercise 3)
oc get kubedescheduler cluster \
-n openshift-kube-descheduler-operator \
-o jsonpath='{.spec.mode} {.spec.profiles}{"\n"}'
# Metrics API answers with CPU and memory per node
oc adm top nodes
# Attendee RBAC and group in place
oc get clusterrole \
workshop-attendee-node-reader \
workshop-attendee-descheduler-reader
oc get group workshop-attendees
Run as an attendee (or as an administrator with --as=<user> added to each oc auth can-i); every oc auth can-i should answer yes:
oc whoami
oc project <user>-deploy
oc auth can-i list nodes
oc auth can-i list nodes.metrics.k8s.io
oc auth can-i list priorityclasses
oc auth can-i get kubedeschedulers \
-n openshift-kube-descheduler-operator
oc auth can-i create pods --subresource=exec
oc auth can-i create horizontalpodautoscalers.autoscaling
oc auth can-i create verticalpodautoscalers.autoscaling.k8s.io
# Both exercise images pull and start (STATUS Running), then clean up
oc run smoke-nginx --image=quay.io/nginx/nginx-unprivileged:latest
oc run smoke-redis --image=quay.io/sclorg/redis-7-c9s:latest
oc get pods smoke-nginx smoke-redis
oc delete pod smoke-nginx smoke-redis
# Workstation tools
oc version --client
jq --version