Kubernetes

Reminders

  • HW2 due next week Feb 25
    • Contact me if you need a Brave API key
  • AWS invites have been sent out, look for an email with the subject "AWS @ Penn access"
  • Drop deadline is Feb 23

Agenda

  1. Motivation for Kubernetes
  2. Kubernetes Concepts
  3. Managing Kubernetes with Manifests
  4. Helm

Motivation for Kubernetes

Docker Compose Recap

  • We've been using Docker Compose to run multiple containers locally
  • Define services in compose.yaml
  • Easy to run: docker compose up
  • Works great for local development!

Limitations of Docker Compose

Docker-compose is not suitable for production.

  • Single machine: All containers run on one host
  • No auto-recovery: If a container crashes, it stays down (unless configured)
  • No load balancing: Can't distribute traffic across multiple instances
  • No auto-scaling: Can't add more containers based on load
  • Limited networking: Simple bridge networks, no advanced routing

What if we want to...

  • Run containers across multiple machines?
  • Automatically restart failed containers?
  • Scale services up/down based on traffic?
  • Rolling updates without downtime?
  • Manage complex networking between services?
  • Handle secrets and configuration separately?

We need an orchestrator

Enter: Kubernetes

  • Kubernetes (K8s): Container orchestration platform
  • Originally developed by Google, now open source
  • Manages containerized applications across a cluster of machines
  • Provides:
    • Automatic scaling and load balancing
    • Self-healing (restarts failed containers)
    • Rolling updates and rollbacks
    • Service discovery and networking

k8s logo

Kubernetes Concepts

Kubernetes Architecture

  • Cluster: A set of machines running Kubernetes
  • Control Plane: Manages the cluster (scheduling, monitoring, etc.)
  • Nodes: Worker machines that run your containers

Kubernetes arch

Basic Building Blocks

Kubernetes introduces a some new concepts. The hierarchy from smallest to largest:

  1. Container: The Docker container (what we already know)
  2. Pod: One or more containers that share resources
  3. Node: A physical or virtual machine running pods
  4. Cluster: Multiple nodes managed together

Containers

  • The same Docker containers we've been using, nothing new here
  • Kubernetes doesn't replace Docker, it orchestrates it
  • Each container runs a single process

Pods

  • Pod: The smallest deployable unit in Kubernetes
  • Contains one or more containers that should run together
  • Containers in a pod:
    • Share the same network namespace (can talk via localhost)
    • Share storage volumes
    • Are always scheduled on the same node
    • Effectively running multiple docker containers on one machine

Why Pods?

Single Container Pod

  • Most pods have one container
  • The container is your application

Multi-Container Pod

  • Main application container
  • "Sidecar" containers that support it
    • Log collector
    • Proxy
    • Monitoring agent

Nodes

  • Node: A worker machine in the cluster
  • Can be physical or virtual
  • Each node runs:
    • kubelet: Agent that manages pods on the node
    • Container runtime: Docker or other container engine
    • kube-proxy: Handles networking
  • One node can run many pods

Nodes

k8s node

K8s: Managing Resources

  • We typically want to orchestrate how nodes/pods are deployed or managed
  • Kubernetes provides abstractions for workload management, networking, and configuration
    • Deployments are ways to define a group of pods and their lifecycle
    • Services provide stable endpoints for a group of pods
    • ConfigMaps decouple configuration from containers
    • Many more...

Deployments

  • Deployment: Manages a set of identical pods
  • You specify:
    • Which container image to run
    • How many replicas (copies) you want
    • Resource limits (CPU, memory)
  • Kubernetes ensures the desired state is maintained
    • If a pod dies, Deployment creates a new one
    • If you update the image, Deployment performs a rolling update

Deployments: Example

replicas: 3
image: myapp:v1.0
  • Kubernetes will ensure 3 pods are always running
  • If one crashes, a new one is created automatically
  • If you change to myapp:v2.0, Kubernetes rolls out the update

Services

  • Problem: Pods are ephemeral and have no stable endpoint/IP
  • Solution: A Service provides a stable endpoint for a set of pods
  • Services handle load balancing across pods
  • Other pods/services use the Service name for discovery
  • This is similar to how docker-compose provided a named endpoint

Other Kubernetes Resources

  • ConfigMap: Store configuration data (environment variables, config files)
  • Secret: Store sensitive data (passwords, API keys)
  • Volume: Persistent storage that survives pod restarts
  • Namespace: Virtual cluster for organizing resources
  • Ingress: Manage external HTTP(S) access to services

