Imaxes listas para a produción para k8s

Esta historia trata sobre como usamos os contedores nun ambiente de produción, concretamente Kubernetes. O artigo dedícase a recoller métricas e rexistros de contedores, así como a construír imaxes.

Imaxes listas para a produción para k8s

Somos da empresa fintech Exness, que desenvolve servizos para o comercio en liña e produtos fintech para B2B e B2C. O noso I+D ten moitos equipos diferentes, o departamento de desenvolvemento ten máis de 100 empregados.

Representamos ao equipo responsable da plataforma para que os nosos desenvolvedores recompilen e executen código. En particular, somos responsables de recoller, almacenar e informar de métricas, rexistros e eventos das aplicacións. Actualmente operamos aproximadamente tres mil contedores Docker nun ambiente de produción, mantemos o noso almacenamento de grandes datos de 50 TB e ofrecemos solucións arquitectónicas que se constrúen arredor da nosa infraestrutura: Kubernetes, Rancher e varios provedores de nube pública. 

A nosa motivación

Que arde? Ninguén pode responder. Onde está a lareira? É difícil de entender. Cando se incendiou? Podes descubrir, pero non de inmediato. 

Imaxes listas para a produción para k8s

Por que uns contedores están en pé mentres outros caeron? De que recipiente tivo a culpa? Despois de todo, o exterior dos contedores é o mesmo, pero no interior cada un ten o seu propio Neo.

Imaxes listas para a produción para k8s

Os nosos desenvolvedores son rapaces competentes. Fan bos servizos que traen beneficios á empresa. Pero hai fallos cando os contedores con aplicacións se desvían. Un contedor consome demasiada CPU, outro consome a rede, un terceiro consome operacións de E/S e o cuarto non está completamente claro o que fai cos sockets. Todo cae e o barco afunde. 

Axentes

Para entender o que está a pasar no interior, decidimos colocar axentes directamente en contedores.

Imaxes listas para a produción para k8s

Estes axentes son programas de contención que manteñen os contedores en tal estado que non se rompen entre si. Os axentes están estandarizados, e iso permite un enfoque estandarizado para o servizo de contedores. 

No noso caso, os axentes deben proporcionar rexistros nun formato estándar, etiquetados e limitados. Tamén deberían proporcionarnos métricas estandarizadas que sexan extensibles desde a perspectiva da aplicación empresarial.

Os axentes tamén significan utilidades de operación e mantemento que poden funcionar en diferentes sistemas de orquestración que admiten diferentes imaxes (Debian, Alpine, Centos, etc.).

Finalmente, os axentes deben admitir CI/CD sinxelos que inclúan ficheiros Docker. En caso contrario, o barco desmoronarase, porque os contedores comezarán a ser entregados por carrís "torcidos".

Proceso de construción e dispositivo de imaxe de destino

Para manter todo estandarizado e manexable, hai que seguir algún tipo de proceso de compilación estándar. Polo tanto, decidimos recoller contedores por contedores: isto é recursividade.

Imaxes listas para a produción para k8s

Aquí os recipientes están representados por contornos sólidos. Ao mesmo tempo, decidiron poñerlles kits de distribución para que "a vida non pareza framboesa". Por que se fixo isto, explicaremos a continuación.
 
O resultado é unha ferramenta de compilación, un contedor específico para a versión que fai referencia a versións de distribución específicas e versións de script específicas.

Como o usamos? Temos un Docker Hub que contén un contedor. Reflexímolo dentro do noso sistema para desfacernos das dependencias externas. O resultado é un recipiente marcado en amarelo. Creamos un modelo para instalar todas as distribucións e scripts que necesitamos no contedor. Despois diso, montamos unha imaxe lista para usar: os desenvolvedores poñen nel código e algunhas das súas propias dependencias especiais. 

Que ten de bo este enfoque? 

  • En primeiro lugar, control completo de versións das ferramentas de compilación: versións de contenedor de compilación, script e distribución. 
  • En segundo lugar, conseguimos a estandarización: creamos do mesmo xeito modelos, imaxe intermedia e lista para usar. 
  • En terceiro lugar, os contedores dannos portabilidade. Hoxe usamos Gitlab, e mañá cambiaremos a TeamCity ou Jenkins e poderemos executar os nosos contedores do mesmo xeito. 
  • En cuarto lugar, minimizar as dependencias. Non foi unha casualidade que puxeramos no contedor os kits de distribución, xa que isto permítenos evitar cada vez descargalos de Internet. 
  • En quinto lugar, aumentou a velocidade de compilación: a presenza de copias locais das imaxes permítelle evitar perder tempo na descarga, xa que hai unha imaxe local. 

Noutras palabras, conseguimos un proceso de montaxe controlado e flexible. Usamos as mesmas ferramentas para construír calquera contedor totalmente versionado. 

Como funciona o noso procedemento de construción

Imaxes listas para a produción para k8s

A montaxe lánzase cun comando, o proceso execútase na imaxe (resaltado en vermello). O programador ten un ficheiro Docker (resaltado en amarelo), nós renderizamos, substituíndo as variables por valores. E ao longo do camiño engadimos cabeceiras e pés de páxina: estes son os nosos axentes. 

A cabeceira engade distribucións a partir das imaxes correspondentes. E footer instala os nosos servizos dentro, configura o lanzamento da carga de traballo, rexistro e outros axentes, substitúe o punto de entrada, etc. 

Imaxes listas para a produción para k8s

Durante moito tempo pensamos se instalar un supervisor. Ao final, decidimos que o necesitabamos. Escollemos S6. O supervisor proporciona a xestión do contedor: permítelle conectarse a el se o proceso principal falla e proporciona unha xestión manual do contedor sen recrealo. Os rexistros e as métricas son procesos que se executan dentro do contedor. Tamén hai que controlar dalgún xeito, e facémolo coa axuda dun supervisor. Finalmente, o S6 encárgase da limpeza, procesamento de sinal e outras tarefas.

