Overview #
In this tutorial I’m using the following K3s cluster with 3 worker nodes:
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
ubuntu1 Ready control-plane,master 10d v1.30.5+k3s1 192.168.30.10 <none> Ubuntu 24.04.1 LTS 6.8.0-45-generic containerd://1.7.21-k3s2
ubuntu2 Ready worker 10d v1.30.5+k3s1 192.168.30.11 <none> Ubuntu 24.04.1 LTS 6.8.0-45-generic containerd://1.7.21-k3s2
ubuntu3 Ready worker 10d v1.30.5+k3s1 192.168.30.12 <none> Ubuntu 24.04.1 LTS 6.8.0-45-generic containerd://1.7.21-k3s2
ubuntu4 Ready worker 10d v1.30.5+k3s1 192.168.30.13 <none> Ubuntu 24.04.1 LTS 6.8.0-45-generic containerd://1.7.21-k3s2
Prerequisites #
Create Namespace #
# Create a "example-deployment" namespace for the example deployment
kubectl create ns example-deployment
ReplicaSets #
ReplicaSet Overview #
-
Ensures a specified number of pod replicas are running at all times. The placement of those pods across nodes is handled by Kubernetes.
-
Pods are scheduled regarding available resources on the Kubernetes nodes. It does not matter if the pods are distributed on all nodes. Only that the right number of pods running across the cluster counts.
-
Failed pods are terminated and it will start another pod to maintain the defined number of running pods.
Note: The “restartPolicy” in a pod only affects how the individual containers in the pod behave when they exit or fail, not the behavior of the ReplicaSet itself.
Example ReplicaSet (Without Node Selection) #
Example Deployment #
# Create a manifest for the deployment
vi example-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-deployment
namespace: example-deployment
labels:
app: some-pod
spec:
replicas: 3
selector:
matchLabels:
app: some-pod
template:
metadata:
labels:
app: some-pod
spec:
containers:
- name: busybox
image: busybox:latest
command: ['sh', '-c', 'tail -f /dev/null']
imagePullPolicy: IfNotPresent
restartPolicy: Always
# Apply the manifest
kubectl apply -f example-deployment.yaml
Verify Deployment #
Verify the ReplicaSet:
# List the ReplicaSets in the "example-deployment" namespace
kubectl get replicaset -n example-deployment
# Shell output:
NAME DESIRED CURRENT READY AGE
example-deployment-7fcf97b89d 3 3 3 7s
Verify the Pods:
# List pods in the "example-deployment" namespace
kubectl get pods -o wide -n example-deployment
# Shell output:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
example-deployment-7fcf97b89d-bph8k 1/1 Running 0 77s 10.42.3.30 ubuntu4 <none> <none>
example-deployment-7fcf97b89d-fsl72 1/1 Running 0 77s 10.42.2.29 ubuntu3 <none> <none>
example-deployment-7fcf97b89d-t978k 1/1 Running 0 77s 10.42.1.28 ubuntu2 <none> <none>
Verify all Resources:
# List resources in the "example-deployment" namespace
kubectl get all -n example-deployment
# Shell output:
NAME READY STATUS RESTARTS AGE
pod/example-deployment-7fcf97b89d-bph8k 1/1 Running 0 2m3s
pod/example-deployment-7fcf97b89d-fsl72 1/1 Running 0 2m3s
pod/example-deployment-7fcf97b89d-t978k 1/1 Running 0 2m3s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/example-deployment 3/3 3 3 2m3s
NAME DESIRED CURRENT READY AGE
replicaset.apps/example-deployment-7fcf97b89d 3 3 3 2m3s
Delete the Deployment #
# Delete the deployment
kubectl delete deployment example-deployment -n example-deployment
Example ReplicaSet (With Node Selection) #
Label Kubernetes Nodes #
# List Kubernetes nodes
kubectl get nodes -o wide
# Shell output:
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
ubuntu1 Ready control-plane,master 10d v1.30.5+k3s1 192.168.30.10 <none> Ubuntu 24.04.1 LTS 6.8.0-45-generic containerd://1.7.21-k3s2
ubuntu2 Ready worker 10d v1.30.5+k3s1 192.168.30.11 <none> Ubuntu 24.04.1 LTS 6.8.0-45-generic containerd://1.7.21-k3s2
ubuntu3 Ready worker 10d v1.30.5+k3s1 192.168.30.12 <none> Ubuntu 24.04.1 LTS 6.8.0-45-generic containerd://1.7.21-k3s2
ubuntu4 Ready worker 10d v1.30.5+k3s1 192.168.30.13 <none> Ubuntu 24.04.1 LTS 6.8.0-45-generic containerd://1.7.21-k3s2
# Label one or more of the Kubernetes nodes
kubectl label node ubuntu2 project=app-no-1
Verify Node Labels #
# List "monitoring-enabled" label
kubectl get nodes -o custom-columns=NAME:.metadata.name,project:.metadata.labels.project
# Shell output:
NAME project
ubuntu1 <none>
ubuntu2 app-no-1
ubuntu3 <none>
ubuntu4 <none
Example Deployment #
# Create a manifest for the deployment
vi example-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-deployment
namespace: example-deployment
labels:
app: some-pod
spec:
replicas: 4
selector:
matchLabels:
app: some-pod
template:
metadata:
labels:
app: some-pod
spec:
nodeSelector:
project: "app-no-1"
containers:
- name: busybox
image: busybox:latest
command: ['sh', '-c', 'tail -f /dev/null']
imagePullPolicy: IfNotPresent
restartPolicy: Always
# Apply the manifest
kubectl apply -f example-deployment.yaml
Verify Deployment #
# List pods in "example-deployment" namespace
kubectl get pods -o wide -n example-deployment
# Shell output:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
example-deployment-f98f569bc-hdxvd 1/1 Running 0 20s 10.42.1.7 ubuntu2 <none> <none>
example-deployment-f98f569bc-ktms9 1/1 Running 0 20s 10.42.1.4 ubuntu2 <none> <none>
example-deployment-f98f569bc-kv4x5 1/1 Running 0 20s 10.42.1.6 ubuntu2 <none> <none>
example-deployment-f98f569bc-vb65n 1/1 Running 0 20s 10.42.1.5 ubuntu2 <none> <none>
Delete the Deployment #
# Delete the deployment
kubectl delete deployment example-deployment -n example-deployment
DaemonSets #
DaemonSet Overview #
-
Ensures that a copy of a pod runs on every Kubernetes node.
-
New Kubernetes nodes that join the cluster will automatically start pods that are part of a DaemonSet.
-
Kubernetes will deschedule pods of a DaemonSet when nodes are deprovisioned.
-
DaemonSets are designed to run a Pod on every Node, also in situations that would normally be prevented. DaemonSet pods will still be scheduled even if a target Node is facing resource constraints or isn’t accepting new Pods.
-
DaemonSets are often used for node monitoring and log collection agents.
Example DaemonSet (All Nodes) #
Example Deployment #
# Create a manifest for the deployment
vi example-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: example-daemonset
namespace: example-deployment
spec:
selector:
matchLabels:
app: some-pod
template:
metadata:
labels:
app: some-pod
spec:
containers:
- name: busybox
image: busybox:latest
command: ['sh', '-c', 'tail -f /dev/null']
imagePullPolicy: IfNotPresent
restartPolicy: Always
# Apply the manifest
kubectl apply -f example-daemonset.yaml
Verify Deployment #
Verify the ReplicaSet:
# List the DaemonSet in the "example-deployment" namespace
kubectl get daemonset -n example-deployment
# Shell output:
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
example-daemonset 4 4 4 4 4 <none> 2m21s
Verify the Pods:
# List pods in the "example-deployment" namespace
kubectl get pods -o wide -n example-deployment
# Shell output:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
example-daemonset-4zhgx 1/1 Running 0 2m31s 10.42.3.31 ubuntu4 <none> <none>
example-daemonset-lsqrr 1/1 Running 0 2m31s 10.42.0.30 ubuntu1 <none> <none>
example-daemonset-lwzdv 1/1 Running 0 2m31s 10.42.2.30 ubuntu3 <none> <none>
example-daemonset-tk26c 1/1 Running 0 2m31s 10.42.1.29 ubuntu2 <none> <none>
Verify all Resources:
# List resources in the "example-deployment" namespace
kubectl get all -n example-deployment
# Shell output:
NAME READY STATUS RESTARTS AGE
pod/example-daemonset-4zhgx 1/1 Running 0 2m45s
pod/example-daemonset-lsqrr 1/1 Running 0 2m45s
pod/example-daemonset-lwzdv 1/1 Running 0 2m45s
pod/example-daemonset-tk26c 1/1 Running 0 2m45s
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/example-daemonset 4 4 4 4 4 <none> 2m45s
Delete DaemonSet #
# Delete the DaemonSet
kubectl delete daemonset example-daemonset -n example-deployment
Example DaemonSet (With Node Selection) #
Label Kubernetes Nodes #
List the Kubernetes nodes:
# List nodes
kubectl get nodes -o wide
# Shell output:
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
ubuntu1 Ready control-plane,master 10d v1.30.5+k3s1 192.168.30.10 <none> Ubuntu 24.04.1 LTS 6.8.0-45-generic containerd://1.7.21-k3s2
ubuntu2 Ready worker 10d v1.30.5+k3s1 192.168.30.11 <none> Ubuntu 24.04.1 LTS 6.8.0-45-generic containerd://1.7.21-k3s2
ubuntu3 Ready worker 10d v1.30.5+k3s1 192.168.30.12 <none> Ubuntu 24.04.1 LTS 6.8.0-45-generic containerd://1.7.21-k3s2
ubuntu4 Ready worker 10d v1.30.5+k3s1 192.168.30.13 <none> Ubuntu 24.04.1 LTS 6.8.0-45-generic containerd://1.7.21-k3s2
Label Kubernetes nodes:
# Label some of the Kubernetes nodes
kubectl label node ubuntu2 monitoring-enabled=true
kubectl label node ubuntu3 monitoring-enabled=true
Verify Node Labels: #
# List "monitoring-enabled" label
kubectl get nodes -o custom-columns=NAME:.metadata.name,MONITORING-ENABLED:.metadata.labels.monitoring-enabled
# Shell output:
NAME MONITORING-ENABLED
ubuntu1 <none>
ubuntu2 true
ubuntu3 true
ubuntu4 <none>
Example Deployment #
# Create a manifest for the deployment
vi example-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: example-daemonset
namespace: example-deployment
spec:
selector:
matchLabels:
app: some-pod
template:
metadata:
labels:
app: some-pod
spec:
nodeSelector:
monitoring-enabled: "true"
containers:
- name: busybox
image: busybox:latest
command: ['sh', '-c', 'tail -f /dev/null']
imagePullPolicy: IfNotPresent
restartPolicy: Always
# Apply the manifest
kubectl apply -f example-daemonset.yaml
Verify Deployment #
Verify the ReplicaSet:
# List the DaemonSet in the "example-deployment" namespace
kubectl get daemonset -n example-deployment
# Shell output:
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
example-daemonset 2 2 2 2 2 monitoring-enabled=true 6s
Verify the Pods:
# List pods in the "example-deployment" namespace
kubectl get pods -o wide -n example-deployment
# Shell output:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
example-daemonset-526v9 1/1 Running 0 18s 10.42.1.30 ubuntu2 <none> <none>
example-daemonset-mt5q6 1/1 Running 0 18s 10.42.2.31 ubuntu3 <none> <none>
Verify all Resources:
# List resources in the "example-deployment" namespace
kubectl get all -n example-deployment
# Shell output:
NAME READY STATUS RESTARTS AGE
pod/example-daemonset-526v9 1/1 Running 0 37s
pod/example-daemonset-mt5q6 1/1 Running 0 37s
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/example-daemonset 2 2 2 2 2 monitoring-enabled=true 37s
Delete DaemonSet #
# Delete the DaemonSet
kubectl delete daemonset example-daemonset -n example-deployment