Espiando a tu Kubernetes con Kubewatch

Desde la Práctica Cloud queremos impulsar la adopción de la nube como forma de trabajo en el mundo de IT. Para ayudar en esta tarea, vamos a publicar multitud de artículos de buenas prácticas y casos de uso, otros hablarán aquellos servicios clave dentro de la nube.

En esta ocasión hablaremos de Kubewatch.

¿Qué es Kubewath?

Kubewatch es una utilidad desarrollada por Bitnami Labs que permite el envío de notificaciones a distintos sistemas de comunicación.

Los webhooks soportados son:

  • Slack
  • Hipchat
  • Mattermost
  • Flock
  • Webhook
  • Smtp

Integración de kubewatch con Slack

Las imágenes disponibles están publicadas en el GitHub de bitnami/kubewatch

Si queréis, podéis descargaros la última versión para probarla en vuestro entorno local:

$ docker pull bitnami/kubewatch 

Una vez dentro del contenedor podéis jugar con las opciones:

$ kubewatch -h

Kubewatch: A watcher for Kubernetes

kubewatch is a Kubernetes watcher that publishes notifications
to Slack/hipchat/mattermost/flock channels. It watches the cluster
for resource changes and notifies them through webhooks.

supported webhooks:
 - slack
 - hipchat
 - mattermost
 - flock
 - webhook
 - smtp

Usage:
  kubewatch [flags]
  kubewatch [command]

Available Commands:
  config      modify kubewatch configuration
  resource    manage resources to be watched
  version     print version

Flags:
  -h, --help   help for kubewatch

Use "kubewatch [command] --help" for more information about a command. 

¿De qué tipos de recursos podemos obtener notificaciones?

¿Cuándo recibiremos una notificación?

En cuanto haya una acción sobre algún objeto de kubernetes, así como creación, destrucción o actualización.

Configuración

En primer lugar, crearemos un canal de slack y le asociaremos un webhook. Para ello, iremos a la sección de Apps de Slack, buscaremos “Incoming WebHooks” y pulsaremos “Add to Slack”:

En el caso de no tener aún un canal creado para este propósito daremos de alta uno nuevo:

En este ejemplo, el canal a crear se llamará “k8s-notifications”. Posteriormente debemos configurar el webhook, yendo para ello al panel de “Incoming WebHooks” y añadiendo una nueva configuración donde tendremos que seleccionar el nombre del canal al que queremos enviar notificaciones. Una vez seleccionado, la configuración nos devolverá una «Webhook URL» que será la que utilicemos para configurar Kubewatch. Opcionalmente, tenemos la posibilidad de seleccionar el icono (opción «Customize Icon») con el que visualizaremos la recepción de eventos y el nombre con el que llegarán (opción “Customize Name”).

En este punto ya estamos listos para configurar los recursos de kubernetes. En el GitHub de Kubewatch tenemos algunos ejemplos de manifiestos y también la opción de instalación por Helm. Sin embargo, aquí construiremos los nuestros propios.

En primer lugar, crearemos un fichero “kubewatch-configmap.yml” con el ConfigMap que servirá para configurar el contenedor de kubewatch:

apiVersion: v1
kind: ConfigMap
metadata:
  name: kubewatch
data:
  .kubewatch.yaml: |
    handler:
      webhook:
        url: https://hooks.slack.com/services/<your_webhook>
    resource:
      deployment: true
      replicationcontroller: true
      replicaset: false
      daemonset: true
      services: true
      pod: false
      job: false
      secret: true
      configmap: true
      persistentvolume: true
      namespace: false 

Simplemente tendremos que activar con “true” o desactivar con «false» los tipos de recursos sobre los que queremos recibir notificaciones. Asimismo, establecemos la url del Incomming Webhook que dimos de alta previamente.

Ahora, para que nuestro contenedor tenga acceso a los recursos de kubernetes a través de su api vamos a dar de alta el fichero “kubewatch-service-account.yml” con un Service Account, un Cluster Role y un Cluster Role Binding:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: kubewatch
rules:
- apiGroups: ["*"]
  resources: ["pods", "pods/exec", "replicationcontrollers", "namespaces", "deployments", "deployments/scale", "services", "daemonsets", "secrets", "replicasets", "persistentvolumes"]
  verbs: ["get", "watch", "list"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: kubewatch
  namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: kubewatch
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: kubewatch
subjects:
  - kind: ServiceAccount
    name: kubewatch
    namespace: default 

Por último, crearemos un fichero “kubewatch.yml” para desplegar la aplicación:

apiVersion: v1
kind: Pod
metadata:
  name: kubewatch
  namespace: default
spec:
  serviceAccountName: kubewatch
  containers:
  - image: bitnami/kubewatch:0.0.4
    imagePullPolicy: Always
    name: kubewatch
    envFrom:
      - configMapRef:
          name: kubewatch
    volumeMounts:
    - name: config-volume
      mountPath: /opt/bitnami/kubewatch/.kubewatch.yaml
      subPath: .kubewatch.yaml
  - image: bitnami/kubectl:1.16.3
    args:
      - proxy
      - "-p"
      - "8080"
    name: proxy
    imagePullPolicy: Always
  restartPolicy: Always
  volumes:
  - name: config-volume
    configMap:
      name: kubewatch
      defaultMode: 0755 

Vemos que el valor de la clave “mountPath” será la ruta del fichero donde se escribirá la configuración de nuestro ConfigMap dentro del contenedor (/opt/bitnami/kubewatch/.kubewatch.yaml). Podemos ampliar aquí la información sobre cómo montar configuraciones en kubernetes. En este ejemplo, vemos que nuestro despliegue del aplicativo será a través de un único pod. Evidentemente, en un sistema productivo tendríamos que definir un Deployment con el número de réplicas que consideremos convenientes para tenerlo así siempre activo, aun en caso de pérdida del pod.

Una vez listos los manifiestos vamos a aplicarlos a nuestro clúster:

$ kubectl apply  -f kubewatch-configmap.yml -f kubewatch-service-account.yml -f kubewatch.yml 

En unos pocos segundos tendremos listo el servicio:

$ kubectl get pods |grep -w kubewatch

kubewatch                                  2/2     Running     0          1m 

El pod de kubewatch tiene asociado dos contenedores: kubewatch y kube-proxy, este último para atacar a la API.

$   kubectl get pod kubewatch  -o jsonpath='{.spec.containers[*].name}'

kubewatch proxy 

Verificamos a través de los logs que ambos contenedores han levantado correctamente y sin mensajes de error:

$ kubectl logs kubewatch kubewatch

==> Config file exists...
level=info msg="Starting kubewatch controller" pkg=kubewatch-daemonset
level=info msg="Starting kubewatch controller" pkg=kubewatch-service
level=info msg="Starting kubewatch controller" pkg="kubewatch-replication controller"
level=info msg="Starting kubewatch controller" pkg="kubewatch-persistent volume"
level=info msg="Starting kubewatch controller" pkg=kubewatch-secret
level=info msg="Starting kubewatch controller" pkg=kubewatch-deployment
level=info msg="Starting kubewatch controller" pkg=kubewatch-namespace
... 
$ kubectl logs kubewatch proxy

Starting to serve on 127.0.0.1:8080 

Podríamos igualmente acceder al contenedor de kubewatch para probar la cli, ver la configuración, etcétera:

$  kubectl exec -it kubewatch -c kubewatch /bin/bash 

¡Ya tenemos listo nuestro notificador de eventos!

Ahora toca probar. Utilizaremos, por ejemplo, la creación de un deployment para testear el correcto funcionamiento:

$ kubectl create deployment nginx-testing --image=nginx
$ kubectl logs -f  kubewatch kubewatch

level=info msg="Processing update to deployment: default/nginx-testing" pkg=kubewatch-deployment 

Los logs ya nos avisan que se ha detectado el nuevo evento, así que vamos a nuestro canal de slack para verificarlo:

¡El evento ha sido notificado correctamente!

Ya podemos eliminar el deployment de prueba:

$ kubectl delete deploy nginx-testing 

Conclusiones

Evidentemente, Kubewatch no suple a los sistemas básicos de alerta y monitorización que todo orquestador productivo debe mantener, pero nos proporciona una manera fácil y eficaz de ampliar nuestro control sobre la creación y modificación de los recursos en kubernetes. En este caso de ejemplo, hemos realizado una configuración de kubewatch transversal a todo el clúster, “espiando” todo tipo de eventos, algunos quizá inservibles si mantenemos una plataforma como servicio, pues nos enteraríamos de cada uno de los pods creados, eliminados o actualizados por cada equipo de desarrollo en su propio namespace, lo cual es usual, legítimo y no aporta valor. Quizá sea más conveniente filtrar por los namespaces sobre cual queremos recibir notificaciones, como por ejemplo de kube-system, que es donde albergaremos generalmente nuestros servicios administrativos y donde solo los administradores deben tener acceso. En ese caso, simplemente tendremos que especificar el namespace en nuestro ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: kubewatch
data:
  .kubewatch.yaml: |
    namespace: "kube-system"
    handler:
      webhook:
        url: https://hooks.slack.com/services/<your_webhook>
    resource:
      deployment: true
      replicationcontroller: true
      replicaset: false 

Otra utilidad interesante puede ser “escuchar” a nuestro clúster tras un ajuste signicativo de la configuración como, por ejemplo, de nuestra estrategia de autoescalado, herramientas de integración, etcétera, pues siempre nos notificará los scale up y scale down, pudiendo ser interesante sobre todo en un momento inicial. En definitiva, Kubewatch amplía el control sobre los clústeres, siendo nosotros quienes decidamos el alcance que le damos. En sucesivos artículos veremos cómo gestionar los logs y las métricas de forma productiva.

¿Quieres saber más de lo que ofrecemos y ver otros casos de éxito?