Service Mesh: Probando Istio


Aprovechando que tenemos montado el “mini cluster” on premise con k3s en la Raspberry pi con ClusterHAT. En este enlace se explican los pasos que he realizado para el montaje. Vamos a probar Istio en el cluster, como gestionarlo y ver que funcionalidades extras nos ofrece.

Introducción a Istio

Istio es un service mesh, un service mesh es una capa extra de red por encima del plugin de red de Kubernetes y que ofrece muchas más funcionalidades. Istio gestiona los flujos de tráfico entre servicios, aplica políticas de acceso y agrupa datos de telemetría sin modificar el código de las aplicaciones. Además, reduce la complejidad del despliegue al integrarse de forma transparente en aplicaciones distribuidas.

A día de hoy existen 3 alternativas de service mesh bastante populares:

He optado por probar Istio ya que es el service mesh más popular y el que lleva más tiempo en el mercado. Además su instalación es muy sencilla y no tiene dependencias. También la documentación de Istio y la comunidad que hay detrás es muy buena.

Arquitectura de Istio

La arquitectura de Istio se podría ver de la siguiente manera:

No voy a entrar en mucho detalle sobre la arquitectura. En este enlace tenéis más información sobre cada uno de los componentes. Solo resaltar que Istio se compone de dos partes diferenciadas, el control plane y el data plane, en el data plane irían los pods de nuestro cluster, a los que Istio agrega un contenedor de tipo sidecar a cada pod con un proxy, de manera transparente para controlar el tráfico de red. Además, por defecto hace que este tráfico de red interno en nuestro cluster vaya cifrado de forma “automágica”. También incluye reglas para el tráfico entrante (ingress) y reglas para el tráfico saliente (egress).

Instalación de Istio

Vamos a seguir el “Getting started” de la documentación oficial de Istio.

Lo primero que vamos a hacer es instalar el comando istioctl para administrar Istio:

$ curl -L https://istio.io/downloadIstio | sh -

añadimos el binario a nuestro PATH y podemos ver que ya muestra la ayuda:

Hay que tener en cuenta que si estamos tenemos configurado varios cluster en nuestro en torno local tenemos que tener seleccionado el contexto del cluster correspondiente dónde lo queremos instalar.

En nuestro caso, si ejecutamos el comando k9s podemos ver que accedemos al cluster de la raspberry Pi:

Desplegando componentes de Istio

Luego instalaremos Istio en nuestro cluster de la raspberry Pi con el siguiente comando con todos los componentes de demo:

$ istioctl install --set profile=demo -y

Con k9s abierto podemos ver que se van desplegando los componentes (pods):

Es posible que el servicio de LoadBalancer de Istio “svclb-instio-ingressgateway” no se despliegue ya que al instalar Kubernetes en nuestra raspberry Pi con k3s, este incluye traefik un ingresscontroler que nos provee, entre otras cosas, la posibilidad de crear servicios de tipo LoadBalancer. En nuestro caso lo vamos a desinstalar con los siguientes comandos de Helm:

$ helm delete -n kube-system traefik
$ helm delete -n kube-system traefik-crd

Una vez instalado Istio, la pinta que debería tener nuestro cluster sería esta:

Luego entraremos en más detalles que haca cada uno de los componentes, de momento el siguiente paso que vamos a dar es crear un nuevo namespace para las pruebas de Istio en nuestro cluster. Hay que tener en cuenta que Istio por defecto viene “desactivado” y no inyecta sus pods sidecars a los pods de nuestras aplicaciones si no lo configuramos para que los pueda inyectar en los namespaces que le indiquemos.

Creamos el namespace:

$ kubectl create namespace pruebas-istio

y luego añadimos el siguiente label al namespace:

$ kubectl label namespace pruebas-istio istio-injection=enabled

A partir de ahora todos los pods que se desplieguen en el namespace pruebas-istio se les incluirá automáticamente y de manera totalmente transparente el contenedor proxy sidecar de Istio.

Desplegando aplicación de ejemplo para las pruebas

Ahora instalamos la aplicación de ejemplo de Istio en nuestro namespace para las pruebas:

$ kubectl apply -n pruebas-istio -f samples/bookinfo/platform/kube/bookinfo.yaml

Con le siguiente comando comprobamos que la aplicación de pruebas está respondiendo:

$ kubectl exec -n pruebas-istio "$(kubectl get pod -n pruebas-istio -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"

<title>Simple Bookstore App</title>

Ahora abrimos la aplicación al trafico exterior:

$ kubectl apply -n pruebas-istio -f samples/bookinfo/networking/bookinfo-gateway.yaml

Esto va a crear dos objetos de Kubernetes para nuestra aplicación, el gateway y el virtualservice.

Vamos a echarle un vistazo al yaml que aplica:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: bookinfo-gateway
spec:
  selector:
    istio: ingressgateway # use istio default controller
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
  - "*"
  gateways:
  - bookinfo-gateway
  http:
  - match:
    - uri:
        exact: /productpage
    - uri:
        prefix: /static
    - uri:
        exact: /login
    - uri:
        exact: /logout
    - uri:
        prefix: /api/v1/products
    route:
    - destination:
        host: productpage
        port:
          number: 9080

Como se puede observar, aquí Istio despliega dos de sus componentes, el Gateway y el VirtualService. En el Gateway se definen los puertos y los hosts que se van a exponer de nuestra app y en el VirtualService definimos los paths. Es muy parecido a un manifiesto de ingress solo que aquí, se divide en dos componentes la definición de los host/puertos y los paths.

Podemos comprobar que la configuración de Istio en el namespace pruebas-istio es la correcta:

$ istioctl analyze -n pruebas-istio

Revisando los servicios de nuestro cluster, podemos observar que tenemos el servicio de LoadBalancer de Istio con la IP externa de nuestra red local asignada y con un port fordward del puerto 80 al puerto 30034 (en mi caso):

Como ya hemos expuesto el servicio de nuestra aplicación de pruebas al mundo exterior podemos ver que podemos acceder desde nuestro pc local desde http://192.168.1.100:30034/productpage

Telemetría y obervabilidad con Kiali

Ahora vamos a instalar el addon de Kiali para monitorizar el tráfico de red de nuestra aplicación de pruebas.

Con el siguiente comando instalamos el dashboard de Kiali, junto con PrometheusGrafana y Jaeger:

$ kubectl apply -f samples/addons
$ kubectl rollout status deployment/kiali -n istio-system

Con el siguiente comando activamos el dashboard de Kiali:

$ istioctl dashboard kiali
http://localhost:20001/kiali

Kiali es una fantástica herramienta que nos muestra mucha información, por ejemplo los servicios activos y con reglas de Gateway VirtualService abiertos al exterior, como en este caso la app de ejemplo de productpage:

Visualización del tráfico de nuestro cluster con Kiali

Otra de las funcionalidades que ofrece Kiali es la visualización de todo el tráfico, entrante/saliente/interno de nuestro cluster, ya que está integrado con Istio y es capaz de recoger los datos del tráfico de cada uno de los pods con el sidecar proxy de Istio.

Para ver un ejemplo real, podemos generar cierto tráfico a la app de productpage:

$ for i in $(seq 1 100); do curl -s -o /dev/null "http://192.168.1.100:30034/productpage"; done

y desde el apartado de Graph seleccionando el namespace, podemos visualizar el tráfico en “tiempo real”:

Como podéis imaginar esta herramienta es bastante potente cuando tenemos muchas aplicaciones en nuestro cluster y queremos detectar posibles fallos o errores.

Otras funcionalidades de ofrece Istio
  • Request routing: Enrutar respuestas de forma dinámica a distintas versiones de un mismo microservicio. Por ejemplo, podemos definir que las peticiones de un usuario concreto que esté logueado en nuestra app, se enruten a una versión determinada de la app. Esto es muy útil para realizar pruebas en entornos productivos de una nueva versión.
  • Fault injection: Podemos inyectar una batería de request fallidos para ver como se comporta nuestra app y realizar test de resiliencia.
  • Traffic shifting: Podemos destinar un porcentaje concreto de requests para que vayan a una versión determinada de nuestra app. Esto es muy útil para poder realizar un despliegue de tipo canary.
  • Querying metrics: Podemos generar métricas de Istio para la monitorización del tráfico con otros sistemas como Prometheus.
  • Visualizing metrics: Podemos visualizar las métricas con Grafana.
  • Accessing external services: Podemos configurar el tráfico saliente de nuestra app, y limitarlo con la configuración del egress.
  • Visualizing your mesh: Y todo lo anterior lo podemos visualizar con Kiali.

En definitiva, Istio es un service mesh que añade muchas funcionalidades extras, y muy potentes a nivel de red en nuestro cluster de Kubernetes.

🍺 🍺 🍺