Daemonset

Un DaemonSet si assicura che ogni nodo del cluster abbia un pod dell'immagine specificata.

Si può restringere il numero di nodi coinvolti con le direttive nodeSelector, nodeAffinity, Taints, e Tolerations.

Usi di DaemonSet:

  • Raccolta di Log - p.es. fluentd , logstash, fluentbit
  • Monitoraggio di Cluster - p.es. Prometheus
  • Benchmark - p.es. kube-bench
  • Sicurezza - sistemi di detezione intrusioni o scansori di vulnerabilità
  • Storaggio - p.es. un plugin di storaggio su ogni nodo
  • Gestione di Rete - p.es. il plugin Calico per CNI

Esempio di DaemonSet

vim ~/scripts/fluentd.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
  namespace: logging
  labels:
    app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd
  template:
    metadata:
      labels:
        name: fluentd
    spec:
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m                                      
            memory: 200Mi                                  
        volumeMounts:                                      
        - name: varlog                                     
          mountPath: /var/log                              
      terminationGracePeriodSeconds: 30                    
      volumes:                         
      - name: varlog                   
        hostPath:                      
          path: /data/varlog

E' opportuno che ogni DaemonSet sia specificato entro il suo namespace esclusivo.

Creare il namespace ed applicare il manifest:

kubectl create ns logging
kubectl apply -f scripts/fluentd.yml

Verifica con:

kubectl get daemonset -n logging
kubectl get pods -n logging -o wide
kubectl describe daemonset -n logging

Editazione Istantanea

Cambiamento istantaneo dei parametri di configurazione con:

kubectl edit daemonset fluentd -n logging

L'editor invocato è quello di sistema o quello indicato dalla variabile d'ambiente EDITOR.

Si può editare soltanto la sezione spec, non ststus.

In caso di errore l'editazione viene rilanciata.

Dopo il salvataggio di un'editazione corretta, avviene un rolling update.

Taints

Un Taint si applica ai nodi.

Il Taint ha la sintassi:

kubectl taint nodes <nodo> <chiave>=<valore>:<effetto>

L'effetto si applica sul nodo indicato a tutti i pod degli oggetti che hanno la chiave e il valore indicato.

L'effetto può essere:

  • NoSchedule
  • PreferNoSchedule
  • NoExecute

Esempio:

kubectl taint node kind-worker2 app=fluentd-logging:NoExecute

Lista di tutti i taints associati ai nodi:

kubectl get node -o custom-columns=NAME:.metadata.name,TAINT:.spec.taints[*]

Rimuovere un taint:

kubectl taint node kind-worker2 app-

Notare alla fine del comando il nome dell'etichetta seguito dal segno meno.

Tolerations

Modificare il file di specifiche del DaemonSet:

vim ~/scripts/fluentd.yml
  ...
  tolerations:
  - key: app
    value: fluentd-logging
    operator: Equal
    effect: NoExecute
  containers:
  ...

E riapplicare:

kubectl apply -f ~/scripts/fluentd.yml

Questo genera una eccezione al Taint.

Rimuovere il DaemonSet dell'esercizio:

kubectl delete -f ~/scripts/fluentd.yml

nodeSelector

Si può usare nodeSelector per avere i pod solo su alcuni nodi specifici. Il controller DaemonSet creai i pod sui nodi che hanno la chiave e il valore del selector.

Per esempio:

kubectl label node kind-worker2 type=platform-tools

E modificare le specifiche inserendo:

    ...
    spec:
      nodeSelector:
        type: platform-tools
      containers:
    ...

Ricreare il Daemonset e verificare:

kubectl apply -f ~/scripts/fluentd.yml
kubectl get pods -n logging -o wide

Per visualizzare i labels di un nodo:

kubectl get node kind-worker2 -o custom-columns=LABELS:.metadata.labels

Per rimuovere un label di nome type:

kubectl label node kind-worker2 type-

Rimuovere il DaemonSet dell'esercizio:

kubectl delete -f ~/scripts/fluentd.yml

nodeAffinity

Il controller DaemonSet crea i pod sui nodi che hanno il corrispondente nodeAffinity.

Vi sono due tipi di nodeAffinity:

  • requiredDuringSchedulingIgnoredDuringExecution - il pod non è schedulato se non si applica la regola
  • preferredDuringSchedulingIgnoredDuringExecution - lo scheduler prova a trovare un nodo conforme con la regola. Se non vi sono nodi che corrispondono, il pod viene schedulato ugualmente

Nel seguente DaemonSet vengono usate entrambe le regole di affinity:

  • required che i nodi abbiano una certa etichetta
  • preferred i nodi che abbiano l'etichetta di tipo t2.large

Modificare il file di specifiche con il seguente.

vim ~/scripts/fluentd.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
  namespace: logging
  labels:
    app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd
  template:
    metadata:
      labels:
        name: fluentd
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: type
                operator: In
                values:
                - platform-tools
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
              - key: instance-type
                operator: In
                values:
                - t2.large
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m                                      
            memory: 200Mi                                  
        volumeMounts:                                      
        - name: varlog                                     
          mountPath: /var/log                              
      terminationGracePeriodSeconds: 30                    
      volumes:                         
      - name: varlog                   
        hostPath:                      
          path: /data/varlog

Ricreare il Daemonset e verificare:

kubectl apply -f ~/scripts/fluentd.yml
kubectl get pods -n logging -o wide

E' meglio usare preferredDuringSchedulingIgnoredDuringExecution invece di requiredDuringSchedulingIgnoredDuringExecution poichè è impossibile lanciare nuovi pod se il numero di nodi richiesto è maggiore del numero di nodi disponibile.

Priorità dei Pod

Determina l'importanza relativa di un pod.

E' utile settare una più alta PriorityClass ad un DaemonSet se questo ha componenti critici, per evitare che i suoi pod vengano sfavoriti da altri pod in caso di competizione di risorse.

PriorityClass definisce la priorità del pod. Valore limite 1 milione. Numeri più alti con priorità più alta.

Creazione di un oggetto priority class:

vim ~/scripts/prioclass.yml
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 100000
globalDefault: false
description: "daemonset priority class"
kubectl apply -f ~/scripts/prioclass.yml
kubectl get priorityClass

Aggiungere al nostro DaemonSet modificando il file di specifiche:

...
spec:
  priorityClassName: high-priority
  containers:
  ...
  terminationGracePeriodSeconds: 30
  volumes:
  ...

Ricreare il Daemonset e verificare:

kubectl apply -f ~/scripts/fluentd.yml
kubectl get pods -n logging -o wide