Correcci贸n de los tiempos de espera de DNS en Docker con una cach茅 de DNS[Tutorial]

Tener pruebas de escamas en tu IC es una pesadilla. No puedes decir si tu nuevo c贸digo rompi贸 algo o si son s贸lo esas pruebas que est谩n siendo escamosas de nuevo. As铆 que cada vez que vemos fallos extra帽os y aleatorios en CI para nuestro proyecto de c贸digo abierto, Adapt, intentamos localizar al culpable lo antes posible. Esta es la historia de c贸mo descubrimos que est谩bamos inundando (accidentalmente) nuestro servidor DNS con tr谩fico y c贸mo usamos una cach茅 de DNS en Docker para resolver el problema.

Fondo

Uno de los proyectos de c贸digo abierto en el que trabajo, AdaptJS puede desplegar aplicaciones en m煤ltiples nubes y tecnolog铆as, por lo que hay una tonelada de pruebas de sistemas y pruebas de extremo a extremo con Docker, Kubernetes, AWS, Google Cloud, etc. Hacemos un uso intensivo de Docker en nuestras pruebas, por lo que terminamos creando un mont贸n de contenedores de corta vida que se ponen en marcha, hacen algunos trabajos, como la construcci贸n o la instalaci贸n de una aplicaci贸n, y luego se eliminan. Y a medida que agreg谩bamos m谩s y m谩s de esas pruebas, empezamos a ver que las pruebas del sistema previamente estables fallaban al azar en la IC.

El s铆ntoma: tiempos de espera de prueba

Los primeros s铆ntomas que vimos fueron tiempos muertos. Tenemos tiempos de espera bastante cortos en muchas de nuestras pruebas de extremo a extremo para que podamos detectar si el nuevo c贸digo de repente hace que las cosas tomen m谩s tiempo para los usuarios finales. Pero ahora, una prueba que normalmente deber铆a durar medio segundo a veces durar铆a 5,5 segundos. 5 segundos adicionales eran una gran pista: 5 segundos sonaban como si pudiera ser un tiempo de espera de alg煤n tipo. Armados con esa corazonada, miramos hacia atr谩s a trav茅s de todas las fallas de las pruebas aparentemente aleatorias y encontramos el hilo com煤n: todas ellas eran pruebas que iniciaban las solicitudes de red. Tambi茅n hemos notado algunas pruebas que han tardado m谩s tiempo en fallar… siempre en incrementos de 5 segundos, no hab铆a demasiados protocolos de red que pudieran estar involucrados aqu铆, as铆 que algunas r谩pidas b煤squedas en Google nos han apuntado en la direcci贸n correcta. El tiempo de espera predeterminado para las consultas a servidores DNS en Linux es de 5 segundos, para ver qu茅 estaba pasando con el DNS, buscamos probablemente la herramienta m谩s importante para depurar problemas de red en Linux: tcpdump. Ejecutamos tcpdump en el sistema host (una instancia de Amazon Workspaces Linux) y usamos un filtro para ver el tr谩fico DNS:

$ tcpdump -n -i eth1 puerto 53
11:35:59:474735 IP 172.16.0.131.54264> 172.16.0.119.dominio: 64859+ AAAA? registry-1.docker.io. (38)
11:35:59:474854 IP 172.16.0.131.49631> 172.16.0.119.dominio: 43524+ A? registry-1.docker.io. (38)
11:35:59:476871 IP 172.16.0.119.dominio> 172.16.0.131.49631: 43524 8/0/1 A 34.197.189.129, A 34.199.40.84, A 34.199.77.19, A 34.201.196.144, A 34.228.211.243, A 34.232.31.24, A 52.2.186.244, A 52.55.198.220 (177)
11:35:59:476957 IP 172.16.0.119.dominio> 172.16.0.131.54264: 64859 0/1/1 (133)

La soluci贸n: una cach茅 de DNS Docker, usando dnsmasq


Para aislar el tr谩fico DNS dentro del host, necesit谩bamos un servidor DNS local que actuara como cach茅. Una gran opci贸n para una cach茅 como esta es dnsmasq. Es confiable, ampliamente utilizado y s煤per sencillo de configurar. La idea b谩sica es bastante simple: ejecutar un contenedor dnsmasq como cach茅 DNS en la red host del Docker y luego ejecutar nuestros contenedores de prueba con la opci贸n 
--dns

apuntando a la direcci贸n IP del contenedor de cach茅.
: "${IMAGE:=andyshinn/dnsmasq:2.76}"
: "${NAME:=dnsmasq}"
: "Obtener la direcci贸n IP de una interfaz, como visible desde el interior de un contenedor# conectado a la interfaz de red del host IP() {{ADAPT_DNS_IP_FILE:=/tmp/adapt_dns_ip}"# Obtener la direcci贸n IP de una interfaz, como visible desde el interior de un contenedor# conectado a la interfaz de red del host IP()
# Ejecutar un contenedor y obtener la salida de ifconfig desde dentro# Necesitamos el ifconfig que ser谩 visible desde dentro del contenedor dnsmaq
docker run --rm --net=host busybox ifconfig "$1" 2>/dev/null |
awk ` /inet /{print(gensub(/^.*inet (addr:)?([0-9.]+)s.*$/, "2", "1))}}".
}
si docker inspect --type container "${NAME}">& /dev/null ; then if [ -f "${ADAPT_DNS_IP_FILE}" ]; then# dnsmasq ya se ha iniciado
cat "${ADAPT_DNS_IP_FILE}"salida 0
elseecho Contenedor de cach茅 DNS ejecut谩ndose pero el archivo ${ADAPT_DNS_IP_FILE} no existe.>&2
salida 1
fifi# S贸lo soportamos la conexi贸n al puente por defecto (host) llamado "bridge".
DOCKER_HOST_NETWORK=puente
# Confirmar que "bridge" es el puente por defecto
IS_DEFAULT=$(la red del acoplador inspecciona "${DOCKER_HOST_NETWORK}" --formato {{(index.Options "com.docker.network.bridge.default_bridge")}})
if [ "${IS_DEFAULT}" != "true" ]; thenecho No puede iniciar la cach茅 DNS. La red Docker llamada "${DOCKER_HOST_NETWORK}Nno existe o no es el puente por defecto.>&2