Create a Deployment with an Env Var and Expose Its Port
Create a Deployment named expose in the existing prepium namespace running 6 replicas of a Pod. Specify a single container using the ifccncf/nginx:1.13.7 image.
Live lab access
This task description is public. Live practice requires full access unless this is the selected free weekly task. AI Lab Coach is available in single-task labs, including the free weekly task. See this week's free task.
Create an account to continue →
On a phone? Read the task and create your account here, then sign in on a desktop or laptop for the terminal lab. Nothing starts until you choose Start.
The task
Task
Create a Deployment named expose in the existing prepium namespace running 6 replicas of a Pod. Specify a single container using the ifccncf/nginx:1.13.7 image.
Add an environment variable named NGINX_PORT with the value 8001 to the container, then expose port 8001.
> Note: the ifccncf/nginx:1.13.7 image does not pull in this environment (just like the real CKAD exam), so the Pods will show ImagePullBackOff. That is expected. Grading checks your Deployment and Service definition, not whether the Pods are Running.
Original Prepium guide · Written for Kubernetes v1.35 and checked against the official documentation on 6 October 2026. Use a disposable practice cluster.
Environment variables, containerPort and Services: what each one really controls
Three settings tend to get blurred together in "deploy and expose" questions. An environment variable is data handed to the process; the process decides whether to use it. containerPort is a declaration in the Pod spec; it does not open, close or move anything. A Service is the only one of the three that changes networking, and it sends traffic to whatever targetPort you give it. Knowing which layer does what makes these tasks fast and makes mistakes easy to diagnose.
env SERVICE_TIER=gold -> read by the process (or ignored)
containerPort: 80 -> metadata: names a port, default for expose
Service port 8080 -> targetPort 80 -> whatever is really listening in the Pod
1. Generate the Deployment with flags
kubectl create namespace prepium-tutorial
kubectl -n prepium-tutorial create deployment menu-api --image=nginx:1.27-alpine \
--replicas=3 --port=80 --dry-run=client -o yaml
Read the output before creating it. --replicas fills spec.replicas, and --port writes a single containerPort into the container. There is no --env flag on kubectl create deployment (that flag belongs to kubectl run), so either add an env list to the YAML or set it in the next step. Run the command again without --dry-run and -o yaml to create it.
2. Add an environment variable and watch the rollout
kubectl -n prepium-tutorial set env deployment/menu-api SERVICE_TIER=gold
kubectl -n prepium-tutorial set env deployment/menu-api --list
kubectl -n prepium-tutorial rollout status deployment/menu-api
kubectl -n prepium-tutorial exec deploy/menu-api -- printenv SERVICE_TIER
set env edits the Pod template, and any template change triggers a new rollout, so the variable only appears in the replacement Pods. Values set through env override variables of the same name baked into the image. Remember that nginx does not read SERVICE_TIER; setting a variable named after a port does not make a program listen there unless the program is written to read it.
3. Expose it and test from inside the cluster
kubectl -n prepium-tutorial expose deployment menu-api --port=8080 --target-port=80
kubectl -n prepium-tutorial get endpointslices -l kubernetes.io/service-name=menu-api
kubectl -n prepium-tutorial run client --image=busybox:1.36 --restart=Never --rm -it -- \
wget -qO- http://menu-api:8080
kubectl expose copies the Deployment's selector into the new Service. Leave out --port and it reuses the container's declared port; leave out --target-port and the target defaults to the same value as the Service port. The type defaults to ClusterIP.
4. Prove that containerPort is only a declaration
kubectl -n prepium-tutorial expose deployment menu-api --name=menu-wrong --port=8080 --target-port=9999
kubectl -n prepium-tutorial run client2 --image=busybox:1.36 --restart=Never --rm -it -- \
wget -T 3 -qO- http://menu-wrong:8080
The Service has ready endpoints, yet the request fails, because nothing in the Pod listens on 9999. The reverse also holds: the Pod API states that leaving a port out of ports does not stop it being reachable. What a declared port does give you is a name (targetPort can reference it), a default for kubectl expose, and documentation for the next reader.
Common mistakes
- Setting the Service
portbut nottargetPortwhen they differ. The target silently equals the Service port and connections are refused. - Expecting an environment variable to reconfigure the listener. Check what the image actually reads before assuming it changes behaviour.
- Checking an old Pod after
set env. The variable lives in new Pods only; userollout statusfirst. - Exposing in the wrong namespace.
exposelooks up the Deployment by name in the namespace you target, so a missing-nmeans it cannot find the Deployment at all.
| Example check | Evidence |
|---|---|
| Replica count | spec.replicas and READY column on the Deployment |
| Variable is in the template | set env --list or .spec.template.spec.containers[0].env |
| Declared container port | .spec.template.spec.containers[0].ports[0].containerPort |
| Service wiring | Service port, targetPort and selector; EndpointSlice lists the Pods |
Cleanup: kubectl delete namespace prepium-tutorial. References: kubectl expose, kubectl set env, Service, Pod API (container ports). Next, try NodePort Services or fixing a broken Service.
Video walkthrough: CKAD Exam Question 17 - Deployment Configuration and Port Exposure on YouTube. It shows the full solution, so try the task first.
What this tests
Roll out and update deployments, run canary and blue-green strategies, and right-size workloads. On the CKAD exam, Application Deployment tasks are graded purely on what you build in the cluster - not multiple choice - so the only way to get faster is to do them on a real cluster against a clock.
Practice it for real
The public description lets you study the task before signing up. Full access includes this live lab; the selected Task of the Week is free with an account. You solve the task in a real terminal, hit validate, and a programmatic checker scores exactly what you got right and wrong (with partial credit). You can open the solution while practising, then retry and use the failed checks to improve your score.