From 24cb687c30fd55d3a0389ca78d25e7e691ca35e0 Mon Sep 17 00:00:00 2001 From: marcel-dempers Date: Wed, 21 Apr 2021 08:09:46 +1000 Subject: [PATCH 1/4] start --- kubernetes/daemonsets/README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 kubernetes/daemonsets/README.md diff --git a/kubernetes/daemonsets/README.md b/kubernetes/daemonsets/README.md new file mode 100644 index 0000000..75284da --- /dev/null +++ b/kubernetes/daemonsets/README.md @@ -0,0 +1,2 @@ +# Kubernetes Daemonsets + From 4dd0bbd98bc366162190988595351f71fce840fd Mon Sep 17 00:00:00 2001 From: marcel-dempers Date: Sun, 2 May 2021 12:53:19 +1000 Subject: [PATCH 2/4] daemonset intro --- kubernetes/daemonsets/README.md | 228 ++++++++++++++++++ .../daemonsets/daemonset-communication.yaml | 55 +++++ kubernetes/daemonsets/daemonset.yaml | 40 +++ kubernetes/daemonsets/kind.yaml | 7 + kubernetes/daemonsets/pod.yaml | 13 + .../services/clusterip-service.yaml | 13 + .../services/headlress-service.yaml | 13 + 7 files changed, 369 insertions(+) create mode 100644 kubernetes/daemonsets/daemonset-communication.yaml create mode 100644 kubernetes/daemonsets/daemonset.yaml create mode 100644 kubernetes/daemonsets/kind.yaml create mode 100644 kubernetes/daemonsets/pod.yaml create mode 100644 kubernetes/daemonsets/services/clusterip-service.yaml create mode 100644 kubernetes/daemonsets/services/headlress-service.yaml diff --git a/kubernetes/daemonsets/README.md b/kubernetes/daemonsets/README.md index 75284da..ee0addc 100644 --- a/kubernetes/daemonsets/README.md +++ b/kubernetes/daemonsets/README.md @@ -1,2 +1,230 @@ # Kubernetes Daemonsets +## We need a Kubernetes cluster + +Lets create a Kubernetes cluster to play with using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/)
+Because a Daemonset is all about running pods on every node, lets create a 3 node cluster: + +``` +cd kubernetes/daemonsets +kind create cluster --name daemonsets --image kindest/node:v1.20.2 --config kind.yaml +``` + +Test our cluster: + +``` +kubectl get nodes +NAME STATUS ROLES AGE VERSION +daemonsets-control-plane Ready control-plane,master 65s v1.20.2 +daemonsets-worker Ready 31s v1.20.2 +daemonsets-worker2 Ready 31s v1.20.2 +daemonsets-worker3 NotReady 31s v1.20.2 +``` + +# Introduction + +Kubernetes provide [documentation](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) for what a Daemonset is with examples. + + +## Basic Daemonset + +Let's deploy a daemonset that runs a pod on each node and collects the name of the node + +``` +kubectl apply -f daemonset.yaml + +kubectl get pods -o wide +NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES +example-daemonset-8lcr5 1/1 Running 0 3m21s 10.244.2.4 daemonsets-worker +example-daemonset-9jhgx 1/1 Running 0 81s 10.244.3.4 daemonsets-worker2 +example-daemonset-lvvsd 1/1 Running 0 2m41s 10.244.1.4 daemonsets-worker3 +example-daemonset-xxcv9 1/1 Running 0 119s 10.244.0.7 daemonsets-control-plane + +``` + +We can see the logs of any pod + +``` +kubectl logs +``` + +Cleanup: + +``` +kubectl delete ds example-daemonset +``` + +## Basic Daemonset: Exposing HTTP + +Let's deploy a daemonset that runs a pod on each node and exposes an HTTP endpoint on each node.
+In this demo we'll use a simple NGINX on port 80 + +``` +kubectl apply -f daemonset-communication.yaml +kubectl get pods +``` + +## Communicating with Daemonset Pods + +https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/#communicating-with-daemon-pods + +Let's deploy a pod that can talk to our daemonset + +``` +kubectl apply -f pod.yaml + +kubectl exec -it pod -- bash +``` + +### Service Type: ClusterIP or LoadBalancer + +Let's deploy a service of type ClusterIP + +``` +kubectl apply -f ./services/clusterip-service.yaml + +while true; do curl http://daemonset-svc-clusterip; sleep 1s; done +Hello from daemonsets-worker2 +Hello from daemonsets-control-plane +Hello from daemonsets-worker2 +Hello from daemonsets-worker3 +Hello from daemonsets-worker +Hello from daemonsets-worker +``` + +### Node IP and Node Port + +We can add the `nodePort` field to the pods port section to expose a port on the node.
+ +Let's expose the node port in the pod spec: + +``` +ports: +- containerPort: 80 + hostPort: 80 + name: "http" +``` +This means we can contact the daemonset pod using the Node IP and port: + +``` +# get the node ips +kubectl get nodes -owide + +NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP KERNEL-VERSION CONTAINER-RUNTIME +daemonsets-control-plane Ready control-plane,master 112m v1.20.2 172.18.0.4 +daemonsets-worker Ready 111m v1.20.2 172.18.0.3 +daemonsets-worker2 Ready 111m v1.20.2 172.18.0.2 +daemonsets-worker3 Ready 111m v1.20.2 172.18.0.6 + +#example: + +bash-5.1# curl http://172.18.0.4:80 +Hello from daemonsets-control-plane +bash-5.1# curl http://172.18.0.2:80 +Hello from daemonsets-worker2 +``` + +### Service: Headless service + +Let's deploy a headless service where `clusterIP: None` + +``` +kubectl apply -f ./services/headlress-service.yaml +``` + +There are a few ways to discover our pods: +1) Discover the [DNS](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#services) records via the "Headless" services + + +``` +apk add --no-cache bind-tools +dig daemonset-svc-headless.default.svc.cluster.local +``` + +Notice it resolves to multiple DNS records for each pod: + +``` + +;; ANSWER SECTION: +daemonset-svc-headless.default.svc.cluster.local. 30 IN A 10.244.0.5 +daemonset-svc-headless.default.svc.cluster.local. 30 IN A 10.244.2.2 +daemonset-svc-headless.default.svc.cluster.local. 30 IN A 10.244.3.2 +daemonset-svc-headless.default.svc.cluster.local. 30 IN A 10.244.1.2 +``` + +2) Discover pods endpoints by retrieving the endpoints for the headless service + +``` +kubectl describe endpoints daemonset-svc-headless +``` + +Example: +``` +Addresses: 10.244.0.5,10.244.1.2,10.244.2.2,10.244.3.2 + +``` + +Get A records for each pod by using the following format:
+ +`..pod..`
+ +``` +#examples: + +10-244-0-5.default.pod.cluster.local +10-244-1-2.default.pod.cluster.local +10-244-2-2.default.pod.cluster.local +10-244-3-2.default.pod.cluster.local +``` + +Communicate with the pods over DNS: + +``` +curl http://10-244-0-5.default.pod.cluster.local +Hello from daemonsets-control-plane +``` + +# Real world Examples: + +## Monitoring Nodes: Node-Exporter Daemonset + +
+We clone the official kube-prometheus repo to get monitoring manifests for Kubernetes. + +``` +git clone https://github.com/prometheus-operator/kube-prometheus.git +``` + +Check the compatibility matrix [here](https://github.com/prometheus-operator/kube-prometheus/tree/v0.8.0#kubernetes-compatibility-matrix) + +For this demo, we will use the compatible version tag 0.8 + +``` +git checkout v0.8.0 +``` + +Deploy Prometheus Operator and CRDs +``` +cd .\manifests\ +kubectl create -f .\setup\ +``` + +Deploy remaining resources including node exporter daemonset + +``` +kubectl create -f . + +# wait for pods to be up +kubectl get pods -n monitoring + +#access prometheus in the browser +kubectl -n monitoring port-forward svc/prometheus-k8s 9090 + +``` +See the Daemonset communications on the Prometheus [targets](http://localhost:9090/targets) page + +Checkout my [monitoring guide for kubernetes](../../monitoring/prometheus/kubernetes/README.md) for more in depth info + +## Monitoring: Logging via Fluentd + +Take a look at my monitoring guide for [Fluentd](../../monitoring/logging/fluentd/kubernetes/README.md) diff --git a/kubernetes/daemonsets/daemonset-communication.yaml b/kubernetes/daemonsets/daemonset-communication.yaml new file mode 100644 index 0000000..e6f629c --- /dev/null +++ b/kubernetes/daemonsets/daemonset-communication.yaml @@ -0,0 +1,55 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: daemonset-communicate + namespace: default + labels: + app: daemonset-communicate +spec: + selector: + matchLabels: + name: daemonset-communicate + template: + metadata: + labels: + name: daemonset-communicate + spec: + tolerations: + # this toleration is to have the daemonset runnable on master nodes + # remove it if your masters can't run pods + - key: node-role.kubernetes.io/master + effect: NoSchedule + initContainers: + - name: create-file + image: alpine + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + command: + - "bin/sh" + - "-c" + - "echo 'Hello from '$NODE_NAME > /usr/share/nginx/html/index.html" + volumeMounts: + - name: nginx-page + mountPath: /usr/share/nginx/html/ + containers: + - name: daemonset-communicate + image: nginx:1.20.0-alpine + volumeMounts: + - name: nginx-page + mountPath: /usr/share/nginx/html/ + resources: + limits: + memory: 500Mi + requests: + cpu: 10m + memory: 100Mi + ports: + - containerPort: 80 + name: "http" + terminationGracePeriodSeconds: 30 + volumes: + - name: nginx-page + emptyDir: {} \ No newline at end of file diff --git a/kubernetes/daemonsets/daemonset.yaml b/kubernetes/daemonsets/daemonset.yaml new file mode 100644 index 0000000..b0503ab --- /dev/null +++ b/kubernetes/daemonsets/daemonset.yaml @@ -0,0 +1,40 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: example-daemonset + namespace: default + labels: + app: example-daemonset +spec: + selector: + matchLabels: + name: example-daemonset + template: + metadata: + labels: + name: example-daemonset + spec: + tolerations: + # this toleration is to have the daemonset runnable on master nodes + # remove it if your masters can't run pods + - key: node-role.kubernetes.io/master + effect: NoSchedule + containers: + - name: example-daemonset + image: alpine:latest + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + command: + - "bin/sh" + - "-c" + - "echo 'Hello! I am running on '$NODE_NAME; while true; do sleep 300s ; done;" + resources: + limits: + memory: 200Mi + requests: + cpu: 100m + memory: 200Mi + terminationGracePeriodSeconds: 30 \ No newline at end of file diff --git a/kubernetes/daemonsets/kind.yaml b/kubernetes/daemonsets/kind.yaml new file mode 100644 index 0000000..3328485 --- /dev/null +++ b/kubernetes/daemonsets/kind.yaml @@ -0,0 +1,7 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +nodes: +- role: control-plane +- role: worker +- role: worker +- role: worker \ No newline at end of file diff --git a/kubernetes/daemonsets/pod.yaml b/kubernetes/daemonsets/pod.yaml new file mode 100644 index 0000000..0bc3165 --- /dev/null +++ b/kubernetes/daemonsets/pod.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Pod +metadata: + name: pod +spec: + containers: + - name: pod + image: alpine + command: + - "/bin/sh" + - "-c" + - "apk add --no-cache curl bash && sleep 60m" + diff --git a/kubernetes/daemonsets/services/clusterip-service.yaml b/kubernetes/daemonsets/services/clusterip-service.yaml new file mode 100644 index 0000000..cc3f6f9 --- /dev/null +++ b/kubernetes/daemonsets/services/clusterip-service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: daemonset-svc-clusterip +spec: + type: ClusterIP + selector: + name: daemonset-communicate + ports: + - protocol: TCP + name: "http" + port: 80 + targetPort: 80 \ No newline at end of file diff --git a/kubernetes/daemonsets/services/headlress-service.yaml b/kubernetes/daemonsets/services/headlress-service.yaml new file mode 100644 index 0000000..d40be5f --- /dev/null +++ b/kubernetes/daemonsets/services/headlress-service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: daemonset-svc-headless +spec: + clusterIP: None + selector: + name: daemonset-communicate + ports: + - protocol: TCP + name: "http" + port: 80 + targetPort: 80 \ No newline at end of file From 8927a39200558ed9499de4b2fc786629bec5eb52 Mon Sep 17 00:00:00 2001 From: Marcel Dempers <34320559+marcel-dempers@users.noreply.github.com> Date: Thu, 27 May 2021 07:08:11 +1000 Subject: [PATCH 3/4] Rename headlress-service.yaml to headless-service.yaml --- .../services/{headlress-service.yaml => headless-service.yaml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename kubernetes/daemonsets/services/{headlress-service.yaml => headless-service.yaml} (85%) diff --git a/kubernetes/daemonsets/services/headlress-service.yaml b/kubernetes/daemonsets/services/headless-service.yaml similarity index 85% rename from kubernetes/daemonsets/services/headlress-service.yaml rename to kubernetes/daemonsets/services/headless-service.yaml index d40be5f..f4e42b9 100644 --- a/kubernetes/daemonsets/services/headlress-service.yaml +++ b/kubernetes/daemonsets/services/headless-service.yaml @@ -10,4 +10,4 @@ spec: - protocol: TCP name: "http" port: 80 - targetPort: 80 \ No newline at end of file + targetPort: 80 From 469d09aa681437825c44307446f1250e633071bb Mon Sep 17 00:00:00 2001 From: Marcel Dempers <34320559+marcel-dempers@users.noreply.github.com> Date: Thu, 27 May 2021 07:09:19 +1000 Subject: [PATCH 4/4] Update README.md --- kubernetes/daemonsets/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kubernetes/daemonsets/README.md b/kubernetes/daemonsets/README.md index ee0addc..5791faf 100644 --- a/kubernetes/daemonsets/README.md +++ b/kubernetes/daemonsets/README.md @@ -129,7 +129,7 @@ Hello from daemonsets-worker2 Let's deploy a headless service where `clusterIP: None` ``` -kubectl apply -f ./services/headlress-service.yaml +kubectl apply -f ./services/headless-service.yaml ``` There are a few ways to discover our pods: