Introduction
This blog post marks the beginning of a series designed to help you prepare for the Certified Kubernetes Application Developer (CKAD) exam through hands-on exercises and practical examples. Whether youâre just starting out with Kubernetes or looking to sharpen your skills, each post will walk you through one of the core competencies required for the certification.
Since these are topics I need to review for my own exam, I thoughtâwhy not publish my notes? They might be useful for others who are considering taking the CKAD for the first time, or for those retaking it and needing a refresher on key concepts.
At the time of writing, the CKAD exam has the following requirements:
Application Design and Build
- Define, build and modify container images.
- Choose and use the right workload resource (Deployment, DaemonSet, CronJob, etc.).
- Understand multi-container Pod design patterns (e.g. sidecar, init and others)
- Utilize persistent and ephemeral volumes
Application Deployment
- Use Kubernetes primitives to implement common deployment strategies (e.g. blue/green or canary)
- Understand Deployments and how to perform rolling updates
- Use the Helm package manager to deploy existing packages
- Kustomize
Application Observability and Maintenance
- Understand API deprecations
- Implement probes and health checks
- Use built-in CLI tools to monitor Kubernetes applications
- Utilize container logs
- Debugging in Kubernetes
Application Environment, Configuration and Security
- Discover and use resources that extend Kubernetes (CRD, Operators)
- Understand authentication, authorization and admission control
- Understand requests, limits, quotas
- Understand ConfigMaps
- Define resource requirements
- Create & consume Secrets
- Understand ServiceAccounts
- Understand Application Security (SecurityContexts, Capabilities, etc.)
Services and Networking
- Demonstrate basic understanding of NetworkPolicies
- Provide and troubleshoot access to applications via services
- Use Ingress rules to expose applications
I know there are a lot of topics, but weâll address them one by one with practical examples.
For now, in this lesson, weâll cover some key concepts. In the next ones, we will prepare the environment needed for our playground experiments.
What Is Kubernetes?
Kubernetes (often abbreviated as K8s) is an open-source platform for automating the deployment, scaling, and management of containerized applications. Originally developed by Google and now maintained by the Cloud Native Computing Foundation (CNCF), Kubernetes has become the de facto standard for container orchestration in modern cloud-native environments.
Why Is Kubernetes Important?
Kubernetes solves several critical challenges in modern software development:
- Orchestration: Automatically manages the lifecycle of containers, ensuring they run where and when needed.
- Scalability: Easily scale applications up or down based on demand.
- Resilience: Automatically restarts failed containers and reschedules workloads on healthy nodes.
- Declarative Configuration: Use YAML manifests to define desired system state, making infrastructure reproducible and version-controlled.
Where Is Kubernetes Used?
Kubernetes is widely adopted across industries and is especially popular in:
- Cloud-native applications: Designed to run in distributed, scalable environments.
- Microservices architectures: Manages multiple loosely coupled services efficiently.
- Hybrid and multi-cloud setups: Offers portability across cloud providers and on-premise infrastructure.
- DevOps workflows: Integrates seamlessly with CI/CD pipelines and infrastructure-as-code tools.
Kubernetes architecture
Kubernetes is built around a master-worker architecture. The Control Plane manages the cluster and makes global decisions (e.g., scheduling), while the Nodes (workers) run the actual applications in containers.
graph TD
subgraph Control Plane
APIServer["kube-apiserver"]
Scheduler["kube-scheduler"]
ControllerManager["kube-controller-manager"]
etcd["etcd (Key-Value Store)"]
end
subgraph Node
Kubelet["kubelet"]
KubeProxy["kube-proxy"]
ContainerRuntime["container runtime"]
Pod["pod (1+ containers)"]
end
User["kubectl / user"]
User --> APIServer
APIServer --> etcd
APIServer --> Scheduler
APIServer --> ControllerManager
Scheduler --> Kubelet
ControllerManager --> Kubelet
APIServer --> Kubelet
Kubelet --> Pod
Kubelet --> ContainerRuntime
KubeProxy --> Pod
Please note that the control plane can also run on a worker node. In these cases, these nodes are usually âtaintedâ, meaning they only run the control plane components and not regular workloads.
đĽď¸ What Is a Node in Kubernetes?
In Kubernetes, a Node is a physical or virtual machine that runs containerized applications. Itâs the worker unit of the clusterâresponsible for executing workloads and hosting the components that make containers run.
A cluster typically has multiple nodes, and Kubernetes distributes Pods across them based on resource availability and scheduling rules.
Every node includes:
- kubelet: The agent that communicates with the control plane and manages Pods on the node.
- container runtime: The software that actually runs containers (e.g., containerd, CRI-O).
- kube-proxy: Handles network routing and service discovery for Pods.
These components work together to ensure that containers are started, monitored, and connected properly.
đ§Š Kubelet and the Container Runtime
Every node in a Kubernetes cluster that runs workloadsâor even components of the control planeârelies on two key services: the kubelet and a container runtime, such as containerd.
The container runtime is the low-level component responsible for actually running containers on the node. containerd, for example, is part of the Open Container Initiative (OCI) stack. Originally bundled with Docker, it has since evolved into a standalone and widely adopted runtime. Under the hood, containerd uses runc to create and manage containers, but we wonât dive into that level of detail here.
The kubelet is the Kubernetes agent that runs on each node. It communicates with the control plane and ensures that containers are running according to the specifications defined in the clusterâs configuration. In short, itâs responsible for managing Pods on its node.
đŚ Pods
Before going further, letâs introduce the concept of a Pod.
A Pod is the smallest deployable unit in Kubernetes. Itâs not just a single container, but rather a logical wrapper around one or more containers that are designed to run together on the same node.
Think of a Pod as a sandbox that:
- Shares a single network namespace (same IP and port space)
- Can share storage volumes
- Has a unified lifecycle (containers start, stop, and are scheduled together)
From Kubernetesâ perspective, the Pod is the only unit that actually runs. Everything elseâDeployments, ReplicaSets, Jobsâis a declarative resource that defines how Pods should be created, managed, scaled, and updated.
đŚ Static Pods
One of the kubeletâs special capabilities is managing static PodsâPods defined directly at the node level, outside the control of the API server.
A static Pod is created and monitored by the kubelet itself. Hereâs how it works:
- The kubelet reads a YAML manifest from a local directory (typically /etc/kubernetes/manifests/)
- It creates and runs the Pod autonomously, even if the control plane isnât active
- These Pods canât be created or deleted via kubectl, although they are visible in the cluster
The kubeletâs configuration file (usually located at /var/lib/kubelet/config.yaml) includes a property that defines the path to the static Pod manifests.
Static Pods are primarily used to bootstrap the cluster, allowing the kubelet to start critical components before the API server is available. In fact, the API server itself is often deployed as a static Pod, along with other essential services like the scheduler, etcd, and the controller manager. In some setups, these components may also be installed as standalone Linux services.
In short: Static Pods are the foundation that allows Kubernetes to start itself.
đ kube-proxy
Letâs now look at kube-proxy, the key component responsible for managing network connectivity between Pods and Services.
kube-proxy runs on every node in the clusterâtypically as a DaemonSet, meaning one Pod per node. Its main job is to implement Kubernetesâ service networking logic, ensuring that traffic reaches the correct backend Pods.
Depending on the mode in use, kube-proxy modifies the kernelâs routing table to redirect traffic. It supports three modes:
- iptables (default): Creates iptables rules for each Service and its endpoints. The kernel handles routing directly, without needing a persistent user-space process.
- ipvs: Uses the Linux IP Virtual Server (IPVS) for more efficient load balancing. Requires the ip_vs kernel module and is ideal for large clusters.
- userspace: An older, deprecated mode where kube-proxy manually forwards traffic. It has been replaced by iptables and ipvs.
In iptables mode, kube-proxy programs kernel DNAT rules to distribute traffic across backend Pods in a pseudo-random (effectively round-robin) fashion. Each new TCP connection is pinned to a selected Pod, ensuring consistent routing for the duration of the connection.
đ Introducing the concept of Service
Since weâve mentioned Services, letâs formally introduce them.
While Pods have IP addresses, they are ephemeralâmeaning their IPs can change at any time. A Service is a Kubernetes API object that provides a stable network endpoint for one or more Pods acting as a backend. This abstraction allows clients (like frontends or other services) to connect without needing to know the details of Pod IPs or lifecycle.
There are several types of Services:
- ClusterIP (default): Creates an internal virtual IP accessible only within the cluster.
- NodePort: Exposes the Service on a static port (30000â32767) of each node.
- LoadBalancer: Delegates the creation of an external load balancer to the cloud or on-prem provider (e.g., MetalLB).
- ExternalName: Maps the Service to an external DNS name.
- Headless Service: Does not create a ClusterIP (clusterIP: None), allowing DNS to return the IPs of individual Pods.
Hereâs a quick recap:
| Service Type | Access | Stable IP | Load Balancer | Typical use case |
|---|---|---|---|---|
| ClusterIP | Internal to cluster | â | â | Internal service-to-service communication |
| NodePort | External (node IP + port) | â | â | Direct access via node (simple exposure / debugging) |
| LoadBalancer | External (public IP) | â | â | Production exposure via cloud or external LB |
| ExternalName | DNS mapping to external service | â | â | Referencing external services by DNS |
| Headless | Direct Pod endpoints (no ClusterIP) | â | â | StatefulSets, distributed databases, custom service discovery |
Note: LoadBalancer and ExternalName may require external components like MetalLB to function in bare-metal environments.
đŁď¸ Introducing the CNI
While kube-proxy handles where traffic should go, it doesnât handle how Pods communicate across nodes. Thatâs the job of the Container Network Interface (CNI).
CNI is a standard that defines how containers connect to each other and to external networks. Kubernetes relies on CNI plugins to provide cluster-wide networking.
Popular CNI plugins like Calico, Cilium, or Flannel can:
- Assign unique IPs to each Pod across the cluster
- Create routing between nodes for cross-node Pod communication
- Enforce network policies (e.g., firewall rules, namespace isolation)
Without a CNI plugin, Pods would only be able to communicate within the same nodeâmaking Kubernetes unusable in multi-node setups.
In summary: kube-proxy decides where traffic should go, CNI ensures it can get there.
đ Introducing CoreDNS: Internal DNS for Kubernetes
Before moving on to the control plane components, letâs introduce the internal DNS used by Kubernetes for name resolution.
CoreDNS is the default DNS server used by Kubernetes to provide internal name resolution for Services and Pods. It runs as a Deployment inside the cluster and is responsible for translating service names (like my-service.default.svc.cluster.local) into IP addresses.
Whenever a Pod tries to reach another Service by name, CoreDNS is what makes that possible.
What Does CoreDNS Do?
- Resolves DNS queries for Kubernetes Services and Pods
- Integrates with Kubernetes API to stay updated on resource changes
- Supports custom DNS configurations via plugins
- Enables service discovery within the cluster
CoreDNS watches the Kubernetes API and dynamically updates its DNS records as Services and Pods are created or removed. This allows applications to communicate reliably using DNS names, even as the underlying IPs change.
đ§ Introducing the Control Plane: Kubernetesâ Brain
In Kubernetes, the Control Plane is the brain of the cluster. Itâs responsible for managing the overall state of the systemâdeciding what should run, where it should run, and how it should behave. While worker nodes execute workloads (i.e., run containers), the control plane makes all the decisions that keep the cluster functioning smoothly.
What Does the Control Plane Do? The control plane continuously monitors the cluster and ensures that the desired state (as defined by your YAML manifests) matches the actual state. If something driftsâlike a Pod crashing or a node going offlineâthe control plane takes action to restore balance.
It handles tasks such as:
- Scheduling Pods to nodes
- Managing cluster-wide configuration
- Monitoring resource health
- Enforcing policies and access control
- Scaling applications up or down
đď¸ kube-scheduler: Assigning Pods to Nodes
The kube-scheduler is a core component of the Kubernetes control plane responsible for assigning newly created Pods to suitable Nodes in the cluster. When a Pod is created without a designated Node, the scheduler evaluates available Nodes and selects the best fit based on several criteria.
The scheduler considers factors such as:
- Resource availability: CPU, memory, and other constraints
- Node affinity/anti-affinity rules
- Taints and tolerations
- Pod affinity/anti-affinity
- Custom scheduling policies
Once a Node is selected, the scheduler updates the Podâs specification with the chosen Node name, allowing the kubelet on that Node to take over and start the Pod.
đ§Š kube-controller-manager: Maintaining Desired State
The kube-controller-manager runs a set of controllers that continuously monitor the cluster and ensure its actual state matches the desired state defined in your manifests.
- Each controller handles a specific task, such as:
- ReplicationController: Ensures the correct number of Pod replicas
- NodeController: Monitors node health and availability
- JobController: Manages Job execution and completion
- EndpointController: Updates Service endpoints
These controllers operate in loops, watching the API server for changes and taking action to reconcile differences.
đ§ API Server: The Front Door of Kubernetes
The API Server is the central hub of communication in a Kubernetes cluster. It acts as the front door to the control plane, exposing a RESTful API that allows users, components, and tools to interact with the cluster.
Whether youâre using kubectl, deploying a new application, or a controller is watching for changesâeverything goes through the API Server.
What Does It Do?
- Validates requests: Ensures submitted manifests are syntactically and semantically correct.
- Serves the Kubernetes API: Provides endpoints for reading and writing cluster state.
- Authentication & Authorization: Verifies who is making the request and whether theyâre allowed to do so.
- Acts as a gateway: Routes requests to other control plane components like the scheduler or controller manager.
In essence, the API Server is the brainâs interfaceâit doesnât make decisions, but it receives all the signals and passes them to the right parts of the system.
đď¸ etcd: The Clusterâs Memory
etcd is a distributed key-value store that serves as the source of truth for all cluster data. It stores the entire state of the Kubernetes clusterâeverything from Pod definitions to ConfigMaps, Secrets, and node status.
Think of etcd as Kubernetesâ memory: if itâs not in etcd, it doesnât exist in the cluster.
What Does It Store?
- Cluster configuration and metadata
- Resource definitions (Pods, Services, Deployments, etc.)
- State information (node health, leases, etc.)
- Security data (RBAC rules, Secrets)
etcd is designed to be highly available and consistent, using the Raft consensus algorithm to replicate data across multiple nodes.
đ Controllers and Control Loops: Managing Workloads in Kubernetes
This is the last topic we have to address. I promise!
One of the most powerful ideas behind Kubernetes is the concept of declarative configuration. You donât tell Kubernetes how to do somethingâyou tell it what you want, and it figures out the rest. This is made possible by controllers, which continuously monitor the cluster and work to ensure that the actual state matches the desired state.
This process is called a control loop.
đ What Is a Controller?
A controller is a background process that watches the Kubernetes API for changes and takes action to reconcile differences. For example, if you declare that you want three replicas of a Pod, but only two are running, the controller will create a third.
Controllers are responsible for creating, updating, and deleting Pods based on higher-level resources.
Kubernetes provides several built-in controllers to manage different types of workloads:
- Deployment: The most common controller for stateless applications.
- StatefulSet: Designed for stateful applications that require stable identities and persistent storage.
- DaemonSet: Ensures that a copy of a Pod runs on every node in the cluster.
In the next lessons, weâll explore each of these aspects in detail. For now, itâs enough to understand that for each workload, a resource is defined that describes the desired state, and a controller reconciles any differences within the cluster.
How Kubernetes Components Run in the Cluster
Below you will find a table listing the components seen in the previous sections:
| Component | Type / Role | How it runs | Namespace / Location |
|---|---|---|---|
kubelet |
Node agent | systemd service (Linux daemon) | runs on every node |
Container runtime (containerd, CRI-O) |
Container engine | systemd service / OS-managed daemon | runs on every node |
kube-proxy |
Service proxy / network routing | DaemonSet (one Pod per node) | kube-system |
etcd |
Cluster state store | Static Pod or systemd service (or external etcd cluster) | control-plane node(s) or external |
kube-apiserver |
Control plane front-end | Static Pod | control-plane (kube-system) |
kube-scheduler |
Pod scheduling | Static Pod | control-plane (kube-system) |
kube-controller-manager |
State reconciliation | Static Pod | control-plane (kube-system) |
CoreDNS |
Internal DNS / service discovery | Deployment | kube-system |
đ Wrapping Up: What Weâve Covered
In this first post, we explored what Kubernetes is, the key requirements for passing the CKAD exam, and the architecture and components that make up a Kubernetes cluster. These may seem like dry fundamentalsâbut theyâre absolutely essential if we want to build a solid understanding of how Kubernetes works under the hood.
Grasping these core concepts sets the stage for everything that follows.
In the upcoming posts, weâll dive into the actual CKAD competencies through hands-on exercises and practical examples. From building container images to deploying applications, configuring probes, and working with Services and Secretsâweâll tackle each topic with real-world scenarios and YAML you can run yourself.
Stay tuned, and letâs get our hands dirty with Kubernetes.