Problemas con nf_conntrack en EKS : table full, dropping packet
Problemas con nf_conntrack en EKS puede aparecer si tienes bastantes conexiones, antes o después te encontraras en los logs del kernel unos errores tipo.
nf_conntrack: table full, dropping packet
Este error lo podemos encontrar con el comando dmesg.
Básicamente nos está diciendo que el sistema está denegando paquetes, ya que la tabla nf_conntrack de netfilter donde se guardan los registros de las conexiones activas de la máquina, está llena.
¿Cómo saber el limite de Amazon para EKS?
Con prometheus operator es muy sencillo ya que recoge métricas sobre los problemas con nf_conntrack, solo tendremos que lanzar la siguiente query, donde podremos ver el numero de registros que tenemos disponibles y poner una alerta acorde.
sum (node_nf_conntrack_entries_limit) by (instance) - sum (node_nf_conntrack_entries) by (instance)
¿Cómo aumentar el limite en EKS?
Tenemos dos formas de hacerlo:
Aumentando el tipo de instancia: Cada tipo de EC2 instances tiene un limite max predefinido, lo podremos comprobar lanzando el siguiente comando desde la instancia.
cat /proc/sys/net/netfilter/nf_conntrack_max
Configurando kube-proxy para cambiar el limite: También podemos usar kube-proxy para establecer el limite mayor y así no tener que cambiar el tipo de instancia que estamos usando, para realizarlo haremos:
Cómo apunte, el rollingupdate de kube-proxy no supone interrupción del servicio, ya que únicamente se encarga de mantener la configuración de iptables actualizada.
Si te has quedado con ganas de más, pásate por estos artículos entretenidos:
Systemd marcó un antes y un después en la gestión de servicios en Linux, dentro de las mil y una opciones que nos aporta también lo podemos usar como gestor de tareas programadas, con systemd.timer, al estilo del bien conocido cron
¿Cómo crear una tarea programada con systemd.timer?
El ejemplo que explicaré esta basado en la necesidad de que un servicio (syncthing) arranque después de un tiempo definido, desde el inicio del sistema, al ser un servicio bastante pesado buscamos que el sistema tenga una carga menor a la que suelen tener al arranque, normalmente alta.
Creación de las unidades systemd.timer y systemd.service
En nuestro caso nos interesa que el servicio anterior arranque 10 minutos después de que el sistema haya arrancado, para ello usaremos systemd.timer.
Crearemos un fichero syncthing.timer ya que el nombre debe ser igual al servicio que hemos creado anteriormente. syncthing.service
sudo vim /usr/lib/systemd/user/syncthing.timer
[Unit]
Description=Run syncthing 60 min after boot
[Timer]
OnBootSec=60min
[Install]
WantedBy=timers.target
Una vez creados, deberemos activarlo para el usuario que deseemos, únicamente la unidad timer.
systemctl enable --user syncthing.timer
Podremos comprobar la lista de tareas programadas usando el siguiente comando
[email protected] ~ $ systemctl --user list-timers
NEXT LEFT LAST PASSED UNIT ACTIVATES
Thu 2018-01-04 13:18:44 CET 42min left n/a n/a syncthing.timer syncthing.service
1 timers listed.
Ahí podemos ver que nuestra tarea y será ejecutada por primera vez en 42 minutos, en ese momento arrancara el servicio de syncthing
Si comprobamos el servicio.
[email protected] ~ $ systemctl status --user syncthing.timer
_ syncthing.timer - Run syncthing 60 min after boot
Loaded: loaded (/usr/lib/systemd/user/syncthing.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Thu 2018-01-04 12:33:59 CET; 1min 26s ago
Podemos ver que esta activa y a la espera de ser lanzada, con ello ya tendremos nuestra tarea programada con systemd en vez de cron.
Pros
Podemos lanzar la tarea programada sin necesidad de esperar a que se auto lance.
Cada tarea puede ser configurada para ser lanzada en un entorno especifico (systemd.exec)
Cada tarea puede ser asignada a un cgroup
Las tareas tendrán independencia gracias a que cada una será una unidad
Podremos usar journalctl para comprobar la salida de cada tarea.
Contras
Necesitamos crear dos unidades de systemd (timer y service) para programar una tarea.
En caso de fallo no se envía el mail automáticamente, deberemos usar la opción OnFailure=
Llevamos un tiempo trabajando en Docker con el dinamismo que ello nos supone, HaProxy con Consul-template nos ofrece una solucion muy similar a marathon-lb, el cual habíamos hablado encomo usar marathon-lbpara conectar nuestras aplicaciones dentro del cluster deApache Mesos.
Marahon-lb es una maravilla, pero no dispone de algunas características que nos hacen falta, así que pensamos, bueno pues nos lo montamos nosotros.
Idea principal
La idea principal es utilizar la información que tenemos de nuestros servicios registrados en Consul, para poder generar la configuración de HaProxycon Consul–template. Fácil.
Lo haremos en dockerasí lo podremos lanzar en la plataforma de Apache Mesos, y claro esta si queremos que HaProxy tenga una configuración dinámica deberemos implementar el zero downtime reload
¿Qué es el Zero downtime reload HaProxy?
Cada vez que tengamos un cambio de configuración en HaProxy deberemos hacer una recarga del servicio, en el caso que tengamos conexiones establecidas esta recarga nos llevara a perderlas y claro, eso no es para nada deseable, ¿cómo solventamos este problema?
Pues seguiremos las indicaciones de Willy TarreauCTO de HAPROXY, lo que nos comenta es que podemos implementar una solución para descartar los paquetes SYN durante el reinicio de HaProxy, y aprovecharnos del funcionamiento de TCP para que se recupere automáticamente, añadiremos la solución en la imagen.
A esta solución hay una vuelta de tuerca mas, que lo explican maravillosamente bien la gente de Yelp, True Zero Downtime HAProxy Reloads.
Creación de los Dockers
Vamos a crear dos imágenes de Docker, por un lado la imagen con Consul-Templaty por otro la imagen de HaProxy que heredara de la primera imagen.
Una de las partes mas importantes es entender el Consul-template que utilizaremos para HaProxy, gracias a Raul Fiestas por la creación del mismo :), podéis pasaros por su github, que tiene cosas muy interesanteshttps://github.com/rfiestas o su tumblr http://sudevops.tumblr.com/
La idea no es hacer una clase de consul-template, pero lo importante es saber las opciones que podemos usar, explicadas a continuación y que también podéis encontrar en https://github.com/maauso/docker-haproxy
¿Qué necesitamos para añadir un nuevo servicio a nuestro HaProxy?
Toda la información del servicio deberá estar en Consul, haremos un ejemplo con el servicio «www»
SERVICE_NAME=www
Este será en nombre de nuestro backend y frontend en la configuración de HaProxy, también será la url de acceso, que se concatenará al valor de HAPROXY_DOM, www.maauso.com
Deberemos usuar Consul Tags, para decidir que servicios de Consul queremos añadir a nuestro HaProxy
HAPROXY.ENABLE=true
Y tendremos otras opciones del backend usando tags.
HAPROXY.PROTOCOL=http
HAPROXY.BACKEND.BALANCE=roundrobin
HAPROXY.BACKEND.MAXCONN=10000
backend www.maauso.com
balance roundrobin
mode http
option forwardfor
option tcp-check
default-server inter 10s fall 1
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
Opciones de configuración para HaProxy
Variables Globales que podemos modificar
HAPROXY_MAXCONN_GLOBAL=50000
HAPROXY_SPREAD_CHECKS=5
HAPROXY_MAX_SPREAD_CHECKS=15000
HAPROXY_SPREAD-CHECKS=5
Variables que no tienen valor por defecto
HAPROXY_DOM=maauso.com
Variables por defecto que podemos cambiar
HAPROXY_RETRIES=3
HAPROXY_BACKLOG=10000
HAPROXY_MAXCONN=10000
HAPROXY_TIMEOUT_CONNECT=3s
HAPROXY_TIMEOUT_CLIENT=30s
HAPROXY_TIMEOUT_SERVER=30s
HAPROXY_TIMEOUT_HTTP_KEEP_ALIVE=1s
HAPROXY_TIMEOUT_HTTP_REQUEST=15s
HAPROXY_TIMEOUT_QUEUE=30s
Por último zero downtime reload.
Para conseguir el zero downtime reload consul-template enviará un SIGHUBal proceso que maneja a HaProxy, este proceso recibirá la señal con un trapy realizará el DROPde los paquetes SYNcon iptables.
Acto seguido creara un nuevo proceso de HaProxy con la opción -sf $LATEST_HAPROXY_PID y eliminara la regla de iptables.