KCNA — Kubernetes and Cloud Native Associate
Opening a Cluster by Hand
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
- Create the namespace
kcna-archand attach the labeltier=lab. - 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 asnode/. - Look at
kubectl api-resourcesand save the APIVERSION value ofdeploymentsto/root/kcna-arch/deploy-apiversion.txtand the short name (SHORTNAMES) ofservicesto/root/kcna-arch/svc-short.txt, one line each. - Use
kubectl explainto find thespecfield that places a Pod directly on a specific node without the scheduler, and use that field to create, in the namespacekcna-arch, a Pod with imagenginx:1.27-alpinenamedpinned. The node name must be one from the list in step 2. - In
/root/kcna-arch/components.txt, fill in the four lines below as they are: after each ofserve-rest-api=,store-cluster-state=,watch-and-place-pods=, andreconcile-desired-state=, append the matching component name (kube-apiserver,etcd,kube-scheduler,kube-controller-manager). Then usekubectl get --rawto call the API server's/healthzand save the response to/root/kcna-arch/healthz.txt. - In the namespace
kcna-arch, create 3 Pods:web-1(app=web,tier=front),web-2(app=web,tier=back), anddb-1(app=db,tier=back). Then save the names of the Pods picked with the selectorapp=web,tier=backto/root/kcna-arch/selected.txt, one per line. - Using
kubectl create deploymentwith--dry-run=client -o yaml, save a Deployment manifest with namekcna-web, imagenginx:1.27-alpine, and replicas 2 to/root/kcna-arch/kcna-web.yaml, and then apply that file declaratively to the namespacekcna-arch.
Notes
- As in
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}', if you iterate withrangeyou can extract one per line. kubectl explain pod.spec --recursiveshows the whole field tree. When you do not know the name, using it together withgrepis fast.- Common mistake 1: writing a resource name such as
deployments.appsin step 3. What is needed is the value of the APIVERSION column. - Common mistake 2: creating it straight in the cluster with
kubectl create deploymentin step 7. Then, even if the manifest file exists, the object carries no trace of a declarative apply, so it does not pass grading.
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.