paint-brush
Como reduzir custos por meio do empacotamento denso de clusters do Google Kubernetes Engine (GKE)por@arslanbekov
459 leituras
459 leituras

Como reduzir custos por meio do empacotamento denso de clusters do Google Kubernetes Engine (GKE)

por Arslabekov Denis5m2023/02/21
Read on Terminal Reader

Muito longo; Para ler

Temos mais de cinco ambientes de teste permanentes e estamos implantando ambientes para desenvolvedores mediante solicitação. O número de módulos durante a semana chega a 5.000 durante o dia e continua crescendo. O pod do servidor de métricas estava apresentando um erro de falta de memória (OOM) e um erro de pânico nos logs. O motivo estava nos limites dos recursos do pod.
featured image - Como reduzir custos por meio do empacotamento denso de clusters do Google Kubernetes Engine (GKE)
Arslabekov Denis HackerNoon profile picture
0-item

Cumprimentos a todos! Hoje gostaríamos de compartilhar nossa experiência usando o Google Kubernetes Engine para gerenciar nossos clusters Kubernetes. Nós o usamos nos últimos três anos em produção e estamos satisfeitos por não precisarmos mais nos preocupar em gerenciar esses clusters nós mesmos.


Atualmente, temos todos os nossos ambientes de teste e clusters de infraestrutura exclusivos sob o controle do Kubernetes. Hoje, queremos falar sobre como encontramos um problema em nosso cluster de teste e como esperamos que este artigo economize tempo e esforço de outras pessoas.


Devemos fornecer informações sobre nossa infraestrutura de teste para entender totalmente nosso problema. Temos mais de cinco ambientes de teste permanentes e estamos implantando ambientes para desenvolvedores mediante solicitação. O número de módulos durante a semana chega a 6.000 durante o dia e continua crescendo. Como a carga é instável, empacotamos os módulos muito bem para economizar custos, e revender recursos é nossa melhor estratégia.

Notificação do Slack KubeAPIErrorsHigh da produção


Essa configuração funcionou bem para nós até que um dia recebemos um alerta e não conseguimos excluir um namespace. A mensagem de erro que recebemos sobre a exclusão do namespace foi:

 $ kubectl delete namespace arslanbekov Error from server (Conflict): Operation cannot be fulfilled on namespaces "arslanbekov": The system is ensuring all content is removed from this namespace. Upon completion, this namespace will automatically be purged by the system.


Mesmo usando a opção de exclusão forçada não resolveu o problema:

 $ kubectl get namespace arslanbekov -o yaml apiVersion: v1 kind: Namespace metadata: ... spec: finalizers: - kubernetes status: phase: Terminating


Para resolver o problema de namespace travado, seguimos um guia . Ainda assim, essa solução temporária não era ideal, pois nossos desenvolvedores deveriam poder criar e excluir seus ambientes à vontade, usando a abstração de namespace.


Determinados a encontrar uma solução melhor, decidimos investigar mais. O alerta indicou um problema de métrica, que confirmamos executando um comando:

 $ kubectl api-resources --verbs=list --namespaced -o name error: unable to retrieve the complete list of server APIs: metrics.k8s.io/v1beta1: the server is currently unable to handle the request


Descobrimos que o pod do servidor de métricas estava apresentando um erro de falta de memória (OOM) e um erro de pânico nos logs:


 apiserver panic'd on GET /apis/metrics.k8s.io/v1beta1/nodes: killing connection/stream because serving request timed out and response had been started goroutine 1430 [running]:


O motivo estava nos limites dos recursos do pod:

O contêiner estava encontrando esses problemas devido à sua definição, que era a seguinte (bloco de limites):

 resources: limits: cpu: 51m memory: 123Mi requests: cpu: 51m memory: 123Mi


O problema era que apenas 51 milhões de CPU foram alocados ao contêiner, o que é aproximadamente equivalente a 0,05 de uma CPU principal , e isso não era suficiente para lidar com as métricas de um número tão grande de pods. Principalmente o agendador CFS é usado.


Normalmente, corrigir esses problemas é direto e envolve simplesmente alocar mais recursos para o pod. No entanto, no GKE, essa opção não está disponível na IU ou por meio da CLI gcloud. Isso ocorre porque o Google protege os recursos do sistema de serem modificados, o que é compreensível, considerando que todo o gerenciamento é feito por eles.


Descobrimos que não éramos os únicos enfrentando esse problema e encontramos um problema semelhante em que o autor tentou alterar a definição do pod manualmente. Ele teve sucesso, mas nós não. Quando tentamos alterar os limites de recursos no arquivo YAML, o GKE os reverteu rapidamente.


Precisávamos encontrar outra solução.


Nosso primeiro passo foi entender por que os limites de recursos foram definidos para esses valores. O pod consistia em dois contêineres: metrics-server e o addon-resizer . Este último era responsável por ajustar os recursos à medida que os nós eram adicionados ou removidos do cluster, atuando como um zelador do dimensionamento automático vertical do cluster.


Sua definição de linha de comando foi a seguinte:

 command: - /pod_nanny - --config-dir=/etc/config - --cpu=40m - --extra-cpu=0.5m - --memory=35Mi - --extra-memory=4Mi ...


Nesta definição, CPU e memória representam os recursos de linha de base, enquanto extra-cpu e extra-memory representam recursos adicionais por nó. Os cálculos para 180 nós seriam os seguintes:

 0.5m * 180 + 40m=~130m


A mesma lógica é aplicada aos recursos de memória.

Infelizmente, a única forma de aumentar os recursos era adicionando mais nós, o que não queríamos fazer. Então, decidimos explorar outras opções.


Apesar de não conseguir resolver totalmente o problema, queríamos estabilizar a implantação o mais rápido possível . Aprendemos que algumas propriedades na definição YAML podem ser alteradas sem serem revertidas pelo GKE. Para resolver isso, aumentamos o número de réplicas de 1 para 5 , adicionamos uma verificação de integridade e ajustamos a estratégia de distribuição de acordo com este artigo .


Essas ações ajudaram a reduzir a carga na instância do servidor de métricas e garantiram que sempre tivéssemos pelo menos um pod de trabalho que pudesse fornecer métricas. Levamos algum tempo para reconsiderar o problema e refrescar nossos pensamentos. A solução acabou sendo simples e óbvia em retrospecto.


Nós nos aprofundamos nas partes internas do addon-resizer e descobrimos que ele pode ser configurado por meio de um arquivo de configuração e parâmetros de linha de comando. À primeira vista, parecia que os parâmetros da linha de comando deveriam substituir os valores de configuração, mas não era o caso.


Ao investigar, descobrimos que o arquivo de configuração foi conectado ao pod por meio dos parâmetros de linha de comando do contêiner addon-resizer:

 --config-dir=/etc/config


O arquivo de configuração foi mapeado como um ConfigMap com o nome metrics-server-config no namespace do sistema, e o GKE não reverte essa configuração.


Adicionamos recursos por meio dessa configuração da seguinte maneira:

 apiVersion: v1 data: NannyConfiguration: |- apiVersion: nannyconfig/v1alpha1 kind: NannyConfiguration baseCPU: 100m cpuPerNode: 5m baseMemory: 100Mi memoryPerNode: 5Mi kind: ConfigMap metadata:


E funcionou! Isso foi uma vitória para nós.


Deixamos dois pods com verificações de integridade e uma estratégia de tempo de inatividade zero enquanto o cluster estava sendo redimensionado e não recebemos mais nenhum alerta depois de fazer essas alterações.


Conclusões

  1. Você pode encontrar problemas com o pod do servidor de métricas se tiver um cluster do GKE densamente compactado. Os recursos padrão alocados para o pod podem não ser suficientes se o número de pods por nó estiver próximo do limite (110 por nó).
  2. O GKE protege os recursos do sistema, incluindo pods do sistema, e o controle direto sobre eles é impossível. No entanto, às vezes é possível encontrar uma solução alternativa.
  3. É importante observar que não há garantia de que a solução ainda funcionará após atualizações futuras. Encontramos esses problemas apenas em nossos ambientes de teste, onde temos uma estratégia de supervenda de recursos, portanto, embora seja frustrante, ainda podemos gerenciá-lo.