We'll explore these as needed

Managing with Manifests

yaml meme

Declarative Configuration

  • In Docker Compose, we declared what we wanted in YAML
  • Kubernetes works the same way!
  • We write YAML files called manifests that describe our desired state
  • We apply these manifests to the cluster
  • Kubernetes makes the actual state match the desired state
  • These manifests can typically get very large, though...

manifest

Anatomy of a Manifest

Every Kubernetes manifest has:

apiVersion: v1              # Which K8s API version
kind: Pod                   # What type of resource
metadata:                   # Info about the resource
  name: my-pod
  labels:
    app: myapp
spec:                       # The desired state
  # Details depend on the resource type

Example: Pod Manifest

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
  - name: nginx
    image: nginx:1.21
    ports:
    - containerPort: 80

Example: Deployment Manifest

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.21

Example: Service Manifest

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

Applying Manifests

Kubernetes is managed through the command line tool kubectl

# Apply a single manifest
kubectl apply -f deployment.yaml

# Apply all manifests in a directory
kubectl apply -f ./manifests/

# View resources
kubectl get pods
kubectl get deployments
kubectl get services

Minikube

How do we test manifests?

  • Minikube: Tool for running Kubernetes locally
  • Creates a single-node cluster on your machine
  • Perfect for learning and development
  • Works similar to production Kubernetes
minikube start    # Start local cluster
minikube stop     # Stop cluster
minikube delete   # Delete cluster

The Problem with Manifests

  • For a real application, you might have:
    • Many deployments
    • Many services
    • Multiple ConfigMaps and Secrets
    • Different configurations for dev/staging/prod
  • Managing potentially hundreds of YAML files gets messy
  • How do we handle environment-specific values while staying DRY?

Helm

What is Helm?

  • Helm: Package manager for Kubernetes
  • Think npm or apt, but for Kubernetes applications
  • Bundles related manifests into a Chart
  • Provides templating for environment-specific configuration
  • The real power comes from being able to define custom templates

Helm Charts

  • A Chart is a collection of Kubernetes manifests
  • Think of a chart as a template
  • Organized in a specific directory structure:
mychart/
  Chart.yaml          # Metadata about the chart
  values.yaml         # Default configuration values
  templates/          # Kubernetes manifest templates
    deployment.yaml
    service.yaml
    configmap.yaml

Templating with Helm

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Values.appName }}
spec:
  replicas: {{ .Values.replicaCount }}
  template:
    spec:
      containers:
      - name: app
        image: {{ .Values.image.repository }}:{{ .Values.image.tag }}

Values come from a provided values.yaml (can be named differently)

values.yaml

appName: myapp
replicaCount: 3
image:
  repository: myapp
  tag: v1.0.0
resources:
  limits:
    memory: "256Mi"
    cpu: "500m"

Values can be structured however you want!

Environment-Specific Configuration

We can create clean separations per environment using values!

values-dev.yaml

replicaCount: 1
image:
  tag: latest
resources:
  limits:
    memory: "128Mi"

values-prod.yaml

replicaCount: 5
image:
  tag: v1.0.0
resources:
  limits:
    memory: "512Mi"
helm install myapp ./mychart -f values-dev.yaml
helm install myapp ./mychart -f values-prod.yaml

Benefits of Helm

  • Package multiple resources: One chart = complete application
  • Templating: Reuse manifests across environments
  • Versioning: Track chart versions, easy rollbacks
  • Sharing: Publish charts to repositories for others to use
  • Dependency management: Charts can depend on other charts

Helm Commands

# Install a chart
helm install myapp ./mychart

# Upgrade an installation
helm upgrade myapp ./mychart

# List installations
helm list

# Rollback to previous version
helm rollback myapp

# Uninstall
helm uninstall myapp

Summary

  • Kubernetes provides powerful abstractions for container orchestration
    • Pods, Deployments, Services abstract away infrastructure complexity
    • Manifests let us declare desired state
  • Helm helps manage complexity with templating
  • In the future: how do we integrate Kubernetes with cloud providers

Lab: Minikube & Helm

Note: Add icon/diagram of a container

Note: Add diagram showing a pod with 2-3 containers inside

Note: Add diagram showing node with multiple pods inside

Note: Add diagram showing deployment with 3 pod replicas

Note: Add diagram showing service routing to multiple pods