Monitoring K3S

Nadat de Kubernetes Cluster ‘up-and-running’ is en er pods met applicaties op draaien, willen we de status van het cluster gaan monitoren. Datgene dat gemonitored kan worden dient ‘gescraped‘ te worden en voor Kubernetes is Prometheus daar de uitgelezen tool voor. Scrapen van de systeem-eigenschappen van de node(s) zelf kan heel goed met ‘node-exporter‘.

NameSpace

De monitoring functies zetten we in een nameSpace genaamd ‘monitoring’ Deze wordt aangemaakt met:

$ kubectl create namespace monitoring

Node Exporter

De nodes worden voorzien van een DaemonSet. Dit is een pod die door Kubernetes op alle nodes geplaatst en uitgevoerd wordt. In dit geval dus met een node-exporter als applicatie zodat de metrics van de nodes uitgelezen kunnen worden. De manifest ziet er alsvolgt uit in node-exporter-daemonset.yml:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: monitoring
  labels:
    name: node-exporter
spec:
  selector:
    matchLabels:
      name: node-exporter
  template:
    metadata:
      labels:
        name: node-exporter
      annotations:
         prometheus.io/scrape: "true"
         prometheus.io/port: "9100"
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master
        value: "true"
        effect: NoSchedule
      - key: node-role.kubernetes.io/master
        value: "true"
        effect: NoExecute
      hostPID: true
      hostIPC: true
      hostNetwork: true
      containers:
        - ports:
            - containerPort: 9100
              protocol: TCP
          resources:
            requests:
              cpu: 0.15
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
              - ALL
            readOnlyRootFilesystem: true
            privileged: false
          image: nokkie/node-exporter:arm64
          args:
            - --path.procfs
            - /host/proc
            - --path.sysfs
            - /host/sys
            - --collector.filesystem.ignored-mount-points
            - '"^/(sys|proc|dev|host|etc)($|/)"'
          name: node-exporter
          volumeMounts:
            - name: dev
              mountPath: /host/dev
            - name: proc
              mountPath: /host/proc
            - name: sys
              mountPath: /host/sys
            - name: rootfs
              mountPath: /rootfs
      volumes:
        - name: proc
          hostPath:
            path: /proc
        - name: dev
          hostPath:
            path: /dev
        - name: sys
          hostPath:
            path: /sys
        - name: rootfs
          hostPath:
            path: /

De tolerations zorgt ervoor dat deze DaemonSet ook op de master-node geïnstalleerd wordt. Vervolgens wordt het met securityContext zo veilig mogelijk ingesteld en alleen het noodzakelijke wordt toegestaan.

De volumes worden gemount en gebruikt in de arguments voor node-exporter zodat de node-exporter de waardes kan inlezen voor de metrics. Het starten van de DaemonSet gaat met het volgende commando:

$ kubectl apply -f node-exporter-daemonset.yml

Ter controle, de node-exporter ‘draait’ op TCP/poort 9100 en de metrics kunnen hierdoor opgehaald worden op de volgende URL van de nodes:

$ curl http://node-naam:9100/metrics

Prometheus

Kubernetes heeft serviceAccounts waarmee ‘rollen’ ingesteld kunnen worden die uitgevoerd kunnen worden met deze serviceAccounts. De rollen worden dan via ‘RoleBindings’ aan de serviceAccount gekoppeld. Een manifest om serviceAccount, Roles en RoleBindings te configureren ziet er alsvolgt uit in prometheus-roles.yml:

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: prometheus
rules:
- apiGroups: [""]
  resources:
  - nodes
  - nodes/proxy
  - services
  - endpoints
  - pods
  verbs: ["get", "list", "watch"]
- apiGroups:
  - extensions
  resources:
  - ingresses
  verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/metrics"]
  verbs: ["get"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: default
  namespace: monitoring
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: prometheus
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: prometheus
subjects:
- kind: ServiceAccount
  name: default
  namespace: monitoring

Om deze in te lezen en te configureren dient het volgende commando:

$ kubectl apply -f prometheus-roles.yml

Prometheus verzamelt de metrics van de aangesloten targets. De targets zijn de nodes waarop de node-exporter draait, dus die gaan we vervolgens in een configuratie-bestand zetten. We geven binnen Kubernetes de instructie aan Prometheus om dit configuratiebestand in te lezen via een ‘ConfigMap’. De inhoud van prometheus-config.yml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-config
  namespace: monitoring
data:
  prometheus.yml: |
    global:
      scrape_interval:     15s 
      evaluation_interval: 15s 

    # Alertmanager configuration
    alerting:
      alertmanagers:
      - static_configs:
        - targets:
          # - alertmanager:9093

    scrape_configs:

      - job_name: 'prometheus'
        static_configs:
        - targets: ['localhost:9090']

      - job_name: 'rpi-1'
        static_configs:
        - targets: ['rpi-1:9100']

      - job_name: 'rpi-2'
        static_configs:
        - targets: ['rpi-2:9100']

      - job_name: 'rpi-3'
        static_configs:
        - targets: ['rpi-3:9100']

Het ‘scrapen‘ (ophalen van de metrics) laten we elke 15 seconden uitvoeren, de ‘alertManager‘ stellen we een andere keer in en de ‘targets‘ zijn de RaspBerry Pi Nodes van het cluster. De commando’s om deze configMap in te stellen:

$ kubectl apply f prometheus-config.yml

Om Prometheus te ‘exposen‘ wordt een Service aangemaakt van het type NodePort die luistert op TCP poort 30900 en de aanvraag doorzet naar de geconfigureerde TCP poort 9090 van Prometheus. De manifest voor de Service is prometheus-service.yml:

apiVersion: v1
kind: Service
metadata:
  name: prometheus
  namespace: monitoring
spec:
  selector:
    app: prometheus
  type: NodePort
  ports:
  - name: prometheus
    protocol: TCP
    port: 9090
    nodePort: 30900

en wordt met de volgende commando’s geconfigureerd en gecontroleerd:

$ kubectl apply -f prometheus-service.yml
$ kubectl get services -n monitoring
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
prometheus   NodePort    10.43.146.46           9090:30900/TCP   27s

De Prometheus-service kan nu in een browser aangeroepen worden op de TCP poort 30900, http://node-naam:30900

Via de ‘Status’ pagina kunnen de ‘Targets‘ bekeken worden en die zouden dan allen de status ‘UP’ moeten hebben.

In Prometheus kunnen metrics opgevraagd worden met de zogenaamde PromQL (Prometheus Query Language) en met behulp van ‘Grafana‘ kunnen de resultaten van de queries grafisch weergegeven worden.

Grafana

Om Grafana uit te rollen als deployment, de service in te stellen en om met behulp van een Ingress loadBalancer de web-pagina te kunnen benaderen, zetten we dit in een manifest dat er zo uit ziet in grafana-deployment.yml:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: grafana
  namespace: monitoring
  labels:
    app: grafana
spec:
  replicas: 1
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  selector:
    matchLabels:
      app: grafana
  template:
    metadata:
      labels:
        app: grafana
    spec:
      containers:
      - image: grafana/grafana
        imagePullPolicy: Always
        name: grafana
---
apiVersion: v1
kind: Service
metadata:
  name: grafana-svc
  namespace: monitoring
  labels:
    app: grafana
spec:
  ports:
  - name: http3000
    port: 3000
    protocol: TCP
    targetPort: 3000
  selector:
    app: grafana
  sessionAffinity: None
  type: ClusterIP
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: grafana-ingress
  namespace: monitoring
spec:
  rules:
  - host: grafana-rpi.digitalinfo.local
    http:
      paths:
      - backend:
          serviceName: grafana-svc
          servicePort: 3000
        path: /
        pathType: ImplementationSpecific

Het bijbehorende commando:

$ kubectl apply -f grafana-deployment.yml

Er is nu een DNS verwijzing nodig naar de hostname die in de ingress is gedefinieerd: grafana-rpi.digitalinfo.local Dit kan in een DNS-server zijn of in een lokale hosts-file. Daarna kan met de browser de Grafana site bekeken worden:

Inloggen kan met de standaard credentials: admin/admin

Als eerste dient nu de Data-Source aangemaakt te worden waarmee de metrics vanuit Prometheus ingelezen kunnen worden. Via het tandwiel-icon (Configuration) en ‘Data Sources’ kan Prometheus toegevoegd worden.

De URL wordt ‘http://prometheus:9090’ en dit gaat werken omdat de Kubernetes service genaamd ‘prometheus’ ingesteld is op poort 9090.

Via ‘Save & Test‘ wordt de data-source opgeslagen en de connectie getest.

Een voorbeeld van een Grafana Dashboard voor Kubernetes kan ge-importeerd worden met nummer 1860 en dat Dashboard ziet er zo uit: