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.