Essa é a versão completa de impressão dessa seção Clique aqui para imprimir.

Retornar à visualização normal.

Administração de Cluster

Detalhes de baixo nível relevantes para criar ou administrar um cluster Kubernetes.

A visão geral da administração do cluster é para qualquer pessoa que crie ou administre um cluster do Kubernetes. É pressuposto alguma familiaridade com os conceitos principais do Kubernetes.

Planejando um cluster

Consulte os guias em Configuração para exemplos de como planejar, instalar e configurar clusters Kubernetes. As soluções listadas neste artigo são chamadas de distros.

Antes de escolher um guia, aqui estão algumas considerações:

  • Você quer experimentar o Kubernetes em seu computador ou deseja criar um cluster de vários nós com alta disponibilidade? Escolha as distros mais adequadas ás suas necessidades.
  • Você vai usar um cluster Kubernetes gerenciado , como o Google Kubernetes Engine, ou vai hospedar seu próprio cluster?
  • Seu cluster será local, ou na nuvem (IaaS)? O Kubernetes não oferece suporte direto a clusters híbridos. Em vez disso, você pode configurar vários clusters.
  • Se você estiver configurando o Kubernetes local, leve em consideração qual modelo de rede se encaixa melhor.
  • Você vai executar o Kubernetes em um hardware bare metal ou em máquinas virtuais? (VMs)?
  • Você deseja apenas executar um cluster ou espera participar ativamente do desenvolvimento do código do projeto Kubernetes? Se for a segunda opção, escolha uma distro desenvolvida ativamente. Algumas distros usam apenas versão binária, mas oferecem uma maior variedade de opções.
  • Familiarize-se com os componentes necessários para executar um cluster.

Gerenciando um cluster

Protegendo um cluster

Protegendo o kubelet

Serviços Opcionais para o Cluster

1 - Visão Geral da Administração de Cluster

A visão geral da administração de cluster é para qualquer um criando ou administrando um cluster Kubernetes. Assume-se que você tenha alguma familiaridade com os conceitos centrais do Kubernetes.

Planejando um cluster

Veja os guias em Setup para exemplos de como planejar, iniciar e configurar clusters Kubernetes. As soluções listadas neste artigo são chamadas distros.

Antes de escolher um guia, aqui estão algumas considerações.

  • Você quer experimentar o Kubernetes no seu computador, ou você quer construir um cluster de alta disponibilidade e multi-nós? Escolha as distros mais adequadas às suas necessidades.

  • Se você esta projetando para alta-disponibilidade, saiba mais sobre configuração clusters em múltiplas zonas.

  • Você usará um cluster Kubernetes hospedado, como Google Kubernetes Engine, ou hospedará seu próprio cluster?

  • Seu cluster será on-premises, ou in the cloud (IaaS)? Kubernetes não suporta diretamente clusters híbridos. Em vez disso, você pode configurar vários clusters.

  • Se você estiver configurando um Kubernetes on-premisess, considere qual modelo de rede melhor se adequa.

  • Você estará executando o Kubernetes em hardware "bare metal" ou em máquinas virtuais (VMs)?

  • Você quer apenas rodar um cluster, ou você espera fazer desenvolvimento ativo do código de projeto do Kubernetes? Se for a segunda opção, escolha uma distro mais ativa. Algumas distros fornecem apenas binários, mas oferecem uma maior variedade de opções.

  • Familiarize-se com os componentes necessários para rodar um cluster.

Nota: Nem todas as distros são ativamente mantidas. Escolha as distros que foram testadas com uma versão recente do Kubernetes.

Gerenciando um cluster

  • Gerenciando um cluster descreve vários tópicos relacionados ao ciclo de vida de um cluster: criando um novo cluster, atualizando o nó mestre e os nós de trabalho do cluster, executando manutenção de nó (por exemplo, atualizações de kernel) e atualizando a versão da API do Kubernetes de um cluster em execução.

  • Aprender como gerenciar um nó.

  • Aprender como configurar e gerenciar o recurso de quota para um cluster compartilhado.

Protegendo um cluster

Protegendo o kubelet

Serviços Opcionais do Cluster

2 - Certificates

Ao usar um client para autenticação de certificado, você pode gerar certificados manualmente através easyrsa, openssl ou cfssl.

easyrsa

easyrsa pode gerar manualmente certificados para o seu cluster.

  1. Baixe, descompacte e inicialize a versão corrigida do easyrsa3.

    curl -LO https://dl.k8s.io/easy-rsa/easy-rsa.tar.gz
    tar xzf easy-rsa.tar.gz
    cd easy-rsa-master/easyrsa3
    ./easyrsa init-pki
    
  2. Gerar o CA. (--batch set automatic mode. --req-cn default CN to use.)

    ./easyrsa --batch "--req-cn=${MASTER_IP}@`date +%s`" build-ca nopass
    
  3. Gere o certificado e a chave do servidor. O argumento --subject-alt-name define os possíveis IPs e nomes (DNS) que o servidor de API usará para ser acessado. O MASTER_CLUSTER_IP é geralmente o primeiro IP do serviço CIDR que é especificado como argumento em --service-cluster-ip-range para o servidor de API e o componente gerenciador do controlador. O argumento --days é usado para definir o número de dias após o qual o certificado expira. O exemplo abaixo também assume que você está usando cluster.local como DNS de domínio padrão

    ./easyrsa --subject-alt-name="IP:${MASTER_IP},"\
    "IP:${MASTER_CLUSTER_IP},"\
    "DNS:kubernetes,"\
    "DNS:kubernetes.default,"\
    "DNS:kubernetes.default.svc,"\
    "DNS:kubernetes.default.svc.cluster,"\
    "DNS:kubernetes.default.svc.cluster.local" \
    --days=10000 \
    build-server-full server nopass
    
  4. Copie pki/ca.crt, pki/issued/server.crt, e pki/private/server.key para o seu diretório.

  5. Preencha e adicione os seguintes parâmetros aos parâmetros de inicialização do servidor de API:

    --client-ca-file=/yourdirectory/ca.crt
    --tls-cert-file=/yourdirectory/server.crt
    --tls-private-key-file=/yourdirectory/server.key
    

openssl

openssl pode gerar manualmente certificados para o seu cluster.

  1. Gere um ca.key com 2048bit:

    openssl genrsa -out ca.key 2048
    
  2. De acordo com o ca.key, gere um ca.crt (use -days para definir o tempo efetivo do certificado):

     openssl req -x509 -new -nodes -key ca.key -subj "/CN=${MASTER_IP}" -days 10000 -out ca.crt
    
  3. Gere um server.key com 2048bit:

    openssl genrsa -out server.key 2048
    
  4. Crie um arquivo de configuração para gerar uma solicitação de assinatura de certificado (CSR - Certificate Signing Request). Certifique-se de substituir os valores marcados com colchetes angulares (por exemplo, <MASTER_IP>) com valores reais antes de salvá-lo em um arquivo (por exemplo, csr.conf). Note que o valor para o MASTER_CLUSTER_IP é o IP do cluster de serviços para o Servidor de API, conforme descrito na subseção anterior. O exemplo abaixo também assume que você está usando cluster.local como DNS de domínio padrão

    [ req ]
    default_bits = 2048
    prompt = no
    default_md = sha256
    req_extensions = req_ext
    distinguished_name = dn
    
    [ dn ]
    C = <country>
    ST = <state>
    L = <city>
    O = <organization>
    OU = <organization unit>
    CN = <MASTER_IP>
    
    [ req_ext ]
    subjectAltName = @alt_names
    
    [ alt_names ]
    DNS.1 = kubernetes
    DNS.2 = kubernetes.default
    DNS.3 = kubernetes.default.svc
    DNS.4 = kubernetes.default.svc.cluster
    DNS.5 = kubernetes.default.svc.cluster.local
    IP.1 = <MASTER_IP>
    IP.2 = <MASTER_CLUSTER_IP>
    
    [ v3_ext ]
    authorityKeyIdentifier=keyid,issuer:always
    basicConstraints=CA:FALSE
    keyUsage=keyEncipherment,dataEncipherment
    extendedKeyUsage=serverAuth,clientAuth
    subjectAltName=@alt_names
    
  5. Gere a solicitação de assinatura de certificado com base no arquivo de configuração:

    openssl req -new -key server.key -out server.csr -config csr.conf
    
  6. Gere o certificado do servidor usando o ca.key, ca.crt e server.csr:

    openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
    -CAcreateserial -out server.crt -days 10000 \
    -extensions v3_ext -extfile csr.conf -sha256
    
  7. Veja o certificado:

    openssl x509  -noout -text -in ./server.crt
    

Por fim, adicione os mesmos parâmetros nos parâmetros iniciais do Servidor de API.

cfssl

cfssl é outra ferramenta para geração de certificados.

  1. Baixe, descompacte e prepare as ferramentas de linha de comando, conforme mostrado abaixo. Observe que você pode precisar adaptar os comandos de exemplo abaixo com base na arquitetura do hardware e versão cfssl que você está usando.

    curl -L https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -o cfssl
    chmod +x cfssl
    curl -L https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -o cfssljson
    chmod +x cfssljson
    curl -L https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -o cfssl-certinfo
    chmod +x cfssl-certinfo
    
  2. Crie um diretório para conter os artefatos e inicializar o cfssl:

    mkdir cert
    cd cert
    ../cfssl print-defaults config > config.json
    ../cfssl print-defaults csr > csr.json
    
  3. Crie um arquivo de configuração JSON para gerar o arquivo CA, por exemplo, ca-config.json:

    {
      "signing": {
        "default": {
          "expiry": "8760h"
        },
        "profiles": {
          "kubernetes": {
            "usages": [
              "signing",
              "key encipherment",
              "server auth",
              "client auth"
            ],
            "expiry": "8760h"
          }
        }
      }
    }
    
  4. Crie um arquivo de configuração JSON para o CA - solicitação de assinatura de certificado (CSR - Certificate Signing Request), por exemplo, ca-csr.json. Certifique-se de substituir os valores marcados com colchetes angulares por valores reais que você deseja usar.

    {
      "CN": "kubernetes",
      "key": {
        "algo": "rsa",
        "size": 2048
      },
      "names":[{
        "C": "<country>",
        "ST": "<state>",
        "L": "<city>",
        "O": "<organization>",
        "OU": "<organization unit>"
      }]
    }
    
  5. Gere a chave CA (ca-key.pem) e o certificado (ca.pem):

    ../cfssl gencert -initca ca-csr.json | ../cfssljson -bare ca
    
  6. Crie um arquivo de configuração JSON para gerar chaves e certificados para o Servidor de API, por exemplo, server-csr.json. Certifique-se de substituir os valores entre colchetes angulares por valores reais que você deseja usar. O MASTER_CLUSTER_IP é o IP do serviço do cluster para o servidor da API, conforme descrito na subseção anterior. O exemplo abaixo também assume que você está usando cluster.local como DNS de domínio padrão

    {
      "CN": "kubernetes",
      "hosts": [
        "127.0.0.1",
        "<MASTER_IP>",
        "<MASTER_CLUSTER_IP>",
        "kubernetes",
        "kubernetes.default",
        "kubernetes.default.svc",
        "kubernetes.default.svc.cluster",
        "kubernetes.default.svc.cluster.local"
      ],
      "key": {
        "algo": "rsa",
        "size": 2048
      },
      "names": [{
        "C": "<country>",
        "ST": "<state>",
        "L": "<city>",
        "O": "<organization>",
        "OU": "<organization unit>"
      }]
    }
    
  7. Gere a chave e o certificado para o Servidor de API, que são, por padrão, salvos nos arquivos server-key.pem e server.pem respectivamente:

    ../cfssl gencert -ca=ca.pem -ca-key=ca-key.pem \
    --config=ca-config.json -profile=kubernetes \
    server-csr.json | ../cfssljson -bare server
    

Distribuindo Certificado CA auto assinado

Um nó cliente pode se recusar a reconhecer o certificado CA self-signed como válido. Para uma implementação de não produção ou para uma instalação que roda atrás de um firewall, você pode distribuir certificados auto-assinados para todos os clientes e atualizar a lista de certificados válidos.

Em cada cliente, execute as seguintes operações:

sudo cp ca.crt /usr/local/share/ca-certificates/kubernetes.crt
sudo update-ca-certificates
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d....
done.

API de certificados

Você pode usar a API certificates.k8s.io para provisionar certificados x509 a serem usados ​​para autenticação conforme documentado aqui.

3 - Conectividade do Cluster

Conectividade é uma parte central do Kubernetes, mas pode ser desafiador entender exatamente como é o seu funcionamento esperado. Existem 4 problemas distintos em conectividade que devem ser tratados:

  1. Comunicações contêiner-para-contêiner altamente acopladas: Isso é resolvido por Pods e comunicações através do localhost.
  2. Comunicações pod-para-pod: Esse é o foco primário desse documento.
  3. Comunicações pod-para-serviço (service): Isso é tratado em Services.
  4. Comunicações Externas-para-serviços: Isso é tratado em services.

Kubernetes é basicamente o compartilhamento de máquinas entre aplicações. Tradicionalmente, compartilhar máquinas requer a garantia de que duas aplicações não tentem utilizar as mesmas portas. Coordenar a alocação de portas entre múltiplos desenvolvedores é muito dificil de fazer em escala e expõe os usuários a problemas em nível do cluster e fora de seu controle.

A alocação dinâmica de portas traz uma série de complicações para o sistema - toda aplicação deve obter suas portas através de flags de configuração, os servidores de API devem saber como inserir números dinämicos de portas nos blocos de configuração, serviços precisam saber como buscar um ao outro, etc. Ao invés de lidar com isso, o Kubernetes faz de uma maneira diferente.

O modelo de conectividade e rede do Kubernetes

Todo Pod obtém seu próprio endereço IP. Isso significa que vocë não precisa criar links explícitos entre os Pods e vocë quase nunca terá que lidar com o mapeamento de portas de contêineres para portas do host. Isso cria um modelo simples, retro-compatível onde os Pods podem ser tratados muito mais como VMs ou hosts físicos da perspectiva de alocação de portas, nomes, descobrimento de serviços (service discovery), balanceamento de carga, configuração de aplicações e migrações.

O Kubernetes impõe os seguintes requisitos fundamentais para qualquer implementação de rede (exceto qualquer política de segmentação intencional):

  • pods em um nó podem se comunicar com todos os pods em todos os nós sem usar NAT.
  • agentes em um nó (por exemplo o kubelet ou um serviço local) podem se comunicar com todos os Pods naquele nó.

Nota: Para as plataformas que suportam Pods executando na rede do host (como o Linux):

  • pods alocados na rede do host de um nó podem se comunicar com todos os pods em todos os nós sem NAT.

Esse modelo não só é menos complexo, mas é principalmente compatível com o desejo do Kubernetes de permitir a portabilidade com baixo esforço de aplicações de VMs para contêineres. Se a sua aplicação executava anteriormente em uma VM, sua VM possuía um IP e podia se comunicar com outras VMs no seu projeto. Esse é o mesmo modelo básico.

Os endereços de IP no Kubernetes existem no escopo do Pod - contêineres em um Pod compartilham o mesmo network namespace - incluíndo seu endereço de IP e MAC. Isso significa que contêineres que compõem um Pod podem se comunicar entre eles através do endereço localhost e respectivas portas. Isso também significa que contêineres em um mesmo Pod devem coordenar a alocação e uso de portas, o que não difere do modelo de processos rodando dentro de uma mesma VM. Isso é chamado de modelo "IP-por-pod".

Como isso é implementado é um detalhe do agente de execução de contêiner em uso.

É possível solicitar uma porta no nó que será encaminhada para seu Pod (chamado de portas do host), mas isso é uma operação muito específica. Como esse encaminhamento é implementado é um detalhe do agente de execução do contêiner. O Pod mesmo desconhece a existência ou não de portas do host.

Como implementar o modelo de conectividade do Kubernetes

Existe um número de formas de implementar esse modelo de conectividade. Esse documento não é um estudo exaustivo desses vários métodos, mas pode servir como uma introdução de várias tecnologias e serve como um ponto de início.

A conectividade no Kubernetes é fornecida através de plugins de CNIs

As seguintes opções estão organizadas alfabeticamente e não implicam preferência por qualquer solução.

Antrea

O projeto Antrea é uma solução de conectividade para Kubernetes que pretende ser nativa. Ela utiliza o Open vSwitch na camada de conectividade de dados. O Open vSwitch é um switch virtual de alta performance e programável que suporta Linux e Windows. O Open vSwitch permite ao Antrea implementar políticas de rede do Kubernetes (NetworkPolicies) de uma forma muito performática e eficiente.

Graças à característica programável do Open vSwitch, o Antrea consegue implementar uma série de funcionalidades de rede e segurança.

AWS VPC CNI para Kubernetes

O AWS VPC CNI oferece conectividade com o AWS Virtual Private Cloud (VPC) para clusters Kubernetes. Esse plugin oferece alta performance e disponibilidade e baixa latência. Adicionalmente, usuários podem aplicar as melhores práticas de conectividade e segurança existentes no AWS VPC para a construção de clusters Kubernetes. Isso inclui possibilidade de usar o VPC flow logs, políticas de roteamento da VPC e grupos de segurança para isolamento de tráfego.

O uso desse plugin permite aos Pods no Kubernetes ter o mesmo endereço de IP dentro do pod como se eles estivessem dentro da rede do VPC. O CNI (Container Network Interface) aloca um Elastic Networking Interface (ENI) para cada nó do Kubernetes e usa uma faixa de endereços IP secundário de cada ENI para os Pods no nó. O CNI inclui controles para pré alocação dos ENIs e endereços IP para um início mais rápido dos pods e permite clusters com até 2,000 nós.

Adicionalmente, esse CNI pode ser utilizado junto com o Calico para a criação de políticas de rede (NetworkPolicies). O projeto AWS VPC CNI tem código fonte aberto com a documentação no Github.

Azure CNI para o Kubernetes

Azure CNI é um plugin de código fonte aberto que integra os Pods do Kubernetes com uma rede virtual da Azure (também conhecida como VNet) provendo performance de rede similar à de máquinas virtuais no ambiente. Os Pods podem se comunicar com outras VNets e com ambientes on-premises com o uso de funcionalidades da Azure, e também podem ter clientes com origem dessas redes. Os Pods podem acessar serviços da Azure, como armazenamento e SQL, que são protegidos por Service Endpoints e Private Link. Você pode utilizar as políticas de segurança e roteamento para filtrar o tráfico do Pod. O plugin associa IPs da VNet para os Pods utilizando um pool de IPs secundário pré-configurado na interface de rede do nó Kubernetes.

O Azure CNI está disponível nativamente no Azure Kubernetes Service (AKS).

Calico

Calico é uma solução de conectividade e segurança para contêineres, máquinas virtuais e serviços nativos em hosts. O Calico suporta múltiplas camadas de conectividade/dados, como por exemplo: uma camada Linux eBPF nativa, uma camada de conectividade baseada em conceitos padrão do Linux e uma camada baseada no HNS do Windows. O calico provê uma camada completa de conectividade e rede, mas também pode ser usado em conjunto com CNIs de provedores de nuvem para permitir a criação de políticas de rede.

Cilium

Cilium é um software de código fonte aberto para prover conectividade e segurança entre contêineres de aplicação. O Cilium pode lidar com tráfego na camada de aplicação (ex. HTTP) e pode forçar políticas de rede nas camadas L3-L7 usando um modelo de segurança baseado em identidade e desacoplado do endereçamento de redes, podendo inclusive ser utilizado com outros plugins CNI.

Flannel

Flannel é uma camada muito simples de conectividade que satisfaz os requisitos do Kubernetes. Muitas pessoas reportaram sucesso em utilizar o Flannel com o Kubernetes.

Google Compute Engine (GCE)

Para os scripts de configuração do Google Compute Engine, roteamento avançado é usado para associar para cada VM uma sub-rede (o padrão é /24 - 254 IPs). Qualquer tráfico direcionado para aquela sub-rede será roteado diretamente para a VM pela rede do GCE. Isso é adicional ao IP principal associado à VM, que é mascarado para o acesso à Internet. Uma brige Linux (chamada cbr0) é configurada para existir naquela sub-rede, e é configurada no docker através da opção --bridge.

O Docker é iniciado com:

DOCKER_OPTS="--bridge=cbr0 --iptables=false --ip-masq=false"

Essa bridge é criada pelo Kubelet (controlada pela opção --network-plugin=kubenet) de acordo com a informação .spec.podCIDR do Nó.

O Docker irá agora alocar IPs do bloco cbr-cidr. Contêineres podem alcançar outros contêineres e nós através da interface cbr0. Esses IPs são todos roteáveis dentro da rede do projeto do GCE.

O GCE mesmo não sabe nada sobre esses IPs, então não irá mascará-los quando tentarem se comunicar com a internet. Para permitir isso uma regra de IPTables é utilizada para mascarar o tráfego para IPs fora da rede do projeto do GCE (no exemplo abaixo, 10.0.0.0/8):

iptables -t nat -A POSTROUTING ! -d 10.0.0.0/8 -o eth0 -j MASQUERADE

Por fim, o encaminhamento de IP deve ser habilitado no Kernel de forma a processar os pacotes vindos dos contêineres:

sysctl net.ipv4.ip_forward=1

O resultado disso tudo é que Pods agora podem alcançar outros Pods e podem também se comunicar com a Internet.

Kube-router

Kube-router é uma solução construída que visa prover alta performance e simplicidade operacional. Kube-router provê um proxy de serviços baseado no LVS/IPVS, uma solução de comunicação pod-para-pod baseada em encaminhamento de pacotes Linux e sem camadas adicionais, e funcionalidade de políticas de redes baseadas no IPTables/IPSet.

Redes L2 e bridges Linux

Se você tem uma rede L2 "burra", como um switch em um ambiente "bare-metal", você deve conseguir fazer algo similar ao ambiente GCE explicado acima. Note que essas instruções foram testadas casualmente - parece funcionar, mas não foi propriamente testado. Se você conseguir usar essa técnica e aperfeiçoar o processo, por favor nos avise!!

Siga a parte "With Linux Bridge devices" desse tutorial super bacana do Lars Kellogg-Stedman.

Multus (Plugin multi redes)

Multus é um plugin Multi CNI para suportar a funcionalidade multi redes do Kubernetes usando objetos baseados em CRDs.

