container orchestration!
The Container Journey: From One to Many
Imagine you’re building a new application. You start with a single container – a lightweight, portable package that holds everything your application needs to run (code, libraries, dependencies, etc.). It’s like having a self-contained mini-computer for your app. For a while, managing one container is simple.
However, as your application grows, you’ll need more containers. Maybe you’re adding new features, deploying to different regions for better availability, or scaling up to handle more users. Soon, that one container turns into tens, hundreds, or even thousands!
This is where the challenge begins. Manually managing a large number of containers becomes incredibly complex and time-consuming. Think about:
- Connecting them: How do different containers talk to each other to form a cohesive application (like a web app connecting to a database)?
- Scaling them: How do you quickly add or remove containers based on demand?
- Managing them: What happens if a container fails? How do you update them without downtime?
- Resource allocation: How do you ensure each container gets the right amount of CPU, memory, and storage?
This is where container orchestration steps in.
What is Container Orchestration?
Container orchestration is an automated process that manages the entire lifecycle of containerized applications. It handles the deployment, management, scaling, networking, and availability of your containers. In simpler terms, it’s like having a highly intelligent conductor for your orchestra of containers, ensuring everything runs smoothly and harmoniously.
Why is Container Orchestration Necessary?
In today’s fast-paced, dynamic environments, container orchestration is crucial because it:
- Streamlines Complexity: It takes away the burden of manually managing individual containers, making large-scale deployments much more manageable.
- Enables Hands-Off Deployment and Scaling: You define how your application should run, and the orchestration tool automatically deploys and scales it to meet demand.
- Increases Speed, Agility, and Efficiency: With automation, you can deploy new features faster, respond to changes more quickly, and use your computing resources more effectively.
- Seamlessly Integrates into CI/CD and DevOps: It fits perfectly into modern development practices, allowing for continuous integration and continuous delivery of software.
- Optimizes Resource Utilization: Development teams can make better use of infrastructure resources, leading to cost savings.
Where Can You Implement It?
Container orchestration isn’t limited to a specific environment. You can implement it:
- On-premises: On your own servers within your data center.
- Public Cloud: On platforms like AWS, Google Cloud, or Azure.
- Private Cloud: In a cloud environment dedicated to a single organization.
- Multi-Cloud: Across multiple public and/or private cloud environments.
It’s also often a critical component of an organization’s Security Orchestration, Automation, and Response (SOAR) requirements, helping to automate security processes and responses.
Key Features of Container Orchestration Tools
Container orchestration tools come with a rich set of features designed to automate and simplify container management:
- Defining Application Structure: You specify which container images make up your application and where they are stored (in a registry).
- Automated Provisioning and Deployment: They automate the process of setting up and deploying containers, making it smoother and more consistent.
- Secure Network Connections: They ensure that containers can communicate with each other securely.
- High Availability and Performance: If a host or container goes down, or if resources become scarce, the orchestration tool can automatically relocate containers to another healthy host, minimizing downtime.
- Intelligent Scaling: They can automatically scale containers up or down to meet fluctuating demand and distribute incoming requests evenly (load balancing).
- Resource Allocation and Scheduling: They efficiently assign CPU, memory, and storage to containers and schedule them to the most appropriate underlying infrastructure.
- Rolling Updates and Rollbacks: They allow you to update your applications without downtime by gradually replacing old containers with new ones. If something goes wrong, you can easily revert to a previous version.
- Health Checks: They continuously monitor the health of your applications and take corrective actions (like restarting or replacing a container) if checks fail.
How Does It Work Under the Hood?
Container orchestration uses configuration files, typically written in YAML or JSON. These files describe:
- Container specifications: How each container should be configured.
- Resource requirements: CPU, memory, etc.
- Networking: How containers connect to each other.
- Storage: Where logs and data are stored.
Based on these files, the orchestration tool automatically:
- Schedules new containers: It finds the best host in a cluster (a group of interconnected machines) for a new container based on predefined settings.
- Manages the container’s lifecycle: It ensures containers adhere to the specified system and file parameters throughout their existence.
This automation significantly enhances productivity and makes scaling much easier.
Popular Container Orchestration Tools
Several powerful tools are available for container orchestration, each with its strengths:
- Marathon (for Apache Mesos): An open-source cluster manager that helps scale container infrastructure by automating management and monitoring tasks. It’s built on Apache Mesos.
- HashiCorp Nomad: A free and open-source tool that manages and schedules various workloads, including Docker containers, virtualized applications, and standalone applications, across different operating systems and infrastructures (on-premises or cloud). Its flexibility makes it suitable for diverse workload types.
- Docker Swarm: Designed specifically to work with Docker Engine and other Docker tools, Docker Swarm automates the deployment of containerized applications. It’s a popular choice for teams already invested in the Docker ecosystem.
- Kubernetes (K8s): Developed by Google and maintained by the Cloud Native Computing Foundation (CNCF), Kubernetes has become the de facto standard for container orchestration. It automates a wide range of container management tasks, including:
- Deployment
- Storage provisioning
- Load balancing
- Scaling
- Service discovery
- Self-healing: The ability to automatically restart, replace, or remove failed containers.
Kubernetes has a vast and expanding ecosystem of open-source tools and is widely supported by leading cloud providers, many of whom offer fully managed Kubernetes services.
The Benefits of Container Orchestration
Container orchestration isn’t just a technical solution; it directly helps businesses achieve their goals and increase profitability through automation. Here are the key benefits for developers and administrators:
- Increased Productivity: By automating the installation and management of individual containers, developers and administrators are freed from repetitive tasks. This reduces errors and allows teams to focus on improving applications and innovating.
- Faster Deployments: You can iteratively release new features and capabilities more rapidly, deploying containers and containerized applications with incredible speed.
- Reduced Costs: Containers are lightweight and have lower overhead compared to virtual machines or traditional servers. This means they use fewer resources, leading to more cost-effective operations.
- Stronger Security: Container orchestration helps in sharing resources efficiently while isolating application processes, which contributes to a more secure container environment.
- Easier Scalability: Scaling applications up or down can often be done with a single command, making it simple to adapt to changing demands.
- Faster Error Recovery: By automatically detecting and resolving issues like infrastructure failures, container orchestration helps maintain high availability and ensures your applications are always accessible.
Wrapping Up
Managing a handful of containers might be easy, but when you deal with hundreds or thousands, it quickly becomes an overwhelming task. Container orchestration automates the entire container lifecycle, from deployment and scaling to networking and self-healing. This results in:
- Faster deployments
- Reduced errors
- Higher availability
- Stronger security
Tools like Marathon, Nomad, Docker Swarm, and especially Kubernetes, are at the forefront of this technology. By adopting container orchestration, organizations can significantly improve productivity, reduce costs, enhance security, and achieve greater agility in their application development and deployment processes.
Introduction to Kubernetes.
Welcome to the World of Kubernetes (K8s)!
Kubernetes, often affectionately called K8s (because there are 8 letters between the ‘K’ and the ‘s’), is a revolutionary open-source system. Its primary purpose is to automate the deployment, scaling, and management of containerized applications.
Think of it as the ultimate orchestrator for your containers. If your applications are a symphony of individual instruments (containers), Kubernetes is the conductor ensuring every instrument plays in harmony, at the right time, and with the right volume.
The Rise of Kubernetes
Kubernetes was initially developed as a project by Google, leveraging their vast experience in running containerized applications at scale. Today, it’s maintained by the Cloud Native Computing Foundation (CNCF), a vendor-neutral organization fostering the adoption of cloud-native technologies.
Its widespread adoption has firmly established it as the de facto choice for container orchestration. This means if you’re working with containers at scale, you’re very likely to encounter Kubernetes.
Portability and Flexibility
One of Kubernetes’ most significant strengths is its portability. You can run Kubernetes clusters:
- On-premises: In your own data centers.
- Across various clouds: On public cloud providers like AWS, Google Cloud, Azure, IBM Cloud, etc.
This flexibility allows organizations to avoid vendor lock-in and choose the infrastructure that best suits their needs.
Declarative Management: The “Desired State”
Kubernetes operates on a principle called declarative management. Instead of telling Kubernetes how to do something step-by-step, you declare the desired state of your application. For example, you might say, “I want three replicas of my web application running, accessible on port 80.”
Kubernetes then constantly monitors the actual state of your cluster and automatically performs the necessary operations to achieve and maintain that desired state. If a container crashes, Kubernetes will automatically restart it. If traffic increases, it can scale up your application.
What Kubernetes Is NOT (Important Distinctions)
To truly understand Kubernetes, it’s helpful to clarify what it’s not:
- Not a Traditional All-Inclusive Platform as a Service (PaaS): Unlike older PaaS solutions that provided a rigid, opinionated framework for building and deploying apps, Kubernetes is much more flexible. It’s a foundational layer upon which you can build your own PaaS or specialized platforms.
- Not Rigid or Opinionated: Kubernetes doesn’t dictate how you build your applications or which programming languages you use. It’s incredibly versatile and supports a wide variety of workloads, including:
- Stateless workloads: Applications that don’t store session data (e.g., a simple web server).
- Stateful workloads: Applications that require persistent storage and maintain state (e.g., databases).
- Data processing workloads: Applications for analyzing large datasets.
- Essentially, if an application can be containerized, Kubernetes can run it.
- Does NOT Provide Built-in CI/CD Pipelines: While crucial for modern development, Kubernetes doesn’t offer tools for building applications or deploying source code directly. It assumes you have a CI/CD pipeline (e.g., Jenkins, GitLab CI, GitHub Actions) that produces container images, which Kubernetes then deploys.
- Does NOT Prescribe Logging, Monitoring, or Alerting Solutions: Kubernetes provides mechanisms to collect logs and metrics, but it doesn’t force you to use specific tools for viewing, analyzing, or alerting on them. Organizations are free to integrate their preferred third-party and open-source solutions (e.g., Prometheus for monitoring, Grafana for visualization, ELK stack for logging).
- Does NOT Provide Built-in Middleware, Databases, or Other Services: Kubernetes is an orchestration platform, not a full-stack application environment. While you can run databases or message queues as containers on Kubernetes, it doesn’t provide them as managed services.
Essential Kubernetes Concepts
Understanding these core concepts is fundamental to working with Kubernetes:
- Pods:
- The smallest deployable compute object in Kubernetes.
- A Pod represents a single instance of a running process in your cluster.
- It can contain one or more containers that are tightly coupled and share resources (network namespace, storage volumes).
- Each Pod is assigned a unique IP address.
- Pods are ephemeral; they can be created, destroyed, and recreated.
- Services:
- Abstract a logical set of Pods and define a policy by which to access them.
- Services provide a stable network endpoint (a single DNS name and IP address) for a group of Pods, even if the underlying Pods are created, destroyed, or moved. This is crucial for load balancing and service discovery.
- Storage:
- Kubernetes supports both persistent (data survives Pod restarts) and temporary (data is lost when a Pod is destroyed) storage for Pods.
- This is handled through various volume types, including local storage, network storage (e.g., NFS, iSCSI), and cloud-specific storage (e.g., AWS EBS, Google Persistent Disk).
- Configuration:
- Refers to how you provision resources and configure your Pods. This includes settings like environment variables, command-line arguments, and files.
- ConfigMaps and Secrets are Kubernetes objects used for storing non-sensitive and sensitive configuration data, respectively.
- Security Measures:
- Enforces security for Pod and API access, crucial for cloud-native workloads.
- This includes Role-Based Access Control (RBAC) to control who can do what within the cluster and Network Policies to control traffic flow between Pods.
- Policies for Groups of Resources:
- Ensuring that Pods match to Nodes (the worker machines in a cluster) so that the kubelet (the agent that runs on each Node) can find and run the Pods. This involves concepts like node selectors, affinities, and anti-affinities.
- Scheduling and Eviction:
- The process by which Kubernetes decides which Node a Pod should run on.
- Eviction proactively terminates one or more Pods on resource-starved Nodes to make room for other Pods.
- Preemption:
- A mechanism for prioritizing Pods. If a higher-priority Pod needs to be scheduled but there isn’t enough capacity, Kubernetes can terminate (preempt) lower-priority Pods to make room.
- Cluster Administration:
- Encompasses all the details necessary to create, maintain, and manage a Kubernetes cluster, including setting up networking, storage, and security.
Powerful Kubernetes Capabilities
Kubernetes offers a wide array of capabilities that automate complex tasks:
- Automated Rollouts and Rollbacks:
- You can declare how you want to update your application (e.g., gradually rolling out new versions).
- Kubernetes automates this process, monitoring the health of new instances. If issues arise, it can automatically roll back to the previous stable version.
- Storage Orchestration:
- Automatically mounts a chosen storage system to your Pods. This can be local storage, network-attached storage, or cloud-specific storage, allowing stateful applications to run reliably.
- Horizontal Scaling:
- Automatically scales your workloads up or down based on metrics (e.g., CPU utilization, custom metrics) or via manual commands. This ensures your application can handle varying loads.
- Automated Bin Packing:
- Increases resource utilization and cost savings by efficiently placing containers on Nodes.
- It intelligently packs containers based on their resource requirements and available Node resources, without sacrificing high availability.
- Secret and Configuration Management:
- Handles sensitive information like passwords, OAuth tokens, and SSH keys securely.
- It allows you to update secrets and configurations without rebuilding container images or redeploying applications.
- IPv4/IPv6 Dual-Stack Support:
- Kubernetes can assign both IPv4 and IPv6 addresses to Pods and Services, enabling modern network configurations.
- Batch Execution and CI Workloads:
- Manages both long-running services and short-lived batch jobs or continuous integration tasks.
- Self-Healing:
- One of its most powerful features. Kubernetes automatically replaces failed containers, restarts unresponsive containers, and terminates containers that don’t pass health checks. This ensures high availability and resilience.
- Service Discovery and Load Balancing:
- Pods can discover each other using IP addresses or DNS names provided by Kubernetes.
- Services automatically load balance traffic across the Pods they manage, distributing requests evenly for better performance and high availability.
- Extensibility:
- Designed to be highly extensible, allowing you to add features to your cluster without modifying its core source code. This is achieved through Custom Resource Definitions (CRDs) and operators.
The Vibrant Kubernetes Ecosystem
The Kubernetes ecosystem is vast and rapidly growing, encompassing a wide range of services, support, and tools from various providers. Running containerized applications at scale often requires more than just Kubernetes itself; it integrates with other specialized tools.
Here’s a glimpse into the different categories of providers within the Kubernetes ecosystem:
- Public Cloud Providers: Offer fully managed Kubernetes services, making it easy to deploy and operate clusters without managing the underlying infrastructure.
- Google (Google Kubernetes Engine - GKE)
- Amazon Web Services (Amazon Elastic Kubernetes Service - EKS)
- IBM
- Microsoft Azure (Azure Kubernetes Service - AKS)
- …and many more.
- Open Source Framework Providers: Companies contributing to and building solutions around Kubernetes.
- Red Hat (OpenShift)
- VMware (Tanzu)
- SUSE
- Docker
- Cloud Foundry
- Mesosphere
- Management Providers: Tools and platforms that simplify the management and operation of Kubernetes clusters.
- DigitalOcean
- Loodse
- SUPERGIANT
- CloudSoft
- Turbonomic
- Tectonic
- Weaveworks
- Tool Providers: Offer specialized tools for various aspects of the container and Kubernetes lifecycle.
- JFrog (Artifactory for registries)
- Univa
- Aspen Mesh
- Bitnami (for pre-packaged applications)
- Cloud 66
- Monitoring and Logging Providers: Solutions for observing the performance and behavior of your applications and infrastructure running on Kubernetes.
- Sumo Logic
- Datadog
- New Relic
- Iguazio
- Grafana (for dashboards and visualization)
- SignalFX
- Sysdig
- Dynatrace
- Security Providers: Focus on securing your containerized applications and Kubernetes clusters.
- Guardicore
- Black Duck
- Yubico
- Cilium (for network security)
- Aqua Security
- Twistlock
- Alcide
- Load Balancing Providers: Tools and services to distribute network traffic to your applications.
- AVI Networks
- VMware
- NGiNX (as an ingress controller)
In Conclusion
Kubernetes is a highly portable, horizontally scalable, open-source container orchestration system that fundamentally automates deployment and simplifies the management of your applications.
Its core concepts revolve around:
- Pods: The basic building blocks.
- Services: For reliable access and load balancing.
- Storage, Configuration, and Security: Essential aspects of application operation.
- Scheduling, Eviction, and Preemption: Mechanisms for efficient resource utilization.
- Cluster Administration: The foundation for managing the entire system.
Kubernetes’ powerful capabilities include:
- Automated rollouts and rollbacks: For seamless updates.
- Storage orchestration: For persistent data.
- Horizontal scaling: To handle varying loads.
- Automated bin packing: For efficient resource use.
- Secret and configuration management: For secure handling of sensitive data.
- Self-healing: For high availability and resilience.
- Service discovery and load balancing: For robust networking.
- Designed for extensibility: To adapt to future needs.
The thriving Kubernetes ecosystem provides a vast array of complementary tools and services from various providers, ensuring that you have the support and resources needed to build, deploy, and manage your containerized applications effectively.
Kubernetes architecture
Understanding Kubernetes Architecture: The Brains and the Brawn
A deployment of Kubernetes is called a Kubernetes cluster. At its core, a Kubernetes cluster is a collection of machines (nodes) that work together to run your containerized applications.
Every Kubernetes cluster is made up of two main logical components:
- The Control Plane (The Brains): This is the “master” part of the cluster. It’s responsible for making global decisions about the cluster and detecting/responding to events. Think of it as the cluster’s operating system or central nervous system.
- Worker Nodes (The Brawn): These are the “worker” machines where your actual applications (containers inside Pods) run.
Let’s break down each of these components.
The Control Plane: The Mastermind of Your Cluster
The control plane is the core set of components that maintain the desired state of your Kubernetes cluster. It continuously monitors the cluster and, if the actual state doesn’t match the desired state you’ve defined, it takes action to correct it.
Analogy: Imagine a thermostat. You set the desired temperature (your desired state). The thermostat (control plane) constantly monitors the room temperature (actual state) and, if it’s too hot or cold, it turns on the heating or cooling system (takes action) to bring the room to your desired temperature.
Examples of control plane decisions and actions:
- Scheduling workloads: Deciding where a newly deployed application (a Pod) should run within the cluster.
- Creating new resources: Automatically spinning up new instances of your application if you’ve configured it to scale based on demand.
The machines running the control plane components are often referred to as master nodes, though Kubernetes can run its control plane across multiple machines for high availability.
Key Components of the Kubernetes Control Plane:
-
Kube-API-Server (The Front-End and Communication Hub)
- What it does: This is the primary interface to the Kubernetes cluster. It exposes the Kubernetes API, which is how all internal and external communication within the cluster happens.
- How it works: When you (or another component) want to view or change the state of the cluster (e.g., deploy an application, check a Pod’s status), you send a command to the API server.
- Scalability: The
kube-api-server
is designed to be highly scalable. You can run multiple instances of it and load balance traffic between them to ensure high availability and performance.
-
Etcd (The Cluster Database)
- What it does:
etcd
is a highly available, distributed key-value store. It serves as the single source of truth for your entire Kubernetes cluster. - How it works: All cluster data, including the desired state of your applications, network configurations, and secrets, is stored here. When you tell Kubernetes to deploy your application, that deployment configuration immediately goes into
etcd
. The entire Kubernetes system works to bring the actual state of the cluster in line with the state defined inetcd
.
- What it does:
-
Kube-Scheduler (The Workload Distributor)
- What it does: The
kube-scheduler
is responsible for assigning newly created Pods (your application workloads) to available worker nodes. - How it works: It looks at various factors like resource requirements (CPU, memory), hardware constraints, policy constraints, data locality, inter-workload interference, and deadlines to select the “most optimal” node for a Pod to run on.
- What it does: The
-
Kube-Controller-Manager (The State Enforcer)
- What it does: The
kube-controller-manager
runs various controller processes. These controllers continuously monitor the cluster’s actual state via the API server and compare it to the desired state stored inetcd
. - How it works: If there’s a discrepancy, a controller takes action to bring the actual state closer to the desired state. For example:
- A replication controller ensures a specified number of Pod replicas are always running.
- A node controller monitors node health.
- A service account controller manages user accounts for processes.
- What it does: The
-
Cloud-Controller-Manager (For Cloud Integrations)
- What it does: This component runs controllers that specifically interact with the underlying cloud provider’s APIs.
- How it works: It allows Kubernetes to integrate with cloud-specific features like:
- Node management: Creating, deleting, or updating cloud instances.
- Route management: Setting up network routes for containers.
- Load balancer management: Provisioning cloud load balancers for Kubernetes Services.
- Why it’s separate: Kubernetes aims to be cloud-agnostic. By having the
cloud-controller-manager
as a separate component, both Kubernetes and cloud providers can evolve independently without tightly coupling their codebases.
Worker Nodes: Where Your Applications Live
Worker nodes are the machines where your user applications actually run. These nodes can be virtual machines (VMs) in a cloud environment or physical servers on-premises. They are managed by the control plane and contain the necessary services to run and connect your containerized applications.
Key Components of a Kubernetes Worker Node:
-
Pods (The Smallest Deployable Unit)
- What they are: As mentioned before, Pods are the smallest deployable compute object in Kubernetes. Each Pod represents a single instance of a running process.
- What they contain: A Pod typically contains one or more containers (e.g., your application code, a sidecar for logging). Containers within the same Pod share the Pod’s network namespace, storage volumes, and can communicate with each other directly.
-
Kubelet (The Node Agent)
- What it does: The
kubelet
is the most important agent running on every worker node. It’s the primary “worker” that communicates with thekube-api-server
. - How it works:
- It receives Pod specifications (instructions on which containers to run and how) from the API server.
- It ensures that the containers specified in the Pod are running and healthy on its node.
- It continuously reports the health and status of the Pods and the node itself back to the control plane.
- When it needs to start a container, the
kubelet
interacts with the container runtime.
- What it does: The
-
Container Runtime (Running Your Containers)
- What it does: The container runtime is the software responsible for downloading container images and running the containers on the worker node.
- How it works: Kubernetes uses a Container Runtime Interface (CRI), which allows for pluggability. This means Kubernetes can work with various container runtimes without being tied to a single one.
- Examples: While Docker is historically well-known, other popular and often more lightweight container runtimes include containerd, Podman, and CRI-O.
-
Kube-Proxy (The Network Proxy)
- What it does: The
kube-proxy
is a network proxy that runs on each node in the cluster. It’s essential for enabling network communication within your Kubernetes cluster. - How it works: It maintains network rules (using
iptables
oripvs
on Linux) on the node that allow network communication to your Pods, both from inside and outside the cluster. When you define a Kubernetes Service,kube-proxy
ensures that traffic directed to that Service’s IP address is correctly routed to the appropriate Pods, often involving load balancing across multiple Pods.
- What it does: The
Putting It All Together
In essence, the Kubernetes control plane is the brain that makes all the decisions, orchestrates resources, and maintains the cluster’s desired state. The worker nodes are the muscle, executing the workloads and running your actual applications, constantly reporting their status back to the control plane.
Kubernetes objects.
Welcome to Kubernetes Objects Part 1: The Building Blocks of Your Cluster
In the world of Kubernetes, everything you manage and control is represented as a Kubernetes Object. These objects are like the fundamental nouns in the Kubernetes language – they describe what you want your cluster to look like.
What is an “Object” in the Computing World?
Before diving into Kubernetes objects, let’s quickly review the general concept of an “object” in computing:
- Real-world Object: Something with an identity (it’s unique), a state (its current condition), and behavior (what it can do). Think of a “window” on your computer screen – it has a unique ID, it’s open/closed/minimized (state), and you can click, drag, or resize it (behavior).
- Software Object: A bundle of data that also has an identity, a state, and behavior. Examples include variables, data structures, or specific functions.
- Entity: Similar to an object, often used in databases to refer to something with an identity and associated data, like a “customer account” in a banking system.
- Persistent: This term means something will last even if there’s a server failure or network attack. Data stored persistently remains available (e.g., persistent storage).
Kubernetes Objects: Persistent Entities
Kubernetes objects are persistent entities that you use to represent the state of your cluster. They describe what you want your applications to look like, how they should run, and the resources they need.
Examples of Kubernetes objects include:
- Pods: The smallest deployable unit.
- Namespaces: For organizing resources.
- ReplicaSets: For maintaining a stable set of identical Pods.
- Deployments: A higher-level object for managing ReplicaSets and enabling updates.
- And many more, such as Services, Volumes, ConfigMaps, Secrets, etc.
The Two Main Fields of a Kubernetes Object: spec
and status
Every Kubernetes object you interact with fundamentally consists of two key fields:
-
spec
(Specification - Desired State):- This is provided by you, the user.
- It defines the desired state of the object. You tell Kubernetes what you want to achieve.
- Example: For a Pod, the
spec
might include the container image to run, the ports to expose, and resource limits. For a Deployment, it defines how many replicas you want.
-
status
(Current State):- This is provided and updated by Kubernetes.
- It describes the current state of the object in the cluster.
- Example: For a Pod, the
status
might show whether it’sRunning
,Pending
, orFailed
. For a Deployment, it shows how many replicas are currently ready.
The Core Principle: Kubernetes continuously works towards matching the current state
(status) to your desired state
(spec). This is the power of declarative management. You declare what you want, and Kubernetes works tirelessly to make it happen.
Interacting with Kubernetes Objects
You interact with Kubernetes objects primarily through the Kubernetes API. You can use:
kubectl
command-line interface (CLI): This is the most common way for humans to interact with the API. You use commands likekubectl apply -f my-pod.yaml
,kubectl get pods
, etc.- Client Libraries: For programmatic interaction (e.g., Go, Python, Java client libraries) to build custom automation or applications that integrate with Kubernetes.
Organizing and Grouping Objects
As your cluster grows, you’ll have many objects. Kubernetes provides mechanisms to organize and group them:
Labels and Label Selectors
- Labels: These are key-value pairs that you attach to objects. They are primarily intended for identification, organization, and grouping of objects.
- Example:
app: nginx
,environment: production
,tier: frontend
. - Important: A label does not uniquely identify a single object. Many objects can have the same labels. This is precisely what makes them powerful for grouping.
- Example:
- Label Selectors: These are the core grouping method in Kubernetes. They allow you to identify and select a set of objects that have specific labels.
- Example: A
Service
might use a label selectorapp: nginx
to route traffic to all Pods with that label.
- Example: A
Namespaces
- What they are: Namespaces provide a mechanism for isolating groups of resources within a single cluster.
- Why they are useful:
- Resource Isolation: Prevent naming collisions between different teams or projects.
- Cost-Saving: Allows multiple teams/projects to share a single, larger cluster without interfering with each other.
- Access Control: You can set up Role-Based Access Control (RBAC) permissions at the namespace level, granting different teams access only to their specific resources.
- Ideal for Large Clusters: Particularly useful when many users or teams share the cluster.
- Examples:
kube-system
: Reserved for Kubernetes system components.default
: The default namespace where user applications are often deployed if no other namespace is specified.
- Naming Scope: Namespaces provide a scope for the names of objects. An object’s name must be unique within its namespace for that resource type. For example, you can have a Pod named
my-app
in thedev
namespace and another Pod also namedmy-app
in theprod
namespace.
Basic Kubernetes Objects and Their Relationships
Now, let’s look at some of the most fundamental Kubernetes objects:
Pods: The Smallest Deployable Unit
-
Definition: A Pod represents a single instance of an application (or part of an application) running in the cluster. It’s the smallest deployable compute object you can create and manage in Kubernetes.
-
Contents: A Pod typically wraps one or more containers. Containers within the same Pod share the same network namespace, storage volumes, and can communicate with each other via
localhost
. -
Scaling: Creating multiple replicas of a Pod (managed by higher-level objects) allows you to scale your application horizontally.
-
Defining a Pod (YAML Example): Kubernetes objects are typically defined using YAML (Yet Another Markup Language) files.
apiVersion: v1 # The Kubernetes API version kind: Pod # The type of Kubernetes object we're defining metadata: name: nginx-pod # The name of our Pod labels: app: nginx # A label for this Pod spec: # The desired state of the Pod containers: - name: nginx # Name of the container within the Pod image: nginx:latest # The Docker image to use ports: - containerPort: 80 # The port the container exposes
kind: Pod
: Specifies that we’re creating a Pod object.spec.containers
: Lists the containers that will run inside this Pod. A Pod must have at least one container.image
: Dictates which container image to use (e.g.,nginx:latest
from Docker Hub).ports
: Lists the ports the container exposes.
ReplicaSets: Ensuring a Stable Number of Pods
- Definition: A ReplicaSet ensures that a specified number of identical running replicas of a Pod are maintained at any given time. It acts as a controller for Pods.
- Purpose: If a Pod fails, the ReplicaSet will automatically create a new one to replace it. If you manually delete a Pod, the ReplicaSet will bring up another.
- Configuration: ReplicaSets have a
replicas
field to specify the desired count and apodTemplate
that defines the Pods it should create. - Selector: A ReplicaSet uses a
selector
(based on labels) to identify which Pods it “owns” and should manage. The labels in thematchLabels
field of the selector must match the labels in the Pod template. - Recommendation: Creating ReplicaSets directly is generally NOT recommended for most users. Why? Because a higher-level object, the Deployment, offers more features and better control.
Deployments: The Go-To for Managing Applications
-
Definition: A Deployment is a higher-level object that provides declarative updates for Pods and ReplicaSets. It manages the lifecycle of your application.
-
Purpose: Deployments are suitable for stateless applications (applications that don’t need to remember past interactions or store persistent data within themselves).
- For stateful applications (like databases), you’d typically use StatefulSets, which provide stable identities and ordered deployments.
-
Features: Deployments run multiple replicas of an application using ReplicaSets and offer additional management capabilities:
- Rolling Updates: This is a key feature provided by Deployments that ReplicaSets alone don’t offer. A rolling update allows you to update your application version with zero downtime. It gradually scales up the new version of your Pods while scaling down the old version, ensuring continuous availability.
- Rollbacks: If a new deployment has issues, you can easily roll back to a previous stable version.
- History: Deployments maintain a revision history, making rollbacks straightforward.
-
Relationship: A Deployment owns and manages ReplicaSets, and the ReplicaSets own and manage Pods.
-
Deployment Specification Example:
apiVersion: apps/v1 # API version for Deployments kind: Deployment # The type of Kubernetes object metadata: name: nginx-deployment # Name of the Deployment spec: replicas: 3 # Desired number of Pod replicas selector: matchLabels: app: nginx # Selects Pods with this label template: # Pod template for the ReplicaSet and Pods metadata: labels: app: nginx # Labels to attach to the Pods spec: containers: - name: nginx image: nginx:1.14.2 # Example: specific version ports: - containerPort: 80
- Notice how the
selector.matchLabels
matches thetemplate.metadata.labels
to link the Deployment to its Pods. - The Deployment tells Kubernetes: “I want 3 Pods running the
nginx:1.14.2
image, and I’ll manage them with rolling updates.” The Deployment then creates a ReplicaSet to ensure 3 Pods are always running.
- Notice how the
Connecting the Dots: How Objects Relate
- You define a Deployment to manage your application.
- The Deployment creates and manages a ReplicaSet.
- The ReplicaSet ensures the desired number of Pods are running.
- Each Pod contains your containers.
- Labels are used to identify and group Pods, allowing Deployments and ReplicaSets to find and manage them.
- Namespaces logically isolate groups of these objects within the cluster.
Conclusion: The Building Blocks of Your Kubernetes World
- Kubernetes objects are persistent entities that represent the desired state of your cluster. They consist of a
spec
(desired state, provided by you) andstatus
(current state, provided by Kubernetes). - Namespaces help in isolating groups of resources within a single cluster, useful for multi-team or multi-project environments.
- Pods are the smallest deployable units, representing a single instance of an application or process. They contain one or more containers.
- ReplicaSets ensure a specified number of identical Pods are always running, providing horizontal scaling and self-healing for Pods.
- Deployments are higher-level objects that manage ReplicaSets and provide advanced features like rolling updates and rollbacks, making them the preferred way to manage stateless applications.
Welcome to Kubernetes Objects Part 2: Connectivity and Specialized Workloads
In Part 1, we covered the foundational objects like Pods, ReplicaSets, and Deployments, which are all about running your applications. Now, we’ll explore how these applications communicate within and outside the cluster, and how Kubernetes handles more specific types of workloads.
Services: The Stable Front for Your Pods
A Service is a fundamental Kubernetes object that acts as a logical abstraction for a set of Pods in a cluster. It provides a stable network endpoint (an IP address and DNS name) and policies for accessing those Pods, effectively acting as a load balancer across them.
Why is a Service Needed?
Pods in Kubernetes are inherently ephemeral and volatile:
- They can be created and destroyed at any time (e.g., due to scaling, updates, failures, or Node reboots).
- When a Pod is destroyed and recreated, it gets a new IP address.
This volatility creates a problem: how do other applications or external users consistently find and communicate with your application if its IP address keeps changing?
The Solution: A Service!
A Service solves this discoverability issue by:
- Keeping track of Pod changes: It continuously monitors the Pods that match its selector (a label selector, just like ReplicaSets and Deployments use).
- Exposing a single, stable IP address or DNS name: This stable endpoint remains the same even if the underlying Pods come and go.
- Load balancing: It automatically distributes incoming requests across the healthy Pods that it targets.
- Eliminating separate service discovery: You don’t need external tools to find your application instances within the cluster.
Service Properties:
- REST Object: Like Pods, Services are RESTful objects defined via YAML.
- Protocols: Supports multiple protocols (TCP, UDP, and others). TCP is the default.
- Multiple Port Definitions: You can define multiple ports for a single Service. The
port
(Service’s port) andtargetPort
(Pod’s port) can be different, allowing flexible mapping. - Optional Selector: A Service uses a label selector to identify the Pods it should manage and route traffic to.
- API Endpoints: For native Kubernetes applications, the Service updates its API endpoints automatically when Pods matching its selector change. For non-native applications, Kubernetes uses a virtual IP-based bridge or load balancer.
Service Types: Controlling Access
Kubernetes offers four main types of Services, each designed for different access patterns:
-
ClusterIP (Default and Most Common)
- Purpose: Exposes the Service on a cluster-internal IP address.
- Access: Makes the Service only reachable from within the cluster. This is ideal for inter-service communication (e.g., your frontend application talking to your backend API, or your application talking to a database running in the cluster).
- Behavior: Kubernetes assigns a unique ClusterIP address. You can optionally set a specific ClusterIP in the Service definition.
-
NodePort (Exposing on Worker Nodes)
- Purpose: An extension of ClusterIP. It exposes the Service on each Worker Node’s IP address at a static port (the “NodePort”).
- Access: Makes the Service reachable from outside the cluster via
NodeIP:NodePort
. - Behavior: When you create a NodePort Service, Kubernetes automatically creates a ClusterIP Service internally. The NodePort Service then routes incoming requests on the specified static port to the ClusterIP Service, and subsequently to your Pods.
- Security Note: Generally not recommended for production use for internet-facing applications due to security concerns (exposes services on every node’s IP, often on a high port range) and lack of advanced load balancing features. It’s more commonly used for development, testing, or specific internal scenarios.
-
LoadBalancer (Cloud Provider Integration)
- Purpose: An extension of NodePort. It exposes the Service to the Internet by provisioning an external load balancer from your cloud provider.
- Access: Makes the Service directly accessible from the Internet via a dedicated external IP address (often a public IP).
- Behavior: When you create a LoadBalancer Service, Kubernetes automatically creates a NodePort and a ClusterIP Service underneath it. The cloud provider’s external load balancer is then configured to direct traffic to the NodePorts on your cluster’s worker nodes, which then route to your Pods.
- Cost: While highly convenient, external load balancers can be expensive and are managed by your cloud provider outside the Kubernetes cluster’s direct control.
-
ExternalName (Mapping to External DNS)
- Purpose: Maps the Service to a DNS name, not to a selector of Pods within the cluster.
- Access: Allows Pods within your cluster to access an external service (e.g., a database hosted outside Kubernetes, or another application in a different cluster) using a Kubernetes Service name.
- Behavior: This Service type returns a
CNAME
record with the value of thespec.externalName
parameter. It does not act as a proxy or load balancer. - Use Cases:
- Creating a Service that represents external storage.
- Enabling Pods from different namespaces to talk to each other without needing to know the other Pod’s internal ClusterIP or DNS name.
Advanced Kubernetes Objects for Specific Workloads
Beyond basic Services, Kubernetes offers specialized objects for various workload patterns:
Ingress: Advanced External Access and Routing
- Purpose: An API object that, when combined with an Ingress Controller, provides routing rules to manage external users’ access to multiple Services in a Kubernetes cluster, often using HTTP/HTTPS.
- Why it’s better than LoadBalancer for multiple services: While a
LoadBalancer
Service provides a single public IP per service,Ingress
allows you to expose multiple services under a single public IP address (or hostname) using routing rules based on hostnames or URL paths. This can be more cost-effective and flexible. - Production Use: In production, Ingress typically exposes applications to the Internet via standard ports: 80 for HTTP and 443 for HTTPS.
- Components:
Ingress
is just the API object that defines the rules. You need an Ingress Controller (e.g., NGINX Ingress Controller, Traefik, GKE Ingress) running in your cluster to actually implement these rules and manage the external load balancer (if needed). - Behavior: The Ingress object describes routing rules (e.g.,
api.example.com
goes to Service A,example.com/blog
goes to Service B). The Ingress Controller watches these Ingress objects and configures an underlying load balancer (which could be internal or external, depending on the setup) to route traffic accordingly.
DaemonSet: Ensuring a Pod on Every Node
- Purpose: A
DaemonSet
ensures that a copy of a specified Pod runs on all (or a selected subset of) nodes in a cluster. - Behavior:
- As nodes are added to the cluster, new Pods are automatically added to them by the DaemonSet.
- As nodes are removed, the DaemonSet’s Pods are garbage collected.
- If you delete a DaemonSet, all Pods it created are removed.
- Ideal Uses:
DaemonSets
are perfectly suited for running cluster-level operations or utilities that need to be present on every node. Examples include:- Storage daemons: Like GlusterFS or Ceph, which need to run on every node to manage storage.
- Log collection agents: Like Fluentd or Logstash, to collect logs from every node.
- Monitoring agents: Like Prometheus Node Exporter or Datadog Agent, to collect metrics from every node.
StatefulSet: Managing Stateful Applications
- Purpose: A
StatefulSet
is an object designed to manage stateful applications. Unlike Deployments, which are great for stateless apps, StatefulSets provide guarantees about the ordering and uniqueness of Pods. - Key Features for Stateful Applications:
- Stable, Unique Network Identifiers: Each Pod in a StatefulSet gets a sticky, persistent identity (e.g.,
my-app-0
,my-app-1
) that remains the same even if the Pod restarts or is rescheduled. This allows other applications to reliably address specific instances. - Stable Persistent Storage: StatefulSets integrate tightly with PersistentVolumes, ensuring that each Pod instance gets its own dedicated, persistent storage volume. When a Pod restarts or is rescheduled, its data volume follows it.
- Ordered, Graceful Deployment and Scaling: StatefulSets deploy Pods in a strict order (e.g.,
my-app-0
thenmy-app-1
). They also scale down Pods in reverse ordinal order and perform graceful shutdowns. This is critical for clustered databases and other stateful systems.
- Stable, Unique Network Identifiers: Each Pod in a StatefulSet gets a sticky, persistent identity (e.g.,
- Examples: Databases (MySQL, PostgreSQL, MongoDB), message queues (Kafka, RabbitMQ), distributed key-value stores (ZooKeeper, etcd).
Job: For Batch Processing and One-Time Tasks
- Purpose: A
Job
creates one or more Pods and ensures that a specified number of them successfully complete their tasks. - Behavior:
- Once the Pod(s) associated with a Job complete their work and exit successfully, the Job marks itself as complete.
- Jobs are retried until completed. If a Pod fails (e.g., due to an error or Node failure), the Job will automatically create new Pods to re-attempt the task until it succeeds.
- Deleting a Job will remove the created Pods.
- Suspending a Job will delete its active Pods until the Job resumes.
- Parallelism: A Job can be configured to run several Pods in parallel, useful for tasks like processing large datasets.
- CronJobs: For tasks that need to run on a regular, iterative schedule (like daily backups or nightly reports), you use a
CronJob
object. ACronJob
automatically createsJob
objects at specified times using a cron-like schedule.
Conclusion: Expanding Your Kubernetes Toolkit
- A Service is a REST object that provides a stable, load-balanced endpoint for a set of Pods, crucial for managing the ephemeral nature of Pods.
- The four main Service types (
ClusterIP
,NodePort
,LoadBalancer
,ExternalName
) cater to different communication needs, from internal-only to public internet exposure and external DNS mapping. - Ingress is an API object that, with an Ingress Controller, provides sophisticated routing rules for external access to multiple Services, often preferred over multiple
LoadBalancer
Services for cost and flexibility. - A DaemonSet ensures that a copy of a Pod runs on every (or selected) worker nodes, ideal for cluster-level utilities like logging or monitoring agents.
- A StatefulSet manages stateful applications, providing stable identities, persistent storage, and ordered deployment/scaling guarantees.
- A Job creates Pods to run and complete specific tasks, automatically retrying until successful. CronJobs schedule these Jobs regularly.
It’s time to get hands-on with Kubernetes! The primary tool you’ll use is kubectl
, the command-line interface. Let’s break down what kubectl
is, its command structure, different ways to use it, and some common commands.
Mastering kubectl
: Your Command Line Gateway to Kubernetes
kubectl
(pronounced “kube-control,” “kube-c-t-l,” or “kube-cud-dle”) is the Kubernetes command-line interface (CLI). It’s an indispensable tool for anyone working with Kubernetes clusters.
What can kubectl
do for you?
kubectl
allows you to:
- Deploy applications: Launch your containerized apps onto the cluster.
- Inspect cluster resources: View the status of your Pods, Deployments, Services, Nodes, and more.
- Manage cluster resources: Create, update, delete, scale, and configure various Kubernetes objects.
- View logs: Access logs from your running containers.
- And much more! It’s your primary interface for interacting with the Kubernetes API server.
The kubectl
Command Structure
All kubectl
commands follow a consistent structure. Keeping each component in order is crucial for successful execution:
kubectl [command] [type] [name] [flags]
Let’s break down each part:
kubectl
: The base command, always required.[command]
: The operation you want to perform. Examples include:create
: To create a new resource.get
: To retrieve information about resources.apply
: To create or update resources based on a definition file (often YAML).delete
: To remove resources.scale
: To change the number of replicas for a Deployment or ReplicaSet.logs
: To view logs from a container.
[type]
: The type of Kubernetes resource you’re operating on. Examples include:pod
(orpods
)deployment
(ordeployments
)service
(orservices
)rs
(for ReplicaSet)node
(ornodes
)ns
(for Namespace)
[name]
: The specific name of the resource, if applicable. This is used when you want to operate on a single instance of a resource (e.g.,kubectl get pod my-nginx-pod
). If omitted, the command usually applies to all resources of that type.[flags]
: Optional parameters or modifiers that override default values or specify additional behavior. Flags typically start with--
or-
. Examples:-o wide
: Show more details in the output.-n my-namespace
: Specify a particular namespace.-f my-file.yaml
: Specify a file to read configuration from.
Three Ways to Use kubectl
: Imperative, Imperative Object, and Declarative
Kubernetes offers three distinct approaches for managing objects using kubectl
, each with its own features, advantages, and disadvantages. Understanding these will help you choose the right method for different scenarios.
1. Imperative Commands (The Quick and Direct Way)
What they are: Imperative commands allow you to create, update, and delete live objects directly by specifying operations and arguments on the command line.
Structure Example: kubectl run <pod-name> --image=<image-name>
Features and Advantages:
- Easy to learn and run: They are straightforward and intuitive for quick tasks.
- Fast for simple operations: Ideal for prototyping, experimenting, or one-off actions.
Disadvantages:
- No Audit Trail: Commands are executed directly; there’s no persistent record (like a configuration file) of how the object was created or its exact configuration. This makes tracking changes difficult.
- Limited Flexibility: Options are specified via flags, which can become cumbersome for complex configurations.
- No Templates: You can’t easily reuse or share a precise configuration.
- Difficult to Integrate with Change Review Processes: Since there’s no file, it’s hard to use version control systems (like Git) or code review workflows.
- Reproducibility Issues: If one developer creates something imperatively, another developer can’t easily recreate the exact same setup without knowing the precise command used.
Best for: Development and test environments, quick debugging, or initial explorations. Not recommended for production.
2. Imperative Object Configuration (Commands + Files)
What it is: With imperative object configuration, you still specify the operation (create
, delete
, replace
) directly on the command line, but you point kubectl
to one or more configuration files (YAML or JSON) that contain the full definition of the objects.
Structure Example: kubectl create -f <filename.yaml>
or kubectl delete -f <filename.json>
Features and Advantages:
- Configuration Files: The full definition of your objects is stored in files.
- Audit Trail: Files can be stored in a source control system (like Git), providing a clear history of changes.
- Templates: Configuration files act as templates, allowing for consistent and reproducible deployments across multiple environments.
- Integrates with Change Processes: Since configurations are in files, they can be part of code reviews and CI/CD pipelines.
- Identical Results: Using the same configuration file in different environments will produce identical deployments.
Disadvantages:
- Requires Schema Understanding: You need to understand the Kubernetes object schema and how to write valid YAML/JSON files.
- Requires Specifying Operations: You still explicitly tell
kubectl
what to do (create
,delete
,replace
). If you want to update an existing object, you might need to usereplace
, which can be disruptive, or manually edit the live object. - Merge Issues: If you manually update a running object (e.g., using
kubectl edit
), and that change isn’t merged back into your configuration file, other developers using the file won’t get that update. The “source of truth” can diverge.
Best for: Environments where version control and reproducibility are important, but you still want explicit control over operations. Better than imperative commands for shared development.
3. Declarative Object Configuration (The Desired State)
What it is: This is the recommended and most powerful approach, especially for production systems. With declarative object configuration, you store configuration data in files, just like with imperative object configuration. However, you use a single command, kubectl apply
, to manage your objects.
Structure Example: kubectl apply -f <filename.yaml>
or kubectl apply -f <directory-of-files>
Features and Advantages:
- Operations Determined by
kubectl
: You do not specify the operation (create, update, delete).kubectl
automatically determines the necessary operations by comparing the desired state in your configuration file(s) with the current state of the objects in the cluster.- If the object doesn’t exist, it’s created.
- If the object exists but is different, it’s updated (merged).
- If a field is removed from the configuration file,
kubectl apply
might remove it from the live object (thoughkubectl prune
is often used for explicit deletion of resources not in files).
- Single Source of Truth: Your configuration files are the single source of truth for your desired state.
- Idempotent: Applying the same configuration file multiple times will produce the same result.
- Ideal for Production: This approach is robust, automated, and scales well for complex systems with many changes.
- Collaboration Friendly: Developers can simply
kubectl apply
the current configuration files, and Kubernetes will ensure the deployed objects match the expected state, even if intermediate changes were missed. - Works on Directories: You can apply configurations from an entire directory, making it easy to manage related objects.
Disadvantages:
- Requires a solid understanding of Kubernetes objects and YAML/JSON.
- Initial learning curve might be slightly steeper than imperative commands.
Best for: Production systems, CI/CD pipelines, collaborative development, and managing complex Kubernetes deployments. This is the gold standard.
Commonly Used kubectl
Commands
Here are some essential kubectl
commands that you’ll use frequently, with examples demonstrating their structure and purpose:
-
kubectl get
: Accesses information about resources.kubectl get pods
: List all Pods in the current namespace.kubectl get deployments -n my-app-namespace
: List Deployments in a specific namespace.kubectl get svc --all-namespaces
: List Services across all namespaces.kubectl get pod my-pod-name -o wide
: Get detailed information about a specific Pod.kubectl get events
: View recent cluster events (useful for debugging).
-
kubectl apply -f
: Creates or updates resources from a YAML/JSON file.kubectl apply -f my-deployment.yaml
: Create or update the resource defined inmy-deployment.yaml
.kubectl apply -f ./configs/
: Apply all YAML/JSON files in theconfigs
directory.
-
kubectl delete
: Deletes resources.kubectl delete pod my-old-pod
: Delete a specific Pod.kubectl delete deployment my-app-dep
: Delete a specific Deployment.kubectl delete -f my-deployment.yaml
: Delete resources defined in a file.kubectl delete all --all-namespaces
: CAUTION! Deletes all resources in all namespaces. Use with extreme care!
-
kubectl logs
: Views logs from a container within a Pod.kubectl logs my-pod-name
: View logs from the first container inmy-pod-name
.kubectl logs my-pod-name -c my-container
: View logs from a specific container in a Pod.kubectl logs -f my-pod-name
: Follow (stream) logs in real-time.
-
kubectl exec
: Executes a command in a container.kubectl exec -it my-pod-name -- bash
: Open an interactive Bash shell in a container (requires Bash to be installed in the container image).
-
kubectl scale
: Scales the number of replicas for a scalable resource.kubectl scale deployment/nginx-deployment --replicas=5
: Scale a Deployment namednginx-deployment
to 5 replicas.kubectl scale rs/my-replicaset --replicas=3
: Scale a ReplicaSet namedmy-replicaset
to 3 replicas.
-
kubectl describe
: Provides a detailed description of a resource, including events and related objects.kubectl describe pod my-pod-name
: Get a detailed description of a Pod.kubectl describe service my-web-service
: Get details about a Service.
-
kubectl edit
: Allows you to edit a live resource’s configuration directly in your default text editor.kubectl edit deployment/my-app-deployment
: Opens the YAML for the deployment in your editor. Use with caution, as changes are applied immediately. This can lead to configuration drift if not synchronized with your source control files.
-
kubectl autoscale
: Configures horizontal Pod autoscaling.kubectl autoscale deployment my-deployment --min=2 --max=10 --cpu-percent=80
: Set up autoscaling for a deployment based on CPU utilization.
Example Walkthrough: Deploying with kubectl apply
Let’s say you have a nginx-deployment.yaml
file like this:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx:latest
ports:
- containerPort: 80
-
Create the Deployment (declarative):
kubectl apply -f nginx-deployment.yaml
Output:
deployment.apps/my-nginx-deployment created
-
Verify the Deployment and Pods:
kubectl get deployment my-nginx-deployment
Output will show:
NAME READY UP-TO-DATE AVAILABLE AGE my-nginx-deployment 3/3 3 3 <some-age>
This confirms that your Deployment is running with 3 ready replicas.
You can also check the Pods:
kubectl get pods -l app=nginx
Output will list the three Nginx Pods.
Conclusion
kubectl
is your primary tool for interacting with a Kubernetes cluster. You’ve learned:
- The basic
kubectl
command structure:kubectl [command] [type] [name] [flags]
. - The three command types:
- Imperative commands: Quick and easy for ad-hoc tasks, but lack audit trails and flexibility.
- Imperative object configuration: Uses configuration files for reproducibility and audit trails, but still requires explicit operation commands.
- Declarative object configuration: The recommended approach for production, where
kubectl apply
automatically determines operations based on the desired state defined in your files, ensuring consistency and idempotence.
- Several commonly used
kubectl
commands likeget
,apply
,delete
,logs
,exec
, andscale
, along with practical examples.
To explore all kubectl
commands and their detailed options, always refer to the official Kubernetes documentation at https://kubernetes.io/docs/reference/kubectl/.
Let’s walk through the process of creating a Kubernetes Service using the Nginx image. This involves two core Kubernetes objects: a Deployment (to manage your Nginx Pods) and a Service (to expose Nginx to traffic).
Task 1: Creating a Kubernetes Service using Nginx
Goal: To run Nginx as a web server inside your Kubernetes cluster and make it accessible.
Nginx is a highly performant and stable open-source web server, known for its efficiency and ability to act as a reverse proxy, load balancer, and HTTP cache.
Here’s how you can achieve this by creating a Deployment and then exposing it as a Service:
Step 1: Create a Deployment named my-deployment1
using the nginx
image.
A Deployment is a powerful Kubernetes object that manages a set of replicated Pods. It ensures that a specified number of Pod replicas are always running and handles updates gracefully (like rolling updates).
We’ll use an imperative command here for simplicity in this example, as it’s a quick way to get things running.
Command:
kubectl create deployment my-deployment1 --image=nginx
Explanation of the Command:
kubectl
: This is the command-line tool for interacting with the Kubernetes API.create deployment
: This tells Kubernetes that you want to create a newDeployment
object.my-deployment1
: This is the chosen name for your Deployment. You can pick any valid name.--image=nginx
: This flag specifies the container image that the Pods managed by this Deployment should use. In this case, it’s the officialnginx
Docker image (by default,nginx:latest
).
What this command does:
This command creates a Deployment named my-deployment1
. Under the hood, this Deployment will automatically create a ReplicaSet (which ensures a desired number of Pods are running) and one or more Pods that run the Nginx container. By default, kubectl create deployment
creates a Deployment with one replica.
Step 2: Expose the my-deployment1
Deployment as a Service.
Now that our Nginx Pods are running (managed by my-deployment1
), we need a way for other applications (or external users) to access them. This is where a Service comes in. We’ll use a NodePort
Service type to make it accessible from outside the cluster for demonstration.
Command:
kubectl expose deployment my-deployment1 --port=80 --type=NodePort --name=my-service1
Explanation of the Command:
kubectl expose deployment
: This command is a convenient way to create a Service that targets an existing Deployment.my-deployment1
: This specifies the Deployment that this Service should target and expose. The Service will automatically find Pods managed bymy-deployment1
using their labels.--port=80
: This defines the port that the Service itself will listen on inside the cluster. When other Pods communicate withmy-service1
on port 80, the Service will forward that traffic.--type=NodePort
: This is a crucial flag that specifies the type of Service.- A
NodePort
Service makes your application accessible on a static port on each of your Kubernetes worker nodes. This means you can access your Nginx service from outside the cluster by going tohttp://<Node_IP_Address>:<NodePort>
. - Kubernetes will automatically assign a unique NodePort (typically in the range 30000-32767).
- A
--name=my-service1
: This is the chosen name for your Service.
What this command does:
This command creates a Service named my-service1
. This Service will automatically:
- Get a
ClusterIP
(internal IP address) that allows other Pods within the cluster to reach it. - Expose itself on a dynamically assigned
NodePort
on all your worker nodes, making it accessible from outside the cluster. - Route incoming traffic on port 80 (the Service port) to the target port 80 of the Nginx containers running inside the Pods (since Nginx’s default HTTP port is 80, this is a common mapping).
Step 3: Verify the Created Services.
It’s always good practice to verify that your Kubernetes objects have been created as expected.
Command:
kubectl get services
Explanation of the Command:
kubectl get services
: This command lists allService
objects in the current namespace (by default, thedefault
namespace).
Expected Output (similar to this):
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP XdYh
my-service1 NodePort 10.101.X.Y <none> 80:3XXXX/TCP XsYm
Interpreting the Output:
NAME
: You’ll seemy-service1
(the Service you just created) and potentiallykubernetes
(the default Service for accessing the Kubernetes API server).TYPE
: Formy-service1
, it will beNodePort
, as specified.CLUSTER-IP
: This is the internal IP address of your Service, reachable only from within the cluster.EXTERNAL-IP
: For aNodePort
Service, this will usually be<none>
, as the external access is via the Node’s IP and NodePort. For aLoadBalancer
Service, this would be a public IP.PORT(S)
: This shows the Service port (80
) and the dynamically assignedNodePort
(e.g.,3XXXX
). The/TCP
indicates the protocol.AGE
: How long the Service has been running.
To Access Your Nginx Service:
Once you have the NodePort
(e.g., 30080
) from the kubectl get services
output, you can access your Nginx web server from your local machine (or any machine that can reach your Kubernetes worker nodes) by pointing your web browser to:
http://<IP_ADDRESS_OF_ANY_WORKER_NODE>:<NodePort>
For example, if one of your worker nodes has the IP 192.168.1.100
and the NodePort is 30080
, you would go to http://192.168.1.100:30080
. You should see the default Nginx welcome page.
Let’s move on to Task 2: Managing Kubernetes Pods and Services. This task focuses on inspecting, labeling, and interacting with individual Pods, which are the core units running your containers.
You’ll need to have completed Task 1 (creating my-deployment1
and my-service1
) for some of these steps to be relevant.
Task 2: Managing Kubernetes Pods and Services
This task will guide you through inspecting Pods, adding labels to them, and running a temporary test Pod to demonstrate logging.
Step 1: Get the list of Pods
Before you can manage individual Pods, you need to know their names. This command will list all Pods in your current namespace (by default, the default
namespace). This list will include the Pod(s) created by your my-deployment1
Deployment from Task 1.
Command:
kubectl get pods
Explanation:
kubectl get
: Retrieves information about resources.pods
: Specifies the resource type you want to list.
Expected Output (example):
You will likely see one or more Pods with names starting with my-deployment1-
followed by a unique hash, and their status (e.g., Running
).
NAME READY STATUS RESTARTS AGE
my-deployment1-6789b7b9b-abcde 1/1 Running 0 5m
(Note: The exact hash part of your Pod name will be different.)
Take note of the full name of one of your my-deployment1
Pods. You’ll need it for the next steps. For example, if your Pod name is my-deployment1-6789b7b9b-abcde
, you’ll use that.
Step 2: Show labels for a specific Pod
Labels are key-value pairs used to identify and organize Kubernetes objects. Pods automatically inherit some labels from their managing Deployment or ReplicaSet. Let’s inspect them.
Command:
kubectl get pod <pod-name> --show-labels
Before running, replace <pod-name>
with the actual name of one of your my-deployment1
Pods from Step 1.
Example:
If your Pod name is my-deployment1-6789b7b9b-abcde
:
kubectl get pod my-deployment1-6789b7b9b-abcde --show-labels
Explanation:
kubectl get pod <pod-name>
: Specifies that you want to get details about a single Pod by its name.--show-labels
: A flag that instructskubectl
to display the labels associated with the Pod in the output.
Expected Output (example):
You’ll see the Pod details along with a LABELS
column at the end:
NAME READY STATUS RESTARTS AGE LABELS
my-deployment1-6789b7b9b-abcde 1/1 Running 0 6m app=my-deployment1,pod-template-hash=6789b7b9b
In this example, you see labels like app=my-deployment1
(inherited from the Deployment) and pod-template-hash=...
(used internally by Kubernetes).
Step 3: Label the Pod
You can add custom labels to existing Kubernetes objects. This is useful for further categorization or for creating custom selection criteria.
Command:
kubectl label pods <pod-name> environment=deployment
Before running, replace <pod-name>
with the actual name of the same Pod you used in Step 2.
Example:
If your Pod name is my-deployment1-6789b7b9b-abcde
:
kubectl label pods my-deployment1-6789b7b9b-abcde environment=deployment
Explanation:
kubectl label pods <pod-name>
: Specifies that you want to add or update a label on a specific Pod.environment=deployment
: This is the new key-value pair for the label you are adding.
Expected Output:
pod/<pod-name> labeled
Step 4: Show labels again to confirm the new label
After adding the label, it’s good to verify that it was applied successfully.
Command:
kubectl get pod <pod-name> --show-labels
Before running, replace <pod-name>
with the actual name of the same Pod.
Example:
If your Pod name is my-deployment1-6789b7b9b-abcde
:
kubectl get pod my-deployment1-6789b7b9b-abcde --show-labels
Expected Output (example):
You should now see your newly added environment=deployment
label in the LABELS
column:
NAME READY STATUS RESTARTS AGE LABELS
my-deployment1-6789b7b9b-abcde 1/1 Running 0 7m app=my-deployment1,environment=deployment,pod-template-hash=6789b7b9b
Step 5: Run a test Pod using the nginx
image
This step demonstrates how to create a single, standalone Pod using an imperative kubectl run
command. The --restart=Never
flag is important here, as it tells Kubernetes that this Pod should not be automatically restarted if it exits or fails. This is typical for “Job-like” or temporary test Pods.
Command:
kubectl run my-test-pod --image=nginx --restart=Never
Explanation:
kubectl run
: An imperative command to create and run a Pod (or other resources like Deployments, depending on flags).my-test-pod
: The name of the Pod you are creating.--image=nginx
: Specifies the Docker image to use for the container inside the Pod.--restart=Never
: This crucial flag means that once the container in this Pod finishes its process (or crashes), Kubernetes will not try to restart it. The Pod will eventually move to aCompleted
orError
status.
Expected Output:
pod/my-test-pod created
You can verify it’s running (or has completed) by running kubectl get pods
again. It will appear alongside your my-deployment1
Pods.
Step 6: Show logs for the test Pod
One of the most frequent tasks in troubleshooting Kubernetes applications is viewing their logs. kubectl logs
allows you to retrieve the standard output and standard error streams from containers running inside your Pods.
Command:
kubectl logs my-test-pod
Explanation:
kubectl logs
: The command to retrieve logs.my-test-pod
: The name of the Pod whose logs you want to view.
Expected Output (example):
You will see the Nginx access and error logs, as Nginx starts up and serves requests (even if no external requests are made yet, you’ll see startup logs).
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to interpret files in order of names:
/docker-entrypoint.sh: running /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
... (Nginx startup logs) ...
2025/06/02 14:45:00 [notice] 1#1: using the "epoll" event method
2025/06/02 14:45:00 [notice] 1#1: nginx/1.27.0
2025/06/02 14:45:00 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14)
2025/06/02 14:45:00 [notice] 1#1: OS: Linux 5.10.0-27-cloud-amd64
225.1.1.2 - - [02/Jun/2025:09:00:00 +0000] "GET / HTTP/1.1" 200 615 "-" "kube-probe/1.29" "-"
(The specific logs will depend on the Nginx version and any internal health checks Kubernetes might run.)
By completing Task 2, you’ve gained practical experience with:
- Listing Pods (
kubectl get pods
) - Inspecting Pod labels (
kubectl get pod --show-labels
) - Adding custom labels to Pods (
kubectl label pods
) - Running a standalone, temporary Pod (
kubectl run --restart=Never
) - Viewing container logs (
kubectl logs
)
Let’s tackle Task 3: Deploying a StatefulSet. This is a more advanced Kubernetes object, crucial for managing applications that require stable network identities, ordered deployments, and persistent storage – typical for databases or clustered applications.
Task 3: Deploying a StatefulSet
Goal: To deploy a stateful application (in this case, Nginx, but configured with persistent storage and unique identities) using a Kubernetes StatefulSet.
Recall that while a Deployment
is great for stateless applications, a StatefulSet
provides stronger guarantees for stateful workloads.
Step 1: Create and open a file named statefulset.yaml
in edit mode.
First, you’ll create an empty file.
Command:
touch statefulset.yaml
Explanation:
touch
: A common Linux command to create an empty file if it doesn’t exist, or update its timestamp if it does.statefulset.yaml
: The chosen name for your configuration file. Using.yaml
is a standard convention.
Step 2: Open statefulset.yaml
and add the provided code, then save the file.
You’ll need a text editor for this. Common choices include nano
, vim
, or any graphical editor if you’re on a desktop environment (e.g., VS Code, Sublime Text).
Command (example using nano
):
nano statefulset.yaml
Once the editor opens, paste the following YAML content into it:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-statefulset
spec:
serviceName: "nginx-headless" # Changed name to avoid conflict with service from task 1
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
volumeMounts: # IMPORTANT: Add this section for persistent storage
- name: www
mountPath: /usr/share/nginx/html # Default Nginx serving directory
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
Important Correction: I’ve changed spec.serviceName: "nginx"
to spec.serviceName: "nginx-headless"
. While the original caption used nginx
, it’s highly recommended to use a headless Service for StatefulSets. A headless Service provides a unique DNS entry for each Pod in the StatefulSet, which is crucial for their stable network identities. Using the same name nginx
might conflict or cause confusion if you also have a regular Service
named nginx
. Also, I’ve added a volumeMounts
section under spec.template.spec.containers
to actually use the persistent storage. Without it, the storage would be provisioned but not mounted into the container.
Explanation of the YAML Fields:
apiVersion: apps/v1
&kind: StatefulSet
:- This specifies that we are defining a
StatefulSet
resource, which is part of theapps/v1
API group (a stable, production-ready API version for application controllers).
- This specifies that we are defining a
metadata.name: my-statefulset
:- Assigns a human-readable name to your StatefulSet resource.
spec.serviceName: "nginx-headless"
:- This is crucial for StatefulSets. It binds the StatefulSet to a headless Service named
nginx-headless
. A headless Service doesn’t get its own ClusterIP; instead, it’s used to provide unique DNS entries for each Pod in the StatefulSet (e.g.,my-statefulset-0.nginx-headless.default.svc.cluster.local
). This ensures each Pod has a stable network identity.
- This is crucial for StatefulSets. It binds the StatefulSet to a headless Service named
spec.replicas: 3
:- Orchestrates three Pod replicas. The StatefulSet will create these Pods in a specific order (
my-statefulset-0
,my-statefulset-1
,my-statefulset-2
).
- Orchestrates three Pod replicas. The StatefulSet will create these Pods in a specific order (
spec.selector.matchLabels: app: nginx
:- Directs the StatefulSet to manage Pods that have the label
app: nginx
. This is how the StatefulSet knows which Pods belong to it.
- Directs the StatefulSet to manage Pods that have the label
spec.template
:- Defines the blueprint for the Pods that the StatefulSet will create.
metadata.labels: app: nginx
: Ensures that new Pods created by this StatefulSet carry the matching label, allowing theselector
to find them.spec.containers
: Configures the container(s) within each Pod:name: nginx
: Name of the container.image: nginx
: The Docker image to use (defaults tonginx:latest
).ports
: Exposes port 80 (HTTP) on the container, named “web”.volumeMounts
: (Crucial addition) This section tells the container where to mount the persistent volume.name: www
: Refers to the volume defined involumeClaimTemplates
.mountPath: /usr/share/nginx/html
: The directory inside the container where the persistent storage will be mounted. For Nginx, this is typically where web content is served from.
volumeClaimTemplates
:- This is a unique and powerful feature of StatefulSets. It automates the creation of a PersistentVolumeClaim (PVC) for each replica of the StatefulSet.
metadata.name: www
: The name of the volume claim. This name is used in thevolumeMounts
section of the Pod template.spec.accessModes: [ "ReadWriteOnce" ]
: Specifies how the volume can be accessed.ReadWriteOnce
means the volume can be mounted as read-write by a single node.spec.resources.requests.storage: 1Gi
: Requests 1 Gigabyte of storage for each Pod. Kubernetes will provision a PersistentVolume (PV) to fulfill this request.
Save the file after pasting the content (in nano
, press Ctrl+S
, then Ctrl+X
).
Step 3: Apply the StatefulSet configuration.
Now, use kubectl apply
to create the StatefulSet and its associated resources in your cluster. This is the declarative way of managing Kubernetes objects.
Command:
kubectl apply -f statefulset.yaml
Explanation:
kubectl apply
: This command instructs Kubernetes to create or update resources based on the definition in the specified file.-f statefulset.yaml
: Specifies the YAML file containing the resource definition.
Expected Output:
statefulset.apps/my-statefulset created
Step 4: Verify that the StatefulSet is created.
After applying the configuration, it’s essential to verify that your StatefulSet, its Pods, and the associated PersistentVolumeClaims have been created correctly.
Command (to check StatefulSet):
kubectl get statefulsets
Expected Output (example):
NAME READY AGE
my-statefulset 0/3 0s # It will take a moment for Pods to spin up and become ready
Keep running this command until READY
shows 3/3
. This indicates all three Pods in your StatefulSet are running.
Command (to check Pods):
kubectl get pods -l app=nginx # Using the label defined in the StatefulSet
Expected Output (example - will show Pods being created in order):
NAME READY STATUS RESTARTS AGE
my-statefulset-0 1/1 Running 0 30s
my-statefulset-1 1/1 Running 0 25s
my-statefulset-2 1/1 Running 0 20s
Notice the stable, ordered names (my-statefulset-0
, -1
, -2
).
Command (to check PersistentVolumeClaims - PVCs):
kubectl get pvc
Expected Output (example):
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-my-statefulset-0 Bound pvc-abcd-1234-abcd-1234-abcd 1Gi RWO standard 1m
www-my-statefulset-1 Bound pvc-efgh-5678-efgh-5678-efgh 1Gi RWO standard 1m
www-my-statefulset-2 Bound pvc-ijkl-9012-ijkl-9012-ijkl 1Gi RWO standard 1m
You’ll see a PVC for each Pod in the StatefulSet, with names like www-my-statefulset-0
, www-my-statefulset-1
, etc., reflecting their stable identity.
Excellent! Let’s proceed with Task 4: Implementing a DaemonSet. This is a powerful Kubernetes object for ensuring that a specific Pod runs on all (or a selected subset of) your cluster nodes. It’s ideal for system-level services like logging agents, monitoring agents, or network proxies that need to be present on every worker machine.
Task 4: Implementing a DaemonSet
Goal: To deploy a DaemonSet that ensures a copy of a specific Pod (in this case, an Nginx container as an example) runs on all available nodes in your Kubernetes cluster.
Step 1: Create a file named daemonset.yaml
and open it in edit mode.
First, let’s create the empty YAML file where you’ll define your DaemonSet.
Command:
touch daemonset.yaml
Explanation:
touch
: Creates an empty file or updates its timestamp.daemonset.yaml
: The name of the file for your DaemonSet definition.
Step 2: Open daemonset.yaml
and add the provided code, then save the file.
Now, open the daemonset.yaml
file using your preferred text editor (like nano
or vim
) and paste the following content into it:
Command (example using nano
):
nano daemonset.yaml
Paste the following YAML:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: my-daemonset
spec:
selector:
matchLabels:
name: my-daemonset
template:
metadata:
labels:
name: my-daemonset
spec:
containers:
- name: my-daemonset-container # Changed container name for clarity
image: nginx
Explanation of the YAML Fields:
apiVersion: apps/v1
&kind: DaemonSet
:- These lines declare that you are defining a
DaemonSet
resource, leveraging the stableapps/v1
API version.
- These lines declare that you are defining a
metadata.name: my-daemonset
:- This assigns a unique name to your DaemonSet within the cluster.
spec.selector.matchLabels
:- This is how the DaemonSet identifies the Pods it is responsible for managing. It will look for Pods that have the label
name: my-daemonset
.
- This is how the DaemonSet identifies the Pods it is responsible for managing. It will look for Pods that have the label
spec.template
:- This is the Pod template, defining the blueprint for the Pods that the DaemonSet will create on each node.
metadata.labels: name: my-daemonset
: These labels are applied to the Pods created by this DaemonSet. They must match thespec.selector.matchLabels
to ensure the DaemonSet correctly manages these Pods.spec.containers
: Defines the container(s) that will run inside each Pod:name: my-daemonset-container
: The name of the container within the Pod. I’ve appended-container
for clarity, butmy-daemonset
would also work.image: nginx
: The Docker image to use for this container (defaults tonginx:latest
). In a real-world scenario, this would be your log collector, monitoring agent, or network proxy image.
Save the file after pasting the content. (In nano
, press Ctrl+O
to write out, then Enter
to confirm, then Ctrl+X
to exit.)
Step 3: Apply the DaemonSet
Now, apply the DaemonSet configuration to your Kubernetes cluster using kubectl apply
.
Command:
kubectl apply -f daemonset.yaml
Explanation:
kubectl apply
: This command is used to create or update Kubernetes resources based on the provided configuration file. It follows a declarative approach.-f daemonset.yaml
: Specifies the YAML file containing the DaemonSet definition.
Expected Output:
daemonset.apps/my-daemonset created
Step 4: Verify that the DaemonSet has been created and its Pods are running
After applying, you should verify that the DaemonSet has been successfully created and that it has launched Pods on your cluster’s nodes.
Command (to check the DaemonSet itself):
kubectl get daemonsets
Explanation:
kubectl get daemonsets
: This command lists allDaemonSet
objects in your current namespace.
Expected Output (example):
The output will provide key information about your my-daemonset
. The DESIRED
and CURRENT
columns should ideally match the number of worker nodes in your cluster.
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
my-daemonset X X X X X <none> YsZm
NAME
: The name of your DaemonSet, which is “my-daemonset”.DESIRED
: The number of Pods that the DaemonSet wants to run. This should typically be equal to the number of eligible nodes in your cluster.CURRENT
: The current number of DaemonSet Pods that are running.READY
: The number of DaemonSet Pods that are ready and available for use (i.e., their containers are running and healthy).UP-TO-DATE
: The number of DaemonSet Pods that are running the latest version of the configuration.AVAILABLE
: The number of DaemonSet Pods that are available and ready.NODE SELECTOR
: Specifies which nodes in the cluster the DaemonSet should run on. In this case, it’s<none>
, meaning it will try to run on all nodes by default. If you had anodeSelector
in your YAML, it would appear here.AGE
: How long the DaemonSet has been running.
Command (to check the Pods created by the DaemonSet):
You can also list the individual Pods to see them running on different nodes.
kubectl get pods -o wide -l name=my-daemonset # Using the label defined in the DaemonSet
Explanation:
kubectl get pods
: Lists Pods.-o wide
: Provides more detailed output, including theNODE
column.-l name=my-daemonset
: Filters the list to show only Pods with the labelname: my-daemonset
, which are the ones created by your DaemonSet.
Expected Output (example):
You should see one Pod for each of your worker nodes (or eligible nodes if you had a node selector).
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
my-daemonset-abcde 1/1 Running 0 XsYm 10.x.x.x node1.example.com <none> <none>
my-daemonset-fghij 1/1 Running 0 XsYm 10.y.y.y node2.example.com <none> <none>
# ... and so on for each node ...
Notice that each Pod created by the DaemonSet has a unique suffix and is running on a different NODE
.
Conclusion
Congratulations! You have successfully completed the practice lab on Kubernetes!
You’ve gone through several foundational and important tasks:
- Created a Kubernetes Service: Setting up a network abstraction to reliably access your Nginx application.
- Used various
kubectl
commands: Gaining hands-on experience withget
,label
,run
, andlogs
for inspecting and interacting with Pods. - Deployed StatefulSets for stateful applications: Understanding how to manage applications that require stable identities and persistent storage.
- Implemented DaemonSets for uniform Pod deployment across cluster nodes: Learning to deploy system-level agents that need to run on every node.
These tasks cover essential concepts and kubectl
operations that are fundamental to working effectively with Kubernetes in real-world scenarios. Keep practicing and exploring the vast capabilities of Kubernetes!
Let’s clarify the distinction between Ingress Objects and Ingress Controllers in Kubernetes. This is a common point of confusion, but understanding their roles is key to effectively managing external access to your applications.
Ingress Objects vs. Ingress Controllers: The Two Sides of External Access
In Kubernetes, providing external access to services, especially for HTTP and HTTPS traffic, involves two core components: the Ingress API object and the Ingress Controller. They work together to expose your applications to the outside world.
Ingress Objects: The “What” (The Rules)
The Ingress object is a Kubernetes API resource that you define (typically in a YAML file) to describe how external traffic should be routed to your internal cluster services. Think of it as a set of declarative traffic rules or a high-level configuration.
Key characteristics of Ingress Objects:
- Role: Acts as a supervisor for external access, defining routes from outside the cluster to internal Services.
- Focus: Primarily designed for HTTP and HTTPS traffic. It doesn’t directly manage arbitrary TCP/UDP ports or other protocols.
- Functionality:
- Provides services with externally accessible URLs (e.g.,
app.example.com
). - Enables load balancing across multiple backend Pods.
- Handles SSL/TLS termination, offloading certificate management from your application Pods.
- Enables name-based virtual hosting (routing traffic based on hostnames).
- Enables path-based routing (routing traffic based on URL paths, e.g.,
/api
goes to one service,/blog
to another).
- Provides services with externally accessible URLs (e.g.,
- Limitations: For non-HTTP/HTTPS services, or if you simply need direct port exposure, you typically use other Service types like
Service.Type=NodePort
orService.Type=LoadBalancer
. - Configuration Source: The rules for routing are defined directly within the Ingress resource YAML.
Analogy: An Ingress object is like writing down a set of instructions on how traffic should be directed at a large intersection: “Cars going to the library should turn left here,” “Cars going to the hospital should go straight,” etc.
Ingress Controllers: The “How” (The Executor)
The Ingress Controller is a separate, active component that runs as a Pod (or set of Pods) within your Kubernetes cluster. Its responsibility is to implement the rules specified by the Ingress API objects. It continuously watches the Kubernetes API for new or updated Ingress objects and then configures an actual load balancer or proxy to fulfill those rules.
Key characteristics of Ingress Controllers:
- Role: The deployed cluster resource responsible for implementing the rules specified by the Ingress API object.
- Deployment: Unlike some built-in controllers (like the Deployment controller), the Ingress Controller requires explicit deployment and activation in your cluster. It’s not part of the core
kube-controller-manager
binary. Popular examples include NGINX Ingress Controller, Traefik, HAProxy, and cloud-provider-specific ones (e.g., GKE Ingress Controller, AWS Load Balancer Controller). - Primary Function: To execute the directives outlined in the Ingress object. This commonly involves:
- Configuring an external load balancer: If it’s a cloud-integrated controller, it might provision and configure a cloud load balancer.
- Setting up internal proxies/frontends: Many controllers (like NGINX) run a proxy server inside the cluster that receives external traffic and forwards it to the correct backend Service/Pods.
- Handling SSL/TLS: Managing certificates and performing TLS termination.
- Updating routing tables: Dynamically updating its own configuration (or the external load balancer’s) as Ingress rules or backend Pods change.
- Traffic Handling: It utilizes a load balancer or configures its own internal proxy mechanisms to handle incoming traffic according to the Ingress rules.
- Handling Protocols: While the Ingress object focuses on HTTP/HTTPS rules, the controller is the actual piece of software that implements those rules, dealing with the underlying network protocols and ports to route the traffic.
Analogy: The Ingress Controller is like the actual traffic police officer or the automated traffic light system that reads those instructions (Ingress objects) and then physically directs the cars (traffic) according to the rules.
Ingress Objects vs. Ingress Controllers: A Feature Comparison
Feature | Ingress Objects | Ingress Controllers |
---|---|---|
Definition | Kubernetes API object (a YAML manifest) | A running Pod (or set of Pods) within the cluster |
Primary Function | Defines the rules for external access and routing | Implements those rules; acts as the traffic proxy/load balancer |
Configuration Source | Rules are defined directly in the Ingress resource YAML | Reads and processes information from Ingress objects |
Traffic Handling | Specifies HTTP/HTTPS routes, hosts, paths | Utilizes a load balancer, configures frontends for traffic, performs TLS termination |
Activation | Created and configured like any other Kubernetes object (e.g., kubectl apply -f ingress.yaml ) | Must be explicitly deployed and running in the cluster for Ingress objects to have any effect |
Handling Protocols | Focused on defining rules for HTTP and HTTPS traffic | The actual component that processes and routes HTTP/HTTPS (and potentially other) traffic |
Automatic Startup | Activated upon configuration with an Ingress resource (but only if a controller is present) | Requires explicit activation/deployment in the cluster |
Analogy | The architectural blueprint; the rule set for traffic | The actual builder/executor; the traffic director (e.g., an NGINX instance) |
Conclusion
In Kubernetes, overseeing external access to your applications is a collaborative effort between Ingress objects and Ingress controllers.
- The Ingress object is the declarative specification – you tell Kubernetes what routing rules you want.
- The Ingress Controller is the operational component – it reads those rules and makes them happen by configuring an underlying load balancer or proxy to direct incoming HTTP/HTTPS traffic to the correct Services and Pods within your cluster.
This is an excellent summary of crucial Kubernetes anti-patterns and their corresponding best practices. Avoiding these common pitfalls is vital for building robust, scalable, and maintainable applications on Kubernetes.
Let’s reiterate and slightly expand on these points for maximum clarity.
Kubernetes Antipatterns: Pitfalls to Avoid for Robust Deployments
Kubernetes is a powerful platform, but without adhering to best practices, it’s easy to fall into “antipatterns” – practices that seem intuitive but ultimately lead to complications, instability, and increased operational overhead. Identifying and avoiding these is crucial for maintaining a healthy container orchestration environment.
Here are ten prevalent Kubernetes anti-patterns and the recommended alternative practices:
1. Anti-pattern: Baking Configuration into Container Images
Issue: Embedding environment-specific configurations (like hardcoded IP addresses, database credentials, or environment-specific prefixes) directly into your Docker images. This leads to:
- Image proliferation: You end up with different images for dev, test, and production, violating the “build once, run anywhere” principle.
- Lack of traceability: The image used in production might differ from the one tested, introducing unknown variables.
- Slow deployments: Every config change requires an image rebuild, pushing, and redeploying.
- Security risks: Sensitive data can be inadvertently committed to version control or reside in image layers.
Best Practice: Create generic, immutable container images independent of runtime settings.
- Containerize your application, not your configuration.
- Pass configuration to containers at runtime using:
- ConfigMaps: For non-sensitive configuration data (e.g., URLs, feature flags).
- Secrets: For sensitive data (e.g., passwords, API keys).
- Environment variables: For simple values (can be sourced from ConfigMaps/Secrets).
- Mounted files: For larger configuration files (can be sourced from ConfigMaps/Secrets). This ensures the same image can be used across all environments, promoting consistency, auditability, and efficiency.
2. Anti-pattern: Mixing Application and Infrastructure Deployment in a Single Pipeline
Issue: Using one continuous integration/continuous delivery (CI/CD) pipeline to deploy both your application code and your underlying infrastructure (e.g., Kubernetes cluster, networking, databases).
- Resource and time wastage: Infrastructure changes are typically less frequent than application code changes. Running full infrastructure deployments for every small application change is inefficient.
- Increased blast radius: A failure in the application deployment part of the pipeline could inadvertently affect infrastructure.
- Slower feedback loops: Infrastructure provisioning can be time-consuming, delaying application deployment.
Best Practice: Separate infrastructure and application deployment into distinct pipelines.
- Infrastructure as Code (IaC) Pipeline: Dedicated pipeline for provisioning and managing your Kubernetes cluster and its core components (e.g., using Terraform, CloudFormation, Pulumi).
- Application Deployment Pipeline: Dedicated pipeline for building, testing, and deploying your application containers and Kubernetes manifests (e.g., using Jenkins, GitLab CI, ArgoCD). This optimizes efficiency, provides clearer separation of concerns, and reduces risk.
3. Anti-pattern: Relying on Specific Deployment Order
Issue: Assuming or enforcing a specific startup order for application components (e.g., database must be up before API, API before frontend). In Kubernetes, Pods and containers are started concurrently.
- Race conditions: Components may try to connect to dependencies that aren’t yet ready, leading to connection errors or Pod crashes.
- Fragile deployments: Network latency or temporary resource contention can easily disrupt assumed startup orders, causing intermittent failures.
- Reduced resilience: The application is not designed to tolerate temporary unavailability of its dependencies.
Best Practice: Design applications to be resilient and tolerant of simultaneous component initiation and transient failures.
- Implement retry mechanisms and backoff strategies: Applications should continuously attempt to connect to their dependencies with increasing delays.
- Use Kubernetes Readiness Probes: Ensure a service doesn’t receive traffic until it’s truly ready to serve requests (see #8).
- Implement graceful startup and shutdown: Applications should handle dependency unavailability during startup and clean up properly on shutdown.
- Decouple components: Use message queues or event streams to reduce direct, synchronous dependencies.
4. Anti-pattern: Not Setting Memory and CPU Limits for Pods
Issue: Running Pods without specifying requests
and limits
for CPU and memory resources.
- Resource starvation: A single “runaway” Pod can monopolize a node’s resources, leading to performance degradation or even crashes for other Pods on the same node.
- Unpredictable performance: The performance of your application can vary widely depending on what other Pods are running on its node.
- Inefficient scheduling: The Kubernetes scheduler has less information to optimally place Pods, potentially leading to over-provisioned or under-utilized nodes.
- No QoS (Quality of Service) guarantees: Without limits, your Pods run with “BestEffort” QoS, making them highly susceptible to being terminated under resource pressure.
Best Practice: Establish resource requests
and limits
for all containers within your Pods.
requests
: The minimum amount of resources a container needs to be scheduled. This defines the QoS class (Guaranteed, Burstable, BestEffort).limits
: The maximum amount of resources a container is allowed to consume. If a container exceeds its memory limit, it will be terminated. If it exceeds its CPU limit, it will be throttled.- Thorough examination: Analyze your application’s behavior under various load conditions to determine appropriate
requests
andlimits
. Start with generous limits and gradually fine-tune them based on actual usage. - Use LimitRanges and ResourceQuotas: Enforce default limits and prevent resource over-consumption at the Namespace level.
5. Anti-pattern: Pulling the latest
Tag in Production
Issue: Using mutable image tags like :latest
in production environments.
- Unforeseen crashes: The
latest
tag can refer to a different image version each time it’s pulled, leading to unexpected behavior, bugs, or crashes in production that weren’t present in testing. - Troubleshooting nightmare: It’s impossible to pinpoint the exact image version that’s causing an issue, making debugging and rollbacks extremely difficult.
- Lack of reproducibility: You can’t reliably recreate the exact production environment.
Best Practice: Use specific, immutable, and meaningful image tags in production.
- Semantic Versioning: Use tags like
v1.2.3
,1.0.0-rc.1
. - Git SHA/Commit Hash: Incorporate the Git commit hash into the tag (e.g.,
my-app:a1b2c3d
). - Build Timestamps: Include date and time of the build (e.g.,
my-app:202506021430
). - Container Image Immutability: Once an image is built and tagged, it should never be altered. If a change is needed, build a new image with a new tag.
- Externalize Data: Store application data externally in Persistent Storage (PersistentVolumes/PersistentVolumeClaims), not inside the container image, as containers are ephemeral.
6. Anti-pattern: Consolidating Production and Non-Production Workloads in a Single Cluster
Issue: Running development, testing, staging, and production workloads within the same Kubernetes cluster.
- Security risks: Default permissions and shared cluster resources increase the blast radius of security incidents. A compromise in a dev environment could impact production.
- Resource contention: Non-production workloads can consume resources needed by production, leading to performance degradation or outages.
- Complexity of Multi-tenancy: Managing permissions, resource isolation, and network policies for different teams and environments within one cluster can become incredibly complex and error-prone.
- Impact of changes: A risky change or experiment in dev could unintentionally affect production.
Best Practice: Maintain at least two separate clusters: one for production and one for non-production (e.g., development, staging).
- Strong Isolation: Provides a clear security boundary and prevents resource contention.
- Reduced Risk: Changes in non-production won’t directly impact critical production systems.
- Simpler Management: Multi-tenancy is easier to manage when environments are physically separate.
- Cost Efficiency: Non-production clusters can often run with fewer, smaller nodes, optimizing costs.
7. Anti-pattern: Ad-Hoc Deployments with kubectl edit
/kubectl patch
Issue: Making direct, manual modifications to live Kubernetes objects using commands like kubectl edit
or kubectl patch
without updating the source configuration files (e.g., YAML in Git).
- Configuration drift: The state of your cluster diverges from your source control, leading to inconsistencies across environments.
- Lack of audit trail: No record of who made what change and when, making debugging and compliance difficult.
- Non-reproducible environments: You can’t easily recreate the exact state of a cluster.
- Failed rollbacks: If you try to roll back to a previous Git commit, it won’t include the ad-hoc changes, potentially causing issues.
Best Practice: Implement GitOps principles: Conduct all deployments and configuration changes through Git commits.
- Source of Truth: Your Git repository becomes the single source of truth for your cluster’s desired state.
- Comprehensive History: Every change is tracked, showing who made it and why.
- Easy Recreation/Rollback: Environments can be easily recreated or rolled back to any previous state by applying the Git-versioned manifests.
- Automated Reconciliation: Tools like ArgoCD or Flux CD can automatically detect and apply changes from Git to the cluster, ensuring continuous synchronization.
8. Anti-pattern: Neglecting Health Checks or Using Overly Complex Probes
Issue: Not configuring liveness and readiness probes, or designing them poorly.
- No Liveness Probe: Kubernetes doesn’t know if your application is truly “alive.” It might be running but unresponsive (e.g., deadlocked). Such Pods continue to receive traffic and cause errors.
- No Readiness Probe: Traffic can be sent to a Pod before it’s ready to handle requests (e.g., still initializing, loading data). This leads to failed requests during startup or scaling.
- Overly Complex/Sensitive Probes: Probes that are too sensitive or have unpredictable timings can cause “flapping” (Pod repeatedly restarting or becoming unready), leading to internal denial-of-service or thrashing.
- Same Liveness and Readiness Probe: Using the same probe for both can lead to issues; readiness should be more strict than liveness.
Best Practice: Configure robust liveness and readiness probes for each container.
- Liveness Probe: Detects if your application is in a broken state and requires a restart.
- Goal: Restart unresponsive containers.
- Implementation: Typically HTTP GET (on a
/healthz
endpoint), TCP socket check, or command execution.
- Readiness Probe: Determines if a container is ready to serve traffic.
- Goal: Prevent traffic from being sent to unready containers.
- Implementation: Often HTTP GET (on a
/readyz
endpoint that checks dependencies like database connections), or command execution.
- Prioritize simple, reliable checks: Avoid complex logic in probes that could introduce their own failures.
- Use
initialDelaySeconds
,periodSeconds
,failureThreshold
: Tune probe parameters to avoid false positives and give your application time to start up.
9. Anti-pattern: Embedding Secrets or Poor Secret Handling
Issue: Storing sensitive information (passwords, API keys, certificates) directly in container images, Git repositories, or using inconsistent/insecure methods for injection.
- Security breaches: Exposed secrets are a major security vulnerability.
- Configuration drift: Difficult to manage secrets across environments.
- Complicated local development: Developers might struggle to get the right secrets for their local environments.
Best Practice: Use a consistent and secure secret handling strategy, typically involving Kubernetes Secrets or dedicated secret management systems.
- Kubernetes Secrets: Store sensitive data securely within the cluster (encoded, not encrypted by default on etcd without encryption at rest).
- Secret Management Systems: For enhanced security, auditability, and centralized control, integrate with dedicated secret management solutions like:
- HashiCorp Vault: A widely used, robust secret management solution.
- Cloud-native secret stores (AWS Secrets Manager, Azure Key Vault, Google Cloud Secret Manager).
- Pass Secrets at Runtime: Never embed secrets directly into container images. Instead, inject them into containers as environment variables or mounted files at runtime via Kubernetes Secrets or a secret management system.
- Encryption at Rest: Ensure
etcd
(Kubernetes’ backing store) is configured with encryption at rest for Kubernetes Secrets.
10. Anti-pattern: Direct Pod Usage or Running Multiple Processes Per Container
Issue:
- Direct Pod Usage: Manually creating Pods (e.g.,
kubectl run --restart=Never
for long-running services) without a higher-level controller like Deployment, StatefulSet, or DaemonSet. Pods are ephemeral; they lack self-healing, automatic rescheduling, and scaling. - Multiple Processes Per Container: Running more than one primary application process within a single container (e.g., an Nginx web server and a database inside the same container).
- Single point of failure: If one process fails, the entire container might crash.
- Limited resource control: Can’t set separate resource limits for each process.
- Complex logging/monitoring: Logs from multiple processes can intermingle.
- Inefficient scaling: You might need to scale only one component, but scaling the container scales all of them.
- No separate lifecycle management:
kubectl exec
into the container and manage processes manually.
Best Practice:
- Utilize Workload Resources: Always deploy long-running applications using higher-level workload resources:
Deployment
: For stateless applications (most common). Provides self-healing, rolling updates, and easy scaling.StatefulSet
: For stateful applications needing stable identities and persistent storage.DaemonSet
: For running one Pod per node (system-level agents).Job
/CronJob
: For batch processing and scheduled tasks.
- One Process Per Container (the “Single Responsibility Principle”):
- Each container should ideally encapsulate a single, primary application process.
- Multiple Containers Per Pod (Sidecars/Ambassadors/Adapters): If related processes absolutely must run together and share resources (like a log shipper sidecar with your main app, or a proxy for an external service), use multiple containers within the same Pod. They share network namespace and volumes.
- Leverage Kubernetes’ controllers for reliability, scalability, and automated management.
Okay, let’s proceed with verifying your Kubernetes environment and command-line tools. This is a crucial first step for any Kubernetes lab or project, ensuring that your setup is ready to interact with a cluster.
Verify the Environment and Command Line Tools
Step 1: Open a Terminal Window (if not already open)
If you don’t already have a terminal window open in your integrated development environment (IDE) or local setup, please open one.
- Using the Menu (common in cloud labs/IDEs): Go to
Terminal > New Terminal
. - Locally: Open your preferred terminal application (e.g.,
bash
,zsh
, PowerShell, Command Prompt).
(Note: If a terminal is already visible and active, you can skip this step.)
Step 2: Verify that kubectl
CLI is installed.
This command checks if the kubectl
command-line tool is installed and can communicate with a Kubernetes cluster. It will show you the client and server versions.
Command:
kubectl version
Explanation:
kubectl
: The Kubernetes command-line tool.version
: This subcommand is used to display the version of thekubectl
client and the Kubernetes API server (ifkubectl
is configured to connect to one).
Expected Output (similar to this, versions may vary):
Client Version: version.Info{Major:"1", Minor:"29", GitVersion:"v1.29.0", GitCommit:"<some-hash>", GitTreeState:"clean", BuildDate:"...", GoVersion:"...", Compiler:"gc", Platform:"..."}
Kustomize Version: v5.0.1
Server Version: version.Info{Major:"1", Minor:"29", GitVersion:"v1.29.0", GitCommit:"<some-hash>", GitTreeState:"clean", BuildDate:"...", GoVersion:"...", Compiler:"gc", Platform:"..."}
Client Version
: This indicates the version of thekubectl
tool installed on your local machine or within your lab environment.Server Version
: This indicates the version of the Kubernetes API server that yourkubectl
client is configured to connect to. This shows that yourkubectl
is successfully communicating with a Kubernetes cluster.
Step 3: Change to your project folder.
It’s good practice to organize your lab files within a specific project directory.
Command:
cd /home/project
Explanation:
cd
: Thechange directory
command in Linux/Unix-like systems./home/project
: This is the target directory. If you are already in this directory, the command won’t change anything but will execute successfully.
(Note: Please skip this step if you are already in the /home/project
directory.)
Step 4: Clone the git repository that contains the artifacts needed for this lab, if it doesn’t already exist.
This command will download the necessary lab files from a Git repository. It uses a conditional statement to only clone the repository if the CC201
directory doesn’t already exist, preventing errors if you run the command multiple times.
Command:
[ ! -d 'CC201' ] && git clone https://github.com/ibm-developer-skills-network/CC201.git
Explanation:
[ ! -d 'CC201' ]
: This is a conditional test.!
: Logical NOT operator.-d 'CC201'
: Tests if a directory namedCC201
exists.- So,
[ ! -d 'CC201' ]
means “if the directory ‘CC201’ does NOT exist”.
&&
: This is a logical AND operator. The command after&&
will only execute if the command before&&
was successful (i.e., theCC201
directory did not exist).git clone https://github.com/ibm-developer-skills-network/CC201.git
: This command clones the specified Git repository into a new directory namedCC201
.
Expected Output:
- If
CC201
does not exist: You will see output fromgit clone
indicating that the repository is being cloned (e.g.,Cloning into 'CC201'...
). - If
CC201
already exists: There will be no output, as the condition[ ! -d 'CC201' ]
will be false, and thegit clone
command will not be executed.
Step 5: Change to the directory for this lab.
Now, navigate into the specific lab directory within the cloned repository.
Command:
cd CC201/labs/2_IntroKubernetes/
Explanation:
cd
: Changes the current working directory.CC201/labs/2_IntroKubernetes/
: The path to the specific lab directory.
Step 6: List the contents of this directory to see the artifacts for this lab.
This command will show you the files and subdirectories present in your current working directory, confirming you are in the correct place and can see the lab artifacts.
Command:
ls
Explanation:
ls
: Thelist
command in Linux/Unix-like systems, which lists the contents of the current directory.
Expected Output (example):
You should see a list of files that are part of this specific lab, such as:
daemonset.yaml deployment.yaml README.md service.yaml statefulset.yaml
This confirms your environment is set up correctly, kubectl
is working, and you have access to the necessary lab files. You are now ready to proceed with Kubernetes tasks!
Okay, let’s explore some basic kubectl
commands that help you understand your Kubernetes configuration and interact with your cluster’s namespaces.
As a reminder, kubectl
needs to know which cluster to talk to and with what credentials. This information is stored in a kubeconfig
file.
Use the kubectl
CLI: Exploring Contexts and Clusters
Step 1: Get Cluster Information
This command displays the names of the Kubernetes clusters that kubectl
is configured to interact with. Your kubeconfig
file stores connection details for one or more clusters.
Command:
kubectl config get-clusters
Explanation:
kubectl config
: This subcommand is used to managekubeconfig
files, which contain information about clusters, users, and contexts.get-clusters
: This specific action lists the names of all the clusters defined in your activekubeconfig
.
Expected Output (example):
You should see at least one cluster listed. The name might vary depending on your Kubernetes environment (e.g., kubernetes
, minikube
, gke_project-name_zone_cluster-name
, docker-desktop
).
NAME
cluster-name-example
Step 2: View Your Current Context
A kubectl
context is a convenient way to group access parameters: a specific cluster, a user (credentials to access that cluster), and a namespace (the default namespace for that cluster for subsequent commands). Viewing your current context helps you understand which cluster and namespace your kubectl
commands will target.
Command:
kubectl config get-contexts
Explanation:
kubectl config
: Again, for managingkubeconfig
.get-contexts
: This action lists all the contexts defined in yourkubeconfig
file. It also indicates which context is currently active by marking it with an asterisk (*
).
Expected Output (example):
You will see a list of contexts. One will be marked with an asterisk, indicating it’s the active context.
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* current-context-name cluster-name-example user-name-example default
CURRENT
: An asterisk*
indicates the active context.NAME
: The name of the context.CLUSTER
: The name of the cluster associated with this context.AUTHINFO
: The user credentials associated with this context.NAMESPACE
: The default namespace for this context. Anykubectl
command you run will target this namespace unless you explicitly specify another one using the-n
or--namespace
flag.
Step 3: List all the Pods in your namespace.
This command will show you any Pods currently running in the default
namespace (or whatever namespace is specified in your current context).
Command:
kubectl get pods
Explanation:
kubectl get
: Retrieves information about Kubernetes resources.pods
: Specifies that you want to list Pods.
Expected Output:
If this is a new session or a clean cluster/namespace, you might see “No resources found in default namespace.”
No resources found in default namespace.
If you have previously run other tasks (like Task 1 or Task 3), you might see some Pods listed, for example:
NAME READY STATUS RESTARTS AGE
my-deployment1-6789b7b9b-abcde 1/1 Running 0 25m
my-statefulset-0 1/1 Running 0 10m
my-statefulset-1 1/1 Running 0 9m
my-statefulset-2 1/1 Running 0 8m
my-test-pod 0/1 Completed 0 15m
This command is fundamental for checking the status of your deployed applications.
Let’s proceed with creating and managing your first Pod using an imperative command. This will involve setting up your environment, building and pushing a container image, and then deploying and inspecting it in Kubernetes.
Create a Pod with an Imperative Command
This section demonstrates the imperative approach to Pod creation, where you directly instruct Kubernetes what to do on the command line.
Step 1: Export your namespace as an environment variable.
It’s common practice to store frequently used values like your namespace in an environment variable. This makes commands more readable and less prone to typos. Make sure $USERNAME
is correctly replaced by your actual username in your lab environment.
Command:
export MY_NAMESPACE=sn-labs-$USERNAME
Explanation:
export
: Makes the variable available to child processes.MY_NAMESPACE
: The name of the environment variable.sn-labs-$USERNAME
: The value assigned to the variable.sn-labs-
is a common prefix for IBM Cloud labs, and$USERNAME
will be substituted with your unique username.
(No direct output from this command.)
Step 2: Navigate to the Dockerfile
and review it.
This step instructs you to visually inspect the Dockerfile
that will be used to build your hello-world
image.
- Action: Click the “Explorer” icon (usually a sheet of paper or folder icon) on the left side of your IDE window.
- Navigation: Navigate through the directories:
CC201 > labs > 2_IntroKubernetes
. - File: Click on the file named
Dockerfile
to open it in the editor.
(No command to run here; this is a navigation and inspection step.)
Step 3: Build and push the image again.
It’s a good habit to rebuild and push your Docker image before deploying to ensure you’re using the latest version, especially if it’s been a while since your last lab session. This command builds the hello-world:1
image and pushes it to your designated IBM Cloud Container Registry namespace.
Command:
docker build -t us.icr.io/$MY_NAMESPACE/hello-world:1 . && docker push us.icr.io/$MY_NAMESPACE/hello-world:1
Explanation:
docker build -t us.icr.io/$MY_NAMESPACE/hello-world:1 .
:docker build
: Command to build a Docker image.-t us.icr.io/$MY_NAMESPACE/hello-world:1
: Tags the image with a fully qualified name, including the registry (IBM Cloud Container Registry), your namespace, image name, and tag (:1
)..
: Specifies that the Dockerfile is in the current directory.
&&
: A shell operator that executes the next command only if the previous command was successful.docker push us.icr.io/$MY_NAMESPACE/hello-world:1
: Pushes the tagged image to the specified container registry.
Expected Output: You will see output from the Docker build process (steps of building the image) and then output from the Docker push process (uploading layers to the registry). This might take a few moments.
Step 4: Run the hello-world
image as a container in Kubernetes.
Now, you’ll create a Pod using an imperative kubectl run
command. This command tells Kubernetes to create a Pod directly. The --overrides
option is used to inject imagePullSecrets
, which are necessary for Kubernetes to authenticate with IBM Cloud Container Registry and pull your private image.
Command:
kubectl run hello-world --image us.icr.io/$MY_NAMESPACE/hello-world:1 --overrides='{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"icr"}]}}}}'
Explanation:
kubectl run hello-world
: Instructs Kubernetes to create a Pod namedhello-world
.--image us.icr.io/$MY_NAMESPACE/hello-world:1
: Specifies the Docker image to be used for the container inside the Pod.--overrides='{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"icr"}]}}}}'
: This is a powerful but verbose way to modify the underlying Pod specification directly from the command line. It injects animagePullSecrets
configuration namedicr
into the Pod’sspec
. Thisicr
secret (which should have been pre-configured in your lab environment) contains the credentials needed to pull images from your private IBM Cloud Container Registry namespace.
Expected Output:
pod/hello-world created
Step 5: List the Pods in your namespace.
Verify that your hello-world
Pod has been created and its status.
Command:
kubectl get pods
Explanation:
kubectl get pods
: Retrieves a list of all Pods in the current namespace (or the namespace specified by your context).
Expected Output (example):
You should see your hello-world
Pod listed. Its status might initially be ContainerCreating
and then transition to Running
.
NAME READY STATUS RESTARTS AGE
hello-world 0/1 ContainerCreating 0 5s
# ... after a few moments ...
hello-world 1/1 Running 0 15s
Step 6: Get more details about the Pod using the wide option.
The -o wide
option provides additional useful information directly in the table output, such as the Pod’s IP address and the Node it’s running on.
Command:
kubectl get pods -o wide
Explanation:
-o wide
: This flag tellskubectl
to output more details in the table format.
Expected Output (example):
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
hello-world 1/1 Running 0 1m 10.x.x.x your-worker-node <none> <none>
Step 7: Describe the Pod to get even more details.
The kubectl describe
command provides an extensive, human-readable summary of a resource, including events, container status, and conditions. This is invaluable for debugging.
Command:
kubectl describe pod hello-world
Explanation:
kubectl describe pod hello-world
: Retrieves a detailed description of the specified Pod.
Expected Output (example - this is a long output, showing key sections):
Name: hello-world
Namespace: default
Priority: 0
Node: your-worker-node/10.x.x.x
Start Time: Mon, 02 Jun 2025 15:00:00 +0545
Labels: run=hello-world
Annotations: <none>
Status: Running
IP: 10.x.x.x
IPs:
IP: 10.x.x.x
Containers:
hello-world:
Container ID: containerd://<container-id-hash>
Image: us.icr.io/sn-labs-<USERNAME>/hello-world:1
Image ID: docker.io/library/hello-world@sha256:<image-id-hash>
Port: <none>
Host Port: <none>
State: Running
Started: Mon, 02 Jun 2025 15:00:05 +0545
Ready: True
Restart Count: 0
Environment: <none>
Mounts: <none>
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes: <none>
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 1m default-scheduler Successfully assigned default/hello-world to your-worker-node
Normal Pulling 55s kubelet Pulling image "us.icr.io/sn-labs-<USERNAME>/hello-world:1"
Normal Pulled 45s kubelet Successfully pulled image "us.icr.io/sn-labs-<USERNAME>/hello-world:1" in 9.99s (9.99s total)
Normal Created 45s kubelet Created container hello-world
Normal Started 45s kubelet Started container hello-world
This output provides detailed information about:
- Pod metadata: Name, Namespace, Labels, Annotations.
- Scheduling details: Node it’s running on, IP address.
- Container details: Container ID, Image name and ID, Ports, Current State (
Running
), Restart Count. - Conditions: The current state of the Pod’s readiness and initialization.
- Events: A chronological log of what happened to the Pod (e.g., Scheduled, Pulling image, Pulled image, Created container, Started container). This is extremely useful for troubleshooting.
Step 8: Delete the Pod.
Since this hello-world
Pod was created imperatively and isn’t managed by a higher-level controller like a Deployment, you need to explicitly delete it.
Command:
kubectl delete pod hello-world
Explanation:
kubectl delete
: Deletes Kubernetes resources.pod hello-world
: Specifies that you want to delete a Pod namedhello-world
.
Expected Output:
pod "hello-world" deleted
(Please wait for the terminal prompt to reappear, as the deletion process takes a moment.)
Step 9: List the Pods to verify that none exist.
Confirm that the hello-world
Pod has been successfully removed.
Command:
kubectl get pods
Expected Output:
No resources found in default namespace.
This confirms that the Pod you created imperatively has been successfully deleted.
Alright, let’s move on to creating a Pod using imperative object configuration. This approach combines the clarity of imperative commands with the reusability of configuration files, allowing you to explicitly state your desired action (like create
) while referencing a detailed YAML definition.
Create a Pod with Imperative Object Configuration
In this method, you’ll use a pre-defined YAML file to describe your Pod and then instruct kubectl
to create
it.
Step 1: View and Edit the Configuration File (hello-world-create.yaml
)
First, you’ll need to locate and modify the provided YAML file to include your specific namespace.
- Action: Click the Explorer icon (looks like a sheet of paper or folder) on the left side of your window.
- Navigation: Navigate to the directory for this lab:
CC201 > labs > 2_IntroKubernetes
. - File: Click on
hello-world-create.yaml
to open it in the editor.
Once opened, you’ll see content similar to this:
apiVersion: v1
kind: Pod
metadata:
name: hello-world
spec:
containers:
- name: hello-world
image: us.icr.io/<my_namespace>/hello-world:1
imagePullSecrets:
- name: icr
Edit the file: Replace <my_namespace>
with your actual namespace. Remember, you defined this earlier as sn-labs-$USERNAME
. So, for example, if your username is user123
, you’d change the line to:
image: us.icr.io/sn-labs-user123/hello-world:1
Save the file after making this change.
Step 2: Imperatively Create a Pod using the Configuration File
Now that your hello-world-create.yaml
file is updated with the correct image path, you can use kubectl create
to deploy the Pod. This is an imperative command because you are explicitly telling Kubernetes to perform the “create” action.
Command:
kubectl create -f hello-world-create.yaml
Explanation:
kubectl create
: This command instructs Kubernetes to create resources.-f hello-world-create.yaml
: The-f
(file) flag specifies the YAML file that contains the definition of the resource(s) to be created.
Expected Output:
pod/hello-world created
Step 3: List the Pods in your namespace.
Let’s confirm that the Pod was successfully created and is running.
Command:
kubectl get pods
Explanation:
kubectl get pods
: Retrieves a list of all Pods in your current namespace.
Expected Output (example):
You should see your hello-world
Pod. It might show ContainerCreating
initially, then transition to Running
.
NAME READY STATUS RESTARTS AGE
hello-world 1/1 Running 0 XsYm
Step 4: Delete the Pod.
Since this Pod was created directly (even with a configuration file), you’ll explicitly delete it.
Command:
kubectl delete pod hello-world
Explanation:
kubectl delete
: The command to remove Kubernetes resources.pod hello-world
: Specifies that you want to delete the Pod namedhello-world
.
Expected Output:
pod "hello-world" deleted
(Please wait for the terminal prompt to reappear, as the deletion process can take a few moments.)
Step 5: List the Pods to verify that none exist.
Finally, confirm that the Pod has been completely removed from your namespace.
Command:
kubectl get pods
Expected Output:
No resources found in default namespace.
Now we’ll work with the declarative command approach in Kubernetes. This is the recommended method for production environments because you define the desired state of your cluster in configuration files, and Kubernetes works to achieve and maintain that state. Instead of telling Kubernetes what to do (like create
or delete
), you tell it what you want.
Create a Pod with a Declarative Command (using a Deployment)
In this section, you’ll create a Deployment
object, which in turn manages your Pods. This demonstrates the self-healing capabilities of Kubernetes.
Step 1: View and Edit the Configuration File (hello-world-apply.yaml
)
You’ll use the Explorer to open and modify the provided YAML file.
- Action: Click the Explorer icon (looks like a sheet of paper or folder) on the left side of your window.
- Navigation: Navigate to the directory for this lab:
CC201 > labs > 2_IntroKubernetes
. - File: Click on
hello-world-apply.yaml
to open it in the editor.
You’ll see content similar to this:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
spec:
replicas: 3
selector:
matchLabels:
app: hello-world
template:
metadata:
labels:
app: hello-world
spec:
containers:
- name: hello-world
image: us.icr.io/<my_namespace>/hello-world:1
imagePullSecrets:
- name: icr
Key observations about this file:
kind: Deployment
: This tells Kubernetes you are defining a Deployment, not just a raw Pod. A Deployment is a higher-level controller that manages Pods.replicas: 3
: This instructs the Deployment to ensure that three identical Pods running your application are always active.image: us.icr.io/<my_namespace>/hello-world:1
: This is the image your Pods will run.
Edit the file: Replace <my_namespace>
with your actual namespace (e.g., sn-labs-yourusername
).
For example, if your username part is user123
, change the line to:
image: us.icr.io/sn-labs-user123/hello-world:1
Save the file after making this change.
Step 2: Use the kubectl apply
command to set this configuration as the desired state.
This is the cornerstone of declarative management in Kubernetes. You are telling Kubernetes: “This is what I want the state of my cluster to be.” kubectl apply
is intelligent enough to create the resource if it doesn’t exist or update it if it does.
Command:
kubectl apply -f hello-world-apply.yaml
Explanation:
kubectl apply
: This command is used to apply a configuration to a resource by file name or stdin. It creates the resource if it doesn’t exist, and updates it if it does.-f hello-world-apply.yaml
: Specifies the YAML file containing the resource definition.
Expected Output:
deployment.apps/hello-world created
Step 3: Get the Deployments to ensure that a Deployment was created.
Verify that the Deployment
object itself has been created.
Command:
kubectl get deployments
Explanation:
kubectl get deployments
: Lists all Deployment objects in your current namespace.
Expected Output (example):
NAME READY UP-TO-DATE AVAILABLE AGE
hello-world 0/3 0 0 5s # Initially, as pods are starting
# ... after a moment ...
hello-world 3/3 3 3 1m
The READY
column will eventually show 3/3
, indicating that three desired replicas are up and running.
Step 4: List the Pods to ensure that three replicas exist.
Confirm that the Deployment has successfully launched three Pods.
Command:
kubectl get pods
Explanation:
kubectl get pods
: Lists all Pods in your current namespace.
Expected Output (example):
You should see three Pods, all with names starting with hello-world-
followed by a unique hash, and all in the Running
status.
NAME READY STATUS RESTARTS AGE
hello-world-774ddf45b5-28k7j 1/1 Running 0 45s
hello-world-774ddf45b5-9cbv2 1/1 Running 0 45s
hello-world-774ddf45b5-svpf7 1/1 Running 0 45s
Step 5: Observe Kubernetes’ Self-Healing: Delete a Pod
This is where the power of declarative management and controllers like Deployments truly shines. When you delete a Pod managed by a Deployment, Kubernetes will automatically create a new one to maintain the desired replica count (which is 3 in our hello-world
Deployment).
Action:
- Note one of the Pod names from the output of the previous
kubectl get pods
command (e.g.,hello-world-774ddf45b5-28k7j
). - Replace
<pod_name>
in the command below with the actual name you noted.
Command:
kubectl delete pod <pod_name> && kubectl get pods
Example (using a hypothetical pod name):
kubectl delete pod hello-world-774ddf45b5-28k7j && kubectl get pods
Explanation:
kubectl delete pod <pod_name>
: Explicitly deletes a specific Pod.&&
: Executes the next command only if the previous one succeeded.kubectl get pods
: Immediately lists the Pods after deletion.
Expected Output (example, showing a Pod being terminated and then only two remaining for a brief moment):
pod "hello-world-774ddf45b5-28k7j" deleted
NAME READY STATUS RESTARTS AGE
hello-world-774ddf45b5-9cbv2 1/1 Running 0 2m
hello-world-774ddf45b5-svpf7 1/1 Running 0 2m
hello-world-774ddf45b5-28k7j 0/1 Terminating 0 2m
You’ll see one Pod enter the Terminating
state, and for a short period, kubectl get pods
might show only two Running
Pods, plus the one terminating.
(Please wait till the terminal prompt appears again after deletion.)
Step 6: List the Pods to see a new one being created.
Kubernetes will quickly detect that the desired replica count (3) is not met and will spin up a new Pod to replace the one you deleted. You might need to run this command a couple of times to see the new Pod appear and become Running
.
Command:
kubectl get pods
Expected Output (example):
After a short while, you will again see three Running
Pods. Note that the name of the new Pod will be different from the one you deleted.
NAME READY STATUS RESTARTS AGE
hello-world-774ddf45b5-9cbv2 1/1 Running 0 3m
hello-world-774ddf45b5-svpf7 1/1 Running 0 3m
hello-world-774ddf45b5-xyz1a 1/1 Running 0 10s # This is the newly created Pod
Conclusion:
This exercise beautifully illustrates the power of declarative management in Kubernetes. You declared your desired state (three hello-world
replicas via a Deployment
), and Kubernetes automatically worked to achieve and maintain that state, demonstrating its self-healing capabilities. This is why declarative management is the preferred method for production environments.
Alright, let’s explore how Kubernetes handles load balancing for your application. Since you have a Deployment
with three replicas, Kubernetes will automatically distribute incoming requests among these Pods. To observe this, we’ll expose the application using a Kubernetes Service
and then access it via a proxy.
Load Balancing the Application
This section demonstrates how Kubernetes provides load balancing across multiple instances of your application by using a Service.
Step 1: Expose your application to the internet using a Kubernetes Service.
You’ll create a Service
that targets your hello-world
Deployment. By default, kubectl expose
will create a ClusterIP
Service, which is accessible from within the cluster.
Command:
kubectl expose deployment/hello-world
Explanation:
kubectl expose
: This command creates a new Service for a given Replication Controller, Service, Deployment, or Pod.deployment/hello-world
: Specifies that you want to expose the Deployment namedhello-world
. Kubernetes will automatically create selectors to match the Pods managed by this Deployment.
Expected Output:
service/hello-world exposed
Step 2: List Services to see that this service was created.
Verify that your hello-world
Service has been created.
Command:
kubectl get services
Explanation:
kubectl get services
: Lists all Service objects in your current namespace.
Expected Output (example):
You should see your hello-world
Service with a ClusterIP
type.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-world ClusterIP 10.x.x.x <none> 80/TCP XsYm
kubernetes ClusterIP 10.x.x.x <none> 443/TCP YdZm
hello-world
: The name of the Service you just created.ClusterIP
: This is the default Service type, providing an internal IP address accessible only from within the cluster.CLUSTER-IP
: The internal IP address assigned to this Service.PORT(S)
: The port the Service is listening on (80/TCP by default for HTTP).
Step 3: Open a new split terminal window.
To run the kubectl proxy
command, which blocks the terminal, you’ll need a separate terminal window.
- Action: Locate the split icon in the top-right corner of your terminal panel (it often looks like two rectangles or a divided screen). Click it to open a new terminal pane.
(You will now have two active terminal windows/panes.)
Step 4: Run the Kubernetes API proxy in the new terminal window.
This command creates a proxy that allows you to access your Kubernetes API server and its proxied services from your local machine. This is useful for testing internal services without setting up external ingress or NodePorts.
Command (in the NEW SPLIT TERMINAL):
kubectl proxy
Explanation:
kubectl proxy
: Creates a local proxy that forwards requests to the Kubernetes API server. This allows you to access internal cluster services vialocalhost:8001
.
Expected Output (in the new terminal):
Starting to serve on 127.0.0.1:8001
(This command will keep running and won’t return to the prompt until you terminate it. Keep this terminal window open and running the proxy.)
Step 5: Ping the application to get a response (in the original terminal window).
Now, switch back to your original terminal window (where your environment variables are set). You’ll use curl
to send a request through the kubectl proxy
to your hello-world
Service. Remember to substitute $USERNAME
with your actual username.
Command (in the ORIGINAL TERMINAL):
curl -L localhost:8001/api/v1/namespaces/sn-labs-$USERNAME/services/hello-world/proxy
Explanation:
curl -L
: A command-line tool for making HTTP requests.-L
follows redirects.localhost:8001
: The address of thekubectl proxy
./api/v1/namespaces/sn-labs-$USERNAME/services/hello-world/proxy
: This is the specific path through the Kubernetes API proxy to reach yourhello-world
Service within your namespace. The/proxy
suffix tells the API server to forward the request to the specified service.
Expected Output (example):
You should see a response from your hello-world
application, which includes the name of the Pod that handled the request.
Hello from hello-world-774ddf45b5-28k7j
(The specific Pod name will vary, but it will be one of your hello-world
Pod replicas.)
Step 6: Send ten consecutive requests to observe load balancing.
Now, let’s send multiple requests quickly to see how Kubernetes distributes them across your three hello-world
Pods.
Command (in the ORIGINAL TERMINAL):
for i in `seq 10`; do curl -L localhost:8001/api/v1/namespaces/sn-labs-$USERNAME/services/hello-world/proxy; done
Explanation:
for i in
seq 10“: This is a shell loop that will run thecurl
command 10 times.curl -L localhost:8001/api/v1/namespaces/sn-labs-$USERNAME/services/hello-world/proxy
: The samecurl
command as before.
Expected Output (example):
You will see 10 lines of output. As you review them, you should notice that the “Hello from…” message includes different Pod names, demonstrating that Kubernetes is indeed load balancing requests across your three hello-world
Pod replicas.
Hello from hello-world-774ddf45b5-28k7j
Hello from hello-world-774ddf45b5-9cbv2
Hello from hello-world-774ddf45b5-svpf7
Hello from hello-world-774ddf45b5-28k7j
Hello from hello-world-774ddf45b5-svpf7
Hello from hello-world-774ddf45b5-9cbv2
Hello from hello-world-774ddf45b5-28k7j
Hello from hello-world-774ddf45b5-9cbv2
Hello from hello-world-774ddf45b5-svpf7
Hello from hello-world-774ddf45b5-28k7j
(The order and distribution of Pod names will vary.)
Step 7: Delete the Deployment and Service.
It’s good practice to clean up resources after you’re done with them. You can delete multiple resources with a single kubectl delete
command by separating them with spaces.
Command (in the ORIGINAL TERMINAL):
kubectl delete deployment/hello-world service/hello-world
Explanation:
kubectl delete
: Deletes Kubernetes resources.deployment/hello-world
: Specifies the Deployment namedhello-world
to be deleted. This will also delete the Pods managed by this Deployment.service/hello-world
: Specifies the Service namedhello-world
to be deleted.
Expected Output:
deployment.apps "hello-world" deleted
service "hello-world" deleted
(Note: If you face any issues in typing further commands in the terminal, pressing Enter might help clear the line.)
Step 8: Return to the proxy terminal and kill it.
Go back to the new split terminal window where kubectl proxy
is running. You need to terminate this process.
Action: Press Ctrl+C
in the terminal window running kubectl proxy
.
Expected Output (in the proxy terminal):
The proxy will stop, and the terminal prompt will return.
Starting to serve on 127.0.0.1:8001
^C
Congratulations! You have successfully completed the lab for the second module of this course!
You’ve learned how Kubernetes services provide stable network access and automatic load balancing to your replicated applications. This concludes the practical exercises for this module.
You’ve covered a comprehensive range of fundamental Kubernetes concepts! This summary effectively highlights the key takeaways from your learning module.
Here’s a structured summary and highlight of the Kubernetes basics you’ve mastered:
Summary & Highlights: Kubernetes Basics
This module has provided a solid foundation in understanding the core components, objects, and capabilities of Kubernetes, along with practical experience in deploying and managing applications.
1. The “Why” of Container Orchestration
- Container orchestration automates the entire lifecycle of containers, offering significant benefits:
- Faster Deployments: Streamlined release processes.
- Reduced Errors: Automation minimizes human mistakes.
- Higher Availability: Ensures applications remain accessible even during failures.
- More Robust Security: Consistent deployment patterns reduce vulnerabilities.
2. What is Kubernetes?
- Kubernetes (K8s) is a highly portable, horizontally scalable, open-source platform designed for:
- Automating deployment.
- Scaling application containers.
- Simplifying management of containerized workloads and services.
3. Kubernetes Architecture: The Brains and the Brawn
-
Kubernetes operates with a Control Plane and one or more Worker Planes.
-
Control Plane (the “brain”): Manages and orchestrates the cluster. It includes:
- Controllers: Watch the desired state and move the cluster towards it (e.g., Deployment controller, ReplicaSet controller).
- API Server (
kube-apiserver
): The front-end for the Kubernetes control plane. All communication (internal and external) goes through it. - Scheduler (
kube-scheduler
): Assigns newly created Pods to available Nodes. - etcd: A consistent and highly available key-value store used as Kubernetes’ backing store for all cluster data.
-
Worker Plane (the “brawn”): Runs the actual application workloads. It includes:
- Nodes: The virtual or physical machines where Pods run.
- Kubelet: An agent that runs on each node, ensuring containers in a Pod are running and healthy.
- Container Runtime: Software responsible for running containers (e.g., containerd, CRI-O, Docker).
- Kube-proxy: Maintains network rules on nodes, enabling network communication to your Pods from inside or outside the cluster.
-
4. Key Kubernetes Objects: The Building Blocks
You’ve learned about fundamental Kubernetes API objects used to define and manage your applications:
- Namespaces: Provide a way to isolate groups of resources within a single cluster, useful for multi-tenancy or organizing projects.
- Pods: The smallest deployable unit in Kubernetes. They represent a single instance of a running process or application. A Pod encapsulates one or more containers (tightly coupled applications), storage resources, a unique network IP, and options that control how the containers run.
- ReplicaSets: Ensures a specified number of identical Pod replicas are running at all times, providing self-healing. (Often managed indirectly by Deployments).
- Deployments: A higher-level abstraction that manages the deployment and scaling of a set of Pods. It provides declarative updates for Pods and ReplicaSets, enabling features like automated rollouts and rollbacks.
- Services: A REST object that defines a logical set of Pods and a policy by which to access them. It provides stable network access to Pods, abstracting away their ephemeral nature.
5. Kubernetes Capabilities: Why It’s Powerful
Kubernetes offers a rich set of features that make it a robust orchestration platform:
- Automated Rollouts & Rollbacks: Safely update applications and revert if issues arise.
- Storage Orchestration: Automatically mounts specified storage systems.
- Horizontal Scaling: Easily scale applications in or out based on demand.
- Automated Bin Packing: Optimally places containers on nodes to maximize resource utilization.
- Secret and Configuration Management: Securely handles sensitive data and non-sensitive configuration.
- IPv4/IPv6 Dual-Stack Support: Enables both IP versions for network communication.
- Batch Execution (Jobs/CronJobs): For running one-time tasks or scheduled tasks.
- Self-Healing: Automatically replaces failed containers, restarts unresponsive containers, and reschedules Pods on healthy nodes.
- Service Discovery: Automatically discovers and registers services within the cluster.
- Load Balancing: Distributes network traffic across multiple Pod instances.
- Extensible Design: Highly customizable and pluggable, allowing for integration with various tools and cloud providers.
6. Service Types: Exposing Your Applications
Different Service types cater to various communication needs:
ClusterIP
:- Provides an internal IP address accessible only from within the cluster.
- Used for inter-service communication (e.g., frontend talking to backend).
NodePort
:- Opens a specific port on every Node in the cluster.
- Traffic to this NodePort is automatically routed to the ClusterIP Service, and then to the backend Pods.
- Externally accessible via
NodeIP:NodePort
.
LoadBalancer
:- Used primarily in cloud environments.
- Automatically provisions an external cloud load balancer (e.g., AWS ELB, GCP Load Balancer) that routes traffic to NodePorts, which then forward to ClusterIP and Pods.
- Creates NodePort and ClusterIP Services automatically.
ExternalName
:- Maps a Service to a
CNAME
record in DNS. - Used to represent external services (e.g., a database hosted outside the cluster) as a Kubernetes Service.
- Enables Pods from different namespaces or clusters to talk to external resources via a familiar Kubernetes Service name.
- Maps a Service to a
7. Advanced Controllers for Specific Use Cases
You also explored specialized workload controllers:
- Ingress:
- An API object that defines HTTP/HTTPS routing rules to manage external users’ access to multiple services in a Kubernetes cluster, often providing features like SSL/TLS termination and name-based virtual hosting.
- Requires an Ingress Controller to function.
- DaemonSet:
- Ensures that a copy of a specific Pod runs on all (or some) eligible nodes in the cluster.
- Ideal for system-level services like logging agents, monitoring agents, or network proxies.
- StatefulSet:
- Manages stateful applications.
- Ensures ordered deployment and scaling.
- Maintains a sticky identity for each Pod (stable hostname, network ID, and persistent storage).
- Provides persistent storage volumes for each Pod (via
volumeClaimTemplates
).
- Job:
- Creates Pods and ensures that a specified number of Pods successfully complete their tasks.
- Jobs are retried until completion.
- CronJob: (Implicitly covered by Job mention)
- Automates the creation of Jobs on a time-based schedule.
This comprehensive overview confirms your strong understanding of Kubernetes fundamentals, preparing you for more advanced topics and real-world deployments!
Here is your cheat sheet summarizing the kubectl
commands you’ve learned for understanding Kubernetes architecture and managing resources:
Cheat Sheet: Understanding Kubernetes Architecture & kubectl
Commands
This cheat sheet provides a quick reference for essential kubectl
commands used to interact with your Kubernetes cluster and its various objects.
Command | Description |
---|---|
for ... do ... done | Runs a command multiple times as specified in a loop. (A general shell construct, useful with kubectl ). |
kubectl apply -f <file.yaml> | Applies a configuration to a resource. Creates the resource if it doesn’t exist, and updates it if it does. This is the declarative way. |
kubectl config get-clusters | Displays the names of clusters defined in your kubeconfig file. |
kubectl config get-contexts | Displays all contexts defined in your kubeconfig file, indicating the current active context. |
kubectl create -f <file.yaml> | Creates a resource by explicitly telling Kubernetes to perform the “create” action based on a configuration file. (Imperative object config). |
kubectl delete <resource-type>/<name> | Deletes resources from the cluster. Can delete multiple resources by separating them with spaces. |
kubectl describe <resource-type> <name> | Shows detailed information about a specific resource or group of resources, including events and status. |
kubectl expose <resource-type>/<name> | Exposes a resource (like a Deployment) to the network by creating a Kubernetes Service. |
kubectl get <resource-type> | Displays resources of a specific type (e.g., pods , deployments , services ). |
kubectl get pods | Lists all Pods in the current namespace. |
kubectl get pods -o wide | Lists all Pods with additional details, such as Node name and IP address. |
kubectl get deployments | Lists all Deployments created in the current namespace. |
kubectl get services | Lists all Services created in the current namespace. |
kubectl proxy | Creates a local proxy server between your localhost and the Kubernetes API server, allowing internal cluster services to be accessed via localhost:8001 . |
kubectl run <name> --image <image> | Creates and runs a particular image in a Pod. This is an imperative command. |
kubectl version | Prints the client (kubectl ) and server (API server) version information. |
This is a very comprehensive glossary of Kubernetes basic terms! It covers many essential concepts needed to understand the platform.
Here’s the provided glossary, well-defined and ready for quick reference:
Glossary: Kubernetes Basics
Term | Definition |
---|---|
Automated bin packing | Increases resource utilization and cost savings by efficiently scheduling a mix of critical and best-effort workloads onto cluster nodes. |
Batch execution | Manages finite or batch tasks, including continuous integration workloads. Jobs are designed to run to completion and automatically replace failed containers if configured to do so. |
Cloud Controller Manager | A Kubernetes control plane component that embeds cloud-specific control logic. It links your cluster into your cloud provider’s API, separating interactions with the cloud platform from components that only interact with your cluster. |
Cluster | A set of worker machines, called Nodes, that run containerized applications. Every cluster has at least one worker Node. |
Container Orchestration | A process that automates the container lifecycle of containerized applications, leading to faster deployments, reduced errors, higher availability, and more robust security. |
Container Runtime | The software responsible for running containers (e.g., containerd, CRI-O, Docker). |
Control Loop | A non-terminating feedback loop that regulates the state of a system. In Kubernetes, controllers are control loops. |
Control Plane | The orchestration layer that exposes the API and interfaces to define, deploy, and manage the lifecycle of containers within the cluster. It’s the “brain” of the Kubernetes cluster. |
Controller | In Kubernetes, controllers are control loops that continuously watch the state of your cluster via the API Server, then make or request changes where needed. Each controller tries to move the current cluster state closer to the desired state defined by your configurations. |
Data (Worker) Plane | The layer that provides capacity such as CPU, memory, network, and storage so that the containers can run and connect to a network. This is where your actual application workloads run. |
DaemonSet | An object that ensures a copy of a specific Pod is running across all (or a defined subset of) Nodes in a cluster. Useful for system-level services. |
Declarative Management | A management approach where you express the desired state of your system (e.g., the number of replicas for an application), and Kubernetes actively works to ensure that the observed (current) state matches this desired state. You declare what you want, not how to achieve it. |
Deployment | A higher-level object that provides declarative updates for Pods and ReplicaSets. Deployments run multiple replicas of an application by creating ReplicaSets and offer additional management capabilities (like rolling updates and rollbacks) on top of those ReplicaSets. They are generally suitable for stateless applications. |
Designed for extensibility | A core feature of Kubernetes that allows adding new features and functionalities to your cluster without needing to modify the Kubernetes source code itself, often through custom resources and controllers. |
Docker Swarm | A container orchestration tool designed specifically to work with Docker Engine and other Docker tools, making it a popular choice for teams already working in Docker environments. It automates the deployment of containerized applications. |
Ecosystem | In the context of Kubernetes, this refers to the vast and rapidly growing composition of services, support, and tools that are widely available and integrate with Kubernetes. |
etcd | A highly available, distributed key-value store that serves as Kubernetes’ backing store for all cluster data. It is the single source of truth for the desired state and current state of a Kubernetes cluster. |
Eviction | The process of terminating one or more Pods on Nodes, often initiated by the Kubelet when a Node experiences resource pressure or when a higher-priority Pod needs to be scheduled. |
Imperative commands | Commands that explicitly create, update, or delete live objects directly on the command line (e.g., kubectl run , kubectl delete pod ). |
Imperative Management | A management approach where you define explicit steps and actions (create , delete , update ) to get to a desired state. |
Ingress | An API object that manages external access to the services in a cluster, typically HTTP and HTTPS traffic. It provides routing rules, SSL/TLS termination, and name-based virtual hosting. (Requires an Ingress Controller to function). |
IPv4/IPv6 dual stack | A Kubernetes networking capability that assigns both IPv4 and IPv6 addresses to Pods and Services, enabling dual-protocol communication. |
Job | A Kubernetes object that creates one or more Pods and ensures that a specified number of them successfully complete their tasks. Jobs are designed for finite or batch tasks and will retry Pods until completion. |
Kubectl | Also known as kubectl , it is the command-line tool for communicating with a Kubernetes cluster’s control plane, using the Kubernetes API. |
Kubelet | The primary “node agent” that runs on each Node. The Kubelet takes a set of PodSpecs (a YAML or JSON object that describes a Pod) provided primarily through the API Server and ensures that the containers described in those PodSpecs are running and healthy. The Kubelet does not manage containers that were not created by Kubernetes. |
Kubernetes | The de facto open-source platform standard for container orchestration. Developed by Google and maintained by the Cloud Native Computing Foundation (CNCF). Kubernetes automates container management tasks, like deployment, storage provisioning, load balancing and scaling, service discovery, and fixing failed containers. Its open-source toolset and wide array of functionalities are very attractive to leading cloud providers. |
Kubernetes API | The application that serves Kubernetes functionality through a RESTful interface and stores the state of the cluster in etcd . All internal and external interactions with the cluster go through the API. |
Kubernetes API Server | The central component of the Kubernetes Control Plane. It validates and configures data for API objects (Pods, Services, Deployments, etc.), services REST operations, and provides the frontend to the cluster’s shared state through which all other components interact. |
Kubernetes Controller Manager | A Control Plane component that runs all the core controller processes (e.g., Replication Controller, Endpoints Controller, Namespace Controller, Service Accounts Controller) that monitor the cluster state and ensures that the actual state of a cluster matches the desired state. |
Kubernetes Proxy (kube-proxy ) | A network proxy that runs on each Node in a cluster. This proxy maintains network rules on nodes, enabling network communication to Pods running on those nodes. It facilitates access to workloads running on the cluster. |
kube-scheduler | A Control Plane component that watches for newly created Pods with no assigned Node, and selects a suitable Node for them to run on based on various constraints and available resources. |
Label Selector | A mechanism that allows users to filter a list of resources (like Pods) based on their assigned Labels. |
Labels | Key-value pairs that are attached to Kubernetes objects (like Pods, Deployments, Services). They are used to tag objects with identifying attributes that are meaningful and relevant to users, and are crucial for organizing and selecting resources. |
Load balancing | The process of distributing network traffic across multiple Pods (or other backend instances) to ensure better performance, high availability, and efficient resource utilization. |
Marathon | An Apache Mesos framework. Apache Mesos is an open-source cluster manager that allows users to scale container infrastructure through the automation of most management and monitoring tasks. Marathon is a system for orchestrating long-running services and batch jobs on Mesos. |
Namespace | An abstraction provided by Kubernetes to support isolation of groups of resources within a single cluster. Namespaces are used for logical separation, resource quotas, and access control. |
Node | The worker machine in a Kubernetes cluster. User applications are run on Nodes. Nodes can be virtual or physical machines, and each Node is managed by the Control Plane and is able to run Pods. |
Nomad (HashiCorp) | A free and open-source cluster management and scheduling tool that supports Docker and other applications on all major operating systems across all infrastructure, whether on-premises or in the cloud. It offers flexibility for managing various types and levels of workloads. |
Object | An entity in the Kubernetes system. The Kubernetes API uses these entities (e.g., Pods, Deployments, Services) to represent the desired state and current state of your cluster. |
Persistence | In Kubernetes, ensures that an object or its associated data exists in the system (e.g., on disk or in etcd ) and survives Pod restarts or Node failures, until the object is explicitly modified or removed. |
Pod | The smallest and simplest Kubernetes object. It represents a single instance of an application process running in a cluster. A Pod usually encapsulates a single container but can, in some cases, encapsulate multiple tightly coupled containers (sidecars) that share resources, network, and storage. |
Preemption | A scheduling mechanism in Kubernetes where the scheduler helps a pending (un-scheduled) Pod find a suitable Node by evicting one or more lower-priority Pods already existing on that Node, if necessary. |
Proxy | In computing, a server that acts as an intermediary for a remote service, forwarding requests and responses. In Kubernetes, kube-proxy and kubectl proxy are examples. |
ReplicaSet | A Kubernetes object that (aims to) maintain a specified set of replica Pods running at any given time. It ensures the availability of a fixed number of identical Pods. (Often managed indirectly by Deployments). |
Self-healing | A core Kubernetes capability where it automatically detects and remedies issues, such as restarting failed containers, replacing unresponsive Pods, rescheduling Pods from failed Nodes, and killing containers that don’t respond to health checks. |
Service | An abstract way to expose an application running on a set of Pods as a network service. It provides a stable IP address and DNS name, acting as a load balancer for traffic directed to the underlying Pods. |
Service Discovery | The process by which applications running within Kubernetes can find and communicate with other services or Pods, typically using their stable IP addresses or a single DNS name provided by Services. |
StatefulSet | A workload API object that manages the deployment and scaling of a set of Pods, and provides guarantees about the ordering and uniqueness of these Pods (e.g., stable network identities, stable persistent storage). It is used for stateful applications. |
Storage | A data store that supports persistent and temporary storage for Pods, enabling applications to store and retrieve data beyond the lifecycle of individual Pods. |
Storage Orchestration | A Kubernetes capability that automatically mounts your chosen storage system into Pods, whether it’s local storage, network-attached storage (like NFS, iSCSI), or cloud-provider specific storage solutions. |
Workload | In Kubernetes, a workload refers to an application (or a component of an application) running on the cluster. Kubernetes provides various workload resources (like Deployments, StatefulSets, DaemonSets, Jobs) to manage different types of workloads. |