$ -weight: 500;">brew -weight: 500;">install minikube
-weight: 500;">brew -weight: 500;">install minikube
-weight: 500;">brew -weight: 500;">install minikube
-weight: 500;">curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
-weight: 600;">sudo -weight: 500;">install minikube-linux-amd64 /usr/local/bin/minikube
-weight: 500;">curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
-weight: 600;">sudo -weight: 500;">install minikube-linux-amd64 /usr/local/bin/minikube
-weight: 500;">curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
-weight: 600;">sudo -weight: 500;">install minikube-linux-amd64 /usr/local/bin/minikube
winget -weight: 500;">install Kubernetes.minikube
winget -weight: 500;">install Kubernetes.minikube
winget -weight: 500;">install Kubernetes.minikube
minikube -weight: 500;">start
minikube -weight: 500;">start
minikube -weight: 500;">start
-weight: 500;">kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# minikube Ready control-plane 10s v1.x.x
-weight: 500;">kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# minikube Ready control-plane 10s v1.x.x
-weight: 500;">kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# minikube Ready control-plane 10s v1.x.x
-weight: 500;">brew -weight: 500;">install kind
-weight: 500;">brew -weight: 500;">install kind
-weight: 500;">brew -weight: 500;">install kind
-weight: 500;">curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.22.0/kind-linux-amd64
chmod +x ./kind
-weight: 600;">sudo mv ./kind /usr/local/bin/kind
-weight: 500;">curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.22.0/kind-linux-amd64
chmod +x ./kind
-weight: 600;">sudo mv ./kind /usr/local/bin/kind
-weight: 500;">curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.22.0/kind-linux-amd64
chmod +x ./kind
-weight: 600;">sudo mv ./kind /usr/local/bin/kind
choco -weight: 500;">install kind
choco -weight: 500;">install kind
choco -weight: 500;">install kind
kind create cluster --name hello-cluster
kind create cluster --name hello-cluster
kind create cluster --name hello-cluster
-weight: 500;">kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# hello-cluster-control-plane Ready control-plane 10s v1.x.x
-weight: 500;">kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# hello-cluster-control-plane Ready control-plane 10s v1.x.x
-weight: 500;">kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# hello-cluster-control-plane Ready control-plane 10s v1.x.x
mkdir k8s-hello && cd k8s-hello
mkdir k8s-hello && cd k8s-hello
mkdir k8s-hello && cd k8s-hello
const http = require('http');
const os = require('os'); const server = http.createServer((req, res) => { res.end(`Hello from Pod: ${os.hostname()}\n`);
}); server.listen(3000, () => console.log('Running on port 3000'));
const http = require('http');
const os = require('os'); const server = http.createServer((req, res) => { res.end(`Hello from Pod: ${os.hostname()}\n`);
}); server.listen(3000, () => console.log('Running on port 3000'));
const http = require('http');
const os = require('os'); const server = http.createServer((req, res) => { res.end(`Hello from Pod: ${os.hostname()}\n`);
}); server.listen(3000, () => console.log('Running on port 3000'));
FROM node:18-alpine
WORKDIR /app
COPY app.js .
CMD ["node", "app.js"]
FROM node:18-alpine
WORKDIR /app
COPY app.js .
CMD ["node", "app.js"]
FROM node:18-alpine
WORKDIR /app
COPY app.js .
CMD ["node", "app.js"]
eval $(minikube -weight: 500;">docker-env)
-weight: 500;">docker build -t hello-app:v1 .
eval $(minikube -weight: 500;">docker-env)
-weight: 500;">docker build -t hello-app:v1 .
eval $(minikube -weight: 500;">docker-env)
-weight: 500;">docker build -t hello-app:v1 .
-weight: 500;">docker build -t hello-app:v1 .
kind load -weight: 500;">docker-image hello-app:v1 --name hello-cluster
-weight: 500;">docker build -t hello-app:v1 .
kind load -weight: 500;">docker-image hello-app:v1 --name hello-cluster
-weight: 500;">docker build -t hello-app:v1 .
kind load -weight: 500;">docker-image hello-app:v1 --name hello-cluster
apiVersion: apps/v1
kind: Deployment
metadata: name: hello-deployment
spec: replicas: 3 selector: matchLabels: app: hello template: metadata: labels: app: hello spec: containers: - name: hello image: hello-app:v1 imagePullPolicy: Never # use local image, don't pull from Docker Hub ports: - containerPort: 3000
---
apiVersion: v1
kind: Service
metadata: name: hello--weight: 500;">service
spec: type: NodePort selector: app: hello # matches the Pod label above this is how Services find Pods ports: - port: 80 targetPort: 3000 nodePort: 30080
apiVersion: apps/v1
kind: Deployment
metadata: name: hello-deployment
spec: replicas: 3 selector: matchLabels: app: hello template: metadata: labels: app: hello spec: containers: - name: hello image: hello-app:v1 imagePullPolicy: Never # use local image, don't pull from Docker Hub ports: - containerPort: 3000
---
apiVersion: v1
kind: Service
metadata: name: hello--weight: 500;">service
spec: type: NodePort selector: app: hello # matches the Pod label above this is how Services find Pods ports: - port: 80 targetPort: 3000 nodePort: 30080
apiVersion: apps/v1
kind: Deployment
metadata: name: hello-deployment
spec: replicas: 3 selector: matchLabels: app: hello template: metadata: labels: app: hello spec: containers: - name: hello image: hello-app:v1 imagePullPolicy: Never # use local image, don't pull from Docker Hub ports: - containerPort: 3000
---
apiVersion: v1
kind: Service
metadata: name: hello--weight: 500;">service
spec: type: NodePort selector: app: hello # matches the Pod label above this is how Services find Pods ports: - port: 80 targetPort: 3000 nodePort: 30080
-weight: 500;">kubectl apply -f deployment.yaml
-weight: 500;">kubectl apply -f deployment.yaml
-weight: 500;">kubectl apply -f deployment.yaml
deployment.apps/hello-deployment created
-weight: 500;">service/hello--weight: 500;">service created
deployment.apps/hello-deployment created
-weight: 500;">service/hello--weight: 500;">service created
deployment.apps/hello-deployment created
-weight: 500;">service/hello--weight: 500;">service created
-weight: 500;">kubectl get pods
-weight: 500;">kubectl get pods
-weight: 500;">kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-deployment-57c4d87bf-abc12 1/1 Running 0 15s
hello-deployment-57c4d87bf-def34 1/1 Running 0 15s
hello-deployment-57c4d87bf-ghi56 1/1 Running 0 15s
NAME READY STATUS RESTARTS AGE
hello-deployment-57c4d87bf-abc12 1/1 Running 0 15s
hello-deployment-57c4d87bf-def34 1/1 Running 0 15s
hello-deployment-57c4d87bf-ghi56 1/1 Running 0 15s
NAME READY STATUS RESTARTS AGE
hello-deployment-57c4d87bf-abc12 1/1 Running 0 15s
hello-deployment-57c4d87bf-def34 1/1 Running 0 15s
hello-deployment-57c4d87bf-ghi56 1/1 Running 0 15s
-weight: 500;">kubectl get replicaset
-weight: 500;">kubectl get -weight: 500;">service hello--weight: 500;">service
-weight: 500;">kubectl get replicaset
-weight: 500;">kubectl get -weight: 500;">service hello--weight: 500;">service
-weight: 500;">kubectl get replicaset
-weight: 500;">kubectl get -weight: 500;">service hello--weight: 500;">service
minikube -weight: 500;">service hello--weight: 500;">service
minikube -weight: 500;">service hello--weight: 500;">service
minikube -weight: 500;">service hello--weight: 500;">service
-weight: 500;">kubectl port-forward -weight: 500;">service/hello--weight: 500;">service 8080:80
-weight: 500;">kubectl port-forward -weight: 500;">service/hello--weight: 500;">service 8080:80
-weight: 500;">kubectl port-forward -weight: 500;">service/hello--weight: 500;">service 8080:80
Hello from Pod: hello-deployment-57c4d87bf-abc12
Hello from Pod: hello-deployment-57c4d87bf-ghi56
Hello from Pod: hello-deployment-57c4d87bf-def34
Hello from Pod: hello-deployment-57c4d87bf-abc12
Hello from Pod: hello-deployment-57c4d87bf-ghi56
Hello from Pod: hello-deployment-57c4d87bf-def34
Hello from Pod: hello-deployment-57c4d87bf-abc12
Hello from Pod: hello-deployment-57c4d87bf-ghi56
Hello from Pod: hello-deployment-57c4d87bf-def34
# grab any pod name
-weight: 500;">kubectl get pods # delete it
-weight: 500;">kubectl delete pod hello-deployment-57c4d87bf-abc12 # watch what happens
-weight: 500;">kubectl get pods -w
# grab any pod name
-weight: 500;">kubectl get pods # delete it
-weight: 500;">kubectl delete pod hello-deployment-57c4d87bf-abc12 # watch what happens
-weight: 500;">kubectl get pods -w
# grab any pod name
-weight: 500;">kubectl get pods # delete it
-weight: 500;">kubectl delete pod hello-deployment-57c4d87bf-abc12 # watch what happens
-weight: 500;">kubectl get pods -w
-weight: 500;">kubectl scale deployment hello-deployment --replicas=5
-weight: 500;">kubectl get pods
-weight: 500;">kubectl scale deployment hello-deployment --replicas=5
-weight: 500;">kubectl get pods
-weight: 500;">kubectl scale deployment hello-deployment --replicas=5
-weight: 500;">kubectl get pods
-weight: 500;">kubectl scale deployment hello-deployment --replicas=1
-weight: 500;">kubectl get pods
-weight: 500;">kubectl scale deployment hello-deployment --replicas=1
-weight: 500;">kubectl get pods
-weight: 500;">kubectl scale deployment hello-deployment --replicas=1
-weight: 500;">kubectl get pods
res.end(`Hello from Pod v2: ${os.hostname()}\n`);
res.end(`Hello from Pod v2: ${os.hostname()}\n`);
res.end(`Hello from Pod v2: ${os.hostname()}\n`);
# Minikube
eval $(minikube -weight: 500;">docker-env)
-weight: 500;">docker build -t hello-app:v2 . # Kind
-weight: 500;">docker build -t hello-app:v2 .
kind load -weight: 500;">docker-image hello-app:v2 --name hello-cluster
# Minikube
eval $(minikube -weight: 500;">docker-env)
-weight: 500;">docker build -t hello-app:v2 . # Kind
-weight: 500;">docker build -t hello-app:v2 .
kind load -weight: 500;">docker-image hello-app:v2 --name hello-cluster
# Minikube
eval $(minikube -weight: 500;">docker-env)
-weight: 500;">docker build -t hello-app:v2 . # Kind
-weight: 500;">docker build -t hello-app:v2 .
kind load -weight: 500;">docker-image hello-app:v2 --name hello-cluster
-weight: 500;">kubectl set image deployment/hello-deployment hello=hello-app:v2
-weight: 500;">kubectl set image deployment/hello-deployment hello=hello-app:v2
-weight: 500;">kubectl set image deployment/hello-deployment hello=hello-app:v2
-weight: 500;">kubectl rollout -weight: 500;">status deployment/hello-deployment
-weight: 500;">kubectl rollout -weight: 500;">status deployment/hello-deployment
-weight: 500;">kubectl rollout -weight: 500;">status deployment/hello-deployment
-weight: 500;">kubectl describe pod <pod-name>
-weight: 500;">kubectl describe pod <pod-name>
-weight: 500;">kubectl describe pod <pod-name>
-weight: 500;">kubectl rollout undo deployment/hello-deployment
-weight: 500;">kubectl rollout undo deployment/hello-deployment
-weight: 500;">kubectl rollout undo deployment/hello-deployment
-weight: 500;">kubectl delete -f deployment.yaml
-weight: 500;">kubectl delete -f deployment.yaml
-weight: 500;">kubectl delete -f deployment.yaml
minikube -weight: 500;">stop
minikube -weight: 500;">stop
minikube -weight: 500;">stop
kind delete cluster --name hello-cluster
kind delete cluster --name hello-cluster
kind delete cluster --name hello-cluster
Your Browser ↓ [Service] ← watched for Pods with label app: hello ↓ [ReplicaSet] ← enforced 3 running replicas at all times ↓ ↓ ↓
[Pod] [Pod] [Pod] ← each ran your Node.js container
Your Browser ↓ [Service] ← watched for Pods with label app: hello ↓ [ReplicaSet] ← enforced 3 running replicas at all times ↓ ↓ ↓
[Pod] [Pod] [Pod] ← each ran your Node.js container
Your Browser ↓ [Service] ← watched for Pods with label app: hello ↓ [ReplicaSet] ← enforced 3 running replicas at all times ↓ ↓ ↓
[Pod] [Pod] [Pod] ← each ran your Node.js container - A containerised Node.js app running in Kubernetes
- 3 replicas managed by a Deployment and ReplicaSet
- A Service exposing the app to your browser
- Hands-on experience with self-healing and scaling - Docker required by both Minikube and Kind
- -weight: 500;">kubectl the Kubernetes CLI
- Either Minikube or Kind (installation covered below) - Minikube: slightly friendlier for beginners, has a built-in way to open services in the browser
- Kind: lighter, faster, great if you already have Docker set up - The Deployment tells Kubernetes to keep 3 replicas of our Pod running at all times
- It automatically creates a ReplicaSet to enforce that replica count
- The Service uses the app: hello label selector to find all matching Pods and route traffic to them
- imagePullPolicy: Never tells Kubernetes to use the locally available image instead of going to Docker Hub - Namespaces isolate workloads for different teams or environments
- ConfigMaps & Secrets externalise config and credentials from your container
- Ingress a cleaner alternative to NodePort for routing external traffic
- Persistent Volumes attach storage that survives Pod restarts
- Liveness & Readiness Probes teach Kubernetes when your Pod is actually healthy