Dado que utilizamos diferentes sistemas de orquestración, despois de construír e executar, o contedor debe comprender en que ambiente se atopa e actuar segundo a situación. Por exemplo:
Isto permítenos construír unha imaxe e executala en diferentes sistemas de orquestración, e lanzarase tendo en conta as particularidades deste sistema de orquestración.

 Imaxes listas para a produción para k8s

Para o mesmo recipiente obtemos diferentes árbores de procesos en Docker e Kubernetes:

Imaxes listas para a produción para k8s

A carga útil execútase baixo a supervisión de S6. Preste atención ao colector e aos eventos: estes son os nosos axentes responsables dos rexistros e das métricas. Kubernetes non os ten, pero Docker si. Por que? 

Se observamos a especificación do "pod" (en diante - pod Kubernetes), veremos que o contenedor de eventos execútase nun pod, que ten un colector separado que realiza a función de recoller métricas e rexistros. Podemos utilizar as capacidades de Kubernetes: executar contedores nun só pod, nun único proceso e/ou espazo de rede. Presenta aos teus axentes e realiza algunhas funcións. E se o mesmo contedor se lanza en Docker, recibirá todas as mesmas capacidades que a saída, é dicir, poderá entregar rexistros e métricas, xa que os axentes lanzaranse internamente. 

Métricas e rexistros

A entrega de métricas e rexistros é unha tarefa complexa. Hai varios aspectos na súa decisión.
A infraestrutura créase para a execución da carga útil e non para a entrega masiva de rexistros. É dicir, este proceso debe realizarse cun mínimo de recursos de contedores. Esforzámonos por axudar aos nosos desenvolvedores: "Obtén un contedor Docker Hub, execútao e poderemos entregar os rexistros". 

O segundo aspecto é limitar o volume de rexistros. Se se produce un aumento no volume de rexistros en varios contedores (a aplicación produce un rastrexo de pila nun bucle), a carga na CPU, as canles de comunicación e o sistema de procesamento de rexistros aumenta, e isto afecta o funcionamento do host como un enteiros e outros recipientes no host, entón ás veces isto leva á "caída" do host. 

O terceiro aspecto é que é necesario admitir tantos métodos de recollida de métricas como sexa posible. Desde a lectura de ficheiros e a consulta de Prometheus-endpoint ata o uso de protocolos específicos da aplicación.

E o último aspecto é minimizar o consumo de recursos.

Escollemos unha solución Go de código aberto chamada Telegraf. Este é un conector universal que admite máis de 140 tipos de canles de entrada (complementos de entrada) e 30 tipos de canles de saída (complementos de saída). Xa o finalizamos e agora contarémosche como o usamos usando Kubernetes como exemplo. 

Imaxes listas para a produción para k8s

Digamos que un programador desprega unha carga de traballo e Kubernetes recibe unha solicitude para crear un pod. Neste punto, créase automaticamente un contedor chamado Collector para cada pod (usamos mutación webhook). O coleccionista é o noso axente. Ao principio, este contedor configúrase para funcionar con Prometheus e o sistema de recollida de rexistros.

  • Para iso, utiliza anotacións de pod e, dependendo do seu contido, crea, por exemplo, un punto final de Prometheus; 
  • En función da especificación da vaina e da configuración específica do recipiente, decide como entregar os rexistros.

Recollemos rexistros a través da API de Docker: os desenvolvedores só precisan poñelos en stdout ou stderr e Collector resolverao. Os rexistros recóllense en anacos con certo atraso para evitar unha posible sobrecarga do host. 

As métricas recóllense en instancias de carga de traballo (procesos) en contedores. Todo está etiquetado: espazo de nomes, baixo, etc., e despois convértese ao formato Prometheus, e queda dispoñible para a súa recollida (excepto os rexistros). Tamén enviamos rexistros, métricas e eventos a Kafka e máis:

  • Os rexistros están dispoñibles en Graylog (para análise visual);
  • Os rexistros, as métricas e os eventos envíanse a Clickhouse para o almacenamento a longo prazo.

Todo funciona exactamente igual en AWS, só que substituímos Graylog por Kafka por Cloudwatch. Enviamos os rexistros alí e todo resulta moi cómodo: inmediatamente queda claro a que clúster e recipiente pertencen. O mesmo ocorre con Google Stackdriver. É dicir, o noso esquema funciona tanto en local con Kafka como na nube. 

Se non temos Kubernetes con pods, o esquema é un pouco máis complicado, pero funciona cos mesmos principios.

Imaxes listas para a produción para k8s

Os mesmos procesos execútanse dentro do contedor, orquestráranse mediante S6. Todos os mesmos procesos están a executarse dentro do mesmo contedor.

Como resultado,

Creamos unha solución completa para crear e lanzar imaxes, con opcións para recoller e entregar rexistros e métricas:

  • Desenvolvemos un enfoque estandarizado para a montaxe de imaxes, e en base a el elaboramos modelos de CI;
  • Os axentes de recollida de datos son as nosas extensións de Telegraf. Probámolos ben na produción;
  • Usamos mutación webhook para implementar contedores con axentes en pods; 
  • Integrado no ecosistema Kubernetes/Rancher;
  • Podemos executar os mesmos contedores en diferentes sistemas de orquestración e obter o resultado que esperamos;
  • Creouse unha configuración de xestión de contedores completamente dinámica. 

Coautor: Ilya Prudnikov

Fonte: www.habr.com

Engadir un comentario