A Gentle Introduction to Kubernetes
K8s' architecture and components may seem complex, but they offer unparalleled power, flexibility, and features in the open-source world.
Join the DZone community and get the full member experience.Join For Free
Kubernetes simplifies deploying, scaling, and managing distributed components and services across various infrastructures. It offers powerful features such as self-healing, service discovery, automated rollouts, and rollbacks, allowing users to manage containerized applications easily.
What Is Kubernetes?
Kubernetes (sometimes called K8s) is an open-source container-orchestration system that simplifies the deployment, scaling, and management of containerized applications. It provides a unified platform for deploying and managing distributed applications. It is designed to be highly scalable, fault-tolerant, and cloud-agnostic, running on multiple cloud platforms and on-premise environments.
As a Kubernetes user, you can easily scale services up or down, perform rolling updates, and switch traffic between different versions of your applications to test features or roll back any deployments.
Kubernetes provides users with the ability to control how their applications run and interact with other applications or the external environment. It offers interfaces and composable platform primitives that enable users to define and manage their applications with great flexibility, power, and reliability.
Kubernetes is structured in layers, with each layer hiding the complexity of the layer below it. To understand how Kubernetes works, it is useful to get an overview of its design.
Kubernetes combines physical or virtual machines into a cluster connected by a shared network. The master server acts as the gateway and brain of the cluster, managing communication between components and assigning work. The other machines in the cluster are nodes responsible for running workloads using local and external resources in containers. The node receives instructions from the master server and creates or destroys containers accordingly, adjusting networking rules to route traffic.
Kubernetes makes it easy for users to deploy and manage applications in a distributed environment. Users interact with the Kubernetes cluster by directly communicating with the main API server or through clients and libraries such as kubectl, Helm, and kubeadm.
To start an application or service, a declarative plan is submitted in JSON or YAML that defines what to create and how to manage it. The master server then takes this plan and works out how to run it on the infrastructure by looking at the requirements and the current state of the system. This layer of user-defined applications running according to a specified plan is Kubernetes' final layer, which is managed by underlying components such as controllers, schedulers, and nodes to ensure that the desired state of the applications matches the actual state of the cluster.
K8s Master Server Components
The master server is the primary control plane for Kubernetes clusters, acting as the main contact point for administrators and users. It provides many cluster-wide systems to the worker nodes, such as accepting user requests, determining the best ways to schedule workload containers, authenticating clients and nodes, adjusting cluster-wide networking, and managing scaling and health-checking responsibilities.
These components can be installed on a single machine or distributed across multiple servers. In this section, we will explore each of the individual components associated with master servers.
etcd is a distributed key-value store that is used to store the configuration data of a Kubernetes cluster. It is an important component of Kubernetes clusters as it provides a reliable way to store and retrieve data from the cluster and set up the desired state of the system.
Kubernetes uses etcd to store cluster state (configuration, nodes, services), current cluster state (which nodes are running which applications/services), and maintain cluster state with features like leader election and distributed locking via a simple HTTP/JSON API.
etcd is similar to other control plane components and can be configured on a single master server or distributed across multiple machines as long as it is accessible to all Kubernetes machines.
The API server — kube-apiserver — is the main management point of the Kubernetes cluster, responsible for exposing API endpoints, authentication/authorization, and interfacing with other components. It also handles authentication and authorization of requests and provides an interface for other components to access the cluster's state.
It implements a RESTful interface, allowing various tools and libraries to communicate with it. The default method of interacting with the Kubernetes cluster from a local computer is through a client called kubectl.
The controller manager — kube-controller-manager — is a general service responsible for managing different controllers that maintain the state of the cluster, manage workload life cycles, and carry out routine tasks.
It watches for changes through the API server, reads new information, and implements procedures to fulfill the desired state, such as scaling an application up or down, adjusting endpoints, etc.
The scheduler — kube-scheduler — is responsible for assigning workloads to specific nodes in the cluster. It reads a workload's requirements, analyzes the infrastructure environment, and places the work on an appropriate node or node.
It also tracks available capacity on each host to ensure workloads are not scheduled in excess of the available resources. It is aware of the total capacity and resources already allocated to existing workloads on each server.
Cloud controller managers enable Kubernetes to interact with different cloud providers, mapping generic representations of resources to the actual resources provided by the provider.
This enables Kubernetes to constantly update its state information based on information gathered from the cloud provider, adjust cloud resources upon changes, and create/utilize additional cloud services to satisfy work demands submitted to the cluster.
Node Server Components
In Kubernetes, servers that run containers are known as nodes. These nodes must meet certain requirements in order to communicate with master components, configure container networking, and run workloads assigned to them.
Kubernetes nodes require a container runtime, usually Docker; however, alternatives such as rkt and runc are also available for use.
The container runtime is responsible for starting and managing containers, which are lightweight operating environments that encapsulate applications. Each unit of work on the cluster is implemented as one or more containers that must be deployed, and the container runtime on each node is the component that runs them.
Kubelet is the main contact point for each node with the cluster group. It relays information to and from the control plane services and interacts with the etcd store to read configuration details or write new values.
Kubelet communicates with the master components to authenticate to the cluster and receive commands and work, which is received in the form of a manifest that defines the workload and operating parameters. It then assumes responsibility for maintaining the state of the work on the node server, controlling the container runtime to launch or destroy containers as needed.
Kube-proxy is a small proxy service run on each node server to manage individual host subnetting and make services available to other components. It forwards requests to the correct containers, performs primitive load balancing, and ensures the networking environment is predictable, accessible, and isolated where appropriate.
Kubernetes Objects and Workloads
Kubernetes provides additional layers of abstraction over the container interface to provide scaling, resiliency, and life cycle management features. Users define and interact with instances composed of various primitives provided by the Kubernetes object model instead of managing containers directly.
These objects are used to define workloads and provide powerful features for managing applications.
Kubernetes deals with pods, which are one or more tightly coupled containers encapsulated in an object.
Pods represent single applications, consisting of a main container and, optionally, some helper containers that facilitate closely related tasks. They share their environment, volumes, and IP space and are managed as a unit.
Horizontal scaling is generally discouraged on the pod level, and users should not manage pods themselves, as higher-level objects provide additional features like sophisticated life cycle management and scaling.
Replication Controllers and Replication Sets
When using Kubernetes, it is common to manage multiple replicas of the same pod instead of a single one. These replicas are created from a template and can be scaled horizontally with the help of replication controllers and replication sets.
A replication controller is an object that enables the scaling of identical replicas of a pod horizontally by increasing or decreasing the number of running copies. This is a native Kubernetes feature that allows for load distribution and increased availability.
The replication controller contains a template that closely resembles a pod definition, allowing it to create new pods as needed. It also ensures that the number of pods deployed in the cluster matches the number specified in its configuration. If any pods or underlying hosts fail, the controller will start new ones to compensate.
Replication controllers can also perform rolling updates to roll over a set of pods to a new version one by one, minimizing disruption to application availability.
Replication sets are like an improved version of replication controllers, offering more flexibility in how the controller identifies the pods it is meant to manage.
The replication sets are becoming increasingly popular and replacing replication controllers, although they cannot perform rolling updates. They are used within higher-level units that provide this functionality, adding horizontal scaling and reliability guarantees but lacking some of the more advanced life cycle management capabilities.
Deployments are one of the most common workloads to directly create and manage, using replication sets as a building block to add life cycle management functionality.
Deployments solve many of the pain points that existed in the implementation of rolling updates with replication controllers, such as tracking history, recovering from network failures during the update, and rolling back bad changes.
Deployments are designed to ease the life cycle management of replicated pods, allowing for easy modification by changing the configuration and managing transitions between different application versions. They also maintain event history and undo capabilities automatically, making them the type of Kubernetes object you will likely work with most frequently.
Stateful sets are specialized pod controllers that provide ordering and uniqueness guarantees, primarily used when special requirements related to deployment ordering, persistent data, or stable networking are needed. They are often used with data-oriented applications like databases, which need access to the same volumes even if rescheduled to a new node.
Stateful sets create a unique, number-based name for each pod that will remain even if the pod is moved to another node, providing stable networking identifiers. They also ensure persistent storage volumes can be transferred with a pod when rescheduling is necessary and persist even after the pod has been deleted to prevent accidental data loss.
Stateful sets perform operations according to the numbered identifier in their name when deploying or adjusting scale, providing greater predictability and control over the order of execution.
Daemon sets are also specialized pod controllers that run a copy of a pod on each node in the cluster (or a subset, if specified). This is often used for deploying pods that help perform maintenance and provide services for the nodes themselves, such as collecting and forwarding logs, aggregating metrics, and running services that increase the capabilities of the node.
Daemon sets often provide essential services and are needed throughout the fleet, allowing them to bypass pod scheduling restrictions that prevent other controllers from assigning pods to certain hosts. For example, they can override the restriction on a pod-by-pod basis to ensure essential services are running on the master server, which is usually unavailable for normal pod scheduling.
Jobs and Cron Jobs
Jobs are workloads that provide a task-based workflow, where the running containers are expected to exit successfully after some time once they have completed their work. They are useful for one-off or batch processing instead of running a continuous service.
Cron jobs build on jobs, providing an interface to run jobs with a scheduling component. They can be used to schedule a job to execute in the future or on a regular, reoccurring basis, essentially reimplementing classic cron behavior using the cluster as a platform instead of a single operating system.
Kubernetes Networking Components
Kubernetes components (Pods, containers, nodes, applications) use various networking methods to communicate with each other. These include container-to-container communication, Pod-to-Pod communication, Pod-to-service communication, and external-to-service communication.
Kubernetes network model allows pods to be treated similarly to VMs or hosts, as they all have unique IP addresses, and containers within pods can be treated like processes running within a VM or host, sharing the same network namespace. This enables Pods to communicate with each other according to network policies set by the network plugin without needing to create links between them or map container ports to host ports. In addition, this makes it easier for applications to be migrated from VMs and hosts to pods managed by Kubernetes.
Kubernetes networking presents a challenge in addressing how internal (east-west) and external (north-south) traffic interact, as the internal network is isolated from the external network. However, traffic between nodes can also flow to and from nodes and an external physical or virtual machine. There are several ways of getting external traffic into a Kubernetes cluster:
LoadBalancer is the standard way to connect a service to the internet. A network load balancer forwards external traffic to a service, each with its own IP address.
The Kubernetes load balancer distributes connections evenly across all available servers, ensuring that no single server is overloaded and services are highly available and can handle large amounts of traffic.
ClusterIP is the default Kubernetes service for internal communications, allowing services within the cluster to communicate with each other.
External traffic can access the default Kubernetes ClusterIP service through a proxy, which is useful for debugging services or displaying internal dashboards. This allows external users to access services running within the cluster without having to expose them directly to the internet.
NodePort opens ports on the nodes or virtual machines, assigning a port to each service. Traffic is then forwarded from the ports to the service, allowing external traffic to access the service without having to configure a load balancer.
NodePort is most often used for services that don't always have to be available, such as demo applications. It is most useful for testing and debugging services, as it allows direct access to the service from outside the cluster.
Ingress enables external traffic to be directed to services running in a Kubernetes cluster. It provides an external gateway for HTTP and HTTPS traffic, allowing you to manage the routing of requests to various services within your cluster. In addition, Ingress offers features such as TLS termination, authentication, and rate limiting.
As a controller, Ingress is useful if you want to use the same IP address to expose multiple services, as it allows you to configure rules for routing traffic based on the URL path or hostname.
Container Networking Interface
Kubernetes networking includes Container Networking Interface (CNI), which enables the communication between Pods across nodes. CNI provides a bridge between a network namespace and a network plugin or provider, offering a wide range of features and functionality.
CNI plugins can dynamically configure a network and resources as Pods are provisioned and destroyed, as well as provision and manage IP addresses when containers are created or deleted.
Kubernetes is the default networking provider for Kubernetes. Still, other CNI plugins such as Flannel, Calico, Canal, and Weave Net offer more control and monitoring capabilities while reducing manual network configuration overhead.
Volumes provide a way to reliably share data between containers and guarantee its availability even after the container restarts. This allows tightly coupled pods to easily share files without complex external mechanisms. However, once the pod is terminated, the shared volume is destroyed, so it is not suitable for truly persistent data.
To address this, Kubernetes also offers Persistent Volumes, which are more robust storage solutions that are not tied to the pod life cycle. Administrators can configure storage resources for the cluster that users can request and claim for their pods. When a pod is done with a persistent volume, the volume's reclamation policy determines whether the volume is kept around until manually deleted or removed along with the data immediately.
Kubernetes is an incredible project that enables users to run containerized workloads at scale with high availability. Its architecture and components may seem complex, but they offer unparalleled power, flexibility, and features in the open-source world. By understanding how the basic building blocks work together, you can design systems that take full advantage of the platform's capabilities to manage your workloads efficiently.
Published at DZone with permission of Saqib Jan. See the original article here.
Opinions expressed by DZone contributors are their own.
A React Frontend With Go/Gin/Gorm Backend in One Project
Essential Architecture Framework: In the World of Overengineering, Being Essential Is the Answer
A Deep Dive Into the Differences Between Kafka and Pulsar
Revolutionizing System Testing With AI and ML