Verify Prerequisites and Prepare the Cluster
Objectives
- Verify container runtime and kubectl connectivity.
- Identify the active context and create a dedicated exercise namespace.
- Explain which prerequisite gaps must be resolved before the labs.
1. Establish the readiness gates
Allow about 20 minutes for this preflight if the tools are already installed; installation or access repairs may take longer. The goal is evidence that your environment is usable, not another introduction to Python or Kubernetes. Use a disposable learning cluster or an explicitly approved development cluster, never a production context.
Work through four gates:
| Gate | Evidence to collect | Resolve before labs if missing |
|---|---|---|
| Python | Run a small script, understand imports, and know how to use an isolated environment | A working Python interpreter and basic scripting practice |
| Containers | Build a tagged image and run its command successfully | Runtime access, build basics, and an understanding of image versus container |
| Basic ML | Explain features, labels, a held-out evaluation set, and a saved model artifact | Enough supervised-learning knowledge to distinguish training from prediction |
| Kubernetes | Recognize a Pod, select an intended context, reach its API, and use a dedicated namespace | Cluster access and basic Pod/YAML familiarity |
This is a course readiness checklist, not a claim that a version command proves each skill. For example, ask yourself: 'If training succeeds but the saved model cannot be found by the prediction process, what output would I inspect?' A useful starting answer is the training logs and the artifact location, rather than immediately changing the learning algorithm.
The examples use Bash-compatible syntax and Docker as the concrete local provider. kind also supports Podman and nerdctl, but rootless providers can need additional setup; do not assume their configuration is identical. [S1]
2. Verify Python and the host container runtime
Run code example 1. The Python expression is deliberately small: it checks interpreter execution without requiring an ML package. A working container CLI alone does not prove that its runtime is reachable; follow the version check with the build-and-run test in code example 2.
Example 2 creates a small directory and Dockerfile under your current working directory. Run it from your course workspace, and do not overwrite an existing directory containing your own files. Its image prints runtime-ok and exits. That message is the expected result of the example, not a captured execution result from your computer. The first build needs access to the base-image registry; a registry or proxy failure is a prerequisite issue to resolve, not a training-code failure.
For the Docker path, require docker info to succeed and the container command to exit successfully. If access fails, start the runtime and repair its connection or permissions using the runtime's supported setup procedure. Do not solve the problem by granting broad system access without understanding why.
Check yourself: Can you explain why a successful local container run does not yet establish that a Kubernetes node can use the image? kind nodes are separate containerized environments; the documented local-image workflow explicitly loads the application image into those nodes. [S1]
3. Choose one cluster path and pin the intended context
First inspect your configuration with kubectl config get-contexts and kubectl config current-context. A context selects the Kubernetes connection configuration; inspect it before making changes. Use explicit context flags for the rest of this lesson rather than relying on a remembered default. [S6]
Path A — existing development cluster: obtain the approved context name from your cluster setup, set CTX to that exact name, and skip cluster creation. For example, type export CTX='your-approved-context' only after replacing that illustrative name. Confirm that you are authorized to create course workloads. If namespace creation is restricted, have the administrator provision a dedicated exercise namespace and substitute its actual name in the following examples.
Path B — local kind cluster: use code example 3. It creates a named, single-node learning cluster using the installed kind release's default prebuilt node image and waits for readiness. No managed cloud service is required. Run kind get clusters first; if mlops-course already exists and is yours, reuse it instead of rerunning the create command. kind's context for this cluster is kind-mlops-course. [S1]
For either path, run:
printf 'Exercise context: %s\n' "$CTX"
kubectl --context="$CTX" cluster-info
kubectl --context="$CTX" get nodes
Require a successful API response and, where you have node visibility, a node with Ready status before continuing. A successful kubectl version --client is only a client-installation check, not a connectivity check. Reading node status is an inspection step, not a guarantee that your later application will schedule or run. [S6]
On restricted clusters, a forbidden node listing can reflect your permissions rather than an unreachable API. Ask the administrator to confirm node readiness and workload capacity; do not request cluster-admin merely to satisfy this checklist.
Do not treat a single RAM number as a guarantee for every exercise. In particular, kind's documented 6 GB minimum and 8 GB recommendation on macOS or Windows are discussed in the Kubernetes node-image build setup, not a universal sizing promise for this course's applications. Resource needs depend on usage. [S1]
4. Create a dedicated exercise namespace and read it back
After reviewing CTX, run code example 4. It generates a Namespace manifest locally, applies it to the explicitly selected context, then reads back that exact namespace. kubectl apply creates or updates resources, while get inspects the stored state. [S6]
The commands use mlops-course as the exercise namespace. On an existing cluster, confirm that this name is available for your exercises; if it already belongs to another project, choose an approved unused name and consistently substitute it. Retain explicit --context="$CTX" and --namespace=mlops-course flags on workload commands. The namespace is an organizational boundary for this course, not a substitute for the cluster's security controls.
The auth can-i commands are narrow permission checks. Look for yes for each resource type shown; later labs may need additional permissions. An empty Pod list in a newly created namespace is expected: it demonstrates a successful list request, not a running application. Context and namespace selection, creating objects, and inspecting them are part of the kubectl workflow. [S6]
Check yourself: If your shell's current context later changes, where will the commands in this lesson act? They still use the context stored in CTX. If you open a new shell, set and review CTX again; do not assume that an earlier shell's variable is present.
5. Keep local images and cluster images distinct
For the Docker-backed kind path only, run code example 5 after building the image in example 2. The load command targets the named cluster. The node inspection should include course-preflight with tag v1; this verifies node-local image availability, not application correctness. The container name in this example belongs to the single-node cluster created in example 3. Do not use it against an unrelated existing cluster. [S1]
For an existing remote cluster, do not run kind load as a substitute for publishing an image. Establish the registry and credentials workflow approved for that cluster before the image-based labs. A laptop image tag is not evidence that remote nodes can fetch it.
When using a loaded image in a later Pod manifest, pair the exact tag with an explicit policy such as:
image: course-preflight:v1
imagePullPolicy: IfNotPresent
This is a container-field fragment, not a complete Pod manifest. A non-latest tag and an appropriate pull policy avoid an unintended registry pull when the image is already loaded. Never is another deliberate local-only choice, but it requires the image to be present on the node. [S1]
Check yourself: Why might an image built on the host still produce an image-pull error in a Pod? Check the image name, node availability, and registry access. Waiting Pods often reveal image-pull problems; inspect the Pod's state and events instead of assuming the model code crashed. [S39]
6. Decide whether to proceed or repair a gap
Before leaving this lesson, record the context name, exercise namespace, Python version, runtime check result, cluster-access result, and image-distribution path in your own course notes. Do not include kubeconfig credentials or tokens.
Use this exit checklist:
- [ ] I can run Python and explain how I will manage the later lab's dependencies.
- [ ] I can build and run the preflight image, or have verified an equivalent supported provider workflow.
- [ ] I can explain features, labels, evaluation data, and a saved model without needing an ML refresher during deployment.
- [ ] I know the intended context and have verified API access.
- [ ] I have read back my dedicated namespace and checked basic workload permissions.
- [ ] I know how my cluster will obtain course images: a verified kind load or an approved registry path.
Pause before labs if the runtime cannot execute containers, API access fails, required permissions are missing, or the basic Python/container/ML concepts remain unclear. An approved restricted cluster may need administrator help with node visibility or namespace provisioning; that is an access gap to resolve, not a reason to bypass policy.
If a later smoke-test Pod stalls, inspect the correct namespace:
kubectl --context="$CTX" --namespace=mlops-course get pods
kubectl --context="$CTX" --namespace=mlops-course get events --sort-by=.metadata.creationTimestamp
Then use kubectl describe pod with the actual Pod name. Scheduling events can expose placement constraints; container state and events help distinguish placement problems from image failures. [S26] Do not invent a Pod name or run troubleshooting in default by habit.
Final self-check: You can run Docker, but kubectl cluster-info fails. Are you ready for the Kubernetes labs? No: the host runtime gate passed, but the cluster-access gate did not. Repair that specific gap before proceeding. Keep the namespace and cluster for subsequent lessons; do not delete them as part of this preflight.
python3 --version
python3 -c 'import json; print(json.dumps({"python_ok": True}))'
docker --version
docker info
kubectl version --client
mkdir course-preflight
cd course-preflight
cat > Dockerfile <<'EOF'
FROM python:3.12-slim
CMD ["python", "-c", "print('runtime-ok')"]
EOF
docker build -t course-preflight:v1 .
docker run --rm course-preflight:v1
cd ..
kind version
kind get clusters
# Run creation only if this named cluster does not already exist.
KIND_EXPERIMENTAL_PROVIDER=docker kind create cluster --name mlops-course --wait 120s
export CTX='kind-mlops-course'
kubectl --context="$CTX" cluster-info
kubectl --context="$CTX" get nodes
# Set and review CTX for your chosen cluster before running this block.
printf 'Target context: %s\n' "$CTX"
kubectl create namespace mlops-course --dry-run=client -o yaml \
| kubectl --context="$CTX" apply -f -
kubectl --context="$CTX" get namespace mlops-course
kubectl --context="$CTX" --namespace=mlops-course auth can-i create pods
kubectl --context="$CTX" --namespace=mlops-course auth can-i create jobs.batch
kubectl --context="$CTX" --namespace=mlops-course auth can-i create deployments.apps
kubectl --context="$CTX" --namespace=mlops-course auth can-i create services
kubectl --context="$CTX" --namespace=mlops-course get pods
# Only for the Docker-backed kind cluster created in example 3.
kind load docker-image course-preflight:v1 --name mlops-course
docker exec mlops-course-control-plane crictl images
Key takeaways
- A CLI version check is not proof of runtime execution or Kubernetes API connectivity.
- Review the intended context before writes, and pass context and namespace explicitly. [S6]
- A named single-node kind cluster provides a local option without requiring a managed cloud cluster. [S1]
- Create the dedicated namespace, then read it back rather than assuming a successful write is sufficient. [S6]
- For kind, load the exact tagged image into the target cluster; a host build alone does not establish node availability. [S1]
- Resolve runtime, access, permission, and foundational knowledge gaps before starting labs.
Common mistakes
- Treating kubectl version --client as a successful cluster check.: Verify the intended context with cluster-info and inspect node readiness where permitted; request administrator confirmation when node visibility is restricted.
- Applying resources to whichever context happens to be current.: Inspect context configuration first, review CTX, and retain explicit context and namespace flags. [S6]
- Assuming a locally built Docker image exists inside kind.: Load the tagged image into the named kind cluster and inspect its node image inventory. [S1]
- Using latest with a local image and overlooking the pull policy.: Use an explicit non-latest tag and choose IfNotPresent or a deliberate local-only Never policy. [S1]
- Continuing after a forbidden workload action or reusing someone else's namespace.: Obtain an approved dedicated namespace and the required permissions before labs; do not bypass cluster policy.
References
- kind Quick Start, Kubernetes SIGs / kind
- kubectl Quick Reference, Kubernetes
- Debug Running Pods, Kubernetes
- Debug Pods, Kubernetes
See the full course: MLOps on Kubernetes: Training, Serving, and Monitoring Models