Ampliación e complementación de Kubernetes (revisión e informe de vídeo)

Ampliación e complementación de Kubernetes (revisión e informe de vídeo)

8 de abril na conferencia Saint HighLoad++ 2019, dentro do apartado “DevOps e Operacións”, entregouse un informe “Ampliando e complementando Kubernetes”, en cuxa creación participaron tres empregados da empresa Flant. Nela, falamos de numerosas situacións nas que queriamos ampliar e complementar as capacidades de Kubernetes, pero para as que non atopamos unha solución preparada e sinxela. Temos as solucións necesarias en forma de proxectos de código aberto, e este discurso tamén está dedicado a eles.

Por tradición, temos o pracer de presentar vídeo do informe (50 minutos, moito máis informativo que o artigo) e o resumo principal en forma de texto. Vaia!

Núcleo e adicións en K8s

Kubernetes está cambiando a industria e os enfoques da administración que se establecen desde hai tempo:

  • Grazas a el abstraccións, xa non operamos con conceptos como configurar unha configuración ou executar un comando (Chef, Ansible...), senón que utilizamos agrupación de contedores, servizos, etc.
  • Podemos preparar aplicacións sen pensar nos matices do sitio específico, sobre o que se lanzará: bare metal, nube dun dos provedores, etc.
  • Con K8s nunca estiveches máis accesible mellores prácticas sobre a organización da infraestrutura: técnicas de escalado, autocuración, tolerancia a fallos, etc.

Non obstante, por suposto, non todo é tan sinxelo: Kubernetes tamén trouxo os seus novos retos.

Kubernetes non é unha combinada que resolve todos os problemas de todos os usuarios. O núcleo Kubernetes só é responsable dun conxunto das funcións mínimas necesarias que están presentes en cada cluster:

Ampliación e complementación de Kubernetes (revisión e informe de vídeo)

O núcleo de Kubernetes define un conxunto básico de primitivos para agrupar contedores, xestionar o tráfico, etc. Falamos deles con máis detalle en informe hai 2 anos.

Ampliación e complementación de Kubernetes (revisión e informe de vídeo)

Por outra banda, K8s ofrece grandes oportunidades para ampliar as funcións dispoñibles, que axudan a pechar outras: específico - necesidades dos usuarios. As adicións a Kubernetes son responsabilidade dos administradores do clúster, que deben instalar e configurar todo o necesario para que o seu clúster "estea na forma correcta" [para resolver os seus problemas específicos]. Que tipo de engadidos son estes? Vexamos algúns exemplos.

Exemplos de complementos

Unha vez instalado Kubernetes, podemos sorprendernos de que a rede tan necesaria para a interacción dos pods tanto dentro dun nodo como entre nós non funcione por si só. O núcleo de Kubernetes non garante as conexións necesarias, senón que determina a rede a interface (CNI) para complementos de terceiros. Debemos instalar un destes complementos, que se encargará da configuración da rede.

Ampliación e complementación de Kubernetes (revisión e informe de vídeo)

Un exemplo próximo son as solucións de almacenamento de datos (disco local, dispositivo de bloqueo de rede, Ceph...). Inicialmente estaban no núcleo, pero coa chegada CSI a situación cambia a algo semellante ao xa descrito: a interface está en Kubernetes e a súa implementación en módulos de terceiros.

Outros exemplos inclúen:

  • Ingreso- controladores (ver a súa revisión en o noso artigo recente).
  • xestor-cert:

    Ampliación e complementación de Kubernetes (revisión e informe de vídeo)

  • Operadores é toda unha clase de complementos (que inclúe o xestor de certificados mencionado), definen primitivos e controladores. A lóxica do seu traballo está limitada só pola nosa imaxinación e permítenos converter compoñentes de infraestrutura prefabricados (por exemplo, un DBMS) en primitivos, que son moito máis fáciles de traballar (que cun conxunto de contedores e a súa configuración). Escribiuse un gran número de operadores, aínda que moitos deles aínda non estean listos para a produción, é só cuestión de tempo:

    Ampliación e complementación de Kubernetes (revisión e informe de vídeo)

  • Métricas - outra ilustración de como Kubernetes separou a interface (API de Metrics) da implementación (complementos de terceiros como o adaptador Prometheus, o axente de clúster Datadog...).
  • Para seguimento e estatística, onde na práctica non só son necesarios Prometeo e Grafana, pero tamén kube-state-metrics, node-exporter, etc.

E esta non é unha lista completa de incorporacións... Por exemplo, na empresa Flant que instalamos actualmente 29 engadidos (todos os cales crean un total de 249 obxectos Kubernetes). En pocas palabras, non podemos ver a vida dun cluster sen adicións.

Automatización

Os operadores están deseñados para automatizar as operacións rutineiras que atopamos todos os días. Aquí tes exemplos da vida real para os que escribir un operador sería unha excelente solución:

  1. Hai un rexistro privado (é dicir, que require un inicio de sesión) con imaxes para a aplicación. Suponse que a cada pod se lle asigna un segredo especial que permite a autenticación no rexistro. A nosa tarefa é asegurarnos de que este segredo se atope no espazo de nomes para que os pods poidan descargar imaxes. Pode haber moitas aplicacións (cada unha delas precisa dun segredo), e é útil actualizar os segredos regularmente, polo que se elimina a opción de expor segredos a man. Aquí é onde o operador acude ao rescate: creamos un controlador que esperará a que apareza o espazo de nomes e, en función deste evento, engadirá un segredo ao espazo de nomes.
  2. Prohíbese por defecto o acceso desde pods a Internet. Pero ás veces pode ser necesario: é lóxico que o mecanismo de permisos de acceso funcione de forma sinxela, sen requirir habilidades específicas, por exemplo, pola presenza dunha determinada etiqueta no espazo de nomes. Como nos pode axudar o operador aquí? Créase un controlador que agarda a que a etiqueta apareza no espazo de nomes e engade a política adecuada para o acceso a Internet.
  3. Unha situación semellante: supoñamos que necesitamos engadir un determinado mancha, se ten unha etiqueta semellante (con algún tipo de prefixo). As accións co operador son obvias...

En calquera clúster hai que resolver as tarefas rutineiras e correctamente isto pódese facer mediante operadores.

Resumindo todas as historias descritas, chegamos á conclusión de que para un traballo cómodo en Kubernetes que necesitas: A) instalar complementos, b) desenvolver operadores (para resolver tarefas administrativas cotiás).

Como escribir unha declaración para Kubernetes?

En xeral, o esquema é sinxelo:

Ampliación e complementación de Kubernetes (revisión e informe de vídeo)

... pero despois resulta que:

  • A API de Kubernetes é unha cousa bastante non trivial que leva moito tempo dominar;
  • a programación tampouco é para todos (a linguaxe Go foi escollida como a linguaxe preferida porque hai un marco especial para iso - SDK do operador);
  • A situación é semellante co propio marco.

A liña inferior: para escribir un controlador (operador) ten que gastar recursos importantes para estudar material. Isto estaría xustificado para operadores "grandes", por exemplo, para o DBMS MySQL. Pero se lembramos os exemplos descritos anteriormente (desvelar segredos, acceder a pods a Internet...), que tamén queremos facer correctamente, entenderemos que o esforzo dedicado superará o resultado que necesitamos agora:

Ampliación e complementación de Kubernetes (revisión e informe de vídeo)

En xeral, xorde un dilema: gastar moitos recursos e atopar a ferramenta adecuada para escribir declaracións, ou facelo á antiga usanza (pero rápido). Para solucionalo -para atopar un compromiso entre estes extremos- creamos o noso propio proxecto: operador de shell (ver tamén o seu anuncio recente no hub).

Operador Shell

Como traballa? O clúster ten un pod que contén un binario Go cun operador de shell. Ao seu carón hai un conxunto de ganchos (máis detalles sobre eles - ver a continuación). O propio operador de shell subscribe certos eventos na API de Kubernetes, ao producirse o cal lanza os correspondentes ganchos.

Como sabe o operador de shell que hooks chamar a que eventos? Esta información transmítese ao operador do shell polos propios ganchos, e fano de forma moi sinxela.

Un gancho é un script Bash ou calquera outro ficheiro executable que acepte un único argumento --config e responde con JSON. Este último determina cales son os obxectos que lle interesan e que eventos (para estes obxectos) deben responderse:

Ampliación e complementación de Kubernetes (revisión e informe de vídeo)

Ilustrarei a implementación no operador de shell dun dos nosos exemplos: descompoñer segredos para acceder a un rexistro privado con imaxes de aplicacións. Consta de dúas etapas.

Práctica: 1. Escribir un gancho

En primeiro lugar, no gancho procesaremos --config, indicando que nos interesan os espazos de nomes, e concretamente, o momento da súa creación:

[[ $1 == "--config" ]] ; then
  cat << EOF
{
  "onKubernetesEvent": [
    {
      "kind": "namespace",
      "event": ["add"]
    }
  ]
}
EOF
…

Como sería a lóxica? Tamén moi sinxelo:

…
else
  createdNamespace=$(jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH)
  kubectl create -n ${createdNamespace} -f - << EOF
Kind: Secret
...
EOF
fi

O primeiro paso é descubrir que espazo de nomes foi creado, e o segundo é crealo usando kubectl segredo para este espazo de nomes.

Práctica: 2. Montaxe da imaxe

Todo o que queda é pasar o gancho creado ao operador de shell - como facelo? O propio operador de shell vén como unha imaxe de Docker, polo que a nosa tarefa é engadir o gancho a un directorio especial nesta imaxe:

FROM flant/shell-operator:v1.0.0-beta.1
ADD my-handler.sh /hooks

Só queda montalo e empurralo:

$ docker build -t registry.example.com/my-operator:v1 .
$ docker push registry.example.com/my-operator:v1

O toque final é despregar a imaxe no clúster. Para iso, imos escribir desenvolvemento:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: my-operator
spec:
  template:
    spec:
      containers:
      - name: my-operator
        image: registry.example.com/my-operator:v1 # 1
      serviceAccountName: my-operator              # 2

Hai dous puntos aos que prestar atención:

  1. indicación da imaxe de nova creación;
  2. Este é un compoñente do sistema que (como mínimo) necesita dereitos para subscribirse a eventos en Kubernetes e para asignar segredos aos espazos de nomes, polo que creamos unha ServiceAccount (e un conxunto de regras) para o gancho.

Resultado: resolvemos o noso problema parentes para Kubernetes de forma que cree un operador para descompoñer segredos.

Outras características do operador de shell

Para limitar os obxectos do tipo escollido cos que traballará o gancho, pódense filtrar, seleccionando segundo determinadas etiquetas (ou usando matchExpressions):

"onKubernetesEvent": [
  {
    "selector": {
      "matchLabels": {
        "foo": "bar",
       },
       "matchExpressions": [
         {
           "key": "allow",
           "operation": "In",
           "values": ["wan", "warehouse"],
         },
       ],
     }
     …
  }
]

Fornecido mecanismo de deduplicación, que, usando un filtro jq, permite converter obxectos JSON grandes en pequenos, onde só quedan aqueles parámetros que queremos supervisar para detectar cambios.

Cando se chama un gancho, o operador de shell pásao datos do obxecto, que se pode utilizar para calquera necesidade.

Os eventos que desencadean hooks non se limitan aos eventos de Kubernetes: o operador de shell ofrece soporte para chamando ganchos polo tempo (semellante ao crontab nun programador tradicional), así como un evento especial onStartup. Todos estes eventos pódense combinar e asignar ao mesmo gancho.

E dúas características máis do shell-operator:

  1. Funciona de forma asíncrona. Dado que se recibiu un evento de Kubernetes (como un obxecto que se está a crear), outros eventos (como o mesmo obxecto que se elimina) poderían ocorrer no clúster e os ganchos deben ter en conta isto. Se o gancho se executou cun erro, será por defecto volver chamar ata completar con éxito (este comportamento pódese cambiar).
  2. Exporta métricas para Prometheus, co que pode entender se o operador de shell está a traballar, descubra o número de erros para cada gancho e o tamaño da cola actual.

Para resumir esta parte do informe:

Ampliación e complementación de Kubernetes (revisión e informe de vídeo)

Instalando complementos

Para un traballo cómodo con Kubernetes, tamén se mencionou a necesidade de instalar complementos. Falareino usando o exemplo do camiño da nosa empresa cara a como o facemos agora.

Comezamos a traballar con Kubernetes con varios clústeres, a única adición que foi Ingress. Necesitaba instalarse de forma diferente en cada clúster, e fixemos varias configuracións de YAML para diferentes ambientes: bare metal, AWS...

Como había máis clusters, había máis configuracións. Ademais, melloramos estas propias configuracións, polo que se fixeron bastante heteroxéneas:

Ampliación e complementación de Kubernetes (revisión e informe de vídeo)

Para poñer todo en orde, comezamos cun guión (install-ingress.sh), que tomou como argumento o tipo de clúster no que despregaremos, xerou a configuración YAML necesaria e lanzouno a Kubernetes.

