TT Lab
Get started
Learn Learning paths Courses

KCNA — Kubernetes and Cloud Native Associate

Finding Pods With Services, and Attaching Config and Storage

Continue in TT Lab

Goal

You build for yourself how a Service finds Pods and what it looks like when it cannot, and check by hand ConfigMap/Secret injection, PVC requests, and the service DNS naming rules.

Why it matters

The overwhelming majority of Service-related outages are not "the Service was not created" but "the Service was created but there is nothing behind it." This is because Kubernetes does not verify that a selector actually catches Pods. Even if a single typo makes the endpoints 0, kubectl get svc looks perfectly fine. That is why in this lab you create that situation on purpose. A failure you have made once by hand gets diagnosed in 3 minutes in the field.

ConfigMap/Secret are the form in which Kubernetes implements the 12-factor rule "config from the environment." The image is the same everywhere, and what differs must be injected values. Just remember that a Secret, despite its name, is not encrypted with default settings; this is an important topic in KCSA.

The metaphor of the PVC as a "request form" is the whole point. A Pod does not point at "/export/data on NFS server 10.0.0.5"; it requests "1Gi of RWO storage." Thanks to this layer of indirection, the same manifest runs on a laptop cluster and in production.

Steps

  1. Create the namespace kcna-net and in it a Deployment shop: image nginx:1.27-alpine, replicas 2, Pod template label app=shop.
  2. Create a Service shop-svc: type ClusterIP, port 80, selector app=shop. Confirm that 2 endpoints are picked up.
  3. In the same namespace, create a Service broken-svc: port 80, but with the selector deliberately app=shopp (one extra p). Confirm that there are 0 endpoints, and save the correct selector that fixes this service to /root/kcna-net/diagnosis.txt as one line in the form app=shop.
  4. Create a Service shop-np: type NodePort, port 80, nodePort 30080, selector app=shop.
  5. Create a ConfigMap shop-config (key APP_MODE, value production). Create a Secret shop-secret (key API_KEY, any string as the value). Then create a Pod shop-client so that the environment variable APP_MODE is taken from shop-config, key APP_MODE, and the environment variable API_KEY is taken from shop-secret, key API_KEY. The image is nginx:1.27-alpine.
  6. Create a PVC shop-data: requested capacity 1Gi, accessModes ReadWriteOnce, storageClassName standard.
  7. Save the fully qualified DNS name (FQDN) of shop-svc to /root/kcna-net/dns.txt on one line, and in the same namespace create a headless Service shop-headless: selector app=shop, port 80, with clusterIP specified as headless.

Notes

Stand up a backend Deployment

Create the namespace kcna-net and in it a Deployment shop: image nginx:1.27-alpine, replicas 2, Pod template label app=shop.

The target the Service will find has to exist first. The label attached to the Pod template has to match the selector later, so check which label gets attached.

Check the ClusterIP Service and endpoints

Create a Service shop-svc: type ClusterIP, port 80, selector app=shop. Confirm that 2 endpoints are picked up.

You can create it with kubectl expose or write YAML. After creating it, be sure to check that the endpoints were actually picked up; a Service having been created and there being somewhere for traffic to go are different matters.

Deliberately reproduce a selector typo

In the same namespace, create a Service broken-svc: port 80, but with the selector deliberately app=shopp (one extra p). Confirm that there are 0 endpoints, and save the correct selector that fixes this service to /root/kcna-net/diagnosis.txt as one line in the form app=shop.

The goal of this step is to create a failure. Create a Service with one extra character in the selector value, and confirm both that no error occurs and that the endpoints are 0. In the diagnosis file, write the correct selector that would fix this service as a single key=value line.

Build a door that lets traffic in from outside with NodePort

Create a Service shop-np: type NodePort, port 80, nodePort 30080, selector app=shop.

The NodePort range is 30000-32767 by default. If you do not specify a number, one is assigned arbitrarily, so to use the graded number you have to state it explicitly in the manifest.

Inject a ConfigMap and a Secret

Create a ConfigMap shop-config (key APP_MODE, value production). Create a Secret shop-secret (key API_KEY, any string as the value). Then create a Pod shop-client so that the environment variable APP_MODE is taken from shop-config, key APP_MODE, and the environment variable API_KEY is taken from shop-secret, key API_KEY. The image is nginx:1.27-alpine.

Using --from-literal with kubectl create configmap and kubectl create secret generic is quick. On the Pod side, for each env entry you specify configMapKeyRef / secretKeyRef through valueFrom. You have to write both places: which key to expose and under which name.

Write a storage request form with a PVC

Create a PVC shop-data: requested capacity 1Gi, accessModes ReadWriteOnce, storageClassName standard.

A PVC is a "request form." This lab cluster has no dynamic provisioner, so it may stay in Pending; that itself is normal, and grading looks at the spec. accessModes is an array and storageClassName is a string.

DNS naming rules and a headless Service

Save the fully qualified DNS name (FQDN) of shop-svc to /root/kcna-net/dns.txt on one line, and in the same namespace create a headless Service shop-headless: selector app=shop, port 80, with clusterIP specified as headless.

A Service's fully qualified DNS name is made of four parts. And a headless Service is created by explicitly setting a specific value in the clusterIP field; this value is hard to specify with kubectl expose, so it is better to use YAML.