Skip to content
Go back

Kubernetes Guide Part 1: Architecture, Core Components & Basics

Edit page

1. Introduction to Container Orchestration

What is Container Orchestration?

Container orchestration is the automated process of managing, deploying, scaling, and networking containers. Think of it as a conductor orchestrating an entire symphony of containers.

Why Do We Need Orchestration Tools?

Modern applications are increasingly built using microservices architecture - breaking down monolithic applications into smaller, independent services. While containers are perfect hosts for these microservices, managing hundreds or thousands of containers manually becomes impossible.

Key Problems Orchestration Solves:

  1. High Availability (No Downtime)

    • Automatically restarts failed containers
    • Distributes workload across multiple machines
    • Ensures your application is always accessible
  2. Scalability

    • Automatically scales applications up or down based on demand
    • Handles load balancing across container replicas
    • Manages resource allocation efficiently
  3. Disaster Recovery

    • Automatic backup and restore capabilities
    • Self-healing mechanisms
    • Data replication across nodes

The Journey: Monolith → Microservices

┌─────────────────────┐         ┌──────────┐ ┌──────────┐ ┌──────────┐
│                     │         │ Service  │ │ Service  │ │ Service  │
│   MONOLITHIC APP    │  ───►   │    A     │ │    B     │ │    C     │
│                     │         │          │ │          │ │          │
└─────────────────────┘         └──────────┘ └──────────┘ └──────────┘
  Single Deployment              Independent Deployments
  Tight Coupling                 Loose Coupling
  Hard to Scale                  Easy to Scale

2. What is Kubernetes?

Kubernetes (K8s) is an open-source container orchestration platform developed by Google. The name comes from the Greek word for “helmsman” or “pilot” - fitting, as it steers your containerized applications.

Why “K8s”?

The “8” represents the eight letters between “K” and “s” in “Kubernetes”.

Official Definition

Kubernetes automates many processes involved in deploying, managing, and scaling containerized applications. It has become the most widely used container orchestration platform in the industry.

What Kubernetes Provides:


3. Core Kubernetes Components

Kubernetes has many components, but let’s focus on the essential ones you need to understand.

3.1 Pod

What is a Pod?

Why Pods are Important:

Pods provide an abstraction layer over Docker/containerd. This means:

Pods are Ephemeral:

Pod Created → Running → Crashes/Dies
     ↓                      ↓
IP: 10.0.0.1          New Pod Created
                      NEW IP: 10.0.0.2 ❌

When a pod dies and is recreated, it gets a new IP address. This makes direct pod-to-pod communication unreliable. That’s where Services come in.

3.2 Service

What is a Service?

Why Services Solve the IP Problem:

┌─────────────┐
│  Service    │ ← Permanent IP: 10.0.0.100
│ 10.0.0.100  │
└──────┬──────┘

   ┌───┴────┐
   │        │
┌──▼──┐  ┌──▼──┐
│ Pod │  │ Pod │  ← Pods can die and be recreated
│ #1  │  │ #2  │     with new IPs, but service IP
└─────┘  └─────┘     remains the same!

Internal vs External Services:

3.3 Ingress

The Problem with External Services: External services give you URLs like http://124.89.101.2:8080 - not very user-friendly!

Ingress to the Rescue: Ingress is the entrypoint to your Kubernetes cluster. It:

Request Flow:

User Browser → Ingress (https://my-app.com) → Service → Pods

3.4 ConfigMap & Secret

Applications need configuration: database URLs, feature flags, etc. Hard-coding these into your application is bad practice.

ConfigMap:

Secret:

Important Security Note: Storing data in Secrets doesn’t automatically make it secure. You need to:

How Pods Use Them:

# Pods can consume ConfigMaps and Secrets as:
- Environment variables
- Command-line arguments  
- Configuration files in a Volume

3.5 Volumes

The Problem: When a container crashes, Kubernetes restarts it with a clean state - all data is lost! 💥

The Solution: Volumes attach physical storage to your pods, persisting data beyond container/pod lifecycles.

Important: Kubernetes does NOT manage data persistence. You are responsible for:

Storage Requirements for Production:

  1. Must be available on all nodes (pods can start anywhere)
  2. Must survive pod lifecycle
  3. Must survive cluster crashes

Think of it as: An external hard drive plugged into your Kubernetes cluster.

3.6 Deployment

What is a Deployment?

Why Not Work Directly with Pods? You never create pods directly. Instead:

You Define → Deployment → Creates → Pods

Example Benefits:

Deployment: "I want 3 replicas of nginx"

Kubernetes Creates:
   ┌──────┐ ┌──────┐ ┌──────┐
   │ Pod1 │ │ Pod2 │ │ Pod3 │
   └──────┘ └──────┘ └──────┘

If Pod2 crashes:
   ┌──────┐ ┌──────┐ ┌──────┐
   │ Pod1 │ │ NEW  │ │ Pod3 │
   └──────┘ │ Pod2 │ └──────┘
            └──────┘

3.7 StatefulSet

For Stateful Applications: While Deployments are great for stateless apps (web servers, APIs), databases and stateful apps need special handling.

StatefulSet provides:

Deployment vs StatefulSet:

FeatureDeploymentStatefulSet
Pod NamesRandom hash (nginx-d98b7f5c-qr9zx)Ordered (mysql-0, mysql-1)
Creation OrderRandom, parallelSequential
StorageShared or noneIndividual persistent storage
Use CaseStateless appsDatabases, message queues

Why StatefulSets are Complex:

MySQL StatefulSet with 3 replicas:

mysql-0 (Master) ← Only this can write

mysql-1 (Slave)  ← Read replicas

mysql-2 (Slave)

Each has its own storage, and data must be
synchronized to avoid inconsistencies!

Note: Deploying stateful applications is significantly more complex than stateless ones. Many teams choose managed databases to avoid this complexity.


4. Kubernetes Architecture

A Kubernetes cluster consists of two types of nodes:

4.1 Worker Nodes

Worker nodes are where your actual applications run. Think of them as the workhorses of your cluster.

Each Worker Node Requires 3 Processes:

1. Container Runtime

2. Kubelet

3. Kube-proxy

Worker Node Visualization:

┌─────────────────────────────────────┐
│        Worker Node                  │
│                                     │
│  ┌──────────────────────────────┐  │
│  │   Container Runtime          │  │
│  └──────────────────────────────┘  │
│                                     │
│  ┌──────────────────────────────┐  │
│  │   Kubelet                    │  │
│  │   - Manages Pods             │  │
│  │   - Reports Status           │  │
│  └──────────────────────────────┘  │
│                                     │
│  ┌──────────────────────────────┐  │
│  │   Kube-proxy                 │  │
│  │   - Network Rules            │  │
│  │   - Load Balancing           │  │
│  └──────────────────────────────┘  │
│                                     │
│  ┌─────┐ ┌─────┐ ┌─────┐          │
│  │ Pod │ │ Pod │ │ Pod │ ← Apps   │
│  └─────┘ └─────┘ └─────┘          │
└─────────────────────────────────────┘

4.2 Control Plane (Master Node)

The Control Plane manages the worker nodes and pods in the cluster. It’s the brain of Kubernetes.

Each Control Plane Requires 4 Processes:

1. API Server

Clients that interact with API Server:

2. Scheduler

Note: The Scheduler only decides where to place the pod. The Kubelet actually starts it.

3. Controller Manager

Self-Healing in Action:

Pod Crashes → Controller Manager Detects

          Requests Scheduler

          Scheduler Decides Node

          Kubelet Starts New Pod

4. etcd

What etcd Stores:

How Other Components Use etcd:

Control Plane Visualization:

┌────────────────────────────────────────────┐
│         Control Plane Node                 │
│                                            │
│  ┌────────────────────────────────────┐   │
│  │      API Server                    │   │
│  │  - Cluster Gateway                 │   │
│  │  - Authentication                  │   │
│  └─────┬──────────────────────────────┘   │
│        │                                   │
│  ┌─────▼──────┐  ┌────────────────┐       │
│  │ Scheduler  │  │ Controller Mgr │       │
│  │            │  │                │       │
│  └─────┬──────┘  └───────┬────────┘       │
│        │                 │                 │
│  ┌─────▼─────────────────▼────────┐       │
│  │          etcd                  │       │
│  │    (Cluster Data Store)        │       │
│  └────────────────────────────────┘       │
└────────────────────────────────────────────┘

4.3 How Components Interact

Example: Creating a Deployment

1. You run: kubectl apply -f deployment.yaml

2. kubectl → API Server (authenticates & validates)

3. API Server → etcd (saves desired state)

4. Controller Manager notices change (watching etcd)

5. Controller Manager → API Server → Scheduler

6. Scheduler decides which node to use

7. API Server → Kubelet on selected node

8. Kubelet → Container Runtime (starts container)

9. Kubelet reports status → API Server → etcd

4.4 Scaling Your Cluster

Adding a Worker Node:

1. Get a new server
2. Install: Container Runtime, Kubelet, Kube-proxy
3. Join to cluster: kubeadm join <control-plane-endpoint>

Adding a Control Plane Node (for high availability):

1. Get a new server
2. Install: API Server, Scheduler, Controller Manager, etcd
3. Join to cluster using kubeadm

Production Recommendation:


5. Getting Started - Local Setup

5.1 Minikube - Local Kubernetes Cluster

What is Minikube?

Why Minikube? Running a full Kubernetes cluster for testing would require:

Minikube makes it simple by running everything in a single VM or container on your laptop.

Installation:

# macOS
brew install minikube

# Linux
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

# Windows
choco install minikube

Start Minikube:

# Start with Docker driver (recommended)
minikube start --driver=docker

# Start with VirtualBox
minikube start --driver=virtualbox

# Check status
minikube status

Useful Minikube Commands:

minikube dashboard        # Open Kubernetes dashboard
minikube service <name>   # Expose a service
minikube stop            # Stop the cluster
minikube delete          # Delete the cluster
minikube ssh             # SSH into the node

5.2 kubectl - Kubernetes Command Line Tool

What is kubectl?

How kubectl Connects: kubectl needs a kubeconfig file to access a cluster. This file contains:

Default Location: ~/.kube/config

When you start Minikube, this config file is created automatically.

5.3 Essential kubectl Commands

Basic Information Commands

# Get cluster information
kubectl cluster-info

# Get all nodes in the cluster
kubectl get nodes

# Get all pods in current namespace
kubectl get pods
kubectl get pod   # alternative

# Get all services
kubectl get services
kubectl get svc   # shorthand

# Get all deployments
kubectl get deployments
kubectl get deploy   # shorthand

# Get all replicasets
kubectl get replicaset
kubectl get rs   # shorthand

# Get everything
kubectl get all

# Filter with grep
kubectl get all | grep "nginx"

Create Resources

# Create a deployment imperatively
kubectl create deployment nginx-depl --image=nginx

# Create from YAML file
kubectl apply -f deployment.yaml

# Create multiple resources
kubectl apply -f .   # Apply all YAML files in current directory

Update Resources

# Edit a deployment (opens in default editor)
kubectl edit deployment nginx-depl

# Scale a deployment
kubectl scale deployment nginx-depl --replicas=3

Debugging Commands

# Get detailed information about a pod
kubectl describe pod <pod-name>

# Get logs from a pod
kubectl logs <pod-name>

# Follow logs in real-time
kubectl logs -f <pod-name>

# Get logs from a specific container in a pod
kubectl logs <pod-name> -c <container-name>

# Execute command in a pod
kubectl exec -it <pod-name> -- /bin/bash
kubectl exec -it <pod-name> -- /bin/sh  # if bash not available

# Get YAML definition of a resource
kubectl get deployment <depl-name> -o yaml

Delete Resources

# Delete a deployment
kubectl delete deployment <depl-name>

# Delete from file
kubectl delete -f deployment.yaml

# Delete all resources of a type
kubectl delete pods --all

Namespace Commands

# Get all namespaces
kubectl get namespace
kubectl get ns   # shorthand

# Get resources in a specific namespace
kubectl get pods -n <namespace-name>

# Get resources from all namespaces
kubectl get pods --all-namespaces
kubectl get pods -A   # shorthand

6. Configuration Files Deep Dive

Kubernetes uses YAML files (also called Kubernetes manifests) to define resources. These files are declarative - you specify the desired state, and Kubernetes makes it happen.

6.1 The Three Parts of Every Config File

Every Kubernetes YAML file has three main sections:

1. metadata

2. specification (spec)

3. status

How Status Works:

Desired State (spec): 2 replicas
Current State (status): 1 replica

Kubernetes sees mismatch → Creates new pod

6.2 Basic Deployment Example

Let’s create a simple nginx deployment:

apiVersion: apps/v1      # API version for Deployment
kind: Deployment         # Type of resource
metadata:
  name: nginx-depl       # Name of the deployment
  labels:
    app: nginx           # Labels for organization
spec:
  replicas: 1            # Number of pod replicas
  selector:
    matchLabels:
      app: nginx         # Which pods this deployment manages
  template:              # Pod template
    metadata:
      labels:
        app: nginx       # Labels for the pods
    spec:
      containers:
      - name: nginx      # Container name
        image: nginx:1.25  # Container image
        ports:
        - containerPort: 80  # Port the container listens on

Apply this configuration:

kubectl apply -f nginx-deployment.yaml

What happens:

  1. Deployment resource is created
  2. ReplicaSet is automatically created
  3. Pod(s) are created based on replica count

Check what was created:

kubectl get deployment
kubectl get replicaset
kubectl get pod

6.3 Understanding the Template

Notice the template section inside the Deployment spec? This is actually a Pod configuration nested inside the Deployment.

template:
  metadata:         # Pod's metadata
    labels:
      app: nginx
  spec:            # Pod's specification
    containers:
    - name: nginx
      image: nginx:1.25

This is why Deployment is called an abstraction over Pods. The Deployment contains the blueprint for creating Pods.

6.4 Service Configuration

Now let’s create a Service to expose our nginx deployment:

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx            # Matches pods with this label
  ports:
  - protocol: TCP
    port: 80              # Port the service exposes
    targetPort: 80        # Port on the pod

Multiple Resources in One File:

You can define multiple resources in one YAML file using --- as a separator:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-depl
# ... deployment spec ...
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
# ... service spec ...

Apply both:

kubectl apply -f nginx-config.yaml

6.5 Labels and Selectors

Labels and Selectors are how Kubernetes resources find and connect to each other.

Labels:

Selectors:

Example Connection:

# Deployment creates pods with label app: nginx
spec:
  template:
    metadata:
      labels:
        app: nginx

---
# Service finds those pods using selector
spec:
  selector:
    app: nginx    # "Find all pods with label app: nginx"

Verify the connection:

# Get the service and check its endpoints
kubectl describe service nginx-service

# Look for the "Endpoints" field - it should show pod IPs

# Get pod IPs to verify
kubectl get pod -o wide

6.6 Understanding Ports

Three types of ports can be confusing. Let’s clarify:

In Service:

In Deployment (Pod spec):

Visual Example:

External Request

[Service: port 80]

  Routes to

[Service: targetPort 8080]

  Forwards to

[Pod Container: containerPort 8080]

Example Configuration:

# Service
spec:
  ports:
  - port: 80          # Clients connect to service on port 80
    targetPort: 8080  # Service forwards to pod on port 8080

---
# Deployment
spec:
  template:
    spec:
      containers:
      - name: app
        ports:
        - containerPort: 8080  # Container listens on port 8080

6.7 Getting YAML Output

You can get the YAML definition of any resource:

# Get deployment YAML
kubectl get deployment nginx-depl -o yaml

# Get pod YAML
kubectl get pod <pod-name> -o yaml

# See the auto-generated status section
kubectl get deployment nginx-depl -o yaml | grep -A 5 "status:"

6.8 Best Practices for Configuration Files

  1. Store in version control (Git)
  2. Use meaningful names for resources
  3. Add labels for organization
  4. Pin image versions (avoid latest)
  5. Define resource limits (coming in deployment spec)
  6. Use separate files for different environments (dev, staging, prod)

7. Practical Example: MongoDB + Mongo Express

Let’s build a complete application stack to see how all components work together. We’ll deploy:

7.1 Architecture Overview

┌─────────────────────────────────────────────────────────┐
│                    Browser                              │
│              http://node-ip:30000                       │
└────────────────────┬────────────────────────────────────┘


        ┌────────────────────────┐
        │  Mongo Express Service │  (External/LoadBalancer)
        │   Type: LoadBalancer   │
        └────────┬───────────────┘


        ┌─────────────────┐
        │ Mongo Express   │
        │     Pod         │  ← Uses Secret for credentials
        └────────┬────────┘  ← Uses ConfigMap for DB URL


        ┌──────────────────┐
        │ MongoDB Service  │  (Internal/ClusterIP)
        └────────┬─────────┘


        ┌─────────────────┐
        │   MongoDB Pod   │  ← Uses Secret for root credentials
        └─────────────────┘

7.2 Step 1: Create Secret for MongoDB Credentials

Secrets must be created before the Deployments that use them.

# mongodb-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mongodb-secret
type: Opaque
data:
  mongo-root-username: dXNlcm5hbWU=  # base64 encoded "username"
  mongo-root-password: cGFzc3dvcmQ=  # base64 encoded "password"

How to encode values:

echo -n 'username' | base64  # dXNlcm5hbWU=
echo -n 'password' | base64  # cGFzc3dvcmQ=

Apply the secret:

kubectl apply -f mongodb-secret.yaml

7.3 Step 2: Create ConfigMap for MongoDB URL

# mongodb-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mongodb-configmap
data:
  database_url: mongodb-service:27017

Important: The database_url uses the Service name (mongodb-service) as the hostname. Kubernetes’ internal DNS resolves this to the service IP.

Apply the ConfigMap:

kubectl apply -f mongodb-configmap.yaml

7.4 Step 3: Deploy MongoDB with Internal Service

# mongodb.yaml
apiVersion: apps/v1 
kind: Deployment
metadata:
  name: mongodb-deployment
  labels:
    app: mongodb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongodb
  template: 
    metadata:
      labels:
        app: mongodb
    spec:
      containers:
      - name: mongodb
        image: mongo
        ports:
        - containerPort: 27017
        env:
        - name: MONGO_INITDB_ROOT_USERNAME
          valueFrom:
            secretKeyRef:
              name: mongodb-secret
              key: mongo-root-username
        - name: MONGO_INITDB_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mongodb-secret
              key: mongo-root-password
---
apiVersion: v1
kind: Service
metadata:
  name: mongodb-service
spec:
  selector:
    app: mongodb
  ports:
  - protocol: TCP
    port: 27017
    targetPort: 27017

Key Points:

Apply:

kubectl apply -f mongodb.yaml

Verify:

kubectl get pod
kubectl get service
kubectl describe service mongodb-service  # Check endpoints

7.5 Step 4: Deploy Mongo Express with External Service

# mongo-express.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongo-express
  labels:
    app: mongo-express
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongo-express
  template:
    metadata:
      labels:
        app: mongo-express
    spec: 
      containers:
      - name: mongo-express
        image: mongo-express
        ports:
        - containerPort: 8081
        env:
        - name: ME_CONFIG_MONGODB_ADMINUSERNAME
          valueFrom: 
            secretKeyRef:
              name: mongodb-secret
              key: mongo-root-username
        - name: ME_CONFIG_MONGODB_ADMINPASSWORD
          valueFrom:
            secretKeyRef:
              name: mongodb-secret
              key: mongo-root-password
        - name: DATABASE_URL
          valueFrom:
            configMapKeyRef:
              name: mongodb-configmap
              key: database_url
        - name: ME_CONFIG_MONGODB_URL
          value: "mongodb://$(ME_CONFIG_MONGODB_ADMINUSERNAME):$(ME_CONFIG_MONGODB_ADMINPASSWORD)@$(DATABASE_URL)"
---
apiVersion: v1
kind: Service
metadata:
  name: mongo-express-service
spec:
  selector:
    app: mongo-express
  type: LoadBalancer
  ports:
  - protocol: TCP
    port: 8081
    targetPort: 8081
    nodePort: 30000

Key Points:

Apply:

kubectl apply -f mongo-express.yaml

7.6 Access the Application

In Minikube:

minikube service mongo-express-service

This automatically opens the Mongo Express UI in your browser.

In a real cluster:

# Get the external IP
kubectl get service mongo-express-service

# Access via: http://<external-ip>:30000

7.7 Complete Request Flow

1. User → http://node-ip:30000
2. LoadBalancer Service (mongo-express-service)
3. Routes to Mongo Express Pod
4. Mongo Express needs to connect to MongoDB
5. Uses DATABASE_URL from ConfigMap: "mongodb-service:27017"
6. Kubernetes DNS resolves "mongodb-service" to ClusterIP
7. ClusterIP Service (mongodb-service)
8. Routes to MongoDB Pod
9. MongoDB authenticates using credentials from Secret
10. Data is returned back through the chain

7.8 Verify Everything Works

# Check all resources
kubectl get all

# Check secrets
kubectl get secret

# Check configmap
kubectl get configmap

# Check if services are properly connected
kubectl describe service mongodb-service
kubectl describe service mongo-express-service

# Check pod logs
kubectl logs <mongo-express-pod-name>
kubectl logs <mongodb-pod-name>

# Verify endpoints
kubectl get endpoints

7.9 Cleanup

kubectl delete -f mongo-express.yaml
kubectl delete -f mongodb.yaml
kubectl delete -f mongodb-configmap.yaml
kubectl delete -f mongodb-secret.yaml

8. Namespaces

8.1 What are Namespaces?

Namespaces provide a mechanism for isolating groups of resources within a single cluster. Think of them as virtual clusters inside a cluster.

Key Characteristics:

8.2 Default Namespaces

When you install Kubernetes, you get 4 default namespaces:

1. default

2. kube-system

3. kube-public

4. kube-node-lease

View namespaces:

kubectl get namespaces
kubectl get ns  # shorthand

8.3 Why Use Namespaces?

Use Case 1: Group Resources Logically

Instead of having everything in the default namespace, organize by function:

├── database namespace
│   ├── mongodb
│   ├── mysql
│   └── redis

├── monitoring namespace
│   ├── prometheus
│   ├── grafana
│   └── alertmanager

└── default namespace
    ├── nginx
    └── api-service

Use Case 2: Isolate Team Resources

Avoid conflicts when multiple teams use the same cluster:

├── team-alpha namespace
│   ├── alpha's deployments
│   └── alpha's services

└── team-beta namespace
    ├── beta's deployments
    └── beta's services

Both teams can have a deployment named api-service without conflicts!

Use Case 3: Share Resources Between Environments

Run multiple environments in the same cluster:

├── production namespace
│   └── production workloads

├── staging namespace
│   └── staging workloads

└── development namespace
    └── development workloads

Or implement Blue-Green deployments:

├── blue namespace (active)
│   └── version 1.0

└── green namespace (preparing)
    └── version 2.0

Use Case 4: Limit Permissions and Resources

# Resource limits per namespace
apiVersion: v1
kind: ResourceQuota
metadata:
  name: dev-quota
  namespace: development
spec:
  hard:
    requests.cpu: "10"
    requests.memory: 20Gi
    pods: "10"

You can also use RBAC to limit what users can do in each namespace.

8.4 Creating Namespaces

Using kubectl:

kubectl create namespace my-namespace

Using YAML:

# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: my-namespace
kubectl apply -f namespace.yaml

8.5 Using Namespaces

Specify namespace in kubectl:

# Get resources in a specific namespace
kubectl get pods -n my-namespace

# Get resources from all namespaces
kubectl get pods --all-namespaces
kubectl get pods -A  # shorthand

Specify namespace in YAML:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
  namespace: my-namespace  # Specify here
spec:
  containers:
  - name: nginx
    image: nginx

Apply to a namespace:

kubectl apply -f pod.yaml -n my-namespace

8.6 Changing Default Namespace

Instead of adding -n namespace every time, change your default context:

# Set default namespace for current context
kubectl config set-context --current --namespace=my-namespace

# Verify
kubectl config view --minify | grep namespace:

Better Tool: kubens

Install kubectx which includes kubens:

# Install on macOS
brew install kubectx

# List all namespaces
kubens

# Switch namespace
kubens my-namespace

# Switch back to previous namespace
kubens -

8.7 Namespaced vs Cluster-Wide Resources

Most resources are namespaced:

# List namespaced resources
kubectl api-resources --namespaced=true

# Examples:
- pods
- services
- deployments
- configmaps
- secrets

Some resources are cluster-wide:

# List cluster-wide resources
kubectl api-resources --namespaced=false

# Examples:
- nodes
- persistentvolumes
- clusterroles
- namespaces

Cluster-wide resources cannot be created within a namespace.

8.8 Accessing Resources Across Namespaces

Services can be accessed across namespaces:

# Service in "database" namespace
apiVersion: v1
kind: Service
metadata:
  name: mongodb-service
  namespace: database

Access from another namespace:

# Pod in "default" namespace
env:
- name: DATABASE_URL
  value: "mongodb-service.database:27017"
  #      <service-name>.<namespace>:<port>

Full DNS format:

<service-name>.<namespace>.svc.cluster.local:<port>

Most resources CANNOT be accessed across namespaces:

Each namespace needs its own copies of these.


9. Kubernetes Services In-Depth

9.1 Why Do We Need Services?

Recap of the problem:

Services provide:

9.2 How Services Work

Services use labels and selectors to find pods:

# Service
spec:
  selector:
    app: nginx  # "Find all pods with label app: nginx"
  
# Deployment creates pods with matching label
spec:
  template:
    metadata:
      labels:
        app: nginx  # This matches!

Service tracks pod endpoints:

kubectl get endpoints

# You'll see pod IPs listed as endpoints

9.3 Service Types

Kubernetes supports 4 types of services:

TypeDescriptionUse Case
ClusterIPInternal, only accessible within clusterDefault, databases, internal APIs
NodePortAccessible on each node’s IP at a static portDevelopment, testing
LoadBalancerExposes service via cloud provider’s load balancerProduction, external access
ExternalNameMaps service to external DNS nameExternal database, third-party API

9.4 ClusterIP Service (Default)

Most common type, used for internal communication.

apiVersion: v1
kind: Service
metadata:
  name: backend-service
spec:
  type: ClusterIP  # Default, can be omitted
  selector:
    app: backend
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

Characteristics:

Access within cluster:

# From another pod, you can access via:
http://backend-service:80
# or
http://backend-service.default.svc.cluster.local:80

Check ClusterIP:

kubectl get service backend-service

# Output:
# NAME              TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
# backend-service   ClusterIP   10.96.45.123   <none>        80/TCP    5m

Multi-Port Services

When you need to expose multiple ports:

apiVersion: v1
kind: Service
metadata:
  name: multi-port-service
spec:
  selector:
    app: my-app
  ports:
  - name: http      # Names are REQUIRED
    protocol: TCP
    port: 80
    targetPort: 8080
  - name: metrics   # for multi-port services
    protocol: TCP
    port: 9090
    targetPort: 9090

Important: Port names are mandatory for multi-port services to avoid ambiguity.

Headless Service

Sometimes you need to talk to a specific pod instead of load balancing:

Use Cases:

Create a headless service:

apiVersion: v1
kind: Service
metadata:
  name: mongodb-headless
spec:
  clusterIP: None  # This makes it headless!
  selector:
    app: mongodb
  ports:
  - protocol: TCP
    port: 27017
    targetPort: 27017

How it works:

Example with StatefulSet:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongodb
spec:
  serviceName: mongodb-headless  # Links to headless service
  replicas: 3
  # ...

Accessing individual pods:

# Pod names in StatefulSet are predictable:
mongodb-0.mongodb-headless.default.svc.cluster.local
mongodb-1.mongodb-headless.default.svc.cluster.local
mongodb-2.mongodb-headless.default.svc.cluster.local

9.5 NodePort Service

Makes a service accessible from outside the cluster by opening a port on all nodes.

apiVersion: v1
kind: Service
metadata:
  name: frontend-service
spec:
  type: NodePort
  selector:
    app: frontend
  ports:
  - protocol: TCP
    port: 80        # ClusterIP port
    targetPort: 8080
    nodePort: 30000  # Port on each node (30000-32767)

What happens:

  1. Kubernetes automatically creates a ClusterIP service
  2. Opens port 30000 on every node
  3. Routes traffic: NodeIP:30000ClusterIP:80Pod:8080

Access the service:

# Get node IP
kubectl get nodes -o wide

# Access via any node IP
curl http://<node-ip>:30000

In Minikube:

minikube service frontend-service

Visual Flow:

External Client

Node IP:30000 (NodePort)

ClusterIP Service :80

Pod :8080

Port Ranges:

Why Not Use in Production?

9.6 LoadBalancer Service

Best option for production when running on a cloud provider.

apiVersion: v1
kind: Service
metadata:
  name: app-service
spec:
  type: LoadBalancer
  selector:
    app: my-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

What happens:

  1. Kubernetes automatically creates NodePort service
  2. Kubernetes automatically creates ClusterIP service
  3. Cloud provider provisions a real load balancer
  4. Load balancer gets a public IP address

Request Flow:

External Client

Cloud Load Balancer (Public IP)

Node IP:NodePort (random)

ClusterIP Service :80

Pods :8080 (Load balanced)

Check external IP:

kubectl get service app-service

# Output:
# NAME          TYPE           CLUSTER-IP    EXTERNAL-IP      PORT(S)        AGE
# app-service   LoadBalancer   10.96.45.12   35.123.45.67     80:31234/TCP   5m
#                                            ↑ Public IP     ↑ NodePort

Cloud Provider Support:

Advantages:



Next: Part 2 →


Edit page
Share this post on:

Previous Post
Kubernetes Guide Part 2: Advanced Networking, Storage, & Config
Next Post
AWS DevOps: Jenkins CI/CD and AWS CLI (Part 2)