Esta publicación es una adaptación de una presentación de Kevin Reedy de Belly Card en nginx.conf en octubre de 2014. Si bien eso fue hace un par de años, el contenido sigue siendo muy relevante hoy en día. Puedes ver una grabación de la presentación en YouTube .
Tabla de contenido
Buenos días a todos. Mi nombre es Kevin Reedy y trabajo para una empresa llamada Belly Card con sede en Chicago. Contamos con unos cien empleados y veinte ingenieros. Hoy voy a hablarles sobre cómo realizamos nuestro balanceo de carga, específicamente en una infraestructura dinámica en constante cambio.
Primero, voy a contarles sobre nuestra pila de infraestructura a lo largo del tiempo, comenzando con la versión 0, a la que llamo la Edad Oscura. Luego, repasaremos cómo usamos Chef para configurar NGINX. Después, hablaremos de cómo hemos dejado de usar eso para usar datos de la plataforma de descubrimiento de servicios Consul para configurar NGINX. Si el tiempo lo permite, tengo algunos consejos profesionales para configurar NGINX, especialmente en lo que respecta a la gestión de la configuración.
Entonces, aunque voy a hablarles sobre Chef y Consul, quiero dejar claro que nada de lo que se dice en esta charla es específico de ellos. Chef, Puppet, Ansible, Salt, CFEngine y el resto son excelentes productos y deberías utilizar uno de ellos. Disfrutamos del Chef y estoy seguro que a mucha otra gente también.
Lo mismo ocurre con el descubrimiento de servicios. Consul, etcd y ZooKeeper son excelentes, así que usa el que funcione para ti.
¿Qué es el vientre? Básicamente, es un reemplazo digital de una tarjeta perforada en una cafetería donde compras diez bebidas y recibes una gratis. Colocamos un iPad en la tienda, los clientes escanean con su teléfono o una tarjeta física con un código QR, hacemos un seguimiento de sus puntos, otorgamos las recompensas y, de hecho, construimos herramientas de marketing sobre eso.
Pero no estoy aquí para hablaros de Belly como empresa. Si estás interesado en ello, puedes ir a nuestro sitio web . Voy a hablaros sobre nuestra pila de infraestructura.
Entonces la versión 0. Cuando éramos tres desarrolladores y antes de trabajar allí, Belly era una aplicação monolítica de Ruby on Rails, lo que significaba que cada llamada a la API y parte de nuestro sitio web se dirigía a una única aplicación de Rails. Estaba respaldada por MySQL, MongoDB y Memcached, y la implementamos en Heroku, un excelente punto de partida.
Así que versión 1 – Una nueva esperanza. Decidimos que Heroku ya no iba a satisfacer nuestras necesidades, así que comenzamos a implementar algo llamado Capistrano, que es esencialmente “mejor que un script de shell” escrito en Ruby. Te ayuda a implementar cosas.
Teníamos alrededor de seis servidores en Amazon Web Services EC2. Ese era un número estático, pero lo aumentábamos si sabíamos que estaba sucediendo algo importante y lo reducíamos si era necesario. Delante de eso teníamos AWS Elastic Load Balancer.
Entonces surgió un proyecto en el que queríamos separar nuestra página de inicio del resto de la API. Queríamos hacer esto para poder avanzar más rápido con nuestra página de inicio y tener diferentes desarrolladores trabajando en ella.
La palabra de moda en ese momento –y todavía hoy– era arquitectura orientada a servicios.
Entonces, la versión 2 de nuestra pila debía permitir la arquitectura orientada a servicios. Nuestro primer plan fue separar la página de inicio de la API. Parece muy sencillo: solo tenemos www.bellycard.com y api.bellycard.com .
Pero resultó ser realmente complejo y nada simple, porque algunas de nuestras aplicações móviles fueron escritas estáticamente para usar www.bellycard.com/api y /api‑assets . Nuestros proveedores de correo electrónico y todos nuestros enlaces de clic que ya se habían enviado por correo electrónico a las personas tenían /eo para “apertura de correo electrónico” y /ec para “clic en correo electrónico”. Nuestra aplicación de Facebook fue configurada en /facebook/callback .
Eso significaba que AWS Elastic Load Balancer ya no nos brindaba la flexibilidad que necesitábamos para enrutar este tráfico a diferentes aplicações. Entonces NGINX llegó para salvar el día. En concreto, podríamos tener múltiples upstreams y reescribir reglas para enrutar el tráfico a nuestras diferentes aplicações.
En este ejemplo muy básico definimos un bloque upstream
con seis servidores para la API y un bloque con dos servidores para la página de inicio.
También hay dos bloques de servidores
[que definen servidores virtuales]. En uno escuchamos api.bellycard.com y enrutamos todo ese tráfico a los servidores API. Por otro lado, escuchamos en www.bellycard.com y gestionamos las cosas en consecuencia.
Esto funcionó muy bien. Permitió a nuestros desarrolladores avanzar rápidamente. Nuestro equipo de frontend trabajaba en un proyecto sin que nuestra API los bloqueara. Así que implementamos un tercer servicio. Creo que fue para la integración con Passbook de Apple. Luego un cuarto: trasladamos todas nuestras funciones de Facebook. Nuestro quinto objetivo fue abordar los eventos de los usuarios en nuestro sitio web.
Luego alguien decidió que era una gran idea escribirlo en Node.js, así que ahora teníamos cinco servicios distintos en dos lenguajes. Todos se implementaron de forma independiente sin mucha gestión de configuración y estábamos editando NGINX manualmente, con lo que estoy seguro que mucha gente comienza.
Necesitábamos una mejor manera de escalar este proceso, así que lo hicimos con Chef.
Chef es una suite de gestión de configuración. Está escrito en Ruby y puedes escribir tu gestión de configuración real en Ruby, por lo que es fantástico para desarrolladores. learnchef.com es un recurso increíble para aprender sobre Chef; puede enseñarte mucho más sobre Chef de lo que yo puedo en 45 minutos.
Repasaré algunos conceptos básicos para que todos estemos en sintonía.
El primer tipo de bloque de construcción en Chef es una receta . El chef utiliza muchos nombres ingeniosos, como cuchillo como herramienta y receta , y todo está en un libro de cocina . Eso lo hace divertido y fácil de entender y proporciona una gran metáfora, pero también hace que sea muy difícil buscar cualquier cosa en Google.
Así que aquí está la receta más básica que se me ocurrió. Instale el paquete nginx
e inicie y habilite el servicio nginx
.
También puedes tener recursos de archivos. Por ejemplo, quiero escribir el contenido ¡Hola
mundo!
en el archivo /usr/share/NGINX/html/index.html .
También puedes incorporarlo en un sistema de plantillas. Aquí tengo un par de variables g
y w
para Hello
y Kevin
y puedo pasar estas variables a un archivo de plantilla, que está en formato ERB (un script de plantillas Ruby).
Entonces, en lugar de simplemente escribir el contenido manualmente, podemos escribir una plantilla para leer y saber a quién saludar.
El último bloque importante es un libro de cocina, que es una colección de recetas, archivos y plantillas. También recursos, proveedores y bibliotecas, que son recursos más complejos. Hay toneladas de libros de cocina de código abierto y otros en https://supermarket.getchef.com , incluidos algunos para NGINX, MySQL, Java, apt
y yum
, e incluso para administrar sus archivos ssh_known_hosts . Prácticamente todos los componentes básicos de lo que estás intentando hacer en la gestión de configuración ya los puedes encontrar en un libro de recetas.
Repasaremos un ejemplo muy rápido de NGINX con Chef, donde instalaremos NGINX y lo configuraremos cambiando un par de variables. Usaremos Chef para descubrir dónde se está ejecutando nuestra aplicação y luego configuraremos NGINX para enrutar el tráfico a nuestra aplicação.
Entonces, en este ejemplo, lo primero que hacemos es establecer algunos atributos de nodo. Para cada nodo, puedes establecer valores de atributos agregando un documento JSON. Utilizaremos un libro de recetas NGINX de terceros que busca configuraciones de estos atributos. Estamos configurandoworker_connections
a un valor determinado, la directivaworker_rlimit_nofile
, qué tipo de evento
vamos a usar en NGINX e incluso client_max_body_size
.
Después de eso, incluimos dos recetas del libro de cocina NGINX. El primero es nginx::repo , que configura un repositorio apt
o yum
dependiendo de su sistema operativo. Luego, [la receta de nginx ] instala NGINX. También puedes instalar NGINX desde el código fuente, pero usar paquetes es más rápido.
A continuación aprovechamos las capacidades de búsqueda de Chef. Cuando ejecutas Chef, puedes ejecutarlo como un agente en la máquina o puedes ejecutarlo en modo individual, que básicamente lo ejecuta como un script. Cuando tiene un agente en una máquina, puede consultar el servidor Chef para obtener nodos y otros atributos.
Aquí le pedimos al Chef que nos dé una lista de todos los nodos que tienen la receta belly-api adjunta. Después de eso, creamos un archivo de sitio llamado /sites‑enabled/api . Su fuente es la plantilla [archivo llamado api.erb que] os mostraré a continuación. Las variables que pasamos son los nodos que buscamos justo antes.
La última novedad aquí es una declaración de notificación
para recargar el servicio nginx . Esto indica que cada vez que esta plantilla cambie, quiero que vuelvas a cargar este servicio.
Así que nuestro archivo de plantilla aquí es bastante simple. Tenemos un upstream llamado api y en ERB iteramos sobre todos los servidores por los que pasamos como una variable, especificando el servidor por dirección IP y puerto 8080. Incluso incluimos un comentario con el nombre del servidor. Cuando un operador busca qué está pasando con este servicio, será un buen comentario para ellos.
También definimos un bloque de servidor
para escuchar en api.bellycard.com . Simplemente paso todo el tráfico a la API ascendente.
También quisiera ofrecer un ejemplo del mundo real. Quizás sea demasiado pequeño para que ustedes lo puedan leer, pero les permitirá tener una idea de cuán complicadas pueden llegar a ser las recetas de su chef. Esta es la plantilla y receta real de algunos de nuestros servidores de producción actuales.
Así que ahora volvamos a nuestra pila. Te dije que habíamos implementado alrededor de cinco aplicações y que todo iba muy bien. Ahora teníamos una forma de dirigir el tráfico hacia ellos, por lo que nuestros desarrolladores se hicieron cargo de esto y hoy tenemos alrededor de 40 aplicações Ruby implementadas en nuestros servidores usando Chef. El tráfico se enruta de forma completamente dinámica mediante NGINX.
Nuestros desarrolladores realmente no tienen que hacer nada más que editar una receta para incluir el nombre de su nuevo servicio. Todo el tráfico es enrutado por NGINX y configurado dinámicamente con Chef.
También teníamos alrededor de diez aplicações JavaScript frontend que son simplemente archivos estáticos que implementamos en S3 con un CDN, [Amazon] CloudFront, delante de él. Servimos index.html desde el depósito S3 y el resto de los activos estaban a través de CloudFront. También teníamos otras cinco aplicaciones que los desarrolladores enviaron a Heroku porque era algo único que eventualmente se convirtió en producción y nadie fue informado al respecto.
[Las cinco aplicaciones en Heroku] estaban separadas, completamente fuera de nuestra infraestructura, hasta un hermoso día de abril cuando se anunció el error Heartbleed. Mucha gente se apresuró. Heartbleed era un error en OpenSSL que permitía a las personas extraer potencialmente sus claves privadas.
Desde que usamos Chef, pudimos actualizar nuestra infraestructura OpenSSL en todas nuestras cajas tan pronto como hubo un parche disponible. Creo que se implementó en unos 20 minutos en toda nuestra infraestructura. Sin embargo, AWS (y por ende, Heroku) tardaron aproximadamente 24 horas en parchear sus Elastic Load Balancers.
Esto nos impulsó a trasladar todo nuestro equilibrio de carga y terminación SSL a NGINX, independientemente de dónde estuviera implementado: tanto S3 como Heroku. Esto supone una pequeña penalización, pero al menos ese día de abril para nosotros valió la pena.
Así, la versión 3 de nuestra pila pasó de ser “SOA todo en uno” a “SSL todo en uno”. Todo nuestro tráfico a bellycard.com y sus subdominios pasa a través de nuestros balanceadores de carga. En realidad, nuestros activos todavía se sirven desde CloudFront en un dominio diferente para mejorar el rendimiento. No queremos la sobrecarga que supone SSL y además solo somos un único centro de datos en la costa este.
Versión 4: la palabra de moda de la que todo el mundo habla este año es Docker. Como Docker estaba, creo, en la versión 0.5, nuestros desarrolladores estaban entusiasmados por comenzar a usarlo.
Las razones [para usar Docker] son simples.
Simplifica enormemente la implementación de aplicações. No hay recetas que escribir. No necesita preocuparse por cómo va a realizar la compilación de activos. No importa si estás escribiendo tu aplicación en Ruby cuando alguien más está escribiendo su aplicación en Python.
Básicamente, separa las responsabilidades de Desarrollo y Operaciones. Sus desarrolladores pueden preocuparse por el código, qué bibliotecas utilizar e incluso qué paquetes de Linux instalar. Las operaciones pueden preocuparse por más cosas como: ¿dónde voy a implementar esto? ¿Cómo voy a capturar el registro? ¿Cómo lo monitorizo? Una vez que hayas resuelto esos problemas y operaciones, todas las aplicação funcionarán, independientemente de cómo estén escritas.
Una ventaja de esto es que permite a nuestros desarrolladores activar fácilmente servicios dependientes en sus propias computadoras portátiles. Como mencioné, tenemos alrededor de 55 aplicações diferentes, muchas de las cuales ahora están en contenedores Docker.
Digamos que estás trabajando en un nuevo servicio para enviar campañas por correo electrónico. Depende del servicio de correo electrónico. Entonces, en su máquina de desarrollo normalmente descargaría el código, ejecutaría bundle
install
, lo iniciaría en segundo plano y "oh, pero en realidad eso depende de otro servicio, el servicio de usuario".
Ese servicio depende de algo más y de algo más. En realidad, el nuevo servicio de campañas de correo electrónico se basa en otros cinco servicios, además de MySQL, Elasticsearch, Redis y la lista continúa.
Con Docker podemos construir esos contenedores a partir de las mismas recetas de Chef que usamos en producción y proporcionar a nuestros desarrolladores contenedores que pueden descargar extremadamente rápido.
Esto acelera la implementación y el desarrollo.
Entonces, en la versión 4 pasamos de implementar nuestras aplicações usando Chef a implementarlas en contenedores. Hay muchísimas soluciones para ello y estoy seguro de que habrá aún más.
El primero es CoreOS y Fleet. CoreOS es un sistema operativo Linux simplificado que ejecuta un motor de descubrimiento de servicios sobre él llamado etcd . Fleet es una forma de definir cosas como "Quiero que un contenedor se ejecute cinco veces y no quiero que se ejecute en las mismas máquinas que este otro servicio".
Hay otro llamado Deis que es similar a Heroku en que tiene una interfaz Git Push. Está Mesos de Apache y Kubernetes de Google; Flynn es otro que salió recientemente. En realidad escribimos el nuestro porque cuando comenzamos este viaje la mayoría de estas herramientas no estaban en un lugar donde pudiéramos usarlas.
El nuestro se llama Jockey y ha funcionado muy bien porque nuestro proceso de implementación es extremadamente testarudo. Lo bueno de Docker es que básicamente proporciona un conjunto de API comunes para la contenedorización. No tenemos que preocuparnos por muchas cosas por las que tendríamos que preocuparnos si solo usáramos los contenedores LXC de Linux.
Tenemos pensado publicarlo en código abierto, pero como mencioné, las implementaciones son muy subjetivas y lo que funciona para nosotros puede no funcionar para usted.
Nuestra estrategia de implementación también cambió cuando nos pasamos a Docker. Anteriormente realizábamos implementaciones sin tiempo de inactividad implementando una nueva versión de la aplicação en el lugar. Esto significa que si tuviéramos ese servicio de fax de usuario en cuatro máquinas, usaríamos Chef para descargar la nueva versión, instalarla sobre [la versión anterior] y luego enviaríamos una señal al servidor web para recargarla. Unicorn es un excelente motor Ruby para hacer eso.
Sin embargo, los contenedores son inmutables. Una vez que tengas un contenedor en funcionamiento, si deseas realizar una nueva compilación deberás crear un nuevo contenedor. Puedes adjuntarlo, ejecutar comandos adicionales y luego guardarlo, tal como lo harías en Git. Pero realmente, si quieres sacar el máximo provecho de Docker, tu contenedor debe ser completamente inmutable.
Eso significa que tuvimos que idear una nueva estrategia de implementación porque ya no podemos realizar la implementación en el lugar. Hay algunos por ahí. El azul verdoso es un color interesante. Aquí es donde, si tiene una aplicação ejecutándose en cuatro máquinas, la ejecuta en cuatro máquinas nuevas y hace que su balanceador de carga apunte a las nuevas máquinas. Una vez que estés seguro de que realmente funciona como esperas, puedes desmontar el azul, y el verde se convierte en azul. Amazon cuenta con herramientas realmente excelentes para hacer esto con AWS.
También existen implementaciones “canarias” en las que implemento una versión de la nueva máquina, la superviso y, si pasa las verificaciones de métricas y de estado, puedo continuar con la implementación.
La diferencia con los contenedores es que en realidad los vas a desmantelar y crear nuevos, por lo que necesitas algún tipo de sistema para rastrear la ubicación de cada aplicação que se ejecuta en tu infraestructura.
De hecho, ser chef se está convirtiendo en una muy buena manera de hacerlo. Hay un libro de recetas que se está fusionando llamado Chef Metal que le permite tratar los contenedores como cualquier otro recurso que trataría en su infraestructura de Chef.
También existe el descubrimiento de servicios. ZooKeeper es una herramienta muy popular que se utiliza en todo Hadoop. [Airbnb] tiene un excelente producto llamado SmartStack que permite realizar implementaciones y realizar un seguimiento de ellas en ZooKeeper.
Mencioné etcd , que es esencialmente un almacén de valores clave distribuido con una interfaz REST. Esto es fantástico en comparación con ZooKeeper, que es más bien una biblioteca de cliente Java, porque ahora puedes comunicarte con etcd desde cualquiera de tus aplicações. Muchas de esas plataformas como servicio de código abierto que mencioné antes (como Deis, Flynn e incluso Kubernetes de Google) utilizan etcd. Si está usando CoreOS, etcd ya está ahí para usted y está integrado.
Ha salido otro, también basado en REST, se llama Consul . Lo lanzó la gente de HashiCorp, que crea Vagrant y Packer y muchas otras herramientas increíbles. En realidad, decidimos utilizar Consul.
Aquí hay un diagrama de los conceptos básicos de Consul. Puedes ver que hay varios centros de datos, cada uno con tres servidores. En el Data Center 1 también hay clientes. Lo interesante es que entre tus agentes de servidor elegirás un agente principal y luego todos tus clientes estarán al tanto no solo de todos los servidores sino también de todos los demás clientes. Luego utilizan un protocolo de chismes para comunicarse con todos los demás agentes.
Me recuerda a un viejo comercial de AT&T donde le dices a dos amigos que le dicen a dos amigos y ellos le dicen a dos amigos y el mensaje se propaga de esa manera por toda tu red de nodos. [ Editor – Bueno, cierre: era un comercial para el champú Faberge Organics ]. Esto se compara con etcd o ZooKeeper donde esencialmente solo tienes agentes de servidor y tus clientes se conectan a ellos.
Con la forma en que Consul hace las cosas, en realidad ejecutarías un cliente Consul en prácticamente todos los servidores, en todos los lugares donde implementamos Docker y en todos los lugares donde ejecutamos nuestros balanceadores de carga. De esta forma siempre podrás hablar con esa API en el puerto local 8500.
Al igual que etcd, [Consul] es un almacén de valores clave distribuido. Puedes configurar y obtener claves y estas mantendrán la linealidad para que puedas asegurarte de que siempre sean consistentes. Hay algunos problemas allí, pero su documentación sobre dónde están esos problemas es fenomenal. Sin embargo, a diferencia de etcd, tratan el descubrimiento de servicios como un ciudadano de primera clase.
En lugar de solo pares clave-valor, también puedes registrar servicios, por ejemplo, una API. Al registrar un servicio, le indicas a Consul en qué nodo se ejecuta. Esto significa que cuando implementamos un contenedor, también le decimos a Consul que registre esta API de servicio en este host también.
Además de eso, Consul ha distribuido controles de estado, por lo que ahora puede definir controles de estado al estilo Nagios directamente dentro de su plataforma de descubrimiento de servicios. Cuando decida consultar a Consul, puede solicitar una lista de todas las ubicaciones donde se ejecuta el servicio API. Puedes enviar una bandera para “todos”, “solo pasantes” o “solo insalubres”.
También tiene soporte para múltiples centros de datos. Mencioné que deberías ejecutar ese cliente Consul en todas partes. Al iniciarlo, pasa un parámetro que especifica el centro de datos. Si tiene un Centro de Datos Este y un Centro de Datos Oeste, puede consultar a su cliente Consul local sin tener que conocer el centro de datos, pedir una dirección o algo así.
En realidad, utilizamos el centro de datos como límite para nuestros entornos de preparación y producción. Nuestra configuración para una aplicação en etapa de prueba podría decir: "pregúnteme dónde está MySQL.services.consul ". Ya sea que se ejecute en un nodo de prueba o en un nodo de producción, obtendrá el valor correcto sin tener que ser consciente del centro de datos o de múltiples entornos.
La otra cosa genial sobre esto (y también sobre etcd) es que tiene un sondeo largo en su interfaz HTTP. Esto significa que puedes consultar y solicitar una lista de todos los servidores que ejecutan este servicio, pero también mantener la conexión abierta durante 60 segundos y recibir una notificación de inmediato si algo cambia. El tiempo de votación puede llegar a durar hasta 10 minutos. Esto significa que puede recibir notificaciones instantáneas de cualquier cambio en su infraestructura.
La otra cosa que ya mencioné es que puedes desarrollar la capacidad de ampliar tus agentes al tener clientes en todas partes. Esto es genial porque siempre puedes hablar con localhost.
La gran pregunta, sin embargo, es: ahora que tengo estos datos en una plataforma de descubrimiento de servicios distribuidos, ¿cómo configuro NGINX a partir de los datos?
Afortunadamente, existe una herramienta llamada Consul Template . Literalmente se publicó ayer, lo que me hizo cambiar mis diapositivas para hoy a partir de este momento. Solía llamarse “Consul HAProxy”, que era un nombre terrible porque en realidad no era específico de HAProxy.
Consul Template le ofrece una interfaz muy sencilla para crear plantillas para suscribirse a cambios en los servicios, a los controles de estado de dichos servicios e incluso a un almacén de valores clave. Esto es para que pueda almacenar configuraciones como [la cantidad de] trabajadores NGINX dentro del almacén de clave-valor y regenerar su configuración cuando eso cambie.
La gran capacidad aquí es generar archivos a partir de plantillas, lo que suena muy similar a lo que hacíamos antes con Chef. La mayor diferencia aquí es que utiliza el lenguaje de plantillas Golang en lugar de ERB, que es Ruby. Una vez que cambia un archivo, puede opcionalmente llamar un comando sobre el cambio, por ejemplo, service
nginx
reload
.
A continuación se muestra un ejemplo de cómo ejecutar Consul Template en la línea de comandos. Lo apunta a su host Consul real, que en este caso es consul‑prod.example.com . En un entorno de producción real, sugeriría ejecutar Consul en todas partes y conectarse al host local.
Luego, pasa un archivo de plantilla, que es una plantilla de Golang. En nuestro caso, pasamos /etc/consul‑templates/api . Luego, pasa qué archivo escribir realmente, en nuestro caso /etc/NGINX/sites‑enabled/api . Luego un comando para llamar: service
nginx
reload
.
La plantilla Consul se parece mucho a una diapositiva que tenía antes, excepto que en lugar de ERB es Golang. Así que definimos aquí dos corrientes arriba. Uno se llama api y el otro se llama pagina de inicio . Tenemos una declaración de rango
para la API de servicio y hay variables integradas para obtener la IP y el puerto donde realmente se ejecuta ese servicio.
Lo bueno de Consul Template y de usarlo de esta manera es que la convergencia en los cambios de servicio es rápida. Antes de implementar con Docker, teníamos Chef ejecutándose cada 5 o 10 minutos, dependiendo de la máquina. Eso fue lo suficientemente rápido para nosotros porque estábamos desplegándonos en el lugar.
Ahora que estamos construyendo un sistema de implementación más avanzado, necesitamos tener notificaciones de esos cambios en segundos en lugar de minutos. En realidad lo obtenemos en milisegundos, en promedio probablemente alrededor de 200 milisegundos.
Sin embargo, todavía se necesita la gestión de la configuración para generar plantillas. No podemos simplemente reemplazar al Chef por el Cónsul. Todavía tenemos que averiguar cómo vamos a implementar Consul y Consul Template y todo.
En realidad, utilizamos plantillas de Chef para implementar nuestras plantillas de Consul, lo que parece un poco complicado. Lo primero que hacemos en nuestra receta del Chef es consultar a nuestro anfitrión Cónsul para obtener una lista de todos los servicios. Luego generamos una plantilla de Consul [con las declaraciones de plantilla
y fuente
] y pasamos nuestro certificado SSL y las ubicaciones de las claves y recargamos consul‑template
. [ Editor: el Sr. Reedy inicialmente se refirió a consul‑haproxy
, que aparece en la primera declaración de notificaciones
en la diapositiva. Luego se corrigió y aclaró que la diapositiva es anterior al lanzamiento de Consul Template. ]
También escribimos un archivo de configuración para la plantilla de Consul y pasamos [variables que especifican] el host de Consul, la fuente, el destino y el comando de recarga. Esto es realmente la esencia de cómo usamos Chef y Consul juntos para obtener actualizaciones instantáneas de nuestras configuraciones NGINX.
A continuación tengo algunos consejos profesionales sobre Chef, Consul y la configuración de NGINX en general.
El primer consejo es que si utilizas la búsqueda de Chef para encontrar dónde se ejecutan tus servicios, deberías consultar la búsqueda parcial de Chef. El problema con la búsqueda de Chef es que hace una copia del nodo completo, incluidos todos los atributos. Si guardas muchas cosas en los atributos de tu nodo, tendrás que pasarlas por el cable mientras hablas con tu servidor Chef y también almacenarlas en la memoria.
Si la búsqueda de Chef devuelve cientos o miles de servidores, podrás ver fácilmente cómo podrías quedarte sin memoria para tu receta real. La búsqueda parcial le permite devolver solo las claves que le interesan.
Por ejemplo, primero tuvimos
nodos = buscar(:nodo, 'receta:belly-api')
Esa búsqueda devuelve toda la información sobre cada objeto. Esto incluye información sobre su espacio en disco, RAM, CPU y todas las aplicações que han escrito sus propios atributos de nodo.
En lugar de ello, podemos utilizar una búsqueda parcial en la que creamos un nuevo hash llamado search_keys
y le damos una lista de claves que nos interesan: en este caso, solo el nombre y la dirección IP. Luego llegamos a una API muy similar llamada partial_search
y pasamos el parámetro adicional [ keys
].
La segunda cosa que nos molestó cuando pasamos al equilibrio de carga frente a S3 y Heroku es que NGINX usa DNS para resolver los nombres de host en los bloques ascendentes
solo en la recarga de la configuración. Esto significa que si está configurando un servidor ascendente en s3.amazonaws.com o any.herokuapp.com y cambia, su balanceador de carga no sabrá acerca de la nueva dirección IP hasta la próxima recarga.
La forma de solucionar esto es realizar la resolución de DNS en Chef y luego activar la recarga de NGINX cuando eso cambia. Esto generó un segundo problema: [el orden de las direcciones en una respuesta DNS] no siempre es el mismo, así que asegúrese de ordenar también la respuesta antes de escribirla en su plantilla.
El otro problema al implementar una gran cantidad de servicios es evitar una configuración obsoleta. [ Editor: El Sr. Reedy pausa brevemente la presentación para responder una pregunta del público]. En Apache, NGINX y otros sistemas UNIX, un patrón de configuración común es tener una carpeta conf.d y luego cargar todo desde ella. Entonces, si implemento los servicios A, B y C, creo service-a.conf , service-b.conf y service-c.conf .
Luego decido reemplazar el servicio B con D, y ahora tengo cuatro configuraciones en la carpeta de configuración NGINX, pero el servicio B ya no existe. Podrías terminar con conflictos entre B y D porque tienen un nombre de host similar.
Hay dos formas en las que hemos abordado esto [eliminar la configuración obsoleta] en el pasado. Con las plantillas puedes agregar una función :delete
, pero esto se volvió un poco difícil de manejar muy rápidamente. Básicamente teníamos una lista de servicios antiguos que siempre intentábamos eliminar si existían. Eso realmente no se expandió.
Otra cosa que puedes hacer es renderizar todas las configuraciones de tu sitio en un solo archivo. Mucha gente se ha referido a esto como “mover la idempotencia hacia arriba”. Básicamente, en lugar de tener una configuración NGINX que se carga desde múltiples fuentes, colóquela toda en su nginx.conf .
Eso lo hace un poco difícil de manejar cuando realmente estás iniciando sesión en el equipo, pero con suerte estamos llegando al punto en el que no estás solucionando problemas de un archivo de configuración en vivo en producción. Si aún resulta un poco difícil de manejar en tus recetas de Chef, lo que hacemos es tener un nginx.conf que carga una serie de sitios diferentes. Por ejemplo, uno de los archivos de configuración de nuestro sitio enumera alrededor de 30 servicios, y luego tenemos uno para Heroku, uno para todos los S3, etc.
Entonces, si procesas todas las configuraciones de tu sitio en un solo archivo o en una pequeña cantidad de ellos, no tendrás que preocuparte por limpiar lo que ya hiciste. Si desde el punto de vista de Chef un servicio desaparece, Chef simplemente deja de representarlo en el archivo real.
P: ¿Cómo ha funcionado Consul para usted hasta ahora?
A: Nos ha encantado Consul, y lo que realmente me gusta de él en comparación con algo como etcd es que hay servicios que siguen desarrollándose sobre él. No tengo que preocuparme por el descubrimiento de servicios. De hecho, si tiene aplicações heredadas e implementa (digamos) sus servidores MySQL utilizando Consul, Consul también proporciona una interfaz DNS.
Su aplicação no necesita conocer Consul; puede simplemente consultar "¿qué dirección obtengo de mysqldb.services.consul ?". En este caso, Consul es el servidor DNS. Configura tu infraestructura DNS de modo que si el TLD [dominio de nivel superior] termina en .consul
, la consulta se dirija a Consul.
Para nosotros ha sido una gran mejora. Estamos ejecutando aproximadamente 3 nodos en producción para agentes de servidor y alrededor de 60 clientes. No hemos tenido ningún contratiempo. Siguen añadiendo funciones y no rompen la compatibilidad con versiones anteriores, por lo que la actualización siempre ha sido genial.
P: ¿Utiliza NGINX Plus?
A: No lo hacemos. Precisamente por eso nos planteamos esto cuando empezamos a trabajar con Consul. Si no necesitáramos un sistema de plantillas, sería fantástico porque podríamos tener un script que escuche ese sondeo largo HTTP y luego hable con la API NGINX en su nombre. El único problema es que probablemente también quieras un sistema de plantillas en caso de que NGINX se reinicie. Recargaría sus configuraciones ascendentes allí mismo.
También hay algún trabajo que otras personas han realizado en NGINX Lua para consultar a Consul directamente. Aún no he visto una buena implementación, porque tienden a caer en una de dos categorías. Lo primero es que consultan a Consul en cada solicitud HTTP, lo cual es lento. El segundo es que lo cargan en el tiempo de ejecución de la configuración y terminas con el mismo problema que tienes con DNS. Por ahora lo mejor es utilizar plantillas, pero no me sorprendería que en el futuro encontremos una forma de hacerlo con NGINX Lua.
P: ¿Alguna vez te alejarías del Chef?
A: No hay una buena manera integrada en Consul de mantener esas plantillas, y ya estamos implementando NGINX con Chef. Nuestras recetas tienen cientos, si no miles, de líneas de largo en este momento para todas las otras cosas que estamos haciendo con NGINX, incluidos el registro, el rastreo y algo de OAuth. No creo que vayamos a dejar de usar Chef en nuestra infraestructura para reemplazarlo, pero es una gran mejora y una buena manera de recibir notificaciones rápidas.
P: ¿Cuántos gastos generales proporciona Chef?
A: Dado que la mayoría de nuestras máquinas realizan una única tarea, nuestros gastos generales reales como Chef son bastante bajos. El uso de RAM es bajo mientras está inactivo. En realidad, se encuentra en un temporizador y puede bifurcarse. Otras personas también lo ejecutan en un cron
si no les importa la velocidad con la que converge. Observamos un pequeño aumento en la CPU en algunas de nuestras recetas más pesadas, pero nada que no podamos solucionar implementando otro servidor.
P: ¿Cuánto has hecho con CloudFormation?
A: Todavía no utilizamos CloudFormation. Está en nuestro radar, pero un cambio que hemos realizado es utilizar muchos más grupos de escalamiento automático. La forma en que funcionará es que cuando surge una instancia, tendrá datos de usuario que contienen su lista de ejecución de Chef.
Una nueva máquina se incorporará a un clúster con una clave ya basada en su imagen, de modo que podrá comunicarse con nuestro servidor Chef, registrarse y descargar los libros de cocina que necesita. Eso resuelve la mayoría de los problemas de CloudFormation para nosotros porque no usamos muchas otras herramientas de AWS que funcionarían de la mano con eso.
P: ¿Cómo actuar si se destruye un servidor?
A: Si un servidor desaparece de un grupo de escalamiento automático, puedes usar Amazon SNS [Servicio de notificación simple] para recibir una notificación al respecto. Tenemos un servicio muy simple que escucha esas notificaciones y luego limpia el servidor Chef.
P: ¿Has utilizado OpsWorks de AWS?
A: No lo hemos hecho. Hemos estado usando el Chef alojado desde el principio y nos ha funcionado muy bien. No estoy seguro de esto, pero creo que OpsWorks es más como Chef Solo, donde lo usas solo para aprovisionamiento. Todavía ejecutamos Chef Agent en casi todas nuestras máquinas y usamos esas mismas recetas de Chef para generar contenedores Docker para el desarrollo.
"Esta publicación de blog puede hacer referencia a productos que ya no están disponibles o que ya no reciben soporte. Para obtener la información más actualizada sobre los productos y soluciones F5 NGINX disponibles, explore nuestra familia de productos NGINX . NGINX ahora es parte de F5. Todos los enlaces anteriores de NGINX.com redirigirán a contenido similar de NGINX en F5.com.