10 erros comúns ao usar Kubernetes

Nota. transl.: Os autores deste artigo son enxeñeiros dunha pequena empresa checa, pipetail. Conseguiron elaborar unha lista marabillosa de problemas [ás veces banais, pero aínda así] moi acuciantes e conceptos erróneos relacionados co funcionamento dos clústeres de Kubernetes.

10 erros comúns ao usar Kubernetes

Ao longo dos anos de uso de Kubernetes, traballamos cun gran número de clústeres (tanto xestionados como non xestionados, en GCP, AWS e Azure). Co paso do tempo, comezamos a notar que algúns erros se repetían constantemente. Non obstante, non hai vergoña disto: a maioría fixémolas nós mesmos!

O artigo contén os erros máis comúns e tamén menciona como corrixilos.

1. Recursos: solicitudes e límites

Este elemento definitivamente merece a atención máis estreita e o primeiro lugar na lista.

Solicitude de CPU normalmente ou non se especifica en absoluto ou ten un valor moi baixo (para colocar tantos pods en cada nodo como sexa posible). Así, os nodos sobrecárganse. Durante os tempos de alta carga, a potencia de procesamento do nodo é totalmente utilizada e unha carga de traballo particular recibe só o que "solicita" Acelerado da CPU. Isto leva a unha maior latencia da aplicación, tempo de espera e outras consecuencias desagradables. (Lea máis sobre isto na nosa outra tradución recente: "Límites da CPU e limitación agresiva en Kubernetes"- aprox. trad.)

Mellor Esforzo (extremadamente non recomendado):

resources: {}

Solicitude de CPU extremadamente baixa (extremadamente non recomendado):

   resources:
      Requests:
        cpu: "1m"

Por outra banda, a presenza dun límite de CPU pode levar a saltar de forma irrazonable os ciclos de reloxo polos pods, aínda que o procesador de nodos non estea completamente cargado. De novo, isto pode levar a un aumento dos atrasos. Continúa a polémica arredor do parámetro Cota de CPU CFS no núcleo de Linux e a limitación da CPU dependendo dos límites establecidos, así como desactivar a cota CFS... Por desgraza, os límites da CPU poden causar máis problemas dos que poden resolver. Pódese atopar máis información sobre isto na seguinte ligazón.

Selección excesiva (sobrecompromiso) problemas de memoria poden levar a problemas maiores. Alcanzar o límite da CPU implica saltar os ciclos de reloxo, mentres que alcanzar o límite de memoria implica matar o pod. Observaches algunha vez OOMkill? Si, diso é exactamente o que estamos a falar.

Queres minimizar a probabilidade de que isto suceda? Non asignes en exceso memoria e utilice a QoS (calidade de servizo) garantida configurando a solicitude de memoria ao límite (como no exemplo seguinte). Ler máis sobre isto en Presentacións de Henning Jacobs (Enxeñeiro xefe en Zalando).

Burstable (maior probabilidade de ser OOMkilled):

   resources:
      requests:
        memory: "128Mi"
        cpu: "500m"
      limits:
        memory: "256Mi"
        cpu: 2

Garantida:

   resources:
      requests:
        memory: "128Mi"
        cpu: 2
      limits:
        memory: "128Mi"
        cpu: 2

Que pode axudar á hora de configurar os recursos?

Con servidor de métricas podes ver o consumo actual de recursos da CPU e o uso de memoria por pods (e contedores dentro deles). O máis probable é que xa o esteas a usar. Só ten que executar os seguintes comandos:

kubectl top pods
kubectl top pods --containers
kubectl top nodes

Non obstante, só mostran o uso actual. Pode darche unha idea aproximada da orde de magnitude, pero finalmente necesitarás historia de cambios nas métricas ao longo do tempo (para responder preguntas como: "Cal foi a carga máxima da CPU?", "Cal foi a carga onte pola mañá?", etc.). Para iso podes usar Prometeu, DataDog e outras ferramentas. Simplemente obteñen métricas do metrics-server e almacenámolas, e o usuario pode consultalas e representalas en consecuencia.

VerticalPodAutoscaler permite automatizar este proceso. Fai un seguimento do historial de uso da CPU e da memoria e establece novas solicitudes e límites en función desta información.

Usar a potencia informática de forma eficiente non é unha tarefa fácil. É como xogar ao Tetris todo o tempo. Se pagas demasiado por potencia de cálculo cun consumo medio baixo (por exemplo, ~10%), recomendámosche que busques produtos baseados en AWS Fargate ou Virtual Kubelet. Están construídos sobre un modelo de facturación sen servidor/paga por uso, que pode resultar máis barato nesas condicións.

2. Sondas de vivacidade e prontidão

De forma predeterminada, as comprobacións de vida e preparación non están activadas en Kubernetes. E ás veces esquécense de acendelos...

Pero como se pode iniciar un reinicio do servizo no caso de producirse un erro fatal? E como sabe o equilibrador de carga que un pod está preparado para aceptar tráfico? Ou que pode xestionar máis tráfico?

Estas probas adoitan confundirse entre si:

  • Vida — comprobación de "supervivencia", que reinicia o pod se falla;
  • Preparación — comprobación de preparación, se falla, desconecta o pod do servizo Kubernetes (pódese verificar usando kubectl get endpoints) e o tráfico non chega ata que se complete correctamente a seguinte comprobación.

Estes dous controis REALIZADA DURANTE TODO O CICLO DE VIDA DO POD. É moi importante.

Unha idea errónea común é que as sondas de preparación só se executan ao inicio para que o equilibrador poida saber que o pod está listo (Ready) e pode comezar a procesar o tráfico. Non obstante, esta é só unha das opcións para o seu uso.

Outra é a posibilidade de descubrir que o tráfico na vaina é excesivo e sobrecárgao (ou o pod realiza cálculos intensivos en recursos). Neste caso, a verificación de preparación axuda reducir a carga na vaina e "arrefriala".. A realización exitosa dunha verificación de preparación no futuro permite aumentar a carga na vaina de novo. Neste caso (se falla a proba de preparación), o fallo da proba de vivacidade sería moi contraproducente. Por que reiniciar un pod que está saudable e traballa duro?

Polo tanto, nalgúns casos, non hai comprobacións en absoluto é mellor que habilitalas con parámetros configurados incorrectamente. Como se dixo anteriormente, se verificación de vida copias verificación de preparación, entón estás nun gran problema. A opción posible é configurar só proba de preparaciónE vivacidade perigosa deixar de lado.

Ambos tipos de comprobacións non deberían fallar cando fallan as dependencias comúns, se non, isto levará a un fallo en cascada (como avalancha) de todos os pods. Noutras palabras, non te fagas dano.

3. LoadBalancer para cada servizo HTTP

O máis probable é que teña no seu clúster servizos HTTP que lle gustaría reenviar ao mundo exterior.

Se abres o servizo como type: LoadBalancer, o seu controlador (dependendo do provedor de servizos) proporcionará e negociará un LoadBalancer externo (non necesariamente funcionando en L7, senón incluso en L4), e isto pode afectar o custo (enderezo IPv4 estático externo, potencia de cálculo, facturación por segundo). ) pola necesidade de crear un gran número destes recursos.

Neste caso, é moito máis lóxico usar un equilibrador de carga externo, abrindo servizos como type: NodePort. Ou mellor aínda, expandir algo así controlador de entrada nginx (Ou traefik), que será o único NodePort punto final asociado co equilibrador de carga externo e enrutará o tráfico no clúster mediante entrada-Recursos Kubernetes.

Outros (micro)servizos intra-clúster que interactúan entre si poden "comunicarse" mediante servizos como ClústerIP e un mecanismo de descubrimento de servizos integrado a través de DNS. Simplemente non use o seu DNS/IP público, xa que isto pode afectar a latencia e aumentar o custo dos servizos na nube.

4. Autoescalar un clúster sen ter en conta as súas características

Ao engadir nodos e eliminalos dun clúster, non debe confiar nalgunhas métricas básicas como o uso da CPU neses nodos. A planificación das pods debe ter en conta moitos restricións, como a afinidade de pod/nodo, manchas e tolerancias, solicitudes de recursos, QoS, etc. Usar un autoscaler externo que non teña en conta estes matices pode dar lugar a problemas.

Imaxina que se debería programar un determinado pod, pero se solicita/desmonta toda a potencia da CPU dispoñible e o pod queda atrapado nun estado Pending. O autoescalador externo ve a carga actual media da CPU (non a solicitada) e non inicia a expansión (escalada) - non engade outro nodo. Como resultado, este pod non se programará.

Neste caso, a escala inversa (ampliación) — eliminar un nodo dun clúster sempre é máis difícil de implementar. Imaxina que tes un pod con estado (co almacenamento persistente conectado). Volumes persistentes normalmente pertencen zona de dispoñibilidade específica e non se reproducen na rexión. Así, se un autoescalador externo elimina un nodo con este pod, o planificador non poderá programar este pod noutro nodo, xa que só se pode facer na zona de dispoñibilidade onde se atopa o almacenamento persistente. Pod quedará atrapado no estado Pending.

Moi popular na comunidade de Kubernetes cluster-autoscaler. Funciona nun clúster, admite API dos principais provedores de nube, ten en conta todas as restricións e pode escalar nos casos anteriores. Tamén é capaz de escalar mantendo todos os límites establecidos, aforrando así cartos (que doutro xeito se gastarían en capacidade non utilizada).

5. Descoidar as capacidades de IAM/RBAC

Teña coidado de usar usuarios de IAM con segredos persistentes para máquinas e aplicacións. Organiza o acceso temporal mediante roles e contas de servizo (contas de servizo).

Moitas veces atopamos o feito de que as claves de acceso (e os segredos) están codificadas na configuración da aplicación, ademais de descoidar a rotación dos segredos a pesar de ter acceso a Cloud IAM. Use roles de IAM e contas de servizo en lugar de usuarios cando corresponda.

10 erros comúns ao usar Kubernetes

Esquece kube2iam e vai directamente aos roles de IAM para as contas de servizo (como se describe en nota do mesmo nome Štěpán Vraný):

apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/my-app-role
  name: my-serviceaccount
  namespace: default

Unha anotación. Non é tan difícil, non?

Ademais, non outorgue privilexios ás contas de servizo e aos perfís de instancia admin и cluster-adminse non o precisan. Isto é un pouco máis difícil de implementar, especialmente nos RBAC K8, pero definitivamente paga a pena o esforzo.

6. Non confíes na antiafinidade automática para as vainas

Imaxina que tes tres réplicas dalgunha implantación nun nodo. O nodo cae, e xunto con el todas as réplicas. Situación desagradable, non? Pero por que estaban todas as réplicas no mesmo nodo? Non se supón que Kubernetes ofrece alta dispoñibilidade (HA)?!

Desafortunadamente, o programador de Kubernetes, por iniciativa propia, non cumpre coas regras de existencia separada (antiafinidade) para vainas. Deben indicarse expresamente:

// опущено для краткости
      labels:
        app: zk
// опущено для краткости
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: "app"
                    operator: In
                    values:
                    - zk
              topologyKey: "kubernetes.io/hostname"

Iso é todo. Agora os pods programaranse en diferentes nodos (esta condición só se verifica durante a programación, pero non durante o seu funcionamento, polo tanto requiredDuringSchedulingIgnoredDuringExecution).

Aquí estamos a falar podAntiAffinity en distintos nodos: topologyKey: "kubernetes.io/hostname", - e non sobre diferentes zonas de dispoñibilidade. Para implementar un HA completo, terás que afondar neste tema.

7. Ignorando os orzamentos de PodDisruption

Imaxina que tes unha carga de produción nun clúster de Kubernetes. Periodicamente, os nodos e o propio clúster teñen que ser actualizados (ou desmantelados). Un PodDisruptionBudget (PDB) é algo así como un acordo de garantía de servizo entre administradores de clúster e usuarios.

PDB permítelle evitar interrupcións de servizo causadas pola falta de nodos:

apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: zk-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: zookeeper

Neste exemplo, ti, como usuario do clúster, indicas aos administradores: "Ei, teño un servizo de coidador do zoolóxico, e fagas o que fagas, gustaríame ter polo menos dúas réplicas deste servizo sempre dispoñibles".

Podes ler máis sobre isto aquí.

8. Múltiples usuarios ou contornos nun clúster común

Espazos de nomes de Kubernetes (espazos de nomes) non proporciona un illamento forte.

Unha idea errónea común é que se implementa unha carga que non sexa de produto nun espazo de nomes e unha carga de produto noutro, entón non se influirán mutuamente de ningún xeito... Non obstante, pódese conseguir un certo nivel de illamento utilizando solicitudes/limitacións de recursos, establecendo cotas e configurando priorityClasses. Algún illamento "físico" no plano de datos é proporcionado por afinidades, tolerancias, manchas (ou nodeselectores), pero esa separación é bastante difícil implementar.

Aqueles que necesiten combinar ambos tipos de cargas de traballo nun mesmo clúster terán que facer fronte á complexidade. Se non hai tal necesidade, e pode permitirse o luxo de ter un un clúster máis (por exemplo, nunha nube pública), entón é mellor facelo. Isto conseguirá un nivel moito maior de illamento.

9. ExternalTrafficPolicy: Clúster

Moitas veces vemos que todo o tráfico dentro do clúster chega a través dun servizo como NodePort, para o que se establece a política predeterminada. externalTrafficPolicy: Cluster... Significa iso NodePort está aberto en todos os nodos do clúster e podes usar calquera deles para interactuar co servizo desexado (conxunto de pods).

10 erros comúns ao usar Kubernetes

Ao mesmo tempo, os pods reais asociados co servizo NodePort mencionado anteriormente adoitan estar dispoñibles só nun determinado subconxunto destes nodos. Noutras palabras, se me conecto a un nodo que non ten o pod necesario, reenviará o tráfico a outro nodo, engadindo un salto e aumento da latencia (se os nodos están situados en diferentes zonas de dispoñibilidade/centros de datos, a latencia pode ser bastante alta; ademais, aumentarán os custos do tráfico de saída).

Por outra banda, se un determinado servizo de Kubernetes ten unha política definida externalTrafficPolicy: Local, entón NodePort ábrese só naqueles nós nos que realmente se están a executar os pods necesarios. Cando se utiliza un equilibrador de carga externo que comproba o estado (control de saúde) puntos finais (como fai AWS ELB), El enviará tráfico só aos nodos necesarios, que terá un efecto beneficioso sobre atrasos, necesidades informáticas, facturas de saída (e o sentido común manda o mesmo).

Hai unha gran probabilidade de que xa esteas usando algo así traefik ou controlador de entrada nginx como punto final de NodePort (ou LoadBalancer, que tamén usa NodePort) para enrutar o tráfico de entrada HTTP, e establecer esta opción pode reducir significativamente a latencia para tales solicitudes.

В esta publicación Podes obter máis información sobre externalTrafficPolicy, as súas vantaxes e inconvenientes.

10. Non te amarres aos clusters e non abuses do plano de control

Anteriormente, era habitual chamar aos servidores por nomes propios: Anton, HAL9000 e Colossus... Hoxe foron substituídos por identificadores xerados aleatoriamente. Non obstante, o hábito mantívose, e agora os nomes propios van aos clusters.

Unha historia típica (baseada en feitos reais): todo comezou cunha proba de concepto, polo que o clúster tiña un nome orgulloso probas... Pasaron os anos e AÍNDA úsase na produción, e todos teñen medo de tocalo.

Non hai nada divertido que os grupos se convertan en mascotas, polo que recomendamos eliminalos periódicamente mentres practicas recuperación ante desastres (isto vai axudar enxeñaría do caos - aprox. transl.). Ademais, non estaría de máis traballar na capa de control (plano de control). Ter medo a tocalo non é bo sinal. Etcd morto? Rapaces, realmente estás en problemas!

Por outra banda, non debe deixarse ​​levar por manipulalo. Co tempo a capa de control pode volverse lenta. O máis probable é que isto débese a que se crean un gran número de obxectos sen a súa rotación (unha situación común cando se usa Helm coa configuración predeterminada, polo que o seu estado en configmaps/segredos non se actualiza; como resultado, acumúlanse miles de obxectos en a capa de control) ou con edición constante de obxectos kube-api (para escalado automático, para CI/CD, para monitorización, rexistros de eventos, controladores, etc.).

Ademais, recomendamos comprobar os acordos de SLA/SLO co provedor de Kubernetes xestionado e prestar atención ás garantías. O vendedor pode garantir controlar a dispoñibilidade da capa (ou os seus subcompoñentes), pero non o atraso p99 das solicitudes que lle envía. Noutras palabras, podes entrar kubectl get nodes, e recibirá unha resposta só despois de 10 minutos, e isto non suporá unha violación dos termos do acordo de servizo.

11. Bonificación: usando a etiqueta máis recente

Pero isto xa é un clásico. Últimamente atopámonos con esta técnica con menos frecuencia, xa que moitos, despois de aprender dunha amarga experiencia, deixaron de usar a etiqueta :latest e comezou a fixar versións. Hurra!

ECR mantén a inmutabilidade das etiquetas da imaxe; Recomendamos que se familiarice con esta característica notable.

Resumo

Non esperes que todo funcione dun día para outro: Kubernetes non é unha panacea. Mala aplicación seguirá sendo así mesmo en Kubernetes (e probablemente empeorará). O descoido levará a unha complexidade excesiva, un traballo lento e estresante da capa de control. Ademais, corre o risco de quedar sen unha estratexia de recuperación ante desastres. Non esperes que Kubernetes proporcione illamento e alta dispoñibilidade fóra da caixa. Pase algún tempo facendo que a súa aplicación sexa verdadeiramente nativa da nube.

Podes familiarizarte coas experiencias sen éxito de varios equipos en esta colección de contos por Henning Jacobs.

Aqueles que desexen engadir á lista de erros que aparece neste artigo poden poñerse en contacto connosco en Twitter (@MarekBartik, @MstrsObserver).

PS do tradutor

Lea tamén no noso blog:

Fonte: www.habr.com

Engadir un comentario