En resumo, o noso camiño posterior e o razoamento asociado a el foron os seguintes:

  • para traballar con configuracións YAML, requírese un motor de modelos (nas primeiras fases isto é simple sed);
  • co aumento do número de clústeres chegou a necesidade dunha actualización automática (a solución máis antiga foi poñer o script en Git, actualizalo mediante cron e executalo);
  • un guión similar era necesario para Prometheus (install-prometheus.sh), con todo, destaca polo feito de que require moitos máis datos de entrada, así como o seu almacenamento (en boa forma - centralizado e nun clúster), e algúns datos (contrasinal) poderían xerarse automaticamente:

    Ampliación e complementación de Kubernetes (revisión e informe de vídeo)

  • o risco de implementar algo mal a un número crecente de clústeres estaba en constante crecemento, polo que nos demos conta de que os instaladores (é dicir, dous guións: para Ingress e Prometheus) era necesario a posta en escena (varias ramas en Git, varios crons para actualizalos nos correspondentes: clusters estables ou de proba);
  • с kubectl apply volveuse difícil traballar porque non é declarativo e só pode crear obxectos, pero non tomar decisións sobre o seu estado/eliminarlos;
  • Faltaban algunhas funcións que non tiñamos implementadas naquel momento:
    • control total sobre o resultado das actualizacións do clúster,
    • determinación automática dalgúns parámetros (entrada para scripts de instalación) a partir dos datos que se poden obter do clúster (descubrimento),
    • o seu desenvolvemento lóxico en forma de descubrimento continuo.

Implementamos toda esta experiencia acumulada no marco do noso outro proxecto - operador-complemento.

Operador de complementos

Está baseado no xa mencionado shell-operator. Todo o sistema ten o seguinte aspecto:

Engádese o seguinte aos ganchos do operador de shell:

  • almacenamento de valores,
  • Gráfico de timón,
  • compoñente que supervisa a tenda de valores e - en caso de cambios - pídelle a Helm que volva a rodar o gráfico.

Ampliación e complementación de Kubernetes (revisión e informe de vídeo)

Así, podemos reaccionar ante un evento en Kubernetes, lanzar un gancho e desde este gancho podemos facer cambios no almacenamento, tras o que volverá descargar o gráfico. No diagrama resultante, separamos o conxunto de ganchos e o gráfico nun compoñente, ao que chamamos módulo:

Ampliación e complementación de Kubernetes (revisión e informe de vídeo)

Pode haber moitos módulos, e a eles engadimos ganchos globais, unha tenda de valores globais e un compoñente que supervisa esta tenda global.

Agora, cando ocorre algo en Kubernetes, podemos reaccionar a el usando un gancho global e cambiar algo na tenda global. Este cambio notarase e fará que todos os módulos do clúster se implementen:

Ampliación e complementación de Kubernetes (revisión e informe de vídeo)

Este esquema cumpre todos os requisitos para instalar complementos que se indicaron anteriormente:

  • Helm é o responsable da elaboración de modelos e da declaración.
  • O problema da actualización automática resolveuse mediante un gancho global, que vai ao rexistro nunha programación e, se ve alí unha nova imaxe do sistema, desenrola (é dicir, "el mesmo").
  • O almacenamento de configuracións no clúster implícase mediante ConfigMap, que contén os datos primarios dos almacenamentos (no inicio cárganse nos almacenamentos).
  • Os problemas coa xeración de contrasinais, o descubrimento e o descubrimento continuo foron resoltos mediante ganchos.
  • A posta en escena conséguese grazas ás etiquetas, que Docker admite fóra da caixa.
  • O resultado é monitor mediante métricas polas que podemos entender o estado.

Todo este sistema está implementado en forma dun único binario en Go, que se chama add-operator. Isto fai que o diagrama pareza máis sinxelo:

Ampliación e complementación de Kubernetes (revisión e informe de vídeo)

O compoñente principal deste diagrama é un conxunto de módulos (resaltado en gris abaixo). Agora podemos escribir un módulo para o complemento necesario cun pouco de esforzo e asegurarnos de que se instalará en cada clúster, que se actualizará e responderá aos eventos que necesite no clúster.

Usos "Flant". operador-complemento en máis de 70 clústeres de Kubernetes. Estado actual - versión alfa. Agora estamos preparando documentación para lanzar a beta, pero polo de agora no repositorio exemplos dispoñibles, en base ao cal podes crear o teu propio complemento.

Onde podo conseguir os módulos para add-operator? Publicar a nosa biblioteca é a seguinte etapa para nós; pensamos facelo no verán.

Vídeos e diapositivas

Vídeo da actuación (~50 minutos):

Presentación do informe:

PS

Outras reportaxes no noso blog:

Tamén pode estar interesado nas seguintes publicacións:

Fonte: www.habr.com

Engadir un comentario