TT Lab
Get started
Learn Learning paths Courses

KCNA — Kubernetes and Cloud Native Associate

Opening a Cluster by Hand

Continue in TT Lab

Goal

You connect to a real Kubernetes cluster and look up namespaces, nodes, and API resources yourself, pull out only the values you want with label selectors and -o jsonpath, and create the same Deployment in two ways, imperative and declarative, to see the difference with your own eyes.

Why it matters

People who use Kubernetes fall into two broad groups: those who search a documentation site every time, and those who ask the cluster directly. kubectl api-resources and kubectl explain tell you what this cluster actually knows right now, so they are more accurate than the docs, since resources extended by CRDs show up too.

And label selectors. Kubernetes has almost no direct references between objects. How a Service finds Pods and how a ReplicaSet counts its own Pods are both label selectors. Thanks to this loose coupling you can replace Pods freely, but the price is that a selector typo silently finds nothing, with no error.

Finally, the declarative style. kubectl run is convenient but leaves no record of what it created. If you keep the manifest as a file and apply it, that file becomes the truth of this cluster, and review, version control, and rollback become possible. The word GitOps is nothing more than this habit scaled up to an organization.

Steps

  1. Create the namespace kcna-arch and attach the label tier=lab.
  2. Save the names of all nodes in the cluster, one per line, to /root/kcna-arch/nodes.txt. Include only the name, without a prefix such as node/.
  3. Look at kubectl api-resources and save the APIVERSION value of deployments to /root/kcna-arch/deploy-apiversion.txt and the short name (SHORTNAMES) of services to /root/kcna-arch/svc-short.txt, one line each.
  4. Use kubectl explain to find the spec field that places a Pod directly on a specific node without the scheduler, and use that field to create, in the namespace kcna-arch, a Pod with image nginx:1.27-alpine named pinned. The node name must be one from the list in step 2.
  5. In /root/kcna-arch/components.txt, fill in the four lines below as they are: after each of serve-rest-api=, store-cluster-state=, watch-and-place-pods=, and reconcile-desired-state=, append the matching component name (kube-apiserver, etcd, kube-scheduler, kube-controller-manager). Then use kubectl get --raw to call the API server's /healthz and save the response to /root/kcna-arch/healthz.txt.
  6. In the namespace kcna-arch, create 3 Pods: web-1 (app=web,tier=front), web-2 (app=web,tier=back), and db-1 (app=db,tier=back). Then save the names of the Pods picked with the selector app=web,tier=back to /root/kcna-arch/selected.txt, one per line.
  7. Using kubectl create deployment with --dry-run=client -o yaml, save a Deployment manifest with name kcna-web, image nginx:1.27-alpine, and replicas 2 to /root/kcna-arch/kcna-web.yaml, and then apply that file declaratively to the namespace kcna-arch.

Notes

Create a working namespace

Create the namespace kcna-arch and attach the label tier=lab.

A namespace is a name space inside the cluster. You can give the label when you create it, or attach it afterward with kubectl label. The label key is tier and the value is lab.

Extract the node list to a file

Save the names of all nodes in the cluster, one per line, to /root/kcna-arch/nodes.txt. Include only the name, without a prefix such as node/.

The default output of kubectl get nodes mixes in a header and several columns. You need only the names, one per line, so it is cleaner to change the output format with -o. Also check that using -o name attaches a node/ prefix.

Find the API group and short name with api-resources

Look at kubectl api-resources and save the APIVERSION value of deployments to /root/kcna-arch/deploy-apiversion.txt and the short name (SHORTNAMES) of services to /root/kcna-arch/svc-short.txt, one line each.

kubectl api-resources shows every resource this cluster knows in the columns NAME/SHORTNAMES/APIVERSION/NAMESPACED/KIND. You can narrow the search with grep. APIVERSION has the form "group/version", and note that for the core group the group name is empty.

Find a field with explain and pin a Pod to a node

Use kubectl explain to find the spec field that places a Pod directly on a specific node without the scheduler, and use that field to create, in the namespace kcna-arch, a Pod with image nginx:1.27-alpine named pinned. The node name must be one from the list in step 2.

If you run kubectl explain pod.spec, descriptions of the fields under spec come out in a long list. The field that skips the scheduler and places the Pod directly on a specific node is among them. For the node name, you can use any one from the list you extracted in step 2.

Sort out component roles and fetch the API server's status

In /root/kcna-arch/components.txt, fill in the four lines below as they are: after each of serve-rest-api=, store-cluster-state=, watch-and-place-pods=, and reconcile-desired-state=, append the matching component name (kube-apiserver, etcd, kube-scheduler, kube-controller-manager). Then use kubectl get --raw to call the API server's /healthz and save the response to /root/kcna-arch/healthz.txt.

Write the roles of the four components covered in the earlier reading, one key=value per line. And with the --raw option, kubectl can call an arbitrary path of the API server as is. The response of the health endpoint is very short.

Attach labels and pick with a selector

In the namespace kcna-arch, create 3 Pods: web-1 (app=web,tier=front), web-2 (app=web,tier=back), and db-1 (app=db,tier=back). Then save the names of the Pods picked with the selector app=web,tier=back to /root/kcna-arch/selected.txt, one per line.

Attach a different label combination to each of the 3 Pods. Then, if you join conditions with a comma in the -l option of kubectl get, it works as AND. When you save the result to a file, specify an output format that prints only the names.

Apply imperatively generated YAML declaratively

Using kubectl create deployment with --dry-run=client -o yaml, save a Deployment manifest with name kcna-web, image nginx:1.27-alpine, and replicas 2 to /root/kcna-arch/kcna-web.yaml, and then apply that file declaratively to the namespace kcna-arch.

If you add --dry-run=client -o yaml to kubectl create, you can extract only the manifest without touching the cluster. If you then apply that file with apply, the object gets one annotation that it would not have had if created with create. Grading distinguishes the two ways by the presence of that annotation.