Multus suporta todos os plugins referência (ex. Flannel, DHCP, Macvlan) que implementam a especificação de CNI e plugins de terceiros (ex. Calico, Weave, Cilium, Contiv). Adicionalmente, Multus suporta cargas de trabalho no Kubernetes que necessitem de funcionalidades como SRIOV, DPDK, OVS-DPDK & VPP.

OVN (Open Virtual Networking)

OVN é uma solução de virtualização de redes de código aberto desenvolvido pela comunidade Open vSwitch. Permite a criação de switches lógicos, roteadores lógicos, listas de acesso, balanceadores de carga e mais, para construir diferences topologias de redes virtuais. Esse projeto possui um plugin específico para o Kubernetes e a documentação em ovn-kubernetes.

Próximos passos

Design inicial do modelo de conectividade do Kubernetes e alguns planos futuros estão descritos com maiores detalhes no documento de design de redes.

4 - Arquitetura de Log

Os logs de aplicativos e sistemas podem ajudá-lo a entender o que está acontecendo dentro do seu cluster. Os logs são particularmente úteis para depurar problemas e monitorar a atividade do cluster. A maioria das aplicações modernas possui algum tipo de mecanismo de logs; como tal, a maioria dos mecanismos de contêineres também é projetada para suportar algum tipo de log. O método de log mais fácil e abrangente para aplicações em contêiner é gravar nos fluxos de saída e erro padrão.

No entanto, a funcionalidade nativa fornecida por um mecanismo de contêiner ou tempo de execução geralmente não é suficiente para uma solução completa de log. Por exemplo, se um contêiner travar, um pod for despejado ou um nó morrer, geralmente você ainda desejará acessar os logs do aplicativo. Dessa forma, os logs devem ter armazenamento e ciclo de vida separados, independentemente de nós, pods ou contêineres. Este conceito é chamado cluster-level-logging. O log no nível de cluster requer um back-end separado para armazenar, analisar e consultar logs. O kubernetes não fornece uma solução de armazenamento nativa para dados de log, mas você pode integrar muitas soluções de log existentes no cluster do Kubernetes.

As arquiteturas de log no nível de cluster são descritas no pressuposto de que um back-end de log esteja presente dentro ou fora do cluster. Se você não estiver interessado em ter o log no nível do cluster, ainda poderá encontrar a descrição de como os logs são armazenados e manipulados no nó para serem úteis.

Log básico no Kubernentes

Nesta seção, você pode ver um exemplo de log básico no Kubernetes que gera dados para o fluxo de saída padrão(standard output stream). Esta demostração usa uma especificação de pod com um contêiner que grava algum texto na saída padrão uma vez por segundo.

apiVersion: v1
kind: Pod
metadata:
  name: counter
spec:
  containers:
  - name: count
    image: busybox
    args: [/bin/sh, -c,
            'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']

Para executar este pod, use o seguinte comando:

kubectl apply -f https://k8s.io/examples/debug/counter-pod.yaml

A saída será:

pod/counter created

Para buscar os logs, use o comando kubectl logs, da seguinte maneira:

kubectl logs counter

A saída será:

0: Mon Jan  1 00:00:00 UTC 2001
1: Mon Jan  1 00:00:01 UTC 2001
2: Mon Jan  1 00:00:02 UTC 2001
...

Você pode usar kubectl logs para recuperar logs de uma instanciação anterior de um contêiner com o sinalizador --previous, caso o contêiner tenha falhado. Se o seu pod tiver vários contêineres, você deverá especificar quais logs do contêiner você deseja acessar anexando um nome de contêiner ao comando. Veja a documentação do kubectl logs para mais destalhes.

Logs no nível do Nó

Log no nível do nó

Tudo o que um aplicativo em contêiner grava no stdout e stderr é tratado e redirecionado para algum lugar por dentro do mecanismo de contêiner. Por exemplo, o mecanismo de contêiner do Docker redireciona esses dois fluxos para um driver de log, configurado no Kubernetes para gravar em um arquivo no formato json.

Por padrão, se um contêiner reiniciar, o kubelet manterá um contêiner terminado com seus logs. Se um pod for despejado do nó, todos os contêineres correspondentes também serão despejados, juntamente com seus logs.

Uma consideração importante no log no nível do nó está implementado a rotação de log, para que os logs não consumam todo o armazenamento disponível no nó. Atualmente, o Kubernentes não é responsável pela rotação de logs, mas uma ferramenta de deployment deve configurar uma solução para resolver isso. Por exemplo, nos clusters do Kubernetes, implementados pelo script kube-up.sh, existe uma ferramenta logrotate configurada para executar a cada hora. Você pode configurar um tempo de execução do contêiner para girar os logs do aplicativo automaticamente, por exemplo, usando o log-opt do Docker. No script kube-up.sh, a última abordagem é usada para imagem COS no GCP, e a anterior é usada em qualquer outro ambiente. Nos dois casos por padrão, a rotação é configurada para ocorrer quando o arquivo de log exceder 10MB.

Como exemplo, você pode encontrar informações detalhadas sobre como o kube-up.sh define o log da imagem COS no GCP no script correspondente.

Quando você executa kubectl logs como no exemplo de log básico acima, o kubelet no nó lida com a solicitação e lê diretamente do arquivo de log, retornando o conteúdo na resposta.

Logs de componentes do sistema

Existem dois tipos de componentes do sistema: aqueles que são executados em um contêiner e aqueles que não são executados em um contêiner. Por exemplo:

  • O scheduler Kubernetes e o kube-proxy são executados em um contêiner.
  • O tempo de execução do kubelet e do contêiner, por exemplo, Docker, não é executado em contêineres.

Nas máquinas com systemd, o tempo de execução do kubelet e do container é gravado no journald. Se systemd não estiver presente, eles gravam em arquivos .log no diretório /var/log. Os componentes do sistema dentro dos contêineres sempre gravam no diretório /var/log, ignorando o mecanismo de log padrão. Eles usam a biblioteca de logs klog. Você pode encontrar as convenções para a gravidade do log desses componentes nos documentos de desenvolvimento sobre log.

Da mesma forma que os logs de contêiner, os logs de componentes do sistema no diretório /var/log devem ser rotacionados. Nos clusters do Kubernetes criados pelo script kube-up.sh, esses logs são configurados para serem rotacionados pela ferramenta logrotate diariamente ou quando o tamanho exceder 100MB.

Arquiteturas de log no nível de cluster

Embora o Kubernetes não forneça uma solução nativa para o log em nível de cluster, há várias abordagens comuns que você pode considerar. Aqui estão algumas opções:

  • Use um agente de log no nível do nó que seja executado em todos os nós.
  • Inclua um contêiner sidecar dedicado para efetuar logging em um pod de aplicativo.
  • Envie logs diretamente para um back-end de dentro de um aplicativo.

Usando um agente de log de nó

Usando um agente de log no nível do nó

Você pode implementar o log em nível de cluster incluindo um agente de log em nível de nó em cada nó. O agente de log é uma ferramenta dedicada que expõe logs ou envia logs para um back-end. Geralmente, o agente de log é um contêiner que tem acesso a um diretório com arquivos de log de todos os contêineres de aplicativos nesse nó.

Como o agente de log deve ser executado em todos os nós, é comum implementá-lo como uma réplica do DaemonSet, um pod de manifesto ou um processo nativo dedicado no nó. No entanto, as duas últimas abordagens são obsoletas e altamente desencorajadas.

O uso de um agente de log no nível do nó é a abordagem mais comum e incentivada para um cluster Kubernetes, porque ele cria apenas um agente por nó e não requer alterações nos aplicativos em execução no nó. No entanto, o log no nível do nó funciona apenas para a saída padrão dos aplicativos e o erro padrão.

O Kubernetes não especifica um agente de log, mas dois agentes de log opcionais são fornecidos com a versão Kubernetes: Stackdriver Logging para uso com o Google Cloud Platform e Elasticsearch. Você pode encontrar mais informações e instruções nos documentos dedicados. Ambos usam fluentd com configuração customizada como um agente no nó.

Usando um contêiner sidecar com o agente de log

Você pode usar um contêiner sidecar de uma das seguintes maneiras:

  • O container sidecar transmite os logs do aplicativo para seu próprio stdout.
  • O contêiner do sidecar executa um agente de log, configurado para selecionar logs de um contêiner de aplicativo.

Streaming sidecar conteiner

Conteiner sidecar com um streaming container

Fazendo com que seus contêineres de sidecar fluam para seus próprios stdout e stderr, você pode tirar proveito do kubelet e do agente de log que já executam em cada nó. Os contêineres sidecar lêem logs de um arquivo, socket ou journald. Cada contêiner sidecar individual imprime o log em seu próprio stdout ou stderr stream.

Essa abordagem permite separar vários fluxos de logs de diferentes partes do seu aplicativo, algumas das quais podem não ter suporte para gravar em stdout ou stderr. A lógica por trás do redirecionamento de logs é mínima, portanto dificilmente representa uma sobrecarga significativa. Além disso, como stdout e stderr são manipulados pelo kubelet, você pode usar ferramentas internas como o kubectl logs.

Considere o seguinte exemplo. Um pod executa um único contêiner e grava em dois arquivos de log diferentes, usando dois formatos diferentes. Aqui está um arquivo de configuração para o Pod:

apiVersion: v1
kind: Pod
metadata:
  name: counter
spec:
  containers:
  - name: count
    image: busybox
    args:
    - /bin/sh
    - -c
    - >
      i=0;
      while true;
      do
        echo "$i: $(date)" >> /var/log/1.log;
        echo "$(date) INFO $i" >> /var/log/2.log;
        i=$((i+1));
        sleep 1;
      done      
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  volumes:
  - name: varlog
    emptyDir: {}

Seria uma bagunça ter entradas de log de diferentes formatos no mesmo fluxo de logs, mesmo se você conseguisse redirecionar os dois componentes para o fluxo stdout do contêiner. Em vez disso, você pode introduzir dois contêineres sidecar. Cada contêiner sidecar pode direcionar um arquivo de log específico de um volume compartilhado e depois redirecionar os logs para seu próprio fluxo stdout.

Aqui está um arquivo de configuração para um pod que possui dois contêineres sidecar:

apiVersion: v1
kind: Pod
metadata:
  name: counter
spec:
  containers:
  - name: count
    image: busybox
    args:
    - /bin/sh
    - -c
    - >
      i=0;
      while true;
      do
        echo "$i: $(date)" >> /var/log/1.log;
        echo "$(date) INFO $i" >> /var/log/2.log;
        i=$((i+1));
        sleep 1;
      done      
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  - name: count-log-1
    image: busybox
    args: [/bin/sh, -c, 'tail -n+1 -f /var/log/1.log']
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  - name: count-log-2
    image: busybox
    args: [/bin/sh, -c, 'tail -n+1 -f /var/log/2.log']
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  volumes:
  - name: varlog
    emptyDir: {}

Agora, quando você executa este pod, é possível acessar cada fluxo de log separadamente, executando os seguintes comandos:

kubectl logs counter count-log-1
0: Mon Jan  1 00:00:00 UTC 2001
1: Mon Jan  1 00:00:01 UTC 2001
2: Mon Jan  1 00:00:02 UTC 2001
...
kubectl logs counter count-log-2
Mon Jan  1 00:00:00 UTC 2001 INFO 0
Mon Jan  1 00:00:01 UTC 2001 INFO 1
Mon Jan  1 00:00:02 UTC 2001 INFO 2
...

O agente no nível do nó instalado em seu cluster coleta esses fluxos de logs automaticamente sem nenhuma configuração adicional. Se desejar, você pode configurar o agente para analisar as linhas de log, dependendo do contêiner de origem.

Observe que, apesar do baixo uso da CPU e da memória (ordem de alguns milicores por CPU e ordem de vários megabytes de memória), gravar logs em um arquivo e depois transmiti-los para o stdout pode duplicar o uso do disco. Se você tem um aplicativo que grava em um único arquivo, geralmente é melhor definir /dev/stdout como destino, em vez de implementar a abordagem de contêiner de transmissão no sidecar.

Os contêineres sidecar também podem ser usados para rotacionar arquivos de log que não podem ser rotacionados pelo próprio aplicativo. Um exemplo dessa abordagem é um pequeno contêiner executando logrotate periodicamente. No entanto, é recomendável usar o stdout e o stderr diretamente e deixar as políticas de rotação e retenção no kubelet.

Contêiner sidecar com um agente de log

Contêiner sidecar com um agente de log

Se o agente de log no nível do nó não for flexível o suficiente para sua situação, você poderá criar um contêiner secundário com um agente de log separado que você configurou especificamente para executar com seu aplicativo.

Como exemplo, você pode usar o Stackdriver, que usa fluentd como um agente de log. Aqui estão dois arquivos de configuração que você pode usar para implementar essa abordagem. O primeiro arquivo contém um ConfigMap para configurar o fluentd.

apiVersion: v1
kind: ConfigMap
metadata:
  name: fluentd-config
data:
  fluentd.conf: |
    <source>
      type tail
      format none
      path /var/log/1.log
      pos_file /var/log/1.log.pos
      tag count.format1
    </source>

    <source>
      type tail
      format none
      path /var/log/2.log
      pos_file /var/log/2.log.pos
      tag count.format2
    </source>

    <match **>
      type google_cloud
    </match>    

O segundo arquivo descreve um pod que possui um contêiner sidecar rodando fluentemente. O pod monta um volume onde o fluentd pode coletar seus dados de configuração.

apiVersion: v1
kind: Pod
metadata:
  name: counter
spec:
  containers:
  - name: count
    image: busybox
    args:
    - /bin/sh
    - -c
    - >
      i=0;
      while true;
      do
        echo "$i: $(date)" >> /var/log/1.log;
        echo "$(date) INFO $i" >> /var/log/2.log;
        i=$((i+1));
        sleep 1;
      done      
    volumeMounts:
    - name: varlog
      mountPath: /var/log
  - name: count-agent
    image: registry.k8s.io/fluentd-gcp:1.30
    env:
    - name: FLUENTD_ARGS
      value: -c /etc/fluentd-config/fluentd.conf
    volumeMounts:
    - name: varlog
      mountPath: /var/log
    - name: config-volume
      mountPath: /etc/fluentd-config
  volumes:
  - name: varlog
    emptyDir: {}
  - name: config-volume
    configMap:
      name: fluentd-config

Depois de algum tempo, você pode encontrar mensagens de log na interface do Stackdriver.

Lembre-se de que este é apenas um exemplo e você pode realmente substituir o fluentd por qualquer agente de log, lendo de qualquer fonte dentro de um contêiner de aplicativo.

Expondo logs diretamente do aplicativo

Expondo logs diretamente do aplicativo

Você pode implementar o log no nível do cluster, expondo ou enviando logs diretamente de todos os aplicativos; no entanto, a implementação desse mecanismo de log está fora do escopo do Kubernetes.

5 - Logs de Sistema

Logs de componentes do sistema armazenam eventos que acontecem no cluster, sendo muito úteis para depuração. Seus níveis de detalhe podem ser ajustados para mais ou para menos. Podendo se ater, por exemplo, a mostrar apenas os erros que ocorrem no componente, ou chegando a mostrar cada passo de um evento. (Como acessos HTTP, mudanças no estado dos pods, ações dos controllers, ou decisões do scheduler).

Klog

Klog é a biblioteca de logs do Kubernetes. Responsável por gerar as mensagens de log para os componentes do sistema.

Para mais informações acerca da sua configuração, veja a documentação da ferramenta de linha de comando.

Um exemplo do formato padrão dos logs da biblioteca:

I1025 00:15:15.525108       1 httplog.go:79] GET /api/v1/namespaces/kube-system/pods/metrics-server-v0.3.1-57c75779f-9p8wg: (1.512ms) 200 [pod_nanny/v0.0.0 (linux/amd64) kubernetes/$Format 10.56.1.19:51756]

Logs Estruturados

ESTADO DA FUNCIONALIDADE: Kubernetes v1.19 [alpha]

A estruturação dos logs trás uma estrutura uniforme para as mensagens de log, permitindo a extração programática de informações. Logs estruturados podem ser armazenados e processados com menos esforço e custo. Esse formato é totalmente retrocompatível e é habilitado por padrão.

Formato dos logs estruturados:

<klog header> "<message>" <key1>="<value1>" <key2>="<value2>" ...

Exemplo:

I1025 00:15:15.525108       1 controller_utils.go:116] "Pod status updated" pod="kube-system/kubedns" status="ready"

Logs em formato JSON

ESTADO DA FUNCIONALIDADE: Kubernetes v1.19 [alpha]

A opção --logging-format=json muda o formato dos logs, do formato padrão da klog para JSON. Abaixo segue um exemplo de um log em formato JSON (identado):

{
   "ts": 1580306777.04728,
   "v": 4,
   "msg": "Pod status updated",
   "pod":{
      "name": "nginx-1",
      "namespace": "default"
   },
   "status": "ready"
}

Chaves com significados especiais:

  • ts - Data e hora no formato Unix (obrigatório, float)
  • v - Nível de detalhe (obrigatório, int, padrão 0)
  • err - Mensagem de erro (opcional, string)
  • msg - Mensagem (obrigatório, string)

Lista dos componentes que suportam o formato JSON atualmente:

Limpeza dos Logs

ESTADO DA FUNCIONALIDADE: Kubernetes v1.20 [alpha]

A opção --experimental-logging-sanitization habilita o filtro de limpeza dos logs. Quando habilitado, esse filtro inspeciona todos os argumentos dos logs, procurando por campos contendo dados sensíveis (como senhas, chaves e tokens). Tais campos não serão expostos nas mensagens de log.

Lista dos componentes que suportam a limpeza de logs atualmente:

Nível de detalhe dos logs

A opção -v controla o nível de detalhe dos logs. Um valor maior aumenta o número de eventos registrados, começando a registrar também os eventos menos importantes. Similarmente, um valor menor restringe os logs apenas aos eventos mais importantes. O valor padrão 0 registra apenas eventos críticos.

Localização dos Logs

Existem dois tipos de componentes do sistema: aqueles que são executados em um contêiner e aqueles que não são. Por exemplo:

Em máquinas com systemd, o kubelet e os agentes de execução gravam os logs no journald. Em outros casos, eles escrevem os logs em arquivos .log no diretório /var/log. Já os componentes executados dentro de contêineres, sempre irão escrever os logs em arquivos .log no diretório /var/log, ignorando o mecanismo padrão de log.

De forma similar aos logs de contêiner, os logs de componentes do sistema no diretório /var/log devem ser rotacionados. Nos clusters Kubernetes criados com o script kube-up.sh, a rotação dos logs é configurada pela ferramenta logrotate. Essa ferramenta rotaciona os logs diariamente ou quando o tamanho do arquivo excede 100MB.

Próximos passos

6 - Métricas para componentes do sistema Kubernetes

Métricas dos componentes do sistema podem dar uma visão melhor do que acontece internamente. Métricas são particularmente úteis para construir dashboards e alertas.

Componentes do Kubernetes emitem métricas no formato Prometheus. Esse formato é um texto simples estruturado, projetado para que pessoas e máquinas possam lê-lo.

Métricas no Kubernetes

Na maioria dos casos, as métricas estão disponíveis no endpoint /metrics do servidor HTTP. Para componentes que não expõem o endpoint por padrão, ele pode ser ativado usando a flag --bind-address.

Exemplos desses componentes:

Em um ambiente de produção, você pode querer configurar o Servidor Prometheus ou algum outro coletor de métricas e disponibilizá-las em algum tipo de banco de dados temporais.

Observe que o kubelet também expõe métricas nos endpoints /metrics/cadvisor, /metrics/resource e /metrics/probes. Essas métricas não possuem o mesmo ciclo de vida.

Se o seu cluster usa RBAC, ler as métricas requer autorização por meio de um usuário, grupo ou ServiceAccount com um ClusterRole que conceda o acesso ao /metrics.

Por exemplo:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: prometheus
rules:
  - nonResourceURLs:
      - "/metrics"
    verbs:
      - get

Ciclo de vida da métrica

Métrica alfa → Métrica estável → Métrica ultrapassada → Métrica oculta → Métrica excluída

A métrica alfa não tem garantias de estabilidade. Essas métricas podem ser modificadas ou deletadas a qualquer momento.

Métricas estáveis possuem a garantia de que não serão alteradas. Isso significa:

  • Uma métrica estável sem uma assinatura ultrapassada não será deletada ou renomeada
  • O tipo de uma métrica estável não será modificado

As métricas ultrapassadas estão programadas para exclusão, mas ainda estão disponíveis para uso. Essas métricas incluem uma anotação sobre a versão em que se tornarão ultrapassadas.

Por exemplo:

  • Antes de se tornar ultrapassado

    # HELP some_counter isso conta coisas
    # TYPE some_counter contador
    some_counter 0
    
  • Depois de se tornar ultrapassado

    # HELP some_counter (obsoleto desde 1.15.0) isso conta coisas
    # TYPE some_counter contador
    some_counter 0
    

Métricas ocultas não são mais publicadas para extração, mas ainda estão disponíveis para uso. Para usar uma métrica oculta, por favor consulte a seção mostrar métricas ocultas.

Métricas excluídas não estão mais disponíveis e não podem mais ser usadas.

Mostrar métricas ocultas

Como descrito anteriormente, administradores podem habilitar métricas ocultas por meio de uma flag de linha de comando em um binário específico. Isso pode ser usado como uma saída de emergência para os administradores caso percam a migração das métricas ultrapassadas na última versão.

A flag show-hidden-metrics-for-version usa uma versão para a qual você deseja mostrar métricas ultrapassadas nessa versão. A versão é expressada como x.y, onde x é a versão principal e y a versão secundária. A versão de patch não é necessária mesmo que uma métrica possa ser descontinuada em uma versão de patch, o motivo é que a política de descontinuação de métricas é executada na versão secundária.

A flag só pode usar a versão secundária anterior como seu valor. Todas as métricas ocultas no anterior serão emitidas se os administradores definirem a versão anterior como show-hidden-metrics-for-version. A versão muito antiga não é permitida porque viola a política de métricas ultrapassadas.

Utilize a métrica A como exemplo, assumindo que A está obsoleto em 1.n. De acordo com a política de métricas ultrapassadas, podemos chegar à seguinte conclusão:

  • Na versão 1.n, a métrica está ultrapassada, e pode ser emitida por padrão.
  • Na versão 1.n+1, a métrica está oculta por padrão e pode ser emitida via linha de comando show-hidden-metrics-for-version=1.n.
  • Na versão 1.n+2, a métrica deve ser removida do código fonte. Não há mais escape hatch.

Se você está atualizando da versão 1.12 para 1.13, mas ainda depende da métrica A ultrapassada em 1.12, você deve definir métricas ocultas via linha de comando: --show-hidden-metrics=1.12 e lembre-se de remover essa dependência de métrica antes de atualizar para 1.14.

Desativar métricas do accelerator

O kubelet coleta métricas do accelerator por meio do cAdvisor. Para coletar essas métricas, para accelerator como as GPUs NVIDIA, o kubelet mantinha uma alça aberta no driver. Isso significava que, para realizar alterações na infraestrutura (por exemplo, atualizar o driver), um administrador do cluster precisa interromper o agente kubelet.

A responsabilidade de colear métricas do accelerator agora pertence ao fornecedor, e não ao kubelet. Os fornecedores devem providenciar um contêiner que colete métricas e as exponha ao serviço de métricas (por exemplo, Prometheus).

O DisableAcceleratorUsageMetrics feature gate desabilita as métricas coletadas pelo kubelet, com uma timeline para habilitar esse recurso por padrão.

Métricas de componentes

Métricas do kube-controller-manager

As métricas do controller manager fornecem informações importantes sobre o desempenho e a integridade do controller manager. Essas métricas incluem métricas comuns do agente de execução da linguagem Go, tais como a quantidade de go_routine e métricas específicas do controller, como latência de requisições etcd ou latência da API dos provedores de serviços de nuvem (AWS, GCE, OpenStack), que podem ser usadas para medir a integridade de um cluster.

A partir do Kubernetes 1.7, métricas detalhadas de provedores de serviços de nuvem estão disponíveis para operações de armazenamento para o GCE, AWS, Vsphere e OpenStack. Essas métricas podem ser usadas para monitorar a integridade das operações de volumes persistentes.

Por exemplo, para o GCE as seguintes métricas são chamadas:

cloudprovider_gce_api_request_duration_seconds { request = "instance_list"}
cloudprovider_gce_api_request_duration_seconds { request = "disk_insert"}
cloudprovider_gce_api_request_duration_seconds { request = "disk_delete"}
cloudprovider_gce_api_request_duration_seconds { request = "attach_disk"}
cloudprovider_gce_api_request_duration_seconds { request = "detach_disk"}
cloudprovider_gce_api_request_duration_seconds { request = "list_disk"}

Métricas do kube-scheduler

ESTADO DA FUNCIONALIDADE: Kubernetes v1.21 [beta]

O scheduler expõe métricas opcionais que relatam os recursos solicitados e os limites desejados de todos os pods em execução. Essas métricas podem ser usadas para criar dashboards de planejamento de capacidade, avaliar os limites de agendamentos atuais ou históricos, identificar rapidamente cargas de trabalho que não podem ser agendadas devido à falta de recursos e comparar o uso atual com a solicitação do pod.

O kube-scheduler identifica as requisições de recursos e limites configurado para cada Pod; quando uma requisição ou limite é diferente de zero o kube-scheduler relata uma timeseries de métricas. Essa timeseries é etiquetada por:

  • namespace
  • nome do pod
  • o nó onde o pod está programado ou uma string vazia caso ainda não esteja programado
  • prioridade
  • o scheduler atribuído para esse pod
  • o nome do recurso (por exemplo, cpu)
  • a unidade do recurso, se conhecida (por exemplo, cores)

Uma vez que o pod alcança um estado de conclusão (sua restartPolicy está como Never ou onFailure e está na fase de Succeeded ou Failed, ou foi deletado e todos os contêineres tem um estado de terminado), a série não é mais relatada já que o scheduler agora está livre para agendar a execução de outros pods. As duas métricas são chamadas de kube_pod_resource_request e kube_pod_resource_limit.

As métricas são expostas no endpoint HTTP /metrics/resources e requerem a mesma autorização que o endpoint /metrics no scheduler. Você deve usar a flag --show-hidden-metrics-for-version=1.20 para expor essas métricas de estabilidade alfa.

Desativando métricas

Você pode desativar explicitamente as métricas via linha de comando utilizando a flag --disabled-metrics. Isso pode ser desejado se, por exemplo, uma métrica estiver causando um problema de desempenho. A entrada é uma lista de métricas desabilitadas (ou seja, --disabled-metrics=metric1,metric2).

Aplicação de cardinalidade de métrica

As métricas com dimensões sem limites podem causar problemas de memória nos componentes que elas instrumentam. Para limitar a utilização de recursos você pode usar a opção de linha de comando --allow-label-value para dinamicamente configurar uma lista de permissões de valores de label para uma métrica.

No estágio alfa, a flag pode receber apenas uma série de mapeamentos como lista de permissões de labels para uma métrica. Cada mapeamento tem o formato <metric_name>,<label_name>=<allowed_labels> onde <allowed_labels> é uma lista separada por vírgulas de nomes aceitáveis para a label.

O formato geral se parece com: --allow-label-value <metric_name>,<label_name>='<allow_value1>, <allow_value2>...', <metric_name2>,<label_name>='<allow_value1>, <allow_value2>...', ....

Por exemplo: --allow-label-value number_count_metric,odd_number='1,3,5', number_count_metric,even_number='2,4,6', date_gauge_metric,weekend='Saturday,Sunday'

Próximos passos

7 - Configurando o Garbage Collection do kubelet

O Garbage collection(Coleta de lixo) é uma função útil do kubelet que limpa imagens e contêineres não utilizados. O kubelet executará o garbage collection para contêineres a cada minuto e para imagens a cada cinco minutos.

Ferramentas externas de garbage collection não são recomendadas, pois podem potencialmente interromper o comportamento do kubelet removendo os contêineres que existem.

Coleta de imagens

O Kubernetes gerencia o ciclo de vida de todas as imagens através do imageManager, com a cooperação do cadvisor.

A política para o garbage collection de imagens leva dois fatores em consideração: HighThresholdPercent e LowThresholdPercent. Uso do disco acima do limite acionará o garbage collection. O garbage collection excluirá as imagens que foram menos usadas recentemente até que o nível fique abaixo do limite.

Coleta de container

A política para o garbage collection de contêineres considera três variáveis definidas pelo usuário. MinAge é a idade mínima em que um contêiner pode ser coletado. MaxPerPodContainer é o número máximo de contêineres mortos que todo par de pod (UID, container name) pode ter. MaxContainers é o número máximo de contêineres mortos totais. Essas variáveis podem ser desabilitadas individualmente, definindo MinAge como zero e definindo MaxPerPodContainer e MaxContainers respectivamente para menor que zero.

O Kubelet atuará em contêineres não identificados, excluídos ou fora dos limites definidos pelos sinalizadores mencionados. Os contêineres mais antigos geralmente serão removidos primeiro. MaxPerPodContainer e MaxContainer podem potencialmente conflitar entre si em situações em que a retenção do número máximo de contêineres por pod (MaxPerPodContainer) estaria fora do intervalo permitido de contêineres globais mortos (MaxContainers). O MaxPerPodContainer seria ajustado nesta situação: O pior cenário seria fazer o downgrade do MaxPerPodContainer para 1 e remover os contêineres mais antigos. Além disso, os contêineres pertencentes a pods que foram excluídos são removidos assim que se tornem mais antigos que MinAge.

Os contêineres que não são gerenciados pelo kubelet não estão sujeitos ao garbage collection de contêiner.

Configurações do usuário

Os usuários podem ajustar os seguintes limites para ajustar o garbage collection da imagem com os seguintes sinalizadores do kubelet:

  1. image-gh-high-threshold, a porcentagem de uso de disco que aciona o garbage collection da imagem. O padrão é 85%.
  2. image-gc-low-threshold, a porcentagem de uso de disco com o qual o garbage collection da imagem tenta liberar. O padrão é 80%.

Também permitimos que os usuários personalizem a política do garbagem collection através dos seguintes sinalizadores do kubelet:

  1. minimum-container-ttl-duration, idade mínima para um contêiner finalizado antes de ser colectado. O padrão é 0 minuto, o que significa que todo contêiner finalizado será coletado como lixo.
  2. maximum-dead-containers-per-container, número máximo de instâncias antigas a serem retidas por contêiner. O padrão é 1.
  3. maximum-dead-containers, número máximo de instâncias antigas de contêineres para retenção global. O padrão é -1, o que significa que não há limite global.

Os contêineres podem ser potencialmente coletados como lixo antes que sua utilidade expire. Esses contêineres podem conter logs e outros dados que podem ser úteis para solucionar problemas. Um valor suficientemente grande para maximum-dead-containers-per-container é altamente recomendado para permitir que pelo menos 1 contêiner morto seja retido por contêiner esperado. Um valor maior para maximum-dead-containers também é recomendados por um motivo semelhante. Consulte esta issue para obter mais detalhes.

Descontinuado

Alguns recursos do Garbage Collection neste documento serão substituídos pelo kubelet eviction no futuro.

Incluindo:

Flag ExistenteNova FlagFundamentação
--image-gc-high-threshold--eviction-hard ou --eviction-softos sinais existentes de despejo podem acionar o garbage collection da imagem
--image-gc-low-threshold--eviction-minimum-reclaimrecuperações de despejo atinge o mesmo comportamento
--maximum-dead-containersdescontinuado quando os logs antigos forem armazenados fora do contexto do contêiner
--maximum-dead-containers-per-containerdescontinuado quando os logs antigos forem armazenados fora do contexto do contêiner
--minimum-container-ttl-durationdescontinuado quando os logs antigos forem armazenados fora do contexto do contêiner
--low-diskspace-threshold-mb--eviction-hard ou eviction-softO despejo generaliza os limites do disco para outros recursos
--outofdisk-transition-frequency--eviction-pressure-transition-periodO despejo generaliza a transição da pressão do disco para outros recursos

Próximos passos

Consulte Configurando a Manipulação de Recursos Insuficientes para mais detalhes.

8 - Proxies no Kubernetes

Esta página descreve o uso de proxies com Kubernetes.

Proxies

Existem vários tipos diferentes de proxies que você pode encontrar usando Kubernetes:

  1. O kubectl proxy:

Quando o kubectl proxy é utilizado ocorre o seguinte: - executa na máquina do usuário ou em um pod - redireciona/encapsula conexões direcionadas ao localhost para o servidor de API - a comunicação entre o cliente e o o proxy usa HTTP - a comunicação entre o proxy e o servidor de API usa HTTPS - o proxy localiza o servidor de API do cluster - o proxy adiciona os cabeçalhos de comunicação.

  1. O apiserver proxy:

    • é um bastion server, construído no servidor de API
    • conecta um usuário fora do cluster com os IPs do cluster que não podem ser acessados de outra forma
    • executa dentro do processo do servidor de API
    • cliente para proxy usa HTTPS (ou HTTP se o servidor de API for configurado)
    • proxy para o destino pode usar HTTP ou HTTPS conforme escolhido pelo proxy usando as informações disponíveis
    • pode ser usado para acessar um Nó, Pod ou serviço
    • faz balanceamento de carga quando usado para acessar um Service.
  2. O kube proxy:

    • executa em todos os Nós
    • atua como proxy para UDP, TCP e SCTP
    • não aceita HTTP
    • provém balanceamento de carga
    • apenas é usado para acessar serviços.
  3. Um Proxy/Balanceador de carga na frente de servidores de API(s):

    • a existência e a implementação de tal elemento varia de cluster para cluster, por exemplo nginx
    • fica entre todos os clientes e um ou mais serviços
    • atua como balanceador de carga se existe mais de um servidor de API.
  4. Balanceadores de carga da nuvem em serviços externos:

    • são fornecidos por algum provedor de nuvem (e.x AWS ELB, Google Cloud Load Balancer)
    • são criados automaticamente quando o serviço de Kubernetes tem o tipo LoadBalancer
    • geralmente suportam apenas UDP/TCP
    • O suporte ao SCTP fica por conta da implementação do balanceador de carga da provedora de nuvem
    • a implementação varia de acordo com o provedor de cloud.

Os usuários de Kubernetes geralmente não precisam se preocupar com outras coisas além dos dois primeiros tipos. O administrador do cluster tipicamente garante que os últimos tipos serão configurados corretamente.

Redirecionamento de requisições

Os proxies substituíram as capacidades de redirecionamento. O redirecionamento foi depreciado.

9 - Instalando Complementos

Complementos estendem as funcionalidades do Kubernetes.

Esta página lista alguns dos complementos disponíveis e links com suas respectivas instruções de instalação.

Rede e Política de Rede

  • ACI fornece rede integrada de contêineres e segurança de rede com a Cisco ACI.
  • Antrea opera nas camadas 3 e 4 do modelo de rede OSI para fornecer serviços de rede e de segurança para o Kubernetes, aproveitando o Open vSwitch como camada de dados de rede.
  • Calico é um provedor de serviços de rede e de políticas de rede. Este complemento suporta um conjunto flexível de opções de rede, de modo a permitir a escolha da opção mais eficiente para um dado caso de uso, incluindo redes overlay (sobrepostas) e não-overlay, com ou sem o uso do protocolo BGP. Calico usa o mesmo mecanismo para aplicar políticas de rede a hosts, pods, e aplicações na camada de service mesh (quando Istio e Envoy estão instalados).
  • Canal une Flannel e Calico, fornecendo rede e política de rede.
  • Cilium é um plug-in de rede de camada 3 e de políticas de rede que pode aplicar políticas HTTP/API/camada 7 de forma transparente. Tanto o modo de roteamento quanto o de sobreposição/encapsulamento são suportados. Este plug-in também consegue operar no topo de outros plug-ins CNI.
  • CNI-Genie permite que o Kubernetes se conecte facilmente a uma variedade de plug-ins CNI, como Calico, Canal, Flannel, Romana ou Weave.
  • Contiv oferece serviços de rede configuráveis para diferentes casos de uso (camada 3 nativa usando BGP, overlay (sobreposição) usando vxlan, camada 2 clássica e Cisco-SDN/ACI) e também um framework rico de políticas de rede. O projeto Contiv é totalmente open source. O instalador fornece opções de instalação com ou sem kubeadm.
  • Contrail é uma plataforma open source baseada no Tungsten Fabric que oferece virtualização de rede multi-nuvem e gerenciamento de políticas de rede. O Contrail e o Tungsten Fabric são integrados a sistemas de orquestração de contêineres, como Kubernetes, OpenShift, OpenStack e Mesos, e fornecem modos de isolamento para cargas de trabalho executando em máquinas virtuais, contêineres/pods e servidores físicos.
  • Flannel é um provedor de redes overlay (sobrepostas) que pode ser usado com o Kubernetes.
  • Knitter é um plug-in para suporte de múltiplas interfaces de rede em Pods do Kubernetes.
  • Multus é um plugin para suporte a várias interfaces de rede em Pods no Kubernetes. Este plug-in pode agir como um "meta-plug-in", ou um plug-in CNI que se comunica com múltiplos outros plug-ins CNI (por exemplo, Calico, Cilium, Contiv, Flannel), além das cargas de trabalho baseadas em SRIOV, DPDK, OVS-DPDK e VPP no Kubernetes.
  • NSX-T Container Plug-in (NCP) fornece integração entre o VMware NSX-T e sistemas de orquestração de contêineres como o Kubernetes. Além disso, oferece também integração entre o NSX-T e as plataformas CaaS/PaaS baseadas em contêiner, como o Pivotal Container Service (PKS) e o OpenShift.
  • Nuage é uma plataforma de rede definida por software que fornece serviços de rede baseados em políticas entre os Pods do Kubernetes e os ambientes não-Kubernetes, com visibilidade e monitoramento de segurança.
  • OVN-Kubernetes é um provedor de rede para o Kubernetes baseado no OVN (Open Virtual Network), uma implementação de redes virtuais que surgiu através do projeto Open vSwitch (OVS). O OVN-Kubernetes fornece uma implementação de rede baseada em overlay (sobreposição) para o Kubernetes, incluindo uma implementação baseada em OVS para serviços de balanceamento de carga e políticas de rede.
  • OVN4NFV-K8S-Plugin é um plug-in controlador CNI baseado no OVN (Open Virtual Network) que fornece serviços de rede cloud native, como Service Function Chaining (SFC), redes overlay (sobrepostas) OVN múltiplas, criação dinâmica de subredes, criação dinâmica de redes virtuais, provedor de rede VLAN e provedor de rede direto, e é plugável a outros plug-ins multi-rede. Ideal para cargas de trabalho que utilizam computação de borda cloud native em redes multi-cluster.
  • Romana é uma solução de rede de camada 3 para redes de pods que também suporta a API NetworkPolicy. Detalhes da instalação do complemento Kubeadm disponíveis aqui.
  • Weave Net fornece rede e política de rede, funciona em ambos os lados de uma partição de rede e não requer um banco de dados externo.

Descoberta de Serviço

  • CoreDNS é um servidor DNS flexível e extensível que pode ser instalado como o serviço de DNS dentro do cluster para ser utilizado por pods.

Visualização & Controle

  • Dashboard é uma interface web para gestão do Kubernetes.
  • Weave Scope é uma ferramenta gráfica para visualizar contêineres, pods, serviços, entre outros objetos do cluster. Pode ser utilizado com uma conta Weave Cloud. Como alternativa, é possível hospedar a interface do usuário por conta própria.

Infraestrutura

  • KubeVirt é um complemento para executar máquinas virtuais no Kubernetes. É geralmente executado em clusters em máquina física.

Complementos Legados

Existem vários outros complementos documentados no diretório cluster/addons que não são mais utilizados.

Projetos bem mantidos devem ser listados aqui. PRs são bem-vindos!

10 - Prioridade e imparcialidade da API

ESTADO DA FUNCIONALIDADE: Kubernetes v1.20 [beta]

Controlar o comportamento do servidor da API Kubernetes em uma situação de sobrecarga é uma tarefa chave para administradores de cluster. O kube-apiserver tem alguns controles disponíveis (ou seja, as flags --max-requests-inflight e --max-mutating-requests-inflight) para limitar a quantidade de trabalho pendente que será aceito, evitando que uma grande quantidade de solicitações de entrada sobrecarreguem, e potencialmente travando o servidor da API, mas essas flags não são suficientes para garantir que as solicitações mais importantes cheguem em um período de alto tráfego.

O recurso de prioridade e imparcialidade da API (do inglês API Priority and Fairness, APF) é uma alternativa que melhora as limitações mencionadas acima. A APF classifica e isola os pedidos de uma forma mais refinada. Também introduz uma quantidade limitada de filas, para que nenhuma solicitação seja rejeitada nos casos de sobrecargas muito breves. As solicitações são despachadas das filas usando uma técnica de filas justa para que, por exemplo, um controller não precise negar as outras requisições (mesmo no mesmo nível de prioridade).

Esse recurso foi projetado para funcionar bem com controladores padrão, que usam informantes e reagem a falhas de solicitações da API com exponencial back-off, e outros clientes que também funcionam desta forma.

Ativando/Desativando a prioridade e imparcialidade da API

O recurso de prioridade e imparcialidade da API é controlado por um feature gate e está habilitado por padrão. Veja Portões de Recurso para uma explicação geral dos portões de recursos e como habilitar e desativá-los. O nome da porta de recurso para APF é "APIPriorityAndFairness". Este recurso também envolve um API Group com: (a) um Versão v1alpha1, desabilitada por padrão, e (b) v1beta1 e Versões v1beta2, habilitadas por padrão. Você pode desativar o feature gate e versões beta do grupo de APIs adicionando a seguinte flag para sua invocação kube-apiserver:

kube-apiserver \
--feature-gates=APIPriorityAndFairness=false \
--runtime-config=flowcontrol.apiserver.k8s.io/v1beta1=false,flowcontrol.apiserver.k8s.io/v1beta2=false \
 # …and other flags as usual

Como alternativa, você pode habilitar a versão v1alpha1 do grupo de APIs com --runtime-config=flowcontrol.apiserver.k8s.io/v1alpha1=true.

A flag --enable-priority-and-fairness=false desabilitará o recurso de prioridade e imparcialidade da API, mesmo que outras flags o tenha ativado.

Conceitos

Existem vários recursos distintos envolvidos na APF. As solicitações recebidas são classificadas por atributos da solicitação usando FlowSchemas e atribuídos a níveis de prioridade. Os níveis de prioridade adicionam um grau de isolamento mantendo limites de simultaneidade separados, para que as solicitações atribuídas a diferentes níveis de prioridade não travem outros. Dentro de um nível de prioridade, um algoritmo de fair queuing impede que solicitações de diferentes flows fiquem sem energia entre si, e permite que os pedidos sejam enfileirados para evitar que um alto tráfego cause falhas nas solicitações quando a carga média é aceitavelmente baixa.

Níveis de prioridade

Sem o APF ativado, a simultaneidade geral no servidor de API é limitada pelo kube-apiserver as flags --max-requests-inflight e --max-mutating-requests-inflight. Com o APF ativado, os limites de simultaneidade definidos por esses sinalizadores são somados e, em seguida, a soma é dividida entre um conjunto configurável de níveis de prioridade. Cada solicitação recebida é atribuída a um nível de prioridade único, e cada nível de prioridade só despachará tantos solicitações simultâneas conforme sua configuração permite.

A configuração padrão, por exemplo, inclui níveis de prioridade separados para solicitações de eleição de líder, solicitações de controladores integrados e solicitações de Pods. Isso significa que um pod mal-comportado que inunda o servidor da API com solicitações não podem impedir a eleição do líder ou ações dos controladores integrados de ter sucesso.

Enfileiramento

Mesmo dentro de um nível de prioridade pode haver um grande número de fontes distintas de tráfego. Em uma situação de sobrecarga, é importante evitar um fluxo de pedidos de outros serviços (em particular, no caso relativamente comum de um único cliente buggy inundando o kube-apiserver com solicitações, esse cliente buggy idealmente não teria muito impacto em outros clientes). Isto é tratadas pelo uso de um algoritmo de fair queuing para processar solicitações que são atribuídas ao mesmo nível de prioridade. Cada solicitação é atribuída a um flow, identificado pelo nome do FlowSchema correspondente mais um flow distincter — que é o usuário solicitante, o namespace do recurso de destino ou nada — e o sistema tenta dar peso aproximadamente igual a solicitações em diferentes fluxos do mesmo nível de prioridade. Para habilitar o tratamento distinto de instâncias distintas, os controladores que muitas instâncias devem ser autenticadas com nomes de usuário distintos

Depois de classificar uma solicitação em um fluxo, a APF pode então atribuir a solicitação a uma fila. Esta atribuição usa uma técnica conhecida como shuffle sharding, que faz uso relativamente eficiente de filas para isolar fluxos de baixa intensidade de fluxos de alta intensidade.

Os detalhes do algoritmo de enfileiramento são ajustáveis ​​para cada nível de prioridade e permitem que os administradores troquem o uso de memória, justiça (a propriedade que fluxos independentes irão progredir quando o tráfego total exceder a capacidade), tolerância para tráfego e a latência adicionada induzida pelo enfileiramento.

Solicitações de isenção

Alguns pedidos são considerados suficientemente importantes para que não estejam sujeitos a qualquer uma das limitações impostas por este recurso. Estas isenções impedem uma configuração de controle de fluxo mal configurada de desabilitar totalmente um servidor da API.

Recursos

A API de controle de fluxo envolve dois tipos de recursos. PriorityLevelConfigurations define as classes de isolamento disponíveis, a parte da concorrência disponível que cada um pode tratar e permite o ajuste fino do comportamento das filas. FlowSchemas são usados ​​para classificar solicitações de entrada individuais, correspondendo cada uma a um único PriorityLevelConfiguration. Há também uma versão v1alpha1 do mesmo grupo de APIs e tem os mesmos tipos com a mesma sintaxe e semântica.

PriorityLevelConfiguration

Um PriorityLevelConfiguration representa uma única classe de isolamento. Cada PriorityLevelConfiguration tem um limite independente no número de solicitações de pendências e limitações no número de solicitações enfileiradas.

Os limites de simultaneidade para PriorityLevelConfigurations não são especificados no número absoluto de solicitações, mas sim em "compartilhamentos de simultaneidade". A simultaneidade limite total para o servidor da API é distribuído entre os PriorityLevelConfigurations existentes em proporção com esses compartilhamentos. Isso permite um administrador de cluster aumentar ou diminuir a quantidade total de tráfego para um servidor reiniciando kube-apiserver com um valor diferente para --max-requests-inflight (ou --max-mutating-requests-inflight), e todos os PriorityLevelConfigurations verá sua simultaneidade máxima permitida aumentar (ou abaixar) pela mesma proporção.

Quando o volume de solicitações de entrada atribuídas a um único PriorityLevelConfiguration é maior do que o permitido por seu nível de simultaneidade, o O campo type de sua especificação determina o que acontecerá com solicitações extras. Um tipo de 'Reject' significa que o excesso de tráfego será imediatamente rejeitado com um erro HTTP 429 (Too Many Requests). Um tipo de Queue significa que as solicitações acima do limite será enfileirado, com as técnicas de shuffle sharding e fair queuing usadas para equilibrar o progresso entre os fluxos de solicitação.

A configuração de enfileiramento permite ajustar o algoritmo de fair queuing para um nível de prioridade. Os detalhes do algoritmo podem ser lidos no proposta de melhoria, mas resumindo:

  • Aumentar as 'filas' reduz a taxa de colisões entre diferentes fluxos, o custo do aumento do uso de memória. Um valor de 1 aqui efetivamente desabilita a lógica de fair queuing, mas ainda permite que as solicitações sejam enfileiradas.

  • Aumentar o queueLengthLimit permite que tráfegos maiores sejam sustentados sem deixar de lado nenhum pedido, ao custo de aumento latência e uso de memória.

  • Alterar handSize permite ajustar a probabilidade de colisões entre fluxos diferentes e a simultaneidade geral disponível para um único fluxo em um situação de sobrecarga.

A seguir está uma tabela mostrando uma coleção interessante de configurações do shuffle sharding, mostrando para cada uma a probabilidade de que um determinado rato (fluxo de baixa intensidade) é esmagado pelos elefantes (fluxo de alta intensidade) para uma coleção ilustrativa de números de elefantes. Veja https://play.golang.org/p/Gi0PLgVHiUg , que calcula esta tabela.

Example Shuffle Sharding Configurations
HandSizeFilas1 elefante4 elefantes16 elefantes
12324.428838398950118e-090.114313488300991440.9935089607656024
10321.550093439632541e-080.06264798402235450.9753101519027554
10646.601827268370426e-120.000455713209903707760.49999929150089345
9643.6310049976037345e-110.000455012123041122730.4282314876454858
8642.25929199850899e-100.00048866970530404460.35935114681123076
81286.994461389026097e-133.4055790161620863e-060.02746173137155063
71281.0579122850901972e-116.960839379258192e-060.02406157386340147
72567.597695465552631e-146.728547142019406e-080.0006709661542533682
62562.7134626662687968e-122.9516464018476436e-070.0008895654642000348
65124.116062922897309e-144.982983350480894e-092.26025764343413e-05
610246.337324016514285e-168.09060164312957e-114.517408062903668e-07

FlowSchema

Um FlowSchema corresponde a algumas solicitações de entrada e as atribui a um nível de prioridade. Cada solicitação de entrada é testada em relação a cada FlowSchema, por sua vez, começando com aqueles com valores numericamente mais baixos --- que consideramos ser o logicamente mais alto --- matchingPrecedence e trabalhando adiante. A primeira correspondência ganha.

Um FlowSchema corresponde a uma determinada solicitação se pelo menos uma de suas regras são correspondidas. Uma regra corresponde se pelo menos um de seus assuntos e pelo menos uma de suas resourceRules ou nonResourceRules (dependendo se a solicitação de entrada é para um recurso ou URL de não-recurso) corresponde à solicitação.

Para o campo name em assuntos, e os campos verbs, apiGroups, resources, namespaces e nonResourceURLs de regras de recursos e não recursos, o wildcard * pode ser especificado para corresponder a todos os valores do campo fornecido, efetivamente removendo-o de consideração.

O distinguisherMethod.type de um FlowSchema determina como as solicitações correspondentes a esse esquema será separado em fluxos. Pode ser ou ByUser, caso em que um usuário solicitante não poderá ser bloqueado por outros, ou ByNamespace, caso em que solicitações de recursos em um namespace não será capaz de privar os pedidos de recursos em outros namespaces de capacidade, ou pode estar em branco (ou distinguisherMethod pode ser omitido inteiramente), caso em que todas as solicitações correspondidas por este FlowSchema serão considerados parte de um único fluxo. A escolha correta para um determinado FlowSchema depende do recurso e do seu ambiente específico.

Padrões

Cada kube-apiserver mantém dois tipos de objetos de configuração APF: obrigatória e sugerida.

Objetos de configuração obrigatórios

Os quatro objetos de configuração obrigatórios refletem no comportamento do guardrail embutido. Este é o comportamento que os servidores tinham antes desses objetos existirem e, quando esses objetos existem, suas especificações refletem esse comportamento. Os quatro objetos obrigatórios são os seguintes.

  • O nível de prioridade obrigatório exempt é usado para solicitações que são não sujeito a controle de fluxo: eles sempre serão despachados imediatamente. O FlowSchema obrigatório exempt classifica todos solicitações do grupo system:masters para este nível de prioridade. Você pode definir outros FlowSchemas que direcionam outras solicitações a este nível de prioridade, se apropriado.

  • O nível de prioridade obrigatório catch-all é usado em combinação com o FlowSchema catch-all obrigatório para garantir que todas as solicitações recebam algum tipo de classificação. Normalmente você não deve confiar nesta configuração catch-all, e deve criar seu próprio FlowSchema catch-all e PriorityLevelConfiguration (ou use o nível de prioridade global-default que é instalado por padrão) como apropriado. Como não se espera que seja usado normalmente, o o nível de prioridade obrigatório catch-all tem uma simultaneidade muito pequena compartilha e não enfileira solicitações.

Objetos de configuração sugeridos

Os FlowSchemas e PriorityLevelConfigurations sugeridos constituem uma configuração padrão razoável. Você pode modificá-los e/ou criar objetos de configuração adicionais, se desejar. Se o seu cluster tiver a probabilidade de experimentar carga pesada, então você deve considerar qual configuração funcionará melhor.

A configuração sugerida agrupa as solicitações em seis níveis de prioridade:

  • O nível de prioridade node-high é para atualizações de integridade dos nós.

  • O nível de prioridade system é para solicitações não relacionadas à integridade do grupo system:nodes, ou seja, Kubelets, que deve ser capaz de contatar o servidor de API para que as cargas de trabalho possam ser agendadas eles.

  • O nível de prioridade leader-election é para solicitações de eleição de líder de controladores embutidos (em particular, solicitações para endpoints, configmaps, ou leases vindo do system:kube-controller-manager ou usuários system:kube-scheduler e contas de serviço no namespace kube-system). Estes são importantes para isolar de outro tráfego porque as falhas na eleição do líder fazem com que seus controladores falhem e reiniciem, o que por sua vez causa tráfego mais caro à medida que os novos controladores sincronizam seus informantes.

  • O nível de prioridade workload-high é para outras solicitações de controladores built-in.

  • O nível de prioridade workload-low é para solicitações de qualquer outra conta de serviço, que normalmente incluirá todas as solicitações de controladores em execução Pods.

  • O nível de prioridade global-default trata de todos os outros tráfegos, por exemplo, comandos kubectl interativos executados por usuários não privilegiados.

Os FlowSchemas sugeridos servem para direcionar as solicitações para os níveis de prioridade acima, e não são enumerados aqui.

Manutenção dos Objetos de Configuração Obrigatórios e Sugeridos

Cada kube-apiserver mantém independentemente os requisitos obrigatórios e objetos de configuração sugeridos, usando comportamento inicial e periódico. Assim, em uma situação com uma mistura de servidores de diferentes versões pode haver thrashing desde que servidores diferentes tenham opiniões sobre o conteúdo adequado desses objetos.

Para os objetos de configuração obrigatórios, a manutenção consiste em garantir que o objeto existe e, se existir, tem a especificação adequada. O servidor se recusa a permitir uma criação ou atualização com uma especificação que é inconsistente com o comportamento do guarda-corpo do servidor.

A manutenção de objetos de configuração sugeridos é projetada para permitir que suas especificações sejam substituídas. A exclusão, por outro lado, não é respeitada: a manutenção restaurará o objeto. Se você não quer um objeto de configuração sugerido, então você precisa mantê-lo por perto, mas defina sua especificação para ter consequências mínimas. Manutenção de objetos sugeridos também é projetada para suportar a migração automática quando uma nova versão do kube-apiserver é lançada, embora potencialmente com thrashing enquanto há uma população mista de servidores.

A manutenção de um objeto de configuração sugerido consiste em cria-lo --- com a especificação sugerida pelo servidor --- se o objeto não existir. OTOH, se o objeto já existir, o comportamento de manutenção depende se os kube-apiservers ou os usuários controlam o objeto. No primeiro caso, o servidor garante que a especificação do objeto é o que o servidor sugere; no último caso, a especificação é deixada sozinho.

A questão de quem controla o objeto é respondida primeiro olhando para uma anotação com a chave apf.kubernetes.io/autoupdate-spec. Se existe tal anotação e seu valor é true então o kube-apiservers controlam o objeto. Se houver tal anotação e seu valor for false, os usuários controlarão o objeto. Se nenhuma dessas condições é satisfeita entaão a metadata.generation do objeto é consultado. Se for 1, o kube-apiservers controla o objeto. Caso contrário, os usuários controlam o objeto. Essas regras foram introduzido na versão 1.22 e sua consideração de metadata.generation é para migrar do mais simples comportamento anterior. Usuários que desejam controlar um objeto de configuração sugerido deve definir sua anotação apf.kubernetes.io/autoupdate-spec para 'falso'.

A manutenção de um objeto de configuração obrigatório ou sugerido também inclui garantir que ele tenha uma anotação apf.kubernetes.io/autoupdate-spec que reflete com precisão se os kube-apiservers controlam o objeto.

A manutenção também inclui a exclusão de objetos que não são obrigatórios nem sugeridos, mas são anotados apf.kubernetes.io/autoupdate-spec=true.

Isenção de simultaneidade da verificação de integridade

A configuração sugerida não dá nenhum tratamento especial a checagem de saúde das requisições verifique solicitações em kube-apiservers de seus kubelets locais --- que tendem a usar a porta segura, mas não fornecem credenciais. Com o configuração sugerida, essas solicitações são atribuídas ao global-default FlowSchema e o nível de prioridade "global-default" correspondente, onde outro tráfego pode bloqueá-los.

Se você adicionar o seguinte FlowSchema adicional, isso isenta aquelas solicitações de limitação de taxa.

apiVersion: flowcontrol.apiserver.k8s.io/v1beta3
kind: FlowSchema
metadata:
  name: health-for-strangers
spec:
  matchingPrecedence: 1000
  priorityLevelConfiguration:
    name: exempt
  rules:
  - nonResourceRules:
    - nonResourceURLs:
      - "/healthz"
      - "/livez"
      - "/readyz"
      verbs:
      - "*"
    subjects:
    - kind: Group
      group:
        name: system:unauthenticated

Diagnóstico

Cada resposta HTTP de um servidor da API com o recurso de prioridade e justiça ativado tem dois cabeçalhos extras: X-Kubernetes-PF-FlowSchema-UID e X-Kubernetes-PF-PriorityLevel-UID, observando o esquema de fluxo que corresponde à solicitação e o nível de prioridade ao qual foi atribuído, respectivamente. Os nomes dos objetos da API não são incluídos nesses cabeçalhos caso o usuário solicitante não tenha permissão para visualizá-los, então ao depurar você pode usar um comando como

kubectl get flowschemas -o custom-columns="uid:{metadata.uid},name:{metadata.name}"
kubectl get prioritylevelconfigurations -o custom-columns="uid:{metadata.uid},name:{metadata.name}"

para obter um mapeamento de UIDs de nomes para FlowSchemas e PriorityLevelConfigurations.

Observabilidade

Metricas

Quando você ativa o APF, o kube-apiserver exporta métricas adicionais. Monitorá-los pode ajudá-lo a determinar se a sua configuração está limitando indevidamente o tráfego importante, ou encontrar cargas de trabalho mal comportadas que podem estar prejudicando a integridade do sistema.

  • apiserver_flowcontrol_rejected_requests_total é um vetor de contador (cumulativo desde o início do servidor) de solicitações que foram rejeitadas, dividido pelos rótulos flow_schema (indicando aquele que correspondeu ao pedido), priority_level (indicando aquele para o qual a solicitação foi atribuída) e reason. A label reason pode ter um dos seguintes valores:

    • queue-full, indicando que muitos pedidos já foram enfileirados,
    • concurrency-limit, indicando que o PriorityLevelConfiguration está configurado para rejeitar em vez de enfileirar solicitações em excesso ou
    • time-out, indicando que a solicitação ainda estava na fila quando seu limite de tempo de fila expirou.
  • apiserver_flowcontrol_dispatched_requests_total é um vetor contador (cumulativo desde o início do servidor) de solicitações que começaram executando, dividido pelos rótulos flow_schema (indicando o um que corresponda à solicitação) e priority_level (indicando o aquele ao qual o pedido foi atribuído).

  • apiserver_current_inqueue_requests é um vetor de medidor de limites máximos do número de solicitações enfileiradas, agrupadas por uma label chamado request_kind cujo valor é mutating ou readOnly. Essas marcas d'água altas descrevem o maior número visto em uma segunda janela concluída recentemente. Estes complementam o mais antigo vetor medidor apiserver_current_inflight_requests que contém o marca d'água alta da última janela de número de solicitações sendo ativamente servido.

  • apiserver_flowcontrol_read_vs_write_request_count_samples é um vetor de histograma de observações do número atual de solicitações, divididas pelos rótulos phase (que assume o valores waiting e executing) e request_kind (que assume os valores mutating e readOnly). As observações são feitas periodicamente a uma taxa elevada.

  • apiserver_flowcontrol_read_vs_write_request_count_watermarks é um vetor de histograma de marcas d'água altas ou baixas do número de solicitações divididas pelos rótulos phase (que assume o valores waiting e executing) e request_kind (que assume os valores mutating e readOnly); o rótulo mark assume valores high e low. As marcas d'água são acumuladas ao longo de janelas delimitadas pelos tempos em que uma observação foi adicionada a apiserver_flowcontrol_read_vs_write_request_count_samples. Esses marcas d'água mostram o intervalo de valores que ocorreram entre as amostras.

  • apiserver_flowcontrol_current_inqueue_requests é um vetor de medidor mantendo o número instantâneo de solicitações enfileiradas (não em execução), dividido pelos rótulos priority_level e flow_schema.

  • apiserver_flowcontrol_current_executing_requests é um vetor de medidor segurando o número instantâneo de execução (não esperando em uma queue), divididas pelos rótulos priority_level e flow_schema.

  • apiserver_flowcontrol_request_concurrency_in_use é um vetor de medidor ocupando o número instantâneo de assentos ocupados, diferenciados pelas labels priority_level e flow_schema.

  • apiserver_flowcontrol_priority_level_request_count_samples é um vetor de histograma de observações do número atual de solicitações divididas pelas labels phase (que assume o valores waiting e executing) e priority_level. Cada histograma obtém observações feitas periodicamente, até a última atividade do tipo relevante. As observações são feitas em nota alta.

  • apiserver_flowcontrol_priority_level_request_count_watermarks é um vetor de histograma de marcas d'água altas ou baixas do número de solicitações divididas pelas labels phase (que assume o valores waiting e executing) e priority_level; a label mark assume valores high e low. As marcas da água são acumulada em janelas delimitadas pelos tempos em que uma observação foi adicionado a apiserver_flowcontrol_priority_level_request_count_samples. Esses marcas d'água mostram o intervalo de valores que ocorreram entre as amostras.

  • apiserver_flowcontrol_request_queue_length_after_enqueue é um vetor de histograma de comprimentos de fila para as filas, dividido pelas labels priority_level e flow_schema, conforme mostrado pelas solicitações enfileiradas. Cada solicitação enfileirada contribui com uma amostra para seu histograma, relatando o comprimento da fila imediatamente depois que o pedido foi adicionado. Observe que isso produz diferentes estatísticas do que uma pesquisa imparcial faria.

  • apiserver_flowcontrol_request_concurrency_limit é um vetor de medidor mantendo o limite de simultaneidade calculado (com base no limite total de simultaneidade do servidor da API e na simultaneidade de PriorityLevelConfigurations share), divididos pela label priority_level.

  • apiserver_flowcontrol_request_wait_duration_seconds é um vetor de histograma de quanto tempo as solicitações ficaram na fila, divididas pelas labels flow_schema (indicando qual corresponde à solicitação), priority_level (indicando aquele para o qual o pedido foi atribuído) e execute (indicando se a solicitação foi iniciada executando).

  • apiserver_flowcontrol_request_execution_seconds é um vetor de histograma de quanto tempo as solicitações levaram para realmente serem executadas, divididas pelas labels flow_schema (indicando qual corresponde à solicitação) e priority_level (indicando aquele para o qual o pedido foi atribuído).

Debug endpoints

Quando você ativa A APF, o kube-apiserver serve os seguintes caminhos adicionais em suas portas HTTP[S].

  • /debug/api_priority_and_fairness/dump_priority_levels - uma lista de todos os níveis de prioridade e o estado atual de cada um. Você pode buscar assim:

    kubectl get --raw /debug/api_priority_and_fairness/dump_priority_levels
    

    A saída é parecido com isto:

    PriorityLevelName, ActiveQueues, IsIdle, IsQuiescing, WaitingRequests, ExecutingRequests,
    workload-low,      0,            true,   false,       0,               0,
    global-default,    0,            true,   false,       0,               0,
    exempt,            <none>,       <none>, <none>,      <none>,          <none>,
    catch-all,         0,            true,   false,       0,               0,
    system,            0,            true,   false,       0,               0,
    leader-election,   0,            true,   false,       0,               0,
    workload-high,     0,            true,   false,       0,               0,
    
  • /debug/api_priority_and_fairness/dump_queues - uma listagem de todas as filas e seu estado atual. Você pode buscar assim:

    kubectl get --raw /debug/api_priority_and_fairness/dump_queues
    

    A saída é parecido com isto:

    PriorityLevelName, Index,  PendingRequests, ExecutingRequests, VirtualStart,
    workload-high,     0,      0,               0,                 0.0000,
    workload-high,     1,      0,               0,                 0.0000,
    workload-high,     2,      0,               0,                 0.0000,
    ...
    leader-election,   14,     0,               0,                 0.0000,
    leader-election,   15,     0,               0,                 0.0000,
    
  • /debug/api_priority_and_fairness/dump_requests - uma lista de todos os pedidos que estão atualmente esperando em uma fila. Você pode buscar assim:

    kubectl get --raw /debug/api_priority_and_fairness/dump_requests
    

    A saída é parecido com isto:

    PriorityLevelName, FlowSchemaName, QueueIndex, RequestIndexInQueue, FlowDistingsher,       ArriveTime,
    exempt,            <none>,         <none>,     <none>,              <none>,                <none>,
    system,            system-nodes,   12,         0,                   system:node:127.0.0.1, 2020-07-23T15:26:57.179170694Z,
    

    Além das solicitações enfileiradas, a saída inclui uma linha fantasma para cada nível de prioridade isento de limitação.

    Você pode obter uma lista mais detalhada com um comando como este:

    kubectl get --raw '/debug/api_priority_and_fairness/dump_requests?includeRequestDetails=1'
    

    A saída é parecido com isto:

    PriorityLevelName, FlowSchemaName, QueueIndex, RequestIndexInQueue, FlowDistingsher,       ArriveTime,                     UserName,              Verb,   APIPath,                                                     Namespace, Name,   APIVersion, Resource, SubResource,
    system,            system-nodes,   12,         0,                   system:node:127.0.0.1, 2020-07-23T15:31:03.583823404Z, system:node:127.0.0.1, create, /api/v1/namespaces/scaletest/configmaps,
    system,            system-nodes,   12,         1,                   system:node:127.0.0.1, 2020-07-23T15:31:03.594555947Z, system:node:127.0.0.1, create, /api/v1/namespaces/scaletest/configmaps,
    

Próximos passos

Para obter informações básicas sobre detalhes de design para prioridade e justiça da API, consulte a proposta de aprimoramento. Você pode fazer sugestões e solicitações de recursos por meio do SIG API Machinery ou do canal do slack.