A seção de Conceitos irá te ajudar a aprender mais sobre as partes do ecossistema Kubernetes e as abstrações que o Kubernetes usa para representar seu cluster.
Ela irá lhe ajudar a obter um entendimento mais profundo sobre como o Kubernetes funciona.
Pods são as menores unidades computacionais implantáveis que você pode criar e gerenciar no Kubernetes.
Um Pod é um grupo de um ou mais contêineres, com recursos de armazenamento e rede compartilhados e uma especificação de como executar os contêineres. O conteúdo de um Pod é sempre colocalizado e coalocado, e executado em um contexto compartilhado. Um Pod modela um "host lógico" específico da aplicação: ele contém um ou mais contêineres de aplicação que são relativamente fortemente acoplados. Em contextos fora da nuvem, aplicações executadas na mesma máquina física ou virtual são análogas a aplicações em nuvem executadas no mesmo host lógico.
Além dos contêineres de aplicação, um Pod pode conter contêineres de inicialização que são executados durante a inicialização do Pod. Você também pode injetar contêineres efêmeros para depurar um Pod em execução.
O contexto compartilhado de um Pod é um conjunto de namespaces do Linux, cgroups e potencialmente outras facetas de isolamento - as mesmas coisas que isolam um contêiner. Dentro do contexto de um Pod, as aplicações individuais podem ter sub-isolamentos adicionais aplicados.
Um Pod é semelhante a um conjunto de contêineres com namespaces compartilhados e volumes de sistema de arquivos compartilhados.
Pods em um cluster Kubernetes são usados de duas maneiras principais:
Pods que executam um único contêiner. O modelo "um-contêiner-por-Pod" é o caso de uso mais comum do Kubernetes; neste caso, você pode pensar em um Pod como um invólucro em torno de um único contêiner; o Kubernetes gerencia Pods ao invés de gerenciar os contêineres diretamente.
Pods que executam múltiplos contêineres que precisam trabalhar juntos. Um Pod pode encapsular uma aplicação composta por múltiplos contêineres colocalizados que são fortemente acoplados e precisam compartilhar recursos. Esses contêineres colocalizados formam uma única unidade coesa.
Agrupar múltiplos contêineres colocalizados e cogerenciados em um único Pod é um caso de uso relativamente avançado. Você deve usar esse padrão apenas em instâncias específicas nas quais seus contêineres são fortemente acoplados.
Você não precisa executar múltiplos contêineres para fornecer replicação (para resiliência ou capacidade); se você precisa de múltiplas réplicas, consulte Gerenciamento de carga de trabalho.
O seguinte é um exemplo de um Pod que consiste em um contêiner executando a imagem nginx:1.14.2.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
Para criar o Pod mostrado acima, execute o seguinte comando:
kubectl apply -f https://k8s.io/examples/pods/simple-pod.yaml
Pods geralmente não são criados diretamente e são criados usando recursos de carga de trabalho. Consulte Trabalhando com Pods para mais informações sobre como os Pods são usados com recursos de carga de trabalho.
Normalmente você não precisa criar Pods diretamente, nem mesmo Pods únicos. Em vez disso, crie-os usando recursos de carga de trabalho como Deployment ou Job. Se seus Pods precisam rastrear estado, considere o recurso StatefulSet.
Cada Pod é destinado a executar uma única instância de uma determinada aplicação. Se você deseja escalar sua aplicação horizontalmente (para fornecer mais recursos gerais executando mais instâncias), você deve usar múltiplos Pods, um para cada instância. No Kubernetes, isso é tipicamente referido como replicação. Pods replicados são geralmente criados e gerenciados como um grupo por um recurso de carga de trabalho e seu controlador.
Consulte Pods e controladores para mais informações sobre como o Kubernetes usa recursos de carga de trabalho, e seus controladores, para implementar escalonamento de aplicação e autorrecuperação.
Pods nativamente fornecem dois tipos de recursos compartilhados para seus contêineres constituintes: rede e armazenamento.
Você raramente criará Pods individuais diretamente no Kubernetes—nem mesmo Pods únicos. Isso ocorre porque os Pods são projetados como entidades relativamente efêmeras e descartáveis. Quando um Pod é criado (diretamente por você, ou indiretamente por um controlador), o novo Pod é alocado para ser executado em um Nó no seu cluster. O Pod permanece naquele nó até que o Pod termine a execução, o objeto Pod seja excluído, o Pod seja removido por falta de recursos, ou o nó falhe.
O nome de um Pod deve ser um valor de subdomínio DNS válido, mas isso pode produzir resultados inesperados para o hostname do Pod. Para melhor compatibilidade, o nome deve seguir as regras mais restritivas para um rótulo DNS.
Kubernetes v1.25 [stable]
Você deve definir o campo .spec.os.name como windows ou linux para indicar o sistema operacional no
qual você deseja que o pod seja executado. Esses dois são os únicos sistemas operacionais suportados até o momento pelo
Kubernetes. No futuro, esta lista pode ser expandida.
No Kubernetes v1.35, o valor de .spec.os.name não afeta
como o kube-scheduler
escolhe um nó para o Pod ser executado. Em qualquer cluster onde há mais de um sistema operacional para
executar nós, você deve definir o
rótulo kubernetes.io/os
corretamente em cada nó, e definir pods com um nodeSelector baseado no rótulo do
sistema operacional. O kube-scheduler aloca seu pod para um nó com base em outros critérios e pode ou não
ter sucesso em escolher uma alocação de nó adequada onde o sistema operacional do nó seja adequado para os contêineres naquele Pod.
Os padrões de segurança de Pod também usam este
campo para evitar impor políticas que não sejam relevantes para o sistema operacional.
Você pode usar recursos de carga de trabalho para criar e gerenciar múltiplos Pods para você. Um controlador para o recurso lida com replicação e implantação e recuperação automática em caso de falha do Pod. Por exemplo, se um nó falha, um controlador percebe que os Pods naquele nó pararam de funcionar e cria um Pod substituto. O alocador coloca o Pod substituto em um nó íntegro.
Aqui estão alguns exemplos de recursos de carga de trabalho que gerenciam um ou mais Pods:
Controladores para recursos de carga de trabalho criam Pods a partir de um modelo de Pod e gerenciam esses Pods em seu nome.
PodTemplates são especificações para criar Pods, e estão incluídos em recursos de carga de trabalho como Deployments, Jobs, e DaemonSets.
Cada controlador para um recurso de carga de trabalho usa o PodTemplate dentro do objeto
de carga de trabalho para criar Pods reais. O PodTemplate é parte do estado desejado de qualquer
recurso de carga de trabalho que você usou para executar sua aplicação.
Quando você cria um Pod, você pode incluir variáveis de ambiente no modelo de Pod para os contêineres que são executados no Pod.
O exemplo abaixo é um manifesto para um Job simples com um template que inicia um
contêiner. O contêiner naquele Pod imprime uma mensagem e então pausa.
apiVersion: batch/v1
kind: Job
metadata:
name: hello
spec:
template:
# Este é o modelo de Pod
spec:
containers:
- name: hello
image: busybox:1.28
command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
restartPolicy: OnFailure
# O modelo de Pod termina aqui
Modificar o modelo de Pod ou alternar para um novo modelo de Pod não tem efeito direto nos Pods que já existem. Se você alterar o modelo de Pod para um recurso de carga de trabalho, esse recurso precisa criar Pods substitutos que usem o modelo atualizado.
Por exemplo, o controlador StatefulSet garante que os Pods em execução correspondam ao modelo de Pod atual para cada objeto StatefulSet. Se você editar o StatefulSet para alterar seu modelo de Pod, o StatefulSet começa a criar novos Pods baseados no modelo atualizado. Eventualmente, todos os Pods antigos são substituídos por novos Pods, e a atualização é concluída.
Cada recurso de carga de trabalho implementa suas próprias regras para lidar com alterações no modelo de Pod. Se você quiser ler mais sobre StatefulSet especificamente, leia Estratégia de atualização no tutorial Básico de StatefulSet.
Nos nós, o kubelet não observa ou gerencia diretamente nenhum dos detalhes relacionados a modelos de Pod e atualizações; esses detalhes são abstraídos. Essa abstração e separação de responsabilidades simplifica a semântica do sistema, e torna viável estender o comportamento do cluster sem alterar código existente.
Como mencionado na seção anterior, quando o modelo de Pod para um recurso de carga de trabalho é alterado, o controlador cria novos Pods baseados no modelo atualizado em vez de atualizar ou corrigir os Pods existentes.
O Kubernetes não impede que você gerencie Pods diretamente. É possível
atualizar alguns campos de um Pod em execução, diretamente na configuração aplicada.
No entanto, operações de atualização de Pod como
patch e
replace,
têm algumas limitações:
A maioria dos metadados sobre um Pod é imutável. Por exemplo, você não pode
alterar os campos namespace, name, uid, ou creationTimestamp.
Se o metadata.deletionTimestamp estiver definido, nenhuma nova entrada pode ser adicionada à
lista metadata.finalizers.
Atualizações de Pod não podem alterar campos além de spec.containers[*].image,
spec.initContainers[*].image, spec.activeDeadlineSeconds, spec.terminationGracePeriodSeconds,
spec.tolerations ou spec.schedulingGates. Para spec.tolerations, você só pode adicionar novas entradas.
Ao atualizar o campo spec.activeDeadlineSeconds, dois tipos de atualizações
são permitidos:
As regras de atualização acima se aplicam a atualizações regulares de Pod, mas outros campos de Pod podem ser atualizados através de subrecursos.
resize permite que recursos de contêiner (spec.containers[*].resources) sejam atualizados.
Consulte Redimensionar Recursos de Contêiner para mais detalhes.ephemeralContainers permite que
contêineres efêmeros
sejam adicionados a um Pod.
Consulte Contêineres Efêmeros para mais detalhes.status permite que o status do Pod seja atualizado.
Isso é tipicamente usado apenas pelo Kubelet e outros controladores do sistema.binding permite definir o spec.nodeName do Pod via uma requisição Binding.
Isso é tipicamente usado apenas pelo escalonador.metadata.generation é único. Ele será automaticamente definido pelo
sistema de forma que novos pods tenham um metadata.generation de 1, e cada atualização em
campos mutáveis na especificação do pod incrementará o metadata.generation em 1.Kubernetes v1.35 [stable](habilitado por padrão)observedGeneration é um campo que é capturado na seção status do objeto
Pod. Se o feature gate PodObservedGenerationTracking estiver definido, o Kubelet definirá status.observedGeneration
para rastrear o estado do Pod ao status atual do Pod. O status.observedGeneration do Pod refletirá a
metadata.generation do Pod no ponto em que o status do Pod está sendo reportado.status.observedGeneration é gerenciado pelo kubelet e controladores externos não devem modificar este campo.Diferentes campos de status podem estar associados à metadata.generation do ciclo de sincronização atual, ou com a
metadata.generation do ciclo de sincronização anterior. A distinção chave é se uma mudança na spec é refletida
diretamente no status ou é um resultado indireto de um processo em execução.
Para campos de status onde a especificação alocada é diretamente refletida, o observedGeneration será
associado à metadata.generation atual (Geração N).
Este comportamento se aplica a:
Waiting.Para campos de status que são um resultado indireto da execução da especificação, o observedGeneration será associado
à metadata.generation do ciclo de sincronização anterior (Geração N-1).
Este comportamento se aplica a:
ContainerStatus.ImageID reflete a imagem da geração anterior até que a nova imagem
seja baixada e o contêiner seja atualizado.Pods permitem o compartilhamento de dados e comunicação entre seus contêineres constituintes.
Um Pod pode especificar um conjunto de volumes de armazenamento compartilhados. Todos os contêineres no Pod podem acessar os volumes compartilhados, permitindo que esses contêineres compartilhem dados. Volumes também permitem que dados persistentes em um Pod sobrevivam caso um dos contêineres precise ser reiniciado. Consulte Armazenamento para mais informações sobre como o Kubernetes implementa armazenamento compartilhado e o torna disponível para Pods.
Cada Pod recebe um endereço IP único para cada família de endereços. Cada
contêiner em um Pod compartilha o namespace de rede, incluindo o endereço IP e
portas de rede. Dentro de um Pod (e somente então), os contêineres que pertencem ao Pod
podem se comunicar uns com os outros usando localhost. Quando contêineres em um Pod se comunicam
com entidades fora do Pod,
eles devem coordenar como usam os recursos de rede compartilhados (como portas).
Dentro de um Pod, contêineres compartilham um endereço IP e espaço de portas, e
podem encontrar uns aos outros via localhost. Os contêineres em um Pod também podem se comunicar
uns com os outros usando comunicações interprocessos padrão como semáforos SystemV
ou memória compartilhada POSIX. Contêineres em Pods diferentes têm endereços IP
distintos e não podem se comunicar por IPC em nível de sistema operacional sem configuração especial.
Contêineres que desejam interagir com um contêiner executando em um Pod diferente podem
usar rede IP para se comunicar.
Contêineres dentro do Pod veem o nome do host do sistema como sendo o mesmo que o
name configurado para o Pod. Mais informações sobre isso na seção de rede.
Para definir restrições de segurança em Pods e contêineres, você usa o
campo securityContext na especificação do Pod. Este campo oferece
controle granular sobre o que um Pod ou contêineres individuais podem fazer. Por exemplo:
windowsOptions.hostProcess no
contexto de segurança da especificação do Pod. Para detalhes e instruções, consulte
Criar um Pod Windows HostProcess.Pods Estáticos são gerenciados diretamente pelo daemon kubelet em um nó específico, sem que o servidor de API os observe. Enquanto a maioria dos Pods são gerenciados pela camada de gerenciamento (por exemplo, um Deployment), para Pods estáticos, o kubelet supervisiona diretamente cada Pod estático (e o reinicia se falhar).
Pods estáticos estão sempre vinculados a um Kubelet em um nó específico. O uso principal para Pods estáticos é executar uma camada de gerenciamento auto-hospedada: em outras palavras, usar o kubelet para supervisionar os componentes da camada de gerenciamento individuais.
O kubelet tenta automaticamente criar um Pod espelho no servidor de API do Kubernetes para cada Pod estático. Isso significa que os Pods em execução em um nó são visíveis no servidor de API, mas não podem ser controlados de lá. Consulte o guia Criar Pods estáticos para mais informações.
spec de um Pod estático não pode referenciar outros objetos de API
(por exemplo, ServiceAccount,
ConfigMap,
Secret, etc).Pods são projetados para suportar múltiplos processos cooperantes (como contêineres) que formam uma unidade coesa de serviço. Os contêineres em um Pod são automaticamente colocalizados e coalocados na mesma máquina física ou virtual no cluster. Os contêineres podem compartilhar recursos e dependências, comunicar-se uns com os outros, e coordenar quando e como são encerrados.
Pods em um cluster Kubernetes são usados de duas maneiras principais:
Por exemplo, você pode ter um contêiner que atua como um servidor web para arquivos em um volume compartilhado, e um contêiner sidecar separado que atualiza esses arquivos de uma fonte remota, como no diagrama a seguir:
Alguns Pods têm contêineres de inicialização assim como contêineres de aplicação. Por padrão, contêineres de inicialização são executados e concluídos antes que os contêineres de aplicação sejam iniciados.
Você também pode ter contêineres sidecar que fornecem serviços auxiliares ao Pod de aplicação principal (por exemplo: uma malha de serviços).
Kubernetes v1.33 [stable](habilitado por padrão)Habilitado por padrão, o feature gate SidecarContainers
permite que você especifique restartPolicy: Always para contêineres de inicialização.
Definir a política de reinicialização Always garante que os contêineres onde você a define sejam
tratados como sidecars que são mantidos em execução durante todo o tempo de vida do Pod.
Contêineres que você define explicitamente como contêineres sidecar
iniciam antes do Pod de aplicação principal e permanecem em execução até que o Pod seja
encerrado.
Uma verificação é um diagnóstico realizado periodicamente pelo kubelet em um contêiner. Para realizar um diagnóstico, o kubelet pode invocar diferentes ações:
ExecAction (realizada com a ajuda do agente de execução de contêiner)TCPSocketAction (verificada diretamente pelo kubelet)HTTPGetAction (verificada diretamente pelo kubelet)Você pode ler mais sobre verificações na documentação de Ciclo de Vida do Pod.
Para entender o contexto de por que o Kubernetes envolve uma API de Pod comum em outros recursos (como StatefulSets ou Deployments), você pode ler sobre trabalhos anteriores, incluindo:
Este guia é destinado a proprietários de aplicações que desejam construir aplicações altamente disponíveis e, portanto, precisam entender quais tipos de interrupções podem acontecer com os Pods.
Também é destinado a administradores de cluster que desejam executar ações automatizadas no cluster, como atualização e escalonamento automático de clusters.
Os Pods não desaparecem até que alguém (uma pessoa ou um controlador) os destrua, ou ocorra um erro inevitável de hardware ou software do sistema.
Chamamos esses casos inevitáveis de interrupções involuntárias para uma aplicação. Exemplos incluem:
Exceto pela condição de falta de recursos, todas essas condições devem ser familiares para a maioria dos usuários; elas não são específicas do Kubernetes.
Chamamos os outros casos de interrupções voluntárias. Estas incluem tanto ações iniciadas pelo proprietário da aplicação quanto aquelas iniciadas por um Administrador de Cluster. Ações típicas do proprietário da aplicação incluem:
As ações do administrador de cluster incluem:
Essas ações podem ser executadas diretamente pelo administrador do cluster, ou por automação executada pelo administrador do cluster, ou pelo seu provedor de hospedagem do cluster.
Consulte seu administrador de cluster ou consulte a documentação do seu provedor de nuvem ou distribuição para determinar se alguma fonte de interrupções voluntárias está habilitada para o seu cluster. Se nenhuma estiver habilitada, você pode pular a criação de Orçamentos de Interrupção de Pods.
Aqui estão algumas maneiras de mitigar interrupções involuntárias:
A frequência de interrupções voluntárias varia. Em um cluster Kubernetes básico, não há interrupções voluntárias automatizadas (apenas aquelas acionadas pelo usuário). No entanto, seu administrador de cluster ou provedor de hospedagem pode executar alguns serviços adicionais que causam interrupções voluntárias. Por exemplo, atualizar o software do nó pode causar interrupções voluntárias. Além disso, algumas implementações de escalonamento automático de cluster (nó) podem causar interrupções voluntárias para desfragmentar e compactar nós. Seu administrador de cluster ou provedor de hospedagem deve ter documentado qual nível de interrupções voluntárias, se houver, esperar. Certas opções de configuração, como usar PriorityClasses na especificação do seu Pod também podem causar interrupções voluntárias (e involuntárias).
Kubernetes v1.21 [stable]
O Kubernetes oferece funcionalidades para ajudá-lo a executar aplicações altamente disponíveis mesmo quando você introduz interrupções voluntárias frequentes.
Como proprietário de uma aplicação, você pode criar um PodDisruptionBudget (PDB) para cada aplicação. Um PDB limita o número de Pods de uma aplicação replicada que estão inativos simultaneamente devido a interrupções voluntárias. Por exemplo, uma aplicação baseada em quórum gostaria de garantir que o número de réplicas em execução nunca seja reduzido abaixo do número necessário para um quórum. Um front-end web pode querer garantir que o número de réplicas atendendo a carga nunca caia abaixo de uma certa porcentagem do total.
Administradores de cluster e provedores de hospedagem devem usar ferramentas que respeitem PodDisruptionBudgets através do uso da API de Remoção em vez de excluir diretamente Pods ou Deployments.
Por exemplo, o subcomando kubectl drain permite marcar um nó como sendo retirado de
serviço. Quando você executa kubectl drain, a ferramenta tenta remover todos os Pods do
nó que você está retirando de serviço. A solicitação de remoção que o kubectl envia em
seu nome pode ser temporariamente rejeitada, então a ferramenta repete periodicamente todas as solicitações
com falha até que todos os Pods no nó de destino sejam encerrados, ou até que um tempo limite
configurável seja atingido.
Um PDB especifica o número de réplicas que uma aplicação pode tolerar ter, em relação a quantas
ela pretende ter. Por exemplo, um Deployment que tem .spec.replicas: 5 deve
ter 5 Pods a qualquer momento. Se seu PDB permite que existam 4 por vez,
então a API de Remoção permitirá a interrupção voluntária de um (mas não dois) Pods por vez.
O grupo de Pods que compõem a aplicação é especificado usando um seletor de rótulos, o mesmo usado pelo controlador da aplicação (deployment, stateful-set, etc.).
O número "pretendido" de Pods é calculado a partir do .spec.replicas do recurso de carga de trabalho
que está gerenciando esses Pods. A camada de gerenciamento descobre o recurso de carga de trabalho proprietário
examinando o .metadata.ownerReferences do Pod.
Interrupções involuntárias não podem ser evitadas por PDBs; no entanto, elas contam contra o orçamento.
Pods que são excluídos ou indisponíveis devido a uma atualização gradual de uma aplicação contam contra o orçamento de interrupção, mas recursos de carga de trabalho (como Deployment e StatefulSet) não são limitados por PDBs ao realizar atualizações graduais. Em vez disso, o tratamento de falhas durante atualizações de aplicações é configurado na especificação do recurso de carga de trabalho específico.
É recomendado definir AlwaysAllow como Política de Remoção de Pods Não Íntegros
em seus PodDisruptionBudgets para suportar a remoção de aplicações com comportamento inadequado durante a drenagem de um nó.
O comportamento padrão é aguardar que os Pods da aplicação se tornem íntegros
antes que a drenagem possa prosseguir.
Quando um Pod é removido usando a API de remoção, ele é controladamente
encerrado, respeitando a
configuração terminationGracePeriodSeconds em sua PodSpec.
Considere um cluster com 3 nós, node-1 a node-3.
O cluster está executando várias aplicações. Uma delas tem 3 réplicas inicialmente chamadas
pod-a, pod-b e pod-c. Outro Pod não relacionado, sem um PDB, chamado pod-x, também é mostrado.
Inicialmente, os Pods estão distribuídos da seguinte forma:
| node-1 | node-2 | node-3 |
|---|---|---|
| pod-a available | pod-b available | pod-c available |
| pod-x available |
Todos os 3 Pods fazem parte de um Deployment, e coletivamente têm um PDB que exige que pelo menos 2 dos 3 Pods estejam disponíveis o tempo todo.
Por exemplo, suponha que o administrador do cluster queira reiniciar em uma nova versão do kernel para corrigir um bug no kernel.
O administrador do cluster primeiro tenta drenar node-1 usando o comando kubectl drain.
Essa ferramenta tenta remover pod-a e pod-x. Isso é bem-sucedido imediatamente.
Ambos os Pods entram no estado terminating ao mesmo tempo.
Isso coloca o cluster neste estado:
| node-1 draining | node-2 | node-3 |
|---|---|---|
| pod-a terminating | pod-b available | pod-c available |
| pod-x terminating |
O Deployment percebe que um dos Pods está sendo encerrado, então cria uma substituição
chamada pod-d. Como node-1 está isolado, ele é alocado em outro nó. Algo também
criou pod-y como substituição para pod-x.
(Nota: para um StatefulSet, pod-a, que seria chamado de algo como pod-0, precisaria
ser totalmente encerrado antes que sua substituição, que também é chamada de pod-0 mas tem um
UID diferente, pudesse ser criada. Caso contrário, o exemplo também se aplica a um StatefulSet.)
Agora o cluster está neste estado:
| node-1 draining | node-2 | node-3 |
|---|---|---|
| pod-a terminating | pod-b available | pod-c available |
| pod-x terminating | pod-d starting | pod-y |
Em algum momento, os Pods são encerrados, e o cluster fica assim:
| node-1 drained | node-2 | node-3 |
|---|---|---|
| pod-b available | pod-c available | |
| pod-d starting | pod-y |
Neste ponto, se um administrador de cluster impaciente tentar drenar node-2 ou
node-3, o comando drain será bloqueado, porque há apenas 2 Pods disponíveis
para o Deployment, e seu PDB exige pelo menos 2. Depois de algum tempo, pod-d se torna disponível.
O estado do cluster agora fica assim:
| node-1 drained | node-2 | node-3 |
|---|---|---|
| pod-b available | pod-c available | |
| pod-d available | pod-y |
Agora, o administrador do cluster tenta drenar node-2.
O comando drain tentará remover os dois Pods em alguma ordem, digamos
pod-b primeiro e depois pod-d. Ele terá sucesso ao remover pod-b.
Mas, quando tentar remover pod-d, será recusado porque isso deixaria apenas
um Pod disponível para o Deployment.
O Deployment cria uma substituição para pod-b chamada pod-e.
Como não há recursos suficientes no cluster para alocar
pod-e, a drenagem será bloqueada novamente. O cluster pode acabar neste
estado:
| node-1 drained | node-2 | node-3 | no node |
|---|---|---|---|
| pod-b terminating | pod-c available | pod-e pending | |
| pod-d available | pod-y |
Neste ponto, o administrador do cluster precisa adicionar um nó de volta ao cluster para prosseguir com a atualização.
Você pode ver como o Kubernetes varia a taxa na qual as interrupções podem acontecer, de acordo com:
Kubernetes v1.31 [stable](habilitado por padrão)Uma condição dedicada DisruptionTarget do Pod condition
é adicionada para indicar
que o Pod está prestes a ser excluído devido a uma interrupção.
O campo reason da condição adicionalmente
indica um dos seguintes motivos para o encerramento do Pod:
PreemptionBySchedulerDeletionByTaintManagerkube-controller-manager) devido a um taint NoExecute que o Pod não tolera; veja remoções baseadas em taint.EvictionByEvictionAPIDeletionByPodGCTerminationByKubeletEm todos os outros cenários de interrupção, como remoção devido a exceder
limites de contêiner do Pod,
os Pods não recebem a condição DisruptionTarget porque as interrupções provavelmente foram
causadas pelo Pod e ocorreriam novamente em uma nova tentativa.
DisruptionTarget pode ser adicionada a um Pod, mas esse Pod pode então não ser
efetivamente excluído. Em tal situação, após algum tempo, a
condição de interrupção do Pod será limpa.Juntamente com a limpeza dos Pods, o coletor de lixo de Pods (PodGC) também os marcará como falhados se estiverem em uma fase não terminal (veja também coleta de lixo de Pod).
Ao usar uma tarefa (ou CronJob), você pode querer usar essas condições de interrupção de Pod como parte da política de falha de Pod da sua tarefa.
Frequentemente, é útil pensar no Administrator do cluster e no Proprietário da aplicação como papéis separados com conhecimento limitado um do outro. Esta separação de responsabilidades pode fazer sentido nestes cenários:
Os Orçamentos de Interrupção de Pods apoiam esta separação de papéis fornecendo uma interface entre os papéis.
Se você não tem essa separação de responsabilidades em sua organização, você pode não precisar usar Orçamentos de Interrupção de Pods.
Se você é um Administrador de cluster e precisa realizar uma ação disruptiva em todos os nós do seu cluster, como uma atualização de nó ou software do sistema, aqui estão algumas opções:
Siga os passos para proteger sua aplicação configurando um Orçamento de Interrupção de Pods.
Saiba mais sobre drenar nós
Saiba mais sobre atualizar um Deployment incluindo passos para manter sua disponibilidade durante a implementação.
O propósito de um ReplicaSet é gerenciar um conjunto de réplicas de Pods em execução a qualquer momento. Por isso, é geralmente utilizado para garantir a disponibilidade de um certo número de Pods idênticos.
Um ReplicaSet é definido por campos, incluindo um seletor que identifica quais Pods podem ser adquiridos, um número de réplicas indicando quantos Pods devem ser mantidos, e um pod template especificando as definições para novos Pods que devem ser criados para atender ao número de réplicas estipuladas. Um ReplicaSet cumpre seu propósito criando e deletando Pods conforme for preciso para atingir o número desejado. Quando um ReplicaSet precisa criar novos Pods, ele usa o seu podTemplate.
Um ReplicaSet é conectado ao seus Pods pelo campo do Pod metadata.ownerReferences, que especifíca qual recurso é dono do objeto atual. Todos os Pods adquiridos por um ReplicaSet possuem as informações de identificação do ReplicaSet vinculado no campo ownerReferences. É por esse elo que o ReplicaSet tem conhecimento do estado dos Pods que está mantendo e assim faz seu planejamento.
Um ReplicaSet identifica novos Pods a serem adquiridos utilizando o seu seletor. Caso exista um Pod que não tenha OwnerReference ou se o OwnerReference não for um Controlador e o seu seletor corresponde com o do ReplicaSet, o Pod é adquirido imediatamente por esse ReplicaSet.
Um ReplicaSet garante que um número de réplicas de um Pod estão executando em qualquer momento. Entretanto, um Deployment é um conceito de nível superior que gerencia ReplicaSets e fornece atualizações declarativas aos Pods assim como várias outras funções úteis. Portanto, nós recomendamos a utilização de Deployments ao invés do uso direto de ReplicaSets, exceto se for preciso uma orquestração de atualização customizada ou que nenhuma atualização seja necessária.
Isso na realidade significa que você pode nunca precisar manipular objetos ReplicaSet: prefira usar um Deployment, e defina sua aplicação na seção spec.
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
# modifique o número de replicas de acordo com o seu caso
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: php-redis
image: gcr.io/google_samples/gb-frontend:v3
Salvando esse manifesto como frontend.yaml e submetendo no cluster Kubernetes irá criar o ReplicaSet definido e os Pods mantidos pelo mesmo.
kubectl apply -f https://kubernetes.io/pt-br/examples/controllers/frontend.yaml
Você pode então retornar os ReplicaSets atualmente existentes atualmente no cluster:
kubectl get rs
E observar o ReplicaSet com o nome de frontend que você criou:
NAME DESIRED CURRENT READY AGE
frontend 3 3 3 6s
Você também pode checar o estado do ReplicaSet:
kubectl describe rs/frontend
E você deve ver uma saída similar a esta:
Name: frontend
Namespace: default
Selector: tier=frontend
Labels: app=guestbook
tier=frontend
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"ReplicaSet","metadata":{"annotations":{},"labels":{"app":"guestbook","tier":"frontend"},"name":"frontend",...
Replicas: 3 current / 3 desired
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: tier=frontend
Containers:
php-redis:
Image: gcr.io/google_samples/gb-frontend:v3
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 117s replicaset-controller Created pod: frontend-wtsmm
Normal SuccessfulCreate 116s replicaset-controller Created pod: frontend-b2zdv
Normal SuccessfulCreate 116s replicaset-controller Created pod: frontend-vcmts
E por fim você consegue verificar os Pods que foram criados:
kubectl get pods
Você deve ver uma informação do Pod similar à esta:
NAME READY STATUS RESTARTS AGE
frontend-b2zdv 1/1 Running 0 6m36s
frontend-vcmts 1/1 Running 0 6m36s
frontend-wtsmm 1/1 Running 0 6m36s
Você consegue também validar que a referência de dono desses pods está definida para o ReplicaSet frontend. Para fazer isso, retorne o yaml de um dos Pods que estão executando:
kubectl get pods frontend-b2zdv -o yaml
O output será semelhante ao exibido abaixo, com as informações do ReplicaSet frontend definidas no campo ownerReferences dentro da metadata do Pod:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2020-02-12T07:06:16Z"
generateName: frontend-
labels:
tier: frontend
name: frontend-b2zdv
namespace: default
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: frontend
uid: f391f6db-bb9b-4c09-ae74-6a1f77f3d5cf
...
Enquanto você pode criar Pods diretamente sem problemas, é fortemente recomendado que você se certifique que esses Pods não tenham labels que combinem com o seletor de um dos seus ReplicaSets. O motivo para isso é que um ReplicaSet não é limitado a possuir apenas Pods estipulados por seu template -- ele pode adquirir outros Pods na maneira descrita nas seções anteriores.
Observe o exemplo anterior do ReplicaSet frontend, e seus Pods especificados no seguinte manifesto:
apiVersion: v1
kind: Pod
metadata:
name: pod1
labels:
tier: frontend
spec:
containers:
- name: hello1
image: gcr.io/google-samples/hello-app:2.0
---
apiVersion: v1
kind: Pod
metadata:
name: pod2
labels:
tier: frontend
spec:
containers:
- name: hello2
image: gcr.io/google-samples/hello-app:1.0
Como esses Pods não possuem um Controller (ou qualquer objeto) referenciados como seu dono e possuem labels que combinam com o seletor do ReplicaSet frontend, eles serão imediatamente adquiridos pelo ReplicaSet.
Imagine que você crie os Pods depois que o ReplicaSet frontend foi instalado e criou as réplicas de Pod inicial definida para cumprir o número de réplicas requiridas:
kubectl apply -f https://kubernetes.io/examples/pods/pod-rs.yaml
Os novos Pods serão adquiridos pelo ReplicaSet, e logo depois terminados já que o ReplicaSet estará acima do número desejado.
Buscando os Pods:
kubectl get pods
O output mostra que os novos Pods ou já estão terminados, ou estão no processo de ser terminados.
NAME READY STATUS RESTARTS AGE
frontend-b2zdv 1/1 Running 0 10m
frontend-vcmts 1/1 Running 0 10m
frontend-wtsmm 1/1 Running 0 10m
pod1 0/1 Terminating 0 1s
pod2 0/1 Terminating 0 1s
Se você criar os Pods primeiro:
kubectl apply -f https://kubernetes.io/examples/pods/pod-rs.yaml
mas em seguida criar o ReplicaSet:
kubectl apply -f https://kubernetes.io/examples/controllers/frontend.yaml
Você vai perceber que o ReplicaSet adquiriu os Pods e criou apenas novos de acordo com o seu spec até que o número de novo Pods e os Pods iniciais seja igual a ao número desejado. Listando os Pods:
kubectl get pods
Irá retornar a seguinte saída:
NAME READY STATUS RESTARTS AGE
frontend-hmmj2 1/1 Running 0 9s
pod1 1/1 Running 0 36s
pod2 1/1 Running 0 36s
Nesse sentido, um ReplicaSet pode possuir um grupo não-homogêneo de Pods
Como todos os outros objetos de Kubernetes API, um ReplicaSet necessita dos campos apiVersion, kind, e metadata.
Para ReplicaSets, o kind sempre será um ReplicaSet.
O nome de um objeto ReplicaSet precisa ser nome de subdomínio de DNS válido.
Um ReplicaSet também precisa de uma seção .spec.
O .spec.template é um template de pod que também necessita de labels configurados. No nosso exemplo frontend.yaml nós temos uma label: tier: frontend.
Fique atento para não sobrepor com seletores de outros controllers, para que eles não tentem adquirir esse Pod.
Para o campo de restart policy do template, .spec.template.spec.restartPolicy, o único valor permitido é Always, que é o padrão.
O campo .spec.selector é um seletor de labels. Como discutido anteriormente esses são os labels usados para identificar Pods em potencial para aquisição. No nosso exemplo frontend.yaml, o seletor era:
matchLabels:
tier: frontend
No ReplicaSet, .spec.template.metadata.labels precisa combinar com spec.selector, ou será rejeitado pela API.
.spec.selector mas diferentes campos de .spec.template.metadata.labels e .spec.template.spec, cada ReplicaSet ignorará os Pods criados pelo outro ReplicaSet.Você pode definir quantos Pods devem executar simultaneamente determinando .spec.replicas. O ReplicaSet irá criar/deletar os Pods para igualar à esse número.
Se você não especificar o .spec.replicas, seu padrão é 1.
Para deletar um ReplicaSet e todos os seus Pods, use kubectl delete. O Garbage collector automaticamente deleta todos os Pods dependentes por padrão.
Quando usar a API REST ou a biblioteca client-go, você precisa definir propagationPolicy para Background ou Foreground na opção -d.
Por exemplo:
kubectl proxy --port=8080
curl -X DELETE 'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \
> -H "Content-Type: application/json"
Você consegue deletar um ReplicaSet sem afetar qualquer um dos Pods usando kubectl delete com a opção --cascade=orphan.
Quando usar a API REST ou a biblioteca client-go, você precisa definir propagationPolicy para Orphan.
Por exemplo:
kubectl proxy --port=8080
curl -X DELETE 'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
> -H "Content-Type: application/json"
Quando o ReplicaSet original for deletado, você pode criar um novo ReplicaSet para substituí-lo. Contanto que o .spec.selector do antigo e do atual sejam o mesmo, o novo irá adquirir os Pods antigos. Porém, o ReplicaSet não atualizará as definições dos Pods existentes caso surja um novo e diferente template de pod.
Para atualizar esses Pods para um novo spec de um modo controlado, use um Deployment, já que ReplicaSets não suportam um atualização gradual diretamente.
Você pode remover Pods de um Replicaset trocando suas labels. Essa técnica pode ser usada para remover Pods de um serviço para depuração, recuperação de dados, etc. Pods que forem removidos por esse método serão substituídos imediatamente (assumindo que o número de replicas não tenha sido alterado).
Um ReplicaSet pode ser facilmente escalonado para cima ou para baixo simplesmente atualizando o campo de .spec.replicas. O Replicaset controller garante que o número desejado de Pods com um seletor de label correspondente estejam disponíveis e operando.
Ao escalonar para baixo, o Replicaset controller escolhe quais pods irá deletar ordenando os pods disponíveis para priorizar quais pods seram escalonados para baixo seguindo o seguinte algoritmo geral:
controller.kubernetes.io/pod-deletion-cost estiver definida, então o pod com o menor valor será priorizado primeiro.LogarithmicScaleDown esteja habilitado)Se o Pod obedecer todos os items acima simultaneamente, a seleção é aleatória.
Kubernetes v1.22 [beta]
Utilizando a anotação controller.kubernetes.io/pod-deletion-cost,
usuários podem definir uma preferência em relação à quais pods serão removidos primeiro caso o ReplicaSet precise escalonar para baixo.
A anotação deve ser definida no pod, com uma variação de [-2147483648, 2147483647]. Isso representa o custo de deletar um pod comparado com outros pods que pertencem à esse mesmo ReplicaSet. Pods com um custo de deleção menor são eleitos para deleção antes de pods com um custo maior.
O valor implícito para essa anotação para pods que não a tem definida é 0; valores negativos são permitidos. Valores inválidos serão rejeitados pelo servidor API.
Esse recurso está em beta e é habilitado por padrão. Você consegue desabilita-lo usando o
feature gate
PodDeletionCost ambos no kube-apiserver e no kube-controller-manager.
Os diferentes Pods de uma aplicação podem ter níveis de utilização divergentes. Ao escalonar para baixo, a aplicação pode preferir remover os pods com a menor utilização. Para evitar atualizações frequentes nos pods, a aplicação deve atualizar controller.kubernetes.io/pod-deletion-cost uma vez antes de expedir o escalonamento para baixo das réplicas (configurando a anotação para um valor proporcional ao nível de utilização do Pod). Isso funciona se a própria aplicação controlar o escalonamento; por exemplo, o pod condutor de um Deployment de Spark.
Um ReplicaSet pode também ser controlado por um Horizontal Pod Autoscalers (HPA). Isto é, um ReplicaSet pode ser automaticamente escalonado por um HPA. Aqui está um exemplo de um HPA controlando o ReplicaSet que nós criamos no exemplo anterior.
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: frontend-scaler
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: ReplicaSet
name: frontend
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 50
Salvando esse manifesto como hpa-rs.yaml e enviando para o cluster Kubernetes deve
criar um HPA definido que autoescalona o ReplicaSet controlado dependendo do uso de CPU
dos Pods replicados.
kubectl apply -f https://k8s.io/examples/controllers/hpa-rs.yaml
Alternativamente, você pode usar o comando kubectl autoscale para realizar a mesma coisa
(e é bem mais simples!)
kubectl autoscale rs frontend --max=10 --min=3 --cpu=50%
Deployment é um objeto o qual pode possuir ReplicaSets, atualizá-los e por consequência seus Pods via atualizações declarativas, gradativas do lado do servidor.
Enquanto ReplicaSets conseguem ser usados independentemente, hoje eles são principalmente usados por Deployments como um mecanismo para orquestrar a criação, deleção e atualização de um Pod. Quando você usa Deployments você não precisa se preocupar com o gerenciamento de ReplicaSets que são criados por ele. Deployments controlam e gerenciam seus ReplicaSets.
Por isso, é recomendado o uso de Deployments quando você deseja ReplicaSets.
Diferente do caso onde um usuário cria Pods diretamente, um ReplicaSet substitui Pods que forem deletados ou terminados por qualquer motivo, como em caso de falha de nó ou manutenção disruptiva de nó, como uma atualização de kernel. Por esse motivo, nós recomendamos que você use um ReplicaSet mesmo que sua aplicação necessite apenas de um único Pod. Pense na semelhança com um supervisor de processos, apenas que ele supervisione vários Pods em múltiplos nós ao invés de apenas um Pod. Um ReplicaSet delega reinicializações de um contêiner local para algum agente do nó (Kubelet ou Docker, por exemplo).
Use um Job no lugar de um ReplicaSet para Pods que tem por objetivo sua terminação no final da execução (como batch jobs).
Use um DaemonSet no lugar de um ReplicaSet para Pods que precisam prover funções no nível de sistema, como monitoramento do sistema ou logs do sistema. Esses Pods tem um tempo de vida ligado à vida útil do sistema:
os Pods precisam estar executando na máquina antes de outros Pods inicializarem, e são seguros de terminarem quando a máquina esta preparada para reiniciar/desligar.
ReplicaSets são sucessores ao ReplicationControllers. Os dois servem para o mesmo propósito, e tem comportamentos semelhantes, exceto que um ReplicationController não suporta os requerimentos de um seletor baseado em definição como descrito no guia de usuário de label. Portanto, ReplicaSets são preferíveis à ReplicationControllers
ReplicaSet é um recurso alto nível na API REST do Kubernetes.
Leia a
ReplicaSet
definição de objeto para entender a API para replica sets.Kubernetes v1.21 [stable]
Um CronJob cria Jobs em um cronograma recorrente.
Um objeto CronJob é como uma linha em um arquivo crontab (tabela cron). Executa uma tarefa periodicamente em um determinado cronograma, escrito no formato Cron.
Todos os horários da propriedade schedule: do CronJob são baseadas no fuso horário do kube-controller-manager.
Se a camada de gerenciamento do cluster executa o kube-controller-manager em Pods ou contêineres avulsos, o fuso horário configurado para o contêiner executando o kube-controller-manager determina o fuso horário que o controlador dos objetos CronJob utiliza.
Ao criar o manifesto para um objeto CronJob, verifique se o nome que você forneceu é um nome de subdomínio DNS válido. O nome não pode ter mais que 52 caracteres. Esta limitação existe porque o controlador do CronJob adicionará automaticamente 11 caracteres ao final do nome escolhido para a tarefa, e o tamanho máximo de um nome de tarefa não pode ultrapassar 63 caracteres.
CronJobs são úteis para criar tarefas periódicas e recorrentes, como a execução de backups ou o envio de mensagens de e-mail. CronJobs também permitem o agendamento de tarefas individuais para um horário específico, como por exemplo uma tarefa que é executada em um período maior de ociosidade do cluster.
Este manifesto de CronJob de exemplo imprime a data e horário atuais, seguidos da mensagem "Hello from the Kubernetes cluster", uma vez por minuto:
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello
spec:
schedule: "* * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
(O artigo Running Automated Tasks with a CronJob demonstra este exemplo com maiores detalhes).
# ┌───────────── minuto (0 - 59)
# │ ┌───────────── hora (0 - 23)
# │ │ ┌───────────── dia do mês (1 - 31)
# │ │ │ ┌───────────── mês (1 - 12)
# │ │ │ │ ┌───────────── dia da semana (0 - 6) (domingo a sábado;
# │ │ │ │ │ 7 também representa domingo em alguns sistemas operacionais)
# │ │ │ │ │
# │ │ │ │ │
# * * * * *
| Expressão | Descrição | Equivalente a |
|---|---|---|
| @yearly (ou @annually) | Executa uma vez por ano, à meia-noite de 1º de janeiro | 0 0 1 1 * |
| @monthly | Executa uma vez por mês, à meia-noite do primeiro dia do mês | 0 0 1 * * |
| @weekly | Executa uma vez por semana, à meia-noite de domingo | 0 0 * * 0 |
| @daily (ou @midnight) | Executa uma vez por dia, à meia-noite | 0 0 * * * |
| @hourly | Executa uma vez por hora, no minuto zero | 0 * * * * |
Por exemplo, a linha abaixo determina que a tarefa deve iniciar toda sexta-feira à meia-noite, bem como em todo dia 13 do mês à meia-noite:
0 0 13 * 5
É também possível gerar expressões de cronograma para CronJobs utilizando ferramentas da web como o crontab.guru.
Um CronJob cria uma tarefa aproximadamente uma vez por tempo de execução de seu cronograma. Dizemos "aproximadamente" porque existem circunstâncias em que duas tarefas podem ser criadas, e outras circunstâncias em que nenhuma tarefa será criada. Tentamos tornar estas situações raras, mas não é possível preveni-las completamente. Portanto, as tarefas devem ser idempotentes.
Se o valor da propriedade startingDeadlineSeconds (limite de tempo de inicialização, em segundos) estiver definido como um valor grande, ou não definido (o padrão), e se a propriedade concurrencyPolicy (política de concorrência) estiver definido como Allow (permitir), as tarefas sempre serão executadas pelo menos uma vez.
startingDeadlineSeconds estiver definida com um valor menor que 10 segundos, a tarefa cron poderá não ser agendada. Isso ocorre porque o cronograma de execução do controlador do CronJob verifica tarefas a cada 10 segundos.Para cada CronJob, o controlador do CronJob verifica quantos agendamentos foram perdidos no tempo entre o último horário agendado e o horário atual. Se houver mais de 100 agendamentos perdidos no período, o controlador não iniciará o trabalho e gerará a seguinte mensagem de erro:
Cannot determine if job needs to be started. Too many missed start time (> 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew.
É importante observar que, se o campo startingDeadlineSeconds estiver definido (não nil), o controlador contará quantas tarefas perdidas ocorreram a partir do valor de startingDeadlineSeconds até agora, e não do último horário agendado até agora. Por exemplo, se startingDeadlineSeconds for 200, o controlador contará quantas tarefas perdidas ocorreram nos últimos 200 segundos.
Um CronJob é considerado perdido se não for criado no horário agendado. Por exemplo, se concurrencyPolicy estiver definido como Forbid (proibir) e uma tentativa de agendamento de um novo CronJob ocorreu quando havia um agendamento anterior ainda em execução, o novo agendamento será contabilizado como perdido.
Por exemplo, suponha que um CronJob esteja definido para agendar uma nova tarefa a cada minuto, começando às 08:30:00, e seu campo startingDeadlineSeconds não esteja definido. Se o controlador do CronJob estiver inativo das 08:29:00 até as 10:21:00, a tarefa não será iniciada, pois o número de tarefas que perderam seus horários agendados é maior que 100.
Para ilustrar melhor este conceito, suponha que um CronJob esteja definido para agendar uma nova tarefa a cada minuto, começando às 08:30:00, e seu startingDeadlineSeconds esteja definido em 200 segundos. Se o controlador do CronJob estiver inativo no mesmo período do exemplo anterior (das 08:29:00 às 10:21:00), a tarefa ainda será iniciada às 10:22:00. Isso acontece pois o controlador agora verifica quantos agendamentos perdidos ocorreram nos últimos 200 segundos (ou seja, 3 agendamentos perdidos), ao invés de verificar o período entre o último horário agendado e o horário atual.
O CronJob é responsável apenas pela criação das tarefas que correspondem à sua programação, e a tarefa, por sua vez, é responsável pelo gerenciamento dos Pods que ele representa.
A partir da versão 1.21 do Kubernetes, a segunda versão do controlador do CronJob é a implementação ativada por padrão. Para desativar o controlador do CronJob padrão e utilizar a versão original do controlador do CronJob, é necessário adicionar o flag de feature gate CronJobControllerV2 à chamada do kube-controller-manager com o valor false (falso). Por exemplo:
--feature-gates="CronJobControllerV2=false"
A página Cron expression format documenta o formato dos campos de agendamento do CronJob.
Para instruções sobre criação e utilização de tarefas cron, e para um exemplo de manifesto de CronJob, veja Running automated tasks with cron jobs.
Essa página é uma visão geral do Kubernetes.
Kubernetes é um plataforma de código aberto, portável e extensiva para o gerenciamento de cargas de trabalho e serviços distribuídos em contêineres, que facilita tanto a configuração declarativa quanto a automação. Ele possui um ecossistema grande, e de rápido crescimento. Serviços, suporte, e ferramentas para Kubernetes estão amplamente disponíveis.
O Google tornou Kubernetes um projeto de código-aberto em 2014. O Kubernetes combina mais de 15 anos de experiência do Google executando cargas de trabalho produtivas em escala, com as melhores idéias e práticas da comunidade.
O nome Kubernetes tem origem no Grego, significando timoneiro ou piloto. K8s é a abreviação derivada pela troca das oito letras "ubernete" por "8", se tornado K"8"s.
Vamos dar uma olhada no porque o Kubernetes é tão útil, voltando no tempo.
Era da implantação tradicional: No início, as organizações executavam aplicações em servidores físicos. Não havia como definir limites de recursos para aplicações em um mesmo servidor físico, e isso causava problemas de alocação de recursos. Por exemplo, se várias aplicações fossem executadas em um mesmo servidor físico, poderia haver situações em que uma aplicação ocupasse a maior parte dos recursos e, como resultado, o desempenho das outras aplicações seria inferior. Uma solução para isso seria executar cada aplicação em um servidor físico diferente. Mas isso não escalava, pois os recursos eram subutilizados, e se tornava custoso para as organizações manter muitos servidores físicos.
Era da implantação virtualizada: Como solução, a virtualização foi introduzida. Esse modelo permite que você execute várias máquinas virtuais (VMs) em uma única CPU de um servidor físico. A virtualização permite que as aplicações sejam isoladas entre as VMs, e ainda fornece um nível de segurança, pois as informações de uma aplicação não podem ser acessadas livremente por outras aplicações.
A virtualização permite melhor utilização de recursos em um servidor físico, e permite melhor escalabilidade porque uma aplicação pode ser adicionada ou atualizada facilmente, reduz os custos de hardware e muito mais. Com a virtualização, você pode apresentar um conjunto de recursos físicos como um cluster de máquinas virtuais descartáveis.
Cada VM é uma máquina completa que executa todos os componentes, incluindo seu próprio sistema operacional, além do hardware virtualizado.
Era da implantação em contêineres: Contêineres são semelhantes às VMs, mas têm propriedades de isolamento flexibilizados para compartilhar o sistema operacional (SO) entre as aplicações. Portanto, os contêineres são considerados leves. Semelhante a uma VM, um contêiner tem seu próprio sistema de arquivos, compartilhamento de CPU, memória, espaço de processo e muito mais. Como eles estão separados da infraestrutura subjacente, eles são portáveis entre nuvens e distribuições de sistema operacional.
Contêineres se tornaram populares porque eles fornecem benefícios extra, tais como:
Os contêineres são uma boa maneira de agrupar e executar suas aplicações. Em um ambiente de produção, você precisa gerenciar os contêineres que executam as aplicações e garantir que não haja tempo de inatividade. Por exemplo, se um contêiner cair, outro contêiner precisa ser iniciado. Não seria mais fácil se esse comportamento fosse controlado por um sistema?
É assim que o Kubernetes vem ao resgate! O Kubernetes oferece uma estrutura para executar sistemas distribuídos de forma resiliente. Ele cuida do escalonamento e da recuperação à falha de sua aplicação, fornece padrões de implantação e muito mais. Por exemplo, o Kubernetes pode gerenciar facilmente uma implantação no método canário para seu sistema.
O Kubernetes oferece a você:
O Kubernetes não é um sistema PaaS (plataforma como serviço) tradicional e completo. Como o Kubernetes opera no nível do contêiner, e não no nível do hardware, ele fornece alguns recursos geralmente aplicáveis comuns às ofertas de PaaS, como implantação, escalonamento, balanceamento de carga, e permite que os usuários integrem suas soluções de logging, monitoramento e alerta. No entanto, o Kubernetes não é monolítico, e essas soluções padrão são opcionais e conectáveis. O Kubernetes fornece os blocos de construção para a construção de plataformas de desenvolvimento, mas preserva a escolha e flexibilidade do usuário onde é importante.
Kubernetes:
Ao implantar o Kubernetes, você obtém um cluster.
Um cluster Kubernetes consiste em um conjunto de servidores de processamento, chamados nós, que executam aplicações conteinerizadas. Todo cluster possui ao menos um servidor de processamento (worker node).
O(s) servidor(es) de processamento hospeda(m) os Pods, que são componentes de uma aplicação. A camada de gerenciamento gerencia os nós de processamento e os Pods no cluster. Em ambientes de produção, a camada de gerenciamento geralmente executa em múltiplos computadores e um cluster geralmente executa múltiplos nós, fornecendo tolerância a falhas e alta disponibilidade.
Este documento descreve os vários componentes que você precisa ter para implantar um cluster Kubernetes completo e funcional.
Os componentes de um cluster do Kubernetes
Os componentes da camada de gerenciamento tomam decisões globais sobre o cluster
(por exemplo, alocação de Pods), bem como detectam e respondem aos eventos
do cluster (por exemplo, inicialização de um novo Pod
quando o campo replicas de um Deployment não está atendido).
Os componentes da camada de gerenciamento podem ser executados em qualquer máquina do cluster. Contudo, para simplificar, os scripts de configuração normalmente iniciam todos os componentes da camada de gerenciamento na mesma máquina, e contêineres com cargas de trabalho do usuário não rodam nesta máquina. Veja Construindo clusters altamente disponíveis com o kubeadm para um exemplo de configuração da camada de gerenciamento que roda em múltiplas máquinas.
O servidor da API é um componente da camada de gerenciamento do Kubernetes que expõe a API do Kubernetes. O servidor da API é o front end para a camada de gerenciamento do Kubernetes.
A principal implementação de um servidor de API do Kubernetes é o kube-apiserver. O kube-apiserver foi projetado para ser escalonado horizontalmente — ou seja, ele pode ser escalonado com a criação de mais instâncias. Você pode executar várias instâncias do kube-apiserver e distribuir o tráfego entre essas instâncias.
Armazenamento do tipo chave-valor consistente e de alta-disponibilidade, usado como armazenamento de apoio do Kubernetes para todos os dados do cluster.
Se o seu cluster Kubernetes usa o etcd como seu armazenamento de apoio, certifique-se de ter um plano de backup para seus dados.
Você pode encontrar informações detalhadas sobre o etcd na documentação oficial.
Componente da camada de gerenciamento que observa os Pods recém-criados e que ainda não foram atribuídos a um nó, e seleciona um nó para executá-los.
Os fatores levados em consideração para as decisões de alocação incluem: requisitos de recursos individuais e coletivos, restrições de hardware/software/política, especificações de afinidade e antiafinidade, localidade de dados, interferência entre cargas de trabalho, e prazos.
Componente da camada de gerenciamento que executa os processos de controlador.
Logicamente, cada controlador está em um processo separado, mas para reduzir a complexidade, eles todos são compilados num único binário e executam em um processo único.
Alguns tipos desses controladores são:
default para novos namespaces.O cloud-controller-manager executa apenas controladores que são específicos para seu provedor de nuvem. Se você estiver executando o Kubernetes em suas próprias instalações ou em um ambiente de aprendizagem dentro de seu próprio PC, o cluster não possui um gerenciador de controlador de nuvem.
Tal como acontece com o kube-controller-manager, o cloud-controller-manager combina vários ciclos de controle logicamente independentes em um binário único que você executa como um processo único. Você pode escalonar horizontalmente (executar mais de uma cópia) para melhorar o desempenho ou para auxiliar na tolerância a falhas.
Os seguintes controladores podem ter dependências de provedor de nuvem:
Os componentes do nó são executados em todos os nós, mantendo os Pods em execução e fornecendo o ambiente de execução do Kubernetes.
Um agente que é executado em cada nó no cluster. Ele garante que os contêineres estejam sendo executados em um Pod.
O kubelet utiliza um conjunto de PodSpecs que são fornecidos por vários mecanismos e garante que os contêineres descritos nesses PodSpecs estejam funcionando corretamente. O kubelet não gerencia contêineres que não foram criados pelo Kubernetes.
kube-proxy é um proxy de rede executado em cada nó no seu cluster, implementando parte do conceito de serviço do Kubernetes.
kube-proxy mantém regras de rede nos nós. Estas regras de rede permitem a comunicação de rede com seus pods a partir de sessões de rede dentro ou fora de seu cluster.
kube-proxy usa a camada de filtragem de pacotes do sistema operacional se houver uma e estiver disponível. Caso contrário, o kube-proxy encaminha o tráfego ele mesmo.
O agente de execução (runtime) de contêiner é o software responsável por executar os contêineres.
O Kubernetes suporta diversos agentes de execução de contêineres: Docker, containerd, CRI-O, e qualquer implementação do Kubernetes CRI (Container Runtime Interface).
Complementos (addons) usam recursos do Kubernetes (DaemonSet,
Deployment, etc) para implementar funcionalidades
do cluster. Como fornecem funcionalidades em nível do cluster, recursos de complementos
que necessitem ser criados dentro de um namespace pertencem ao namespace kube-system.
Alguns complementos selecionados são descritos abaixo; para uma lista estendida dos complementos disponíveis, consulte Instalando Complementos.
Embora os outros complementos não sejam estritamente necessários, todos os clusters do Kubernetes devem ter um DNS do cluster, já que muitos exemplos dependem disso.
O DNS do cluster é um servidor DNS, além de outros servidores DNS em seu ambiente, que fornece registros DNS para serviços do Kubernetes.
Os contêineres iniciados pelo Kubernetes incluem automaticamente esse servidor DNS em suas pesquisas DNS.
O dashboard é uma interface de usuário Web, de uso geral, para clusters do Kubernetes. Ele permite que os usuários gerenciem e solucionem problemas de aplicações em execução no cluster, bem como o próprio cluster.
O monitoramento de recursos do contêiner registra métricas de série temporal genéricas sobre os contêineres em um banco de dados central e fornece uma interface de usuário para navegar por esses dados.
Um mecanismo de logging a nível do cluster é responsável por guardar os logs dos contêineres em um armazenamento central de logs com uma interface para navegação/pesquisa.
Esta página explica como os objetos do Kubernetes são representados na API do Kubernetes e como você pode expressá-los no formato .yaml.
Os objetos do Kubernetes são entidades persistentes no Kubernetes. Kubernetes utiliza estas entidades para representar o estado do cluster. Especificamente, eles podem descrever:
Um objeto do Kubernetes é um “registro de intenção”-uma vez criado o objeto, o sistema do Kubernetes trabalha constantemente para garantir que este objeto existe. Ao criar um objeto, você está efetivamente falando para o sistema do Kubernetes como você quer que a carga do seu cluster seja. Este é o estado desejado do seu cluster.
Para trabalhar com objetos do Kubernetes seja para criar, modificar ou deletar eles, você precisará usar a API do Kubernetes. Quando você usa a interface de linha de comando do kubectl, por exemplo, o CLI faz as chamadas necessárias na API do Kubernetes para você. Você também pode usar a API do Kubernetes diretamente no seu próprio programa usando uma das Bibliotecas.
Quase todos os objetos do Kubernetes incluem dois campos de objetos aninhados que governam a configuração do objeto: a especificação do objeto e o status do objeto. Para objetos que têm especificação, você tem que definir isso quando você cria o objeto, fornecendo uma descrição das características que você quer que o recurso tenha: o seu estado desejado.
O status descreve o estado atual do objeto, fornecido e atualizado pelo Kubernetes e seus componentes. A camada de gerenciamento do Kubernetes gerência continuamente e ativamente o real estado para corresponder ao estado desejado que você forneceu.
Por exemplo, no Kubernetes, o Deployment é um objeto que pode representar uma aplicação executando no seu cluster. Quando você cria o Deployment, você pode alterar a especificaçãopara definir que você quer três réplicas da aplicação em execução simultânea. O Kubernetes lê as especificações do Deployment e inicia três instâncias do seu aplicativo desejado, atualizando o status para corresponder às suas especificações. Se uma dessas instâncias falhar (um status mudar), o Kubernetes responde as diferenças entre as especificações e o status fazendo uma correção-neste caso, iniciando uma instância de substituição.
Para mais informações sobre especificações do objeto, status e metadados, veja Kubernetes API Conventions.
Quando se cria um objeto do Kubernetes, deve-se fornecer a especificação do objeto que descreve seu estado desejado, bem como algumas informações básicas sobre o objeto (como um nome, por exemplo). Quando utiliza a API Kubernetes para criar o objeto (diretamente ou via kubectl), essa solicitação de API deve incluir essa informação como JSON no corpo da solicitação. Na maioria das vezes, você fornece as informações ao comando kubectl em um arquivo .yaml. O comandokubectl converte a informação para JSON ao fazer a requisição para a API.
Aqui está um exemplo de arquivo .yaml que mostra os campos necessários e as especificações de objeto para uma implatação Kubernetes:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # diz ao deployment para executar 2 pods que correspondam ao modelo
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
Uma maneira de criar um Deployment usando um arquivo .yaml como o representado acima é usar o comando kubectl apply na interface de linha de comando kubectl, passando o arquivo .yaml como argumento. Aqui está um exemplo:
kubectl apply -f https://k8s.io/examples/application/deployment.yaml
A saída será similar a esta:
deployment.apps/nginx-deployment created
No arquivo .yaml para o objeto Kubernetes que pretende criar, você precisará definir valores para os seguintes campos:
apiVersion - Qual a versão de API do objeto que será usado no Kubernetes para criar esse objeto.kind - Qual tipo de objeto pretende criar.metadata - Dados que ajudam a identificar de forma única o objeto, incluindo uma string nome, UID e um namespace.spec - Que estado deseja para o objeto.O formato preciso do objeto spec é diferente para cada objeto Kubernetes, e contém campos aninhados específicos para aquele objeto. A documentação de referência da API do Kubernetes pode ajudar a encontrar o formato de especificação para todos os objetos que você pode criar usando Kubernetes.
Por exemplo, veja o campo de spec field para a referência Pod API.
Para cada Pod, o campo .spec especifica o pod e seu estado desejado (como o nome da imagem do contêiner para cada recipiente dentro daquela cápsula).
Outro exemplo de especificação de um objeto é o
campo spec .
Para o StatefulSet, o campo .spec especifica o StatefulSet e seu estado desejado.
Dentro do .spec de um StatefulSet está um template
para objetos de Pod. Esse modelo descreve os Pods que o controlador StatefulSet criará para
satisfazer a especificação do StatefulSet. Diferentes tipos de objetos também podem ter diferentes
.status; novamente, as páginas de referência API detalham a estrutura daquele campo .status,
e seu conteúdo para cada tipo diferente de objeto.
Aprenda sobre os mais importantes objetos básicos Kubernetes, como o Pod. Aprenda sobre as controladoras do Kubernetes. Usando a API Kubernetes explica mais alguns conceitos da API.
Cada objeto em seu cluster possui um Nome que é único para aquele tipo de recurso. Todo objeto do Kubernetes também possui um UID que é único para todo o cluster.
Por exemplo, você pode ter apenas um Pod chamado myapp-1234 dentro de um
namespace, porém
você pode ter um Pod e um Deployment ambos com o nome myapp-1234.
Para atributos não-únicos definidos pelo usuário, o Kubernetes fornece labels e annotations.
Uma string fornecida pelo cliente que referencia um objeto em uma URL de
recurso, como por exemplo /api/v1/pods/qualquer-nome.
Somente um objeto de um dado tipo pode ter um certo nome por vez. No entanto, se você remover o objeto, você poderá criar um novo objeto com o mesmo nome.
Abaixo estão descritos quatro tipos de restrições de nomes comumente utilizadas para recursos.
A maior parte dos recursos do Kubernetes requerem um nome que possa ser utilizado como um nome de subdomínio DNS, conforme definido na RFC 1123. Isso significa que o nome deve:
Alguns tipos de recurso requerem que seus nomes sigam o padrão de rótulos DNS definido na RFC 1123. Isso significa que o nome deve:
Alguns tipos de recurso requerem que seus nomes sigam o padrão de rótulos DNS definido na RFC 1035. Isso significa que o nome deve:
Alguns tipos de recurso requerem que seus nomes possam ser seguramente codificados como um segmento de caminho, ou seja, o nome não pode ser "." ou ".." e não pode conter "/" ou "%".
Exemplo de um manifesto para um Pod chamado nginx-demo.
apiVersion: v1
kind: Pod
metadata:
name: nginx-demo
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
Uma string gerada pelos sistemas do Kubernetes para identificar objetos de forma única.
Cada objeto criado durante todo o ciclo de vida do cluster do Kubernetes possui um UID distinto. O objetivo deste identificador é distinguir ocorrências históricas de entidades semelhantes.
UIDs no Kubernetes são identificadores únicos universais (também conhecidos como UUIDs). UUIDs seguem os padrões ISO/IEC 9834-8 e ITU-T X.667.
No Kubernetes, namespaces disponibilizam um mecanismo para isolar grupos de recursos dentro de um único cluster. Nomes de recursos precisam ser únicos dentro de um namespace, porém podem se repetir em diferentes namespaces. Escopos baseados em namespaces são aplicáveis apenas para objetos com namespace (como: Deployments, Services, etc) e não em objetos que abrangem todo o cluster (como: StorageClass, Nodes, PersistentVolumes, etc).
Namespaces devem ser utilizados em ambientes com múltiplos usuários espalhados por diversos times ou projetos. Para clusters com poucos ou até algumas dezenas de usuários, você não deveria precisar criar ou pensar a respeito de namespaces. Comece a utilizar namespaces quando você precisar das funcionalidades que eles oferecem.
Namespaces oferecem escopo para nomes. Nomes de recursos precisam ser únicos dentro de um namespace, porém não em diferentes namespaces. Namespaces não podem ser aninhados dentro de outros namespaces e cada recurso Kubernetes pode pertencer à apenas um namespace.
Namespaces nos permitem dividir os recursos do cluster entre diferentes usuários (via resource quota).
Não é necessário utilizar múltiplos namespaces para separar recursos levemente diferentes, como diferentes versões de um mesmo software: use labels para distinguir recursos dentro de um mesmo namespace.
default. Em vez disso, crie e utilize outros namespaces.O Kubernetes é inicializado com quatro namespaces:
defaultkube-node-leasekube-publickube-systemCriação e eliminação de namespaces estão descritas na documentação de namespaces do guia de administradores.
kube-, já que este prefixo é reservado para namespaces do sistema Kubernetes.Você pode obter uma lista dos namespaces atuais dentro de um cluster com:
kubectl get namespace
NAME STATUS AGE
default Active 1d
kube-node-lease Active 1d
kube-public Active 1d
kube-system Active 1d
Para preparar o namespace para a requisição atual, utilize o parâmetro --namespace. Por exemplo:
kubectl run nginx --image=nginx --namespace=<insert-namespace-name-here>
kubectl get pods --namespace=<insert-namespace-name-here>
Você pode salvar permanentemente o namespace para todos os comandos kubectl subsequentes no mesmo contexto:
kubectl config set-context --current --namespace=<insert-namespace-name-here>
# Validando
kubectl config view --minify | grep namespace:
Quando você cria um Serviço, ele cria uma
entrada DNS correspondente.
Esta entrada possui o formato: <service-name>.<namespace-name>.svc.cluster.local, de forma que se um contêiner utilizar apenas <service-name> ele será resolvido para um serviço que é local ao namespace.
Isso é útil para utilizar a mesma configuração em vários namespaces, por exemplo em Desenvolvimento, Staging e Produção. Se você quiser acessar múltiplos namespaces, precisará utilizar um Fully Qualified Domain Name (FQDN).
Nomes de namespaces devem ser válidos conforme a RFC 1123 para rótulos DNS.
Ao criar namespaces com o mesmo nome de domínios de topo públicos (TLDs), os Services dentro desses namespaces podem ter nomes DNS curtos que colidem com registros DNS públicos. Com isso, cargas de trabalho de qualquer namespace que realizem consultas DNS sem um ponto final (trailing dot) podem ser redirecionadas para esses serviços, tendo precedência sobre o DNS público.
Para mitigar esse risco, limite a criação de namespaces apenas a usuários confiáveis. Se necessário, você também pode configurar controles de segurança de terceiros, como admission webhooks, para bloquear a criação de namespaces com nomes que coincidam com TLDs públicos.
A maior parte dos recursos Kubernetes (como Pods, Services, controladores de replicação e outros) pertencem a algum namespace. Entretanto, recursos de namespaces não pertencem a nenhum namespace. Além deles, recursos de baixo nível, como nodes e persistentVolumes, também não pertencem a nenhum namespace.
Para visualizar quais recursos Kubernetes pertencem ou não a algum namespace, utilize:
# Em um namespace
kubectl api-resources --namespaced=true
# Sem namespace
kubectl api-resources --namespaced=false
Kubernetes 1.22 [stable]
A camada de gerenciamento Kubernetes configura um label imutável kubernetes.io/metadata.name em todos os namespaces.
O valor do label é o nome do namespace.
Os Seletores de Campos permitem que você selecione recursos do Kubernetes baseado no valor de um ou mais campos de um recurso. Seguem alguns exemplos de buscas utilizando seletores de campos:
metadata.name=my-servicemetadata.namespace!=defaultstatus.phase=PendingO comando kubectl, mostrado a seguir, seleciona todos os Pods nos quais o valor do campo status.phase é Running:
kubectl get pods --field-selector status.phase=Running
kubectl sejam equivalentes: kubectl get pods e kubectl get pods --field-selector ""Os campos de seleção suportados variam dependendo do tipo de recurso Kubernetes. Todos os tipos de recursos suportam os campos metadata.name e metadata.namespace. Utilizar campos não suportados produz um erro. Como por exemplo:
kubectl get ingress --field-selector foo.bar=baz
Error from server (BadRequest): Unable to find "ingresses" that match label selector "", field selector "foo.bar=baz": "foo.bar" is not a known field selector: only "metadata.name", "metadata.namespace"
Você pode utilizar os operadores =, == e != com seletores de campos (= e == significam a mesma coisa). Por exemplo, o comando kubectl a seguir seleciona todos os Kubernetes Services que não estão no namespace default:
kubectl get services --all-namespaces --field-selector metadata.namespace!=default
Assim como label e outros tipos de seletores, podem ser utilizados em cadeia através de uma lista separada por vírgula. O comando kubectl a seguir seleciona todos os Pods nos quais status.phase não é igual a Running e spec.restartPolicy é igual a Always
kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always
Você pode utilizar seletores de campos através de múltiplos tipos de recursos. Por exemplo, o comando kubectl a seguir seleciona todos Statefulsets e Services que não estão presentes no namespace default.
kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace!=default
Um cluster Kubernetes consiste em um control plane mais um conjunto de máquinas trabalhadoras, chamadas de nodes, que executam aplicações conteinerizadas. Todo cluster precisa de pelo menos um worker node para executar Pods.
Os worker nodes hospedam os Pods que são os componentes da carga de trabalho da aplicação. O control plane gerencia os worker nodes e os Pods no cluster. Em ambientes de produção, o control plane geralmente executa em múltiplos computadores e um cluster geralmente executa múltiplos nodes, fornecendo tolerância a falhas e alta disponibilidade.
Este documento descreve os vários componentes que você precisa ter para um cluster Kubernetes completo e funcional.
Figura 1. Componentes do cluster Kubernetes.
O diagrama na Figura 1 apresenta um exemplo de arquitetura de referência para um cluster Kubernetes. A distribuição real dos componentes pode variar com base em configurações e requisitos específicos do cluster.
No diagrama, cada node executa o componente kube-proxy. Você precisa de um
componente de proxy de rede em cada node para garantir que a
API de Service e comportamentos associados
estejam disponíveis na rede do seu cluster. No entanto, alguns plugins de rede fornecem sua própria
implementação de proxy de terceiros. Quando você usa esse tipo de plugin de rede,
o node não precisa executar o kube-proxy.
Os componentes do control plane tomam decisões globais sobre o cluster (por exemplo, agendamento),
bem como detectam e respondem a eventos do cluster (por exemplo, iniciar um novo
pod quando o campo
replicas de um Deployment não está satisfeito).
Os componentes do control plane podem ser executados em qualquer máquina do cluster. No entanto, para simplicidade, scripts de configuração normalmente iniciam todos os componentes do control plane na mesma máquina, e não executam contêineres de usuário nesta máquina. Consulte Criando clusters altamente disponíveis com kubeadm para um exemplo de configuração do control plane que executa em múltiplas máquinas.
O servidor da API é um componente da camada de gerenciamento do Kubernetes que expõe a API do Kubernetes. O servidor da API é o front end para a camada de gerenciamento do Kubernetes.
A principal implementação de um servidor de API do Kubernetes é o kube-apiserver. O kube-apiserver foi projetado para ser escalonado horizontalmente — ou seja, ele pode ser escalonado com a criação de mais instâncias. Você pode executar várias instâncias do kube-apiserver e distribuir o tráfego entre essas instâncias.
Armazenamento do tipo chave-valor consistente e de alta-disponibilidade, usado como armazenamento de apoio do Kubernetes para todos os dados do cluster.
Se o seu cluster Kubernetes usa o etcd como seu armazenamento de apoio, certifique-se de ter um plano de backup para seus dados.
Você pode encontrar informações detalhadas sobre o etcd na documentação oficial.
Componente da camada de gerenciamento que observa os Pods recém-criados e que ainda não foram atribuídos a um nó, e seleciona um nó para executá-los.
Os fatores levados em consideração para as decisões de alocação incluem: requisitos de recursos individuais e coletivos, restrições de hardware/software/política, especificações de afinidade e antiafinidade, localidade de dados, interferência entre cargas de trabalho, e prazos.
Componente da camada de gerenciamento que executa os processos de controlador.
Logicamente, cada controlador está em um processo separado, mas para reduzir a complexidade, eles todos são compilados num único binário e executam em um processo único.
Existem muitos tipos diferentes de controllers. Alguns exemplos deles são:
A lista acima não é exaustiva.
O cloud-controller-manager executa apenas controllers que são específicos do seu provedor de nuvem. Se você está executando o Kubernetes em suas próprias instalações, ou em um ambiente de aprendizado dentro do seu próprio PC, o cluster não tem um cloud controller manager.
Assim como o kube-controller-manager, o cloud-controller-manager combina vários loops de controle logicamente independentes em um único binário que você executa como um único processo. Você pode escalar horizontalmente (executar mais de uma cópia) para melhorar o desempenho ou para ajudar a tolerar falhas.
Os seguintes controllers podem ter dependências do provedor de nuvem:
Os componentes do node executam em cada node, mantendo pods em execução e fornecendo o ambiente de runtime do Kubernetes.
Um agente que é executado em cada nó no cluster. Ele garante que os contêineres estejam sendo executados em um Pod.
O kubelet utiliza um conjunto de PodSpecs que são fornecidos por vários mecanismos e garante que os contêineres descritos nesses PodSpecs estejam funcionando corretamente. O kubelet não gerencia contêineres que não foram criados pelo Kubernetes.
kube-proxy é um proxy de rede executado em cada nó no seu cluster, implementando parte do conceito de serviço do Kubernetes.
kube-proxy mantém regras de rede nos nós. Estas regras de rede permitem a comunicação de rede com seus pods a partir de sessões de rede dentro ou fora de seu cluster.
kube-proxy usa a camada de filtragem de pacotes do sistema operacional se houver uma e estiver disponível. Caso contrário, o kube-proxy encaminha o tráfego ele mesmo.
Se você usar um plugin de rede que implementa encaminhamento de pacotes para Services por si só, e fornece comportamento equivalente ao kube-proxy, então você não precisa executar kube-proxy nos nodes do seu cluster.O agente de execução (runtime) de contêiner é o software responsável por executar os contêineres.
O Kubernetes suporta diversos agentes de execução de contêineres: Docker, containerd, CRI-O, e qualquer implementação do Kubernetes CRI (Container Runtime Interface).
Addons usam recursos do Kubernetes (DaemonSet,
Deployment, etc) para implementar funcionalidades do cluster.
Como estes estão fornecendo funcionalidades no nível do cluster, recursos com namespace para
addons pertencem ao namespace kube-system.
Addons selecionados são descritos abaixo; para uma lista estendida de addons disponíveis, consulte Addons.
Embora os outros addons não sejam estritamente necessários, todos os clusters Kubernetes devem ter DNS do cluster, pois muitos exemplos dependem dele.
DNS do cluster é um servidor DNS, além do(s) outro(s) servidor(es) DNS em seu ambiente, que serve registros DNS para services do Kubernetes.
Contêineres iniciados pelo Kubernetes automaticamente incluem este servidor DNS em suas buscas DNS.
Dashboard é uma UI baseada na web de propósito geral para clusters Kubernetes. Ela permite aos usuários gerenciar e solucionar problemas de aplicações executando no cluster, bem como o próprio cluster.
Monitoramento de Recursos de Contêiner grava métricas genéricas de séries temporais sobre contêineres em um banco de dados central, e fornece uma UI para navegar nesses dados.
Um mecanismo de logging no nível do cluster é responsável por salvar logs de contêineres em um armazenamento central de logs com uma interface de busca/navegação.
Plugins de rede são componentes de software que implementam a especificação da interface de rede de contêineres (CNI). Eles são responsáveis por alocar endereços IP para pods e permitir que eles se comuniquem uns com os outros dentro do cluster.
Embora os componentes principais do Kubernetes permaneçam consistentes, a forma como eles são implantados e gerenciados pode variar. Entender essas variações é crucial para projetar e manter clusters Kubernetes que atendam às necessidades operacionais específicas.
Os componentes do control plane podem ser implantados de várias maneiras:
O posicionamento de cargas de trabalho, incluindo os componentes do control plane, pode variar com base no tamanho do cluster, requisitos de desempenho e políticas operacionais:
Ferramentas como kubeadm, kops e Kubespray oferecem diferentes abordagens para implantar e gerenciar clusters, cada uma com seu próprio método de layout e gerenciamento de componentes.
A flexibilidade da arquitetura do Kubernetes permite que organizações adaptem seus clusters às necessidades específicas, equilibrando fatores como complexidade operacional, desempenho e sobrecarga de gerenciamento.
A arquitetura do Kubernetes permite customização significativa:
A flexibilidade da arquitetura do Kubernetes permite que organizações adaptem seus clusters às necessidades específicas, equilibrando fatores como complexidade operacional, desempenho e sobrecarga de gerenciamento.
Saiba mais sobre o seguinte:
O Kubernetes executa sua carga de trabalho colocando contêineres em Pods para serem executados em Nós. Um nó pode ser uma máquina virtual ou física, dependendo do cluster. Cada nó é gerenciado pela camada de gerenciamento e contém os serviços necessários para executar Pods.
Normalmente, você tem vários nós em um cluster; em um ambiente de aprendizado ou limitado por recursos, você pode ter apenas um nó.
Os componentes em um nó incluem o kubelet, um agente de execução de contêiner, e o kube-proxy.
Existem duas maneiras principais de adicionar Nós ao Servidor da API:
Depois de criar um objeto Nó, ou o kubelet em um nó se registra automaticamente, a camada de gerenciamento verifica se o novo objeto Nó é válido. Por exemplo, se você tentar criar um nó a partir do seguinte manifesto JSON:
{
"kind": "Node",
"apiVersion": "v1",
"metadata": {
"name": "10.240.79.157",
"labels": {
"name": "my-first-k8s-node"
}
}
}
O Kubernetes cria um objeto nó internamente (a representação). O Kubernetes verifica se um kubelet se registrou no servidor da API que corresponde ao campo metadata.name do Nó. Se o nó estiver íntegro (ou seja, todos os serviços necessários estiverem em execução), ele será elegível para executar um Pod. Caso contrário, esse nó é ignorado para qualquer atividade de cluster até que se torne íntegro.
O Kubernetes mantém o objeto nó inválido e continua verificando se ele se torna íntegro.
Você, ou um controlador, deve excluir explicitamente o objeto Nó para interromper essa verificação de integridade.
O nome de um objeto nó deve ser um nome de subdomínio válido de DNS.
O nome identifica um nó. Dois nós não podem ter o mesmo nome ao mesmo tempo. O Kubernetes também assume que um recurso com o mesmo nome é o mesmo objeto. No caso de um nó, assume-se implicitamente que uma instância usando o mesmo nome terá o mesmo estado (por exemplo, configurações de rede, conteúdo do disco raiz) e atributos como label de nó. Isso pode levar a inconsistências se uma instância for modificada sem alterar seu nome. Se o nó precisar ser substituído ou atualizado significativamente, o objeto Nó existente precisa ser removido do servidor da API primeiro e adicionado novamente após a atualização.
Quando a opção --register-node do kubelet for verdadeira (padrão), o kubelet tentará se registrar no servidor da API. Este é o padrão preferido, usado pela maioria das distribuições.
Para auto-registro, o kubelet é iniciado com as seguintes opções:
--kubeconfig - O caminho das credenciais para se autenticar no servidor da API.--cloud-provider - Como comunicar com um provedor de nuvem
para ler metadados sobre si mesmo.--register-node - Registrar automaticamente no servidor da API.--register-with-taints - Registra o nó com a lista fornecida de taints (separadas por vírgula <key>=<value>:<effect>).Não funciona se o register-node for falso.
--node-ip - endereço IP do nó.--node-labels - Labels a serem adicionados ao registrar o nó
no cluster (consulte as restrições de label impostas pelo plug-in de admissão NodeRestriction).--node-status-update-frequency - Especifica com que frequência o kubelet publica o status do nó no servidor da API.Quando o modo de autorização do nó e o plug-in de admissão NodeRestriction estão ativados, os kubelets somente estarão autorizados a criar/modificar seu próprio recurso do nó.
Como mencionado na seção de singularidade do nome do nó, quando a configuração do nó precisa ser atualizada, é uma boa prática registrar novamente o nó no servidor da API. Por exemplo, se o kubelet estiver sendo reiniciado com o novo conjunto de --node-labels, mas o mesmo nome de nó for usado, a alteração não entrará em vigor, pois os labels estão sendo definidos no registro do Nó.
Pods já agendados no Nó podem ter um comportamento anormal ou causar problemas se a configuração do Nó for alterada na reinicialização do kubelet. Por exemplo, o Pod já em execução pode estar marcado diferente dos labels atribuídos ao Nó, enquanto outros Pods, que são incompatíveis com esse Pod, serão agendados com base nesse novo label. O novo registro do nó garante que todos os Pods sejam drenados e devidamente reiniciados.
Você pode criar e modificar objetos Nó usando o kubectl.
Quando você quiser manualmente criar objetos Nó, defina a opção do kubelet --register-node=false.
Você pode modificar os objetos Nó, independentemente da configuração de --register-node. Por exemplo, você pode definir labels em um nó existente ou marcá-lo como não disponível.
Você pode usar labels nos Nós em conjunto com seletores de nós nos Pods para controlar a disponibilidade. Por exemplo, você pode restringir um Pod a ser elegível apenas para ser executado em um subconjunto dos nós disponíveis.
Marcar um nó como não disponível impede que o escalonador coloque novos pods nesse nó, mas não afeta os Pods existentes no nó. Isso é útil como uma etapa preparatória antes da reinicialização de um nó ou outra manutenção.
Para marcar um nó como não disponível, execute:
kubectl cordon $NODENAME
Consulte Drenar um nó com segurança para obter mais detalhes.
O status de um nó contém as seguintes informações:
Você pode usar o kubectl para visualizar o status de um nó e outros detalhes:
kubectl describe node <insira-nome-do-nó-aqui>
Cada seção da saída está descrita abaixo.
O uso desses campos pode mudar dependendo do seu provedor de nuvem ou configuração dedicada.
kernel do nó. Pode ser substituído através do parâmetro kubelet --hostname-override.cluster).cluster.O campo conditions descreve o status de todos os nós em execução. Exemplos de condições incluem:
| Condições do nó | Descrição |
|---|---|
Ready |
True Se o nó estiver íntegro e pronto para aceitar pods, False se o nó não estiver íntegro e não estiver aceitando pods, e desconhecido Unknown se o controlador do nó tiver sem notícias do nó no último node-monitor-grace-period (o padrão é de 40 segundos) |
DiskPressure |
True Se houver pressão sobre o tamanho do disco, ou seja, se a capacidade do disco for baixa; caso contrário False |
MemoryPressure |
True Se houver pressão na memória do nó, ou seja, se a memória do nó estiver baixa; caso contrário False |
PIDPressure |
True Se houver pressão sobre os processos, ou seja, se houver muitos processos no nó; caso contrário False |
NetworkUnavailable |
True Se a rede do nó não estiver configurada corretamente, caso contrário False |
Condition inclui SchedulingDisabled. SchedulingDisabled não é uma condição na API do Kubernetes; em vez disso, os nós isolados são marcados como Unschedulable em suas especificações.Na API do Kubernetes, a condição de um nó é representada como parte do .status do recurso do nó. Por exemplo, a seguinte estrutura JSON descreve um nó íntegro:
"conditions": [
{
"type": "Ready",
"status": "True",
"reason": "KubeletReady",
"message": "kubelet is posting ready status",
"lastHeartbeatTime": "2019-06-05T18:38:35Z",
"lastTransitionTime": "2019-06-05T11:41:27Z"
}
]
Se o status da condição Ready permanecer desconhecido (Unknown) ou falso (False) por mais tempo do que o limite da remoção do pod (pod-eviction-timeout) (um argumento passado para o kube-controller-manager), o controlador de nó acionará o remoção iniciado pela API para todos os Pods atribuídos a esse nó. A duração padrão do tempo limite da remoção é de cinco minutos. Em alguns casos, quando o nó está inacessível, o servidor da API não consegue se comunicar com o kubelet no nó. A decisão de excluir os pods não pode ser comunicada ao kubelet até que a comunicação com o servidor da API seja restabelecida. Enquanto isso, os pods agendados para exclusão podem continuar a ser executados no nó particionado.
O controlador de nós não força a exclusão dos pods até que seja confirmado que eles pararam de ser executados no cluster. Você pode ver os pods que podem estar sendo executados em um nó inacessível como estando no estado de terminando (Terminating) ou desconhecido (Unknown). Nos casos em que o Kubernetes não retirar da infraestrutura subjacente se um nó tiver deixado permanentemente um cluster, o administrador do cluster pode precisar excluir o objeto do nó manualmente. Excluir o objeto do nó do Kubernetes faz com que todos os objetos Pod em execução no nó sejam excluídos do servidor da API e libera seus nomes.
Quando ocorrem problemas nos nós, a camada de gerenciamento do Kubernetes cria automaticamente taints que correspondem às condições que afetam o nó. O escalonador leva em consideração as taints do Nó ao atribuir um Pod a um Nó. Os Pods também podem ter tolerations que os permitem funcionar em um nó, mesmo que tenha uma taint específica.
Consulte Nó Taint por Condição para mais detalhes.
Descreve os recursos disponíveis no nó: CPU, memória e o número máximo de pods que podem ser agendados no nó.
Os campos no bloco de capacidade indicam a quantidade total de recursos que um nó possui. O bloco alocado indica a quantidade de recursos em um nó que está disponível para ser consumido por Pods normais.
Você pode ler mais sobre capacidade e recursos alocados enquanto aprende a reservar recursos de computação em um nó.
Descreve informações gerais sobre o nó, como a versão do kernel, a versão do Kubernetes (versão do kubelet e kube-proxy), detalhes do tempo de execução do contêiner e qual sistema operacional o nó usa. O kubelet coleta essas informações do nó e as publica na API do Kubernetes.
Os Heartbeats, enviados pelos nós do Kubernetes, ajudam seu cluster a determinar a disponibilidade de cada nó e a agir quando as falhas forem detectadas.
Para nós, existem duas formas de heartbeats:
.status de um Nókube-node-lease. Cada nó tem um objeto de Lease associado.Em comparação com as atualizações no .status de um nó, um Lease é um recurso mais leve. O uso de Leases para heartbeats reduz o impacto no desempenho dessas atualizações para grandes clusters.
O kubelet é responsável por criar e atualizar o .status dos Nós e por atualizar suas Leases relacionadas.
Lease a cada 10 segundos (o intervalo de atualização padrão). As atualizações de Lease ocorrem independentemente das atualizações no .status do Nó. Se a atualização do Lease falhar, o kubelet voltará a tentativas, usando um recuo exponencial que começa em 200 milissegundos e limitado a 7 segundos.O controlador de nós é um componente da camada de gerenciamento do Kubernetes que gerencia vários aspectos dos nós.
O controlador de nó tem várias funções na vida útil de um nó. O primeiro é atribuir um bloco CIDR ao nó quando ele é registrado (se a atribuição CIDR estiver ativada).
O segundo é manter a lista interna de nós do controlador de nós atualizada com a lista de máquinas disponíveis do provedor de nuvem. Ao ser executado em um ambiente de nuvem e sempre que um nó não é íntegro, o controlador de nó pergunta ao provedor de nuvem se a VM desse nó ainda está disponível. Caso contrário, o controlador de nós exclui o nó de sua lista de nós.
O terceiro é monitorar a saúde dos nós. O controlador do nó é responsável por:
.status do nó. Nesse caso, o controlador do nó define a condição de pronto (NodeReady) como condição desconhecida (ConditionUnknown).ConditionUnknown) e enviar a primeira solicitação de remoção.O controlador de nó verifica o estado de cada nó a cada --node-monitor-period segundos.
Na maioria dos casos, o controlador de nós limita a taxa de remoção a --node-eviction-rate (0,1 por padrão) por segundo, o que significa que ele não removerá pods de mais de 1 nó por 10 segundos.
O comportamento de remoção do nó muda quando um nó em uma determinada zona de disponibilidade se torna não íntegro. O controlador de nós verifica qual porcentagem de nós na zona não são íntegras (a condição NodeReady é desconhecida ConditionUnknown ou falsa ConditionFalse) ao mesmo tempo:
--unhealthy-zone-threshold (padrão 0,55), então a taxa de remoção será reduzida.--large-cluster-size-threshold - padrão 50), então as remoções serão interrompidas.--secondary-node-eviction-rate de nós secundários (padrão 0,01) por segundo.A razão pela qual essas políticas são implementadas por zona de disponibilidade é porque a camada de gerenciamento pode perder conexão com uma zona de disponibilidade, enquanto as outras permanecem conectadas. Se o seu cluster não abranger várias zonas de disponibilidade de provedores de nuvem, o mecanismo de remoção não levará em conta a indisponibilidade por zona.
Uma das principais razões para espalhar seus nós pelas zonas de disponibilidade é para que a carga de trabalho possa ser transferida para zonas íntegras quando uma zona inteira cair. Portanto, se todos os nós em uma zona não estiverem íntegros, o controlador do nó removerá na taxa normal de --node-eviction-rate. O caso especial é quando todas as zonas estiverem completamente insalubres (nenhum dos nós do cluster será íntegro). Nesse caso, o controlador do nó assume que há algum problema com a conectividade entre a camada de gerenciamento e os nós e não realizará nenhuma remoção. (Se houver uma interrupção e alguns nós reaparecerem, o controlador do nó expulsará os pods dos nós restantes que estiverem insalubres ou inacessíveis).
O controlador de nós também é responsável por remover pods em execução nos nós com NoExecute taints, a menos que esses pods tolerem essa taint. O controlador de nó também adiciona as taints correspondentes aos problemas de nó, como nó inacessível ou não pronto. Isso significa que o escalonador não colocará Pods em nós não íntegros.
Os objetos do nó rastreiam informações sobre a capacidade de recursos do nó: por exemplo, a quantidade de memória disponível e o número de CPUs. Os nós que se auto-registram relatam sua capacidade durante o registro. Se você adicionar manualmente um nó, precisará definir as informações de capacidade do nó ao adicioná-lo.
O escalonador do Kubernetes garante que haja recursos suficientes para todos os Pods em um nó. O escalonador verifica se a soma das solicitações de contêineres no nó não é maior do que a capacidade do nó. Essa soma de solicitações inclui todos os contêineres gerenciados pelo kubelet, mas exclui quaisquer contêineres iniciados diretamente pelo agente de execução de contêiner e também exclui quaisquer processos executados fora do controle do kubelet.
Kubernetes v1.16 [alpha]
Se você ativou os [recursos]](/docs/reference/command-line-tools-reference/feature-gates/) de TopologyManager, o kubelet pode usar dicas da topologia ao tomar decisões de atribuição de recursos. Consulte Controle das Políticas de Gerenciamento de Topologia em um Nó para obter mais informações.
Kubernetes v1.21 [beta]
O kubelet tenta detectar o desligamento do sistema do nó e encerra os pods em execução no nó.
O Kubelet garante que os pods sigam o processo normal de término do podpod-lifecycle/#pod-termination) durante o desligamento do nó.
O recurso de desligamento gradual do nó depende do systemd, pois aproveita os bloqueios do inibidor do systemd para atrasar o desligamento do nó com uma determinada duração.
O desligamento gradual do nó é controlado com recursos GracefulNodeShutdown, que é ativado por padrão na versão 1.21.
Observe que, por padrão, ambas as opções de configuração descritas abaixo, shutdownGracePeriod and shutdownGracePeriodCriticalPods estão definidas como zero, não ativando assim a funcionalidade de desligamento gradual do nó. Para ativar o recurso, as duas configurações do kubelet devem ser configuradas adequadamente e definidas como valores diferentes de zero.
Durante um desligamento gradual, o kubelet encerra os pods em duas fases:
O recurso de desligamento gradual do nó é configurado com duas opções KubeletConfiguration:
shutdownGracePeriod:
shutdownGracePeriodCriticalPods:
shutdownGracePeriod.Por exemplo, se shutdownGracePeriod=30s e shutdownGracePeriodCriticalPods=10s, o kubelet atrasará o desligamento do nó em 30 segundos. Durante o desligamento, os primeiros 20 (30-10) segundos seriam reservados para encerrar gradualmente os pods normais, e os últimos 10 segundos seriam reservados para encerrar pods críticos.
Quando os pods forem removidos durante o desligamento gradual do nó, eles serão marcados como desligados. Executar o kubectl get pods para mostrar o status dos pods removidos como Terminated. E o kubectl describe pod indica que o pod foi removido por causa do desligamento do nó:
Reason: Terminated
Message: Pod was terminated in response to imminent node shutdown.
Kubernetes v1.24 [beta]
Para fornecer mais flexibilidade durante o desligamento gradual do nó em torno da ordem de pods durante o desligamento, o desligamento gradual do nó respeita a PriorityClass dos Pods, desde que você tenha ativado esse recurso em seu cluster. O recurso permite que o cluster defina explicitamente a ordem dos pods durante o desligamento gradual do nó com base em classes de prioridade.
O recurso Desligamento Gradual do Nó, conforme descrito acima, desliga pods em duas fases, pods não críticos, seguidos por pods críticos. Se for necessária flexibilidade adicional para definir explicitamente a ordem dos pods durante o desligamento de uma maneira mais granular, o desligamento gradual baseado na prioridade do pod pode ser usado.
Quando o desligamento gradual do nó respeita as prioridades do pod, isso torna possível fazer o desligamento gradual do nó em várias fases, cada fase encerrando uma classe de prioridade específica de pods. O kubelet pode ser configurado com as fases exatas e o tempo de desligamento por fase.
Assumindo as seguintes classes de prioridade de pod personalizadas em um cluster,
| Nome das classes de prioridade | Valor das classes de prioridade |
|---|---|
custom-class-a |
100000 |
custom-class-b |
10000 |
custom-class-c |
1000 |
regular/unset |
0 |
Na configuração do kubelet, as configurações para shutdownGracePeriodByPodPriority são semelhantes a:
| Valor das classes de prioridade | Tempo de desligamento |
|---|---|
| 100000 | 10 segundos |
| 10000 | 180 segundos |
| 1000 | 120 segundos |
| 0 | 60 segundos |
A configuração correspondente do YAML do kubelet seria:
shutdownGracePeriodByPodPriority:
- priority: 100000
shutdownGracePeriodSeconds: 10
- priority: 10000
shutdownGracePeriodSeconds: 180
- priority: 1000
shutdownGracePeriodSeconds: 120
- priority: 0
shutdownGracePeriodSeconds: 60
A tabela acima implica que qualquer pod com valor priority >= 100000 terá apenas 10 segundos para parar qualquer pod com valor >= 10000 e < 100000 e terá 180 segundos para parar, qualquer pod com valor >= 1000 e < 10000 terá 120 segundos para parar. Finalmente, todos os outros pods terão 60 segundos para parar.
Não é preciso especificar valores correspondentes para todas as classes. Por exemplo, você pode usar estas configurações:
| Valor das classes de prioridade | Tempo de desligamento |
|---|---|
| 100000 | 300 segundos |
| 1000 | 120 segundos |
| 0 | 60 segundos |
No caso acima, os pods com custom-class-b irão para o mesmo bucket que custom-class-c para desligamento.
Se não houver pods em um intervalo específico, o kubelet não irá espera por pods nesse intervalo de prioridades. Em vez disso, o kubelet pula imediatamente para o próximo intervalo de valores da classe de prioridade.
Se esse recurso estiver ativado e nenhuma configuração for fornecida, nenhuma ação de pedido será tomada.
O uso desse recurso requer ativar os recursos GracefulNodeShutdownBasedOnPodPriority e definir o ShutdownGracePeriodByPodPriority da configuração do kubelet para a configuração desejada, contendo os valores da classe de prioridade do pod e seus respectivos períodos de desligamento.
Kubernetes v1.22 [alpha]
Antes do Kubernetes 1.22, os nós não suportavam o uso de memória swap, e um kubelet, por padrão, não iniciaria se a troca fosse detectada em um nó. A partir de 1.22, o suporte a memória swap pode ser ativado por nó.
Para ativar a troca em um nó, o recursos NodeSwap deve estar ativado no kubelet, e a configuração de comando de linha --fail-swap-on ou failSwapOn deve ser definida como falsa.
Secret que foram gravados no tmpfs, agora podem ser trocados para o disco.Opcionalmente, um usuário também pode configurar memorySwap.swapBehavior para especificar como um nó usará memória swap. Por exemplo,
memorySwap:
swapBehavior: LimitedSwap
As opções de configuração disponíveis para swapBehavior são:
LimitedSwap: As cargas de trabalho do Kubernetes são limitadas na quantidade de troca que podem usar. Cargas de trabalho no nó não gerenciadas pelo Kubernetes ainda podem ser trocadas.UnlimitedSwap: As cargas de trabalho do Kubernetes podem usar tanta memória de swap quanto solicitarem, até o limite do sistema.Se a configuração do memorySwap não for especificada e o recurso estiver ativado, por padrão, o kubelet aplicará o mesmo comportamento que a configuração LimitedSwap.
O comportamento da configuração LimitedSwap depende se o nó estiver sendo executado com v1 ou v2 de grupos de controle (também conhecidos como "cgroups"):
Para obter mais informações e para ajudar nos testes e fornecer feedback, consulte KEP-2400 e sua proposta de design.
Este documento cataloga os caminhos de comunicação entre o servidor de API e o cluster Kubernetes. A intenção é permitir que os usuários personalizem sua instalação para endurecer a configuração de rede de tal forma que o cluster pode ser executado em uma rede não confiável (ou em IPs totalmente públicos em um provedor de nuvem).
O Kubernetes tem um padrão de API "hub-and-spoke". Todo uso da API dos nós (ou dos pods que eles executam) termina no servidor de API. Nenhum dos outros componentes da camada de gerenciamento são projetados para expor serviços remotos. O servidor de API é configurado para escutar conexões remotas em uma porta HTTPS segura (tipicamente 443) com uma ou mais formas de autenticação de cliente habilitada. Uma ou mais formas de autorização devem ser habilitadas, especialmente se requisições anônimas ou tokens da conta de serviço são permitidos.
Os nós devem ser provisionados com o certificado raiz público do cluster de tal forma que eles podem se conectar de forma segura ao servidor de API junto com credenciais de cliente válidas. Uma boa abordagem é que as credenciais de cliente fornecidas ao kubelet estejam na forma de um certificado de cliente. Veja inicialização TLS do kubelet para provisionamento automatizado de certificados de cliente do kubelet.
Pods que desejam se conectar ao servidor de API podem fazê-lo com segurança, aproveitando uma conta de serviço para
que o Kubernetes injete automaticamente o certificado raiz público e um token de portador válido
no pod quando ele for instanciado.
O serviço kubernetes (no namespace default) é configurado com um endereço IP virtual que é
redirecionado (via kube-proxy) para o endpoint HTTPS no servidor de API.
Os componentes da camada de gerenciamento também se comunicam com o servidor de API através da porta segura.
Como resultado, o modo de operação padrão para conexões dos nós e dos pods em execução nos nós para a camada de gerenciamento é seguro por padrão e pode operar em redes não confiáveis e/ou públicas.
Existem dois caminhos de comunicação primários da camada de gerenciamento (o servidor de API) para os nós. O primeiro é do servidor de API para o processo kubelet que executa em cada nó no cluster. O segundo é do servidor de API para qualquer nó, pod, ou serviço através da funcionalidade de proxy do servidor de API.
As conexões do servidor de API para o kubelet são usadas para:
kubectl) a pods em execução.Essas conexões terminam no endpoint HTTPS do kubelet. Por padrão, o servidor de API não verifica o certificado de serviço do kubelet, o que torna a conexão sujeita a ataques man-in-the-middle e insegura para executar por redes não confiáveis e/ou públicas.
Para verificar essa conexão, use a flag --kubelet-certificate-authority para fornecer ao servidor de API
um pacote de certificado raiz para usar e verificar o certificado de serviço do kubelet.
Se isso não for possível, use túneis SSH entre o servidor de API e kubelet se necessário para evitar conectar por uma rede não confiável ou pública.
Finalmente, Autenticação e/ou autorização do Kubelet deve ser habilitada para proteger a API do kubelet.
As conexões do servidor de API com um nó, pod, ou serviço são conexões HTTP simples por padrão
e, portanto, não são autenticadas nem criptografadas. Elas podem ser executadas por uma conexão HTTPS
segura prefixando https: ao nome do nó, pod, ou serviço na URL da API, mas elas não
validarão o certificado fornecido pelo endpoint HTTPS nem fornecerão credenciais de cliente. Então
enquanto a conexão será criptografada, ela não fornecerá nenhuma garantia de integridade. Essas
conexões não são atualmente seguras para executar por redes não confiáveis e/ou públicas.
O Kubernetes suporta túneis SSH para proteger os caminhos de comunicação da camada de gerenciamento para os nós. Nesta configuração, o servidor de API inicia um túnel SSH para cada nó no cluster (conectando ao servidor SSH escutando na porta 22) e passa todo o tráfego destinado a um kubelet, nó, pod, ou serviço através do túnel. Este túnel garante que o tráfego não seja exposto fora da rede na qual os nós estão executando.
Kubernetes v1.18 [beta]
Como um substituto aos túneis SSH, o serviço Konnectivity fornece proxy de nível TCP para a comunicação da camada de gerenciamento para o cluster. O serviço Konnectivity consiste em duas partes: o servidor Konnectivity na rede da camada de gerenciamento e os agentes Konnectivity na rede dos nós. Os agentes Konnectivity iniciam conexões com o servidor Konnectivity e mantêm as conexões de rede. Após habilitar o serviço Konnectivity, todo o tráfego da camada de gerenciamento para os nós passa por essas conexões.
Siga a tarefa do serviço Konnectivity para configurar o serviço Konnectivity no seu cluster.
O conceito do Cloud Controller Manager (CCM) (não confundir com o binário) foi originalmente criado para permitir que o código específico de provedor de nuvem e o núcleo do Kubernetes evoluíssem independentemente um do outro. O Cloud Controller Manager é executado junto com outros componentes principais, como o Kubernetes controller manager, o servidor de API e o scheduler. Também pode ser iniciado como um addon do Kubernetes, caso em que é executado em cima do Kubernetes.
O design do Cloud Controller Manager é baseado em um mecanismo de plug-in que permite que novos provedores de nuvem se integrem facilmente ao Kubernetes usando plug-ins. Existem planos para integrar novos provedores de nuvem no Kubernetes e para migrar provedores de nuvem que estão utilizando o modelo antigo para o novo modelo de CCM.
Este documento discute os conceitos por trás do Cloud Controller Manager e fornece detalhes sobre suas funções associadas.
Aqui está a arquitetura de um cluster Kubernetes sem o Cloud Controller Manager:

No diagrama anterior, o Kubernetes e o provedor de nuvem são integrados através de vários componentes diferentes:
O CCM consolida toda a lógica que depende da nuvem dos três componentes anteriores para criar um único ponto de integração com a nuvem. A nova arquitetura com o CCM se parece com isso:

O CCM separa algumas das funcionalidades do KCM (Kubernetes Controller Manager) e o executa como um processo separado. Especificamente, isso elimina os controladores no KCM que dependem da nuvem. O KCM tem os seguintes loops de controlador dependentes de nuvem:
Na versão 1.9, o CCM executa os seguintes controladores da lista anterior:
O plano original para suportar volumes usando o CCM era usar volumes Flex para suportar volumes plugáveis. No entanto, um esforço concorrente conhecido como CSI está sendo planejado para substituir o Flex.
Considerando essas dinâmicas, decidimos ter uma medida de intervalo intermediário até que o CSI esteja pronto.
O CCM herda suas funções de componentes do Kubernetes que são dependentes de um provedor de nuvem. Esta seção é estruturada com base nesses componentes.
A maioria das funções do CCM é derivada do KCM. Conforme mencionado na seção anterior, o CCM executa os seguintes ciclos de controle:
O Node Controller é responsável por inicializar um nó obtendo informações sobre os nós em execução no cluster do provedor de nuvem. O Node Controller executa as seguintes funções:
O Route Controller é responsável por configurar as rotas na nuvem apropriadamente, de modo que os contêineres em diferentes nodes no cluster do Kubernetes possam se comunicar entre si. O Route Controller é aplicável apenas para clusters do Google Compute Engine.
O Service controller é responsável por ouvir os eventos de criação, atualização e exclusão do serviço. Com base no estado atual dos serviços no Kubernetes, ele configura os balanceadores de carga da nuvem (como o ELB, o Google LB ou o Oracle Cloud Infrastrucutre LB) para refletir o estado dos serviços no Kubernetes. Além disso, garante que os back-ends de serviço para balanceadores de carga da nuvem estejam atualizados.
O Node Controller contém a funcionalidade dependente da nuvem do kubelet. Antes da introdução do CCM, o kubelet era responsável por inicializar um nó com detalhes específicos da nuvem, como endereços IP, rótulos de região / zona e informações de tipo de instância. A introdução do CCM mudou esta operação de inicialização do kubelet para o CCM.
Nesse novo modelo, o kubelet inicializa um nó sem informações específicas da nuvem. No entanto, ele adiciona uma marca (taint) ao nó recém-criado que torna o nó não programável até que o CCM inicialize o nó com informações específicas da nuvem. Em seguida, remove essa mancha (taint).
O Cloud Controller Manager usa interfaces Go para permitir implementações de qualquer nuvem a ser conectada. Especificamente, ele usa a Interface CloudProvider definidaaqui.
A implementação dos quatro controladores compartilhados destacados acima, e algumas estruturas que ficam junto com a interface compartilhada do provedor de nuvem, permanecerão no núcleo do Kubernetes. Implementações específicas para provedores de nuvem serão construídas fora do núcleo e implementarão interfaces definidas no núcleo.
Para obter mais informações sobre o desenvolvimento de plug-ins, consulteDesenvolvendo o Cloud Controller Manager.
Esta seção divide o acesso necessário em vários objetos da API pelo CCM para executar suas operações.
O Node Controller só funciona com objetos Node. Ele requer acesso total para obter, listar, criar, atualizar, corrigir, assistir e excluir objetos Node.
v1/Node:
O Rote Controller escuta a criação do objeto Node e configura as rotas apropriadamente. Isso requer acesso a objetos Node.
v1/Node:
O Service Controller escuta eventos de criação, atualização e exclusão de objeto de serviço e, em seguida, configura pontos de extremidade para esses serviços de forma apropriada.
Para acessar os Serviços, é necessário listar e monitorar o acesso. Para atualizar os Serviços, ele requer patch e atualização de acesso.
Para configurar endpoints para os Serviços, é necessário acesso para criar, listar, obter, assistir e atualizar.
v1/Service:
A implementação do núcleo do CCM requer acesso para criar eventos e, para garantir a operação segura, requer acesso para criar ServiceAccounts.
v1/Event:
v1/ServiceAccount:
O RBAC ClusterRole para o CCM se parece com isso:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cloud-controller-manager
rules:
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- update
- apiGroups:
- ""
resources:
- nodes
verbs:
- '*'
- apiGroups:
- ""
resources:
- nodes/status
verbs:
- patch
- apiGroups:
- ""
resources:
- services
verbs:
- list
- patch
- update
- watch
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- create
- apiGroups:
- ""
resources:
- persistentvolumes
verbs:
- get
- list
- update
- watch
- apiGroups:
- ""
resources:
- endpoints
verbs:
- create
- get
- list
- watch
- update
Os seguintes provedores de nuvem implementaram CCMs:
Você vai encontrar instruções completas para configurar e executar o CCM aqui.
Em robótica e automação um control loop, ou em português ciclo de controle, é um ciclo não terminado que regula o estado de um sistema.
Aqui está um exemplo de um ciclo de controle: um termostato em uma sala.
Quando você define a temperatura, isso indica ao termostato sobre o seu estado desejado. A temperatura ambiente real é o estado atual. O termostato atua para trazer o estado atual mais perto do estado desejado, ligando ou desligando o equipamento.
No Kubernetes, controladores são ciclos de controle que observam o estado do seu cluster, e então fazer ou requisitar mudanças onde necessário. Cada controlador tenta mover o estado atual do cluster mais perto do estado desejado.Um controlador rastreia pelo menos um tipo de recurso Kubernetes. Estes objetos têm um campo spec que representa o estado desejado. O(s) controlador(es) para aquele recurso são responsáveis por fazer o estado atual se aproximar daquele estado desejado.
O controlador pode executar a ação ele próprio; mais comumente, no Kubernetes, um controlador enviará mensagens para o servidor de API que têm efeitos colaterais úteis. Você verá exemplos disso abaixo.
O controlador Job é um exemplo de um controlador embutido do Kubernetes. Controladores embutidos gerenciam estado através da interação com o servidor de API do cluster.
Job é um recurso do Kubernetes que executa um Pod, ou talvez vários Pods, para realizar uma tarefa e depois parar.
(Uma vez agendado, objetos Pod se tornam parte do estado desejado para um kubelet).
Quando o controlador Job vê uma nova tarefa, ele garante que, em algum lugar no seu cluster, os kubelets em um conjunto de Nodes estão executando o número correto de Pods para realizar o trabalho. O controlador Job não executa nenhum Pod ou contêiner ele próprio. Em vez disso, o controlador Job informa o servidor de API para criar ou remover Pods. Outros componentes no camada de gerenciamento atuam na nova informação (existem novos Pods para serem agendados e executados), e eventualmente o trabalho é feito.
Após criar um novo Job, o estado desejado é que esse Job seja completado. O controlador Job faz com que o estado atual para esse Job esteja mais próximo do seu estado desejado: criando Pods que fazem o trabalho que você queria para esse Job, para que o Job esteja mais próximo da conclusão.
Controladores também atualizam os objetos que os configuram.
Por exemplo: uma vez que o trabalho de um Job está completo,
o controlador Job atualiza esse objeto Job para marcá-lo como Finished.
(Isso é um pouco como alguns termostatos desligam uma luz para indicar que a sala está agora na temperatura que você definiu).
Em contraste com Job, alguns controladores precisam fazer mudanças em coisas fora do seu cluster.
Por exemplo, se você usar um ciclo de controle para garantir que existem Nodes suficientes no seu cluster, então esse controlador precisa de algo fora do cluster atual para configurar novos Nodes quando necessário.
Controladores que interagem com estado externo encontram seu estado desejado a partir do servidor de API, então comunicam diretamente com um sistema externo para trazer o estado atual mais próximo da linha.
(Existe na verdade um controlador que escala horizontalmente os nodes no seu cluster.)
O ponto importante aqui é que o controlador faz algumas mudanças para trazer seu estado desejado, e então relata o estado atual de volta ao servidor de API do seu cluster. Outros ciclos de controle podem observar esses dados relatados e tomar suas próprias ações.
No exemplo do termostato, se a sala estiver muito fria, então um controlador diferente pode também ligar um aquecedor de proteção contra geada. Com clusters Kubernetes, a camada de gerenciamento indiretamente trabalha com ferramentas de gerenciamento de endereços IP, serviços de armazenamento, APIs de provedores de nuvem, e outros serviços através de estender o Kubernetes para implementar isso.
O Kubernetes tem uma visão cloud-native de sistemas, e é capaz de lidar com mudanças constantes.
Seu cluster pode estar mudando a qualquer momento conforme o trabalho acontece e ciclos de controle corrigem falhas automaticamente. Isso significa que, potencialmente, seu cluster nunca atinge um estado estável.
Enquanto os controladores do seu cluster estiverem executando e forem capazes de fazer mudanças úteis, não importa se o estado geral é estável ou não.
Como um princípio do seu design, o Kubernetes usa muitos controladores que cada um gerencia um aspecto particular do estado do cluster. Mais comumente, um ciclo de controle particular (controlador) usa um tipo de recurso como seu estado desejado, e tem um tipo diferente de recurso que ele gerencia para fazer esse estado desejado acontecer. Por exemplo, um controlador para Jobs rastreia objetos Job (para descobrir novo trabalho) e objetos Pod (para executar os Jobs, e então ver quando o trabalho termina). Neste caso algo mais cria os Jobs, enquanto o controlador Job cria Pods.
É útil ter controladores simples em vez de um conjunto monolítico de ciclos de controle que estão interligados. Controladores podem falhar, então o Kubernetes foi projetado para permitir isso.
Pode haver vários controladores que criam ou atualizam o mesmo tipo de objeto. Nos bastidores, os controladores do Kubernetes garantem que eles apenas prestam atenção aos recursos ligados ao seu recurso controlador.
Por exemplo, você pode ter Deployments e Jobs; ambos criam Pods. O controlador Job não exclui os Pods que seu Deployment criou, porque existe informação (labels) que os controladores podem usar para diferenciar esses Pods.
O Kubernetes vem com um conjunto de controladores embutidos que executam dentro do kube-controller-manager. Estes controladores embutidos fornecem comportamentos centrais importantes.
O controlador Deployment e o controlador Job são exemplos de controladores que vêm como parte do próprio Kubernetes (controladores "embutidos"). O Kubernetes permite que você execute uma camada de gerenciamento resiliente, para que se qualquer um dos controladores embutidos falhar, outra parte da camada de gerenciamento assumirá o trabalho.
Você pode encontrar controladores que executam fora da camada de gerenciamento, para estender o Kubernetes. Ou, se quiser, pode escrever um novo controlador você mesmo. Você pode executar seu próprio controlador como um conjunto de Pods, ou externamente ao Kubernetes. O que se encaixa melhor dependerá do que esse controlador particular faz.
Coleta de lixo (Garbage collection) é um termo coletivo para os vários mecanismos que o Kubernetes usa para limpar os recursos do cluster. Isso permite a limpeza de recursos como os seguintes:
Muitos objetos no Kubernetes se vinculam uns aos outros através de referências de proprietário. As referências de proprietário informam à camada de gerenciamento quais objetos são dependentes de outros. O Kubernetes usa referências de proprietário para dar à camada de gerenciamento, e outros clientes da API, a oportunidade de limpar recursos relacionados antes de excluir um objeto. Na maioria dos casos, o Kubernetes gerencia referências de proprietário automaticamente.
A propriedade é diferente do mecanismo de labels e seletores
que alguns recursos também usam. Por exemplo, considere um
Service que cria
objetos EndpointSlice. O Service usa labels para permitir que a camada de gerenciamento
determine quais objetos EndpointSlice são usados para esse Service. Além
das labels, cada EndpointSlice que é gerenciado em nome de um Service tem
uma referência de proprietário. As referências de proprietário ajudam diferentes partes do Kubernetes a evitar
interferir com objetos que elas não controlam.
Referências de proprietário entre namespaces são proibidas por design. Dependentes com namespace podem especificar proprietários com escopo de cluster ou com namespace. Um proprietário com namespace deve existir no mesmo namespace que o dependente. Se não existir, a referência de proprietário é tratada como ausente, e o dependente está sujeito à exclusão uma vez que todos os proprietários são verificados como ausentes.
Dependentes com escopo de cluster só podem especificar proprietários com escopo de cluster. Nas versões 1.20 e superiores, se um dependente com escopo de cluster especificar um tipo com namespace como proprietário, ele é tratado como tendo uma referência de proprietário não resolvível, e não pode ser coletado como lixo.
Nas versões v1.20 e superiores, se o coletor de lixo detectar uma ownerReference inválida entre namespaces,
ou um dependente com escopo de cluster com uma ownerReference referenciando um tipo com namespace, um Event de aviso
com um motivo de OwnerRefInvalidNamespace e um involvedObject do dependente inválido é reportado.
Você pode verificar esse tipo de Event executando
kubectl get events -A --field-selector=reason=OwnerRefInvalidNamespace.
O Kubernetes verifica e exclui objetos que não têm mais referências de proprietário, como os Pods deixados para trás quando você exclui um ReplicaSet. Quando você exclui um objeto, pode controlar se o Kubernetes exclui os dependentes do objeto automaticamente, em um processo chamado exclusão em cascata. Existem dois tipos de exclusão em cascata, como segue:
Você também pode controlar como e quando a coleta de lixo exclui recursos que têm referências de proprietário usando finalizadores do Kubernetes.
Na exclusão em cascata em primeiro plano, o objeto proprietário que você está excluindo primeiro entra em um estado de exclusão em progresso. Neste estado, o seguinte acontece com o objeto proprietário:
metadata.deletionTimestamp do objeto
para o momento em que o objeto foi marcado para exclusão.metadata.finalizers para
foregroundDeletion.Depois que o objeto proprietário entra no estado de exclusão em progresso, o controlador exclui dependentes que conhece. Após excluir todos os objetos dependentes que conhece, o controlador exclui o objeto proprietário. Neste ponto, o objeto não é mais visível na API do Kubernetes.
Durante a exclusão em cascata em primeiro plano, os únicos dependentes que bloqueiam a exclusão do proprietário
são aqueles que têm o campo ownerReference.blockOwnerDeletion=true
e estão no cache do controlador de coleta de lixo. O cache do controlador de coleta de lixo
pode não conter objetos cujo tipo de recurso não pode ser listado/observado com sucesso,
ou objetos que são criados simultaneamente com a exclusão de um objeto proprietário.
Veja Usar exclusão em cascata em primeiro plano
para saber mais.
Na exclusão em cascata em segundo plano, o servidor de API do Kubernetes exclui o objeto proprietário imediatamente e o controlador de coleta de lixo (personalizado ou padrão) limpa os objetos dependentes em segundo plano. Se um finalizador existir, ele garante que os objetos não sejam excluídos até que todas as tarefas de limpeza necessárias sejam concluídas. Por padrão, o Kubernetes usa exclusão em cascata em segundo plano, a menos que você use manualmente a exclusão em primeiro plano ou escolha tornar órfãos os objetos dependentes.
Veja Usar exclusão em cascata em segundo plano para saber mais.
Quando o Kubernetes exclui um objeto proprietário, os dependentes deixados para trás são chamados de objetos órfãos. Por padrão, o Kubernetes exclui objetos dependentes. Para aprender como sobrescrever este comportamento, veja Excluir objetos proprietários e tornar órfãos os dependentes.
O kubelet executa coleta de lixo em imagens não utilizadas a cada cinco minutos e em contêineres não utilizados a cada minuto. Você deve evitar usar ferramentas externas de coleta de lixo, pois estas podem quebrar o comportamento do kubelet e remover contêineres que deveriam existir.
Para configurar opções para coleta de lixo de contêineres e imagens não utilizados, ajuste o
kubelet usando um arquivo de configuração
e altere os parâmetros relacionados à coleta de lixo usando o
tipo de recurso KubeletConfiguration.
O Kubernetes gerencia o ciclo de vida de todas as imagens através do seu gerenciador de imagens, que é parte do kubelet, com a cooperação do cadvisor. O kubelet considera os seguintes limites de uso de disco ao tomar decisões de coleta de lixo:
HighThresholdPercentLowThresholdPercentO uso de disco acima do valor HighThresholdPercent configurado aciona a coleta de lixo,
que exclui imagens em ordem baseada na última vez que foram usadas,
começando com a mais antiga primeiro. O kubelet exclui imagens
até que o uso de disco atinja o valor LowThresholdPercent.
Kubernetes v1.35 [stable](habilitado por padrão)Como uma funcionalidade beta, você pode especificar o tempo máximo que uma imagem local pode ficar não utilizada, independentemente do uso de disco. Esta é uma configuração do kubelet que você configura para cada node.
Para configurar a definição, você precisa definir um valor para o campo imageMaximumGCAge
no arquivo de configuração do kubelet.
O valor é especificado como uma duração do Kubernetes. Veja duração no glossário para mais detalhes.
Por exemplo, você pode definir o campo de configuração para 12h45m,
o que significa 12 horas e 45 minutos.
imageMaximumGCAge antes de qualificar imagens para coleta de lixo
baseada na idade da imagem.O kubelet coleta lixo de contêineres não utilizados baseado nas seguintes variáveis, que você pode definir:
MinAge: a idade mínima na qual o kubelet pode coletar lixo de um
contêiner. Desabilite definindo como 0.MaxPerPodContainer: o número máximo de contêineres mortos que cada Pod
pode ter. Desabilite definindo como menor que 0.MaxContainers: o número máximo de contêineres mortos que o cluster pode ter.
Desabilite definindo como menor que 0.Além dessas variáveis, o kubelet coleta lixo de containers não identificados e excluídos, tipicamente começando com o mais antigo primeiro.
MaxPerPodContainer e MaxContainers podem potencialmente entrar em conflito um com o outro
em situações onde manter o número máximo de contêineres por Pod
(MaxPerPodContainer) iria além do total permitido de contêineres mortos globais
(MaxContainers). Nesta situação, o kubelet ajusta
MaxPerPodContainer para resolver o conflito. Um cenário de pior caso seria
rebaixar MaxPerPodContainer para 1 e despejar os containers mais antigos.
Adicionalmente, contêineres pertencentes a Pods que foram excluídos são removidos uma vez
que são mais antigos que MinAge.
Você pode ajustar a coleta de lixo de recursos configurando opções específicas para os controladores que gerenciam esses recursos. As seguintes páginas mostram como configurar coleta de lixo:
Cada contêiner executado é repetível; a padronização de ter dependências incluídas significa que você obtém o mesmo comportamento onde quer que você execute.
Os contêineres separam os aplicativos da infraestrutura de host subjacente. Isso torna a implantação mais fácil em diferentes ambientes de nuvem ou sistema operacional.
Uma imagem de contêiner é um pacote de software pronto para executar, contendo tudo que é preciso para executar uma aplicação: o código e o agente de execução necessário, aplicação, bibliotecas do sistema e valores padrões para qualquer configuração essencial.
Por design, um contêiner é imutável: você não pode mudar o código de um contêiner que já está executando. Se você tem uma aplicação conteinerizada e quer fazer mudanças, você precisa construir uma nova imagem que inclui a mudança, e recriar o contêiner para iniciar a partir da imagem atualizada.
O agente de execução (runtime) de contêiner é o software responsável por executar os contêineres.
O Kubernetes suporta diversos agentes de execução de contêineres: Docker, containerd, CRI-O, e qualquer implementação do Kubernetes CRI (Container Runtime Interface).
Uma imagem de contêiner representa dados binários que encapsulam uma aplicação e todas as suas dependências de software. As imagens de contêiner são pacotes de software executáveis que podem ser executados de forma autônoma e que fazem suposições muito bem definidas sobre seu agente de execução do ambiente.
Normalmente, você cria uma imagem de contêiner da sua aplicação e a envia para um registro antes de fazer referência a ela em um Pod.
Esta página fornece um resumo sobre o conceito de imagem de contêiner.
As imagens de contêiner geralmente recebem um nome como pause, exemplo/meuconteiner, ou kube-apiserver.
As imagens também podem incluir um hostname de algum registro; por exemplo: exemplo.registro.ficticio/nomeimagem,
e um possível número de porta; por exemplo: exemplo.registro.ficticio:10443/nomeimagem.
Se você não especificar um nome de host do registro, o Kubernetes assume que você está se referindo ao registro público do Docker. Você pode alterar esse comportamento definindo um registro de imagem padrão na configuração do agente de execução do contêiner.
Após a parte do nome da imagem, você pode adicionar uma tag ou digest (da mesma forma que faria ao usar comandos
como docker ou podman). As tags permitem identificar diferentes versões da mesma série de imagens.
Digests são identificadores únicos para uma versão específica de uma imagem. Digests são hashes do conteúdo da imagem e são imutáveis. As tags podem ser movidas para apontar para imagens diferentes, mas os digests são fixos.
Tags de imagem consistem em letras minúsculas e maiúsculas, dígitos, sublinhados (_),
pontos (.) e hifens (-). Elas podem ter até 128 caracteres de comprimento e devem seguir
o seguinte padrão de expressão regular: [a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}.
Você pode ler mais sobre e encontrar a expressão regular de validação na
Especificação de Distribuição OCI.
Se você não especificar uma tag, o Kubernetes assume que você está se referindo à tag latest.
Digests de imagem consistem em um algoritmo de hash (como sha256) e um valor de hash. Por exemplo:
sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07.
Você pode encontrar mais informações sobre o formato de digests na
Especificação de Imagem OCI.
Alguns exemplos de nomes de imagem que o Kubernetes pode usar são:
busybox - Nome da imagem apenas, sem tag ou digest. O Kubernetes usará o registro público do Docker e a tag latest. (Equivalente a docker.io/library/busybox:latest)busybox:1.32.0 - Nome da imagem com tag. O Kubernetes usará o registro público do Docker. (Equivalente a docker.io/library/busybox:1.32.0)registry.k8s.io/pause:latest - Nome da imagem com um registro personalizado e tag latest.registry.k8s.io/pause:3.5 - Nome da imagem com um registro personalizado e tag diferente de latest.registry.k8s.io/pause@sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07 - Nome da imagem com digest.registry.k8s.io/pause:3.5@sha256:1ff6c18fbef2045af6b9c16bf034cc421a29027b800e4f9b68ae9b1cb3e9ae07 - Nome da imagem com tag e digest. Apenas o digest será usado para o download.Quando você cria um Deployment,
StatefulSet, Pod ou outro
objeto que inclua um template de Pod, por padrão a política utilizada para baixar as imagens dos contêineres nesse Pod será definida como IfNotPresent quando não especificada explicitamente.
Essa política faz com que o kubelet ignore o download da imagem se ela já existir.
A imagePullPolicy de um contêiner e a tag da imagem afetam quando o
kubelet tenta puxar (download) a imagem especificada.
Aqui está uma lista dos valores que você pode definir para imagePullPolicy e os efeitos
que esses valores têm:
IfNotPresentAlwaysNeverA semântica de cache do provedor de imagens subjacente torna mesmo
imagePullPolicy: Always eficiente, desde que o registro esteja acessível de forma confiável.
Seu agente de execução de contêiner pode perceber que as camadas da imagem já existem no nó,
evitando que precisem ser baixadas novamente.
Você deve evitar o uso da tag :latest ao implantar contêineres em produção,
pois isso torna mais difícil rastrear qual versão da imagem está em execução
e também dificulta realizar um rollback corretamente.
Em vez disso, especifique uma tag significativa como v1.42.0 e/ou um digest.
Para garantir que o Pod sempre use a mesma versão de uma imagem de contêiner,
você pode especificar o digest da imagem;
substitua <image-name>:<tag> por <image-name>@<digest>
(por exemplo, image@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2).
Ao usar tags de imagem, se o registro de imagens alterar o código que a tag representa, você pode acabar com uma mistura de Pods executando o código antigo e o novo. Um digest de imagem identifica de forma única uma versão específica da imagem, então o Kubernetes executa o mesmo código sempre que inicia um contêiner com aquele nome de imagem e digest especificado. Especificar uma imagem por digest fixa o código que será executado, de modo que uma alteração no registro não leve a essa mistura de versões.
Existem controladores de admissão de terceiros que mutam Pods (e templates de Pods) quando eles são criados, de forma que a carga de trabalho em execução seja definida com base em um digest de imagem em vez de uma tag. Isso pode ser útil se você quiser garantir que toda sua carga de trabalho esteja executando o mesmo código, independentemente das mudanças de tags no registro.
Quando você (ou um controlador) envia um novo Pod para o servidor de API, seu cluster define o campo
imagePullPolicy quando certas condições são atendidas:
imagePullPolicy e especificar o digest da imagem do contêiner,
o imagePullPolicy será automaticamente definido como IfNotPresent;imagePullPolicy e a tag da imagem do contêiner for :latest,
o imagePullPolicy será automaticamente definido como Always;imagePullPolicy e não especificar uma tag para a imagem do contêiner,
o imagePullPolicy será automaticamente definido como Always;imagePullPolicy e especificar uma tag para a imagem do contêiner
que não seja :latest, o imagePullPolicy será automaticamente definido como IfNotPresent.O valor de imagePullPolicy do contêiner é sempre definido quando o objeto é criado
pela primeira vez, e não é atualizado se a tag ou o digest da imagem for alterado posteriormente.
Por exemplo, se você criar um Deployment com uma imagem cuja tag não é :latest,
e mais tarde atualizar a imagem desse Deployment para a tag :latest, o campo imagePullPolicy
NÃO será alterado para Always. Você deve alterar manualmente a política de puxar imagem de qualquer
objeto após sua criação inicial.
Se você deseja forçar sempre o download da imagem, pode fazer uma das seguintes opções:
imagePullPolicy do contêiner como Always.imagePullPolicy e use :latest como a tag da imagem a ser usada;
o Kubernetes definirá a política como Always ao enviar o Pod.imagePullPolicy e a tag da imagem a ser usada;
o Kubernetes definirá a política como Always ao enviar o Pod.Quando o kubelet começa a criar contêineres para um Pod usando um agente de execução de contêiner,
é possível que o contêiner esteja no estado Waiting devido a ImagePullBackOff.
O status ImagePullBackOff significa que um contêiner não pôde ser iniciado porque o Kubernetes
não conseguiu fazer o download da imagem do contêiner (por motivos como nome de imagem inválido
ou tentativa de download de um registro privado sem imagePullSecret).
A parte BackOff indica que o Kubernetes continuará tentando fazer o download da imagem,
com um atraso incremental entre as tentativas.
O Kubernetes aumenta o intervalo entre cada tentativa até atingir um limite definido no código, que é de 300 segundos (5 minutos).
Kubernetes v1.29 [alpha](desabilitado por padrão)Se você habilitar o feature gate RuntimeClassInImageCriApi,
o kubelet passará a referenciar imagens de contêiner por uma tupla (nome da imagem, manipulador de agente de execução)
em vez de apenas pelo nome da imagem ou digest.
Seu agente de execução do contêiner pode adaptar seu comportamento
com base no manipulador de agente de execução selecionado.
Fazer download de imagens com base na classe de agente de execução será útil para contêineres baseados em máquina virtual, como contêineres do tipo Windows Hyper-V.
Por padrão, o kubelet realiza downloads de imagens de forma sequencial. Em outras palavras, o kubelet envia apenas uma solicitação de download de imagem por vez para o serviço de imagens. Outras solicitações de download precisam aguardar até que a solicitação em andamento seja concluída.
Os Nós tomam decisões de download de imagem de forma isolada. Mesmo quando você usa downloads de imagem em série, dois Nós diferentes podem puxar a mesma imagem em paralelo.
Se você quiser habilitar downloads de imagem em paralelo, pode definir o campo
serializeImagePulls como false na configuração do kubelet.
Com serializeImagePulls definido como false, as solicitações de download de imagem serão enviadas
imediatamente para o serviço de imagens, permitindo que várias imagens sejam puxadas ao mesmo tempo.
Ao habilitar downloads de imagem em paralelo, certifique-se de que o serviço de imagens do seu agente de execução do contêiner pode lidar com esse tipo de operação.
O kubelet nunca realiza download de múltiplas imagens em paralelo para um único Pod. Por exemplo, se você tiver um Pod com um Init Container e um contêiner de aplicação, os downloads de imagem desses dois contêineres não serão paralelizados. No entanto, se você tiver dois Pods que usam imagens diferentes, o kubelet puxará as imagens em paralelo para os dois Pods diferentes, quando o download paralelo estiver habilitado.
Kubernetes v1.32 [beta]
Quando serializeImagePulls está definido como false, o kubelet, por padrão, não impõe limite
ao número máximo de imagens sendo puxadas ao mesmo tempo. Se você quiser limitar a quantidade
de downloads de imagem paralelos, pode definir o campo maxParallelImagePulls na configuração do kubelet.
Com maxParallelImagePulls definido como n, apenas n imagens podem ser puxadas simultaneamente,
e qualquer download de imagem além de n terá que aguardar até que pelo menos um download em andamento seja concluído.
Limitar o número de downloads de imagem paralelos ajuda a evitar que o processo de download consuma muita largura de banda de rede ou I/O de disco quando esta funcionalidade estiver habilitada.
Você pode definir maxParallelImagePulls para um número positivo maior ou igual a 1.
Se você definir maxParallelImagePulls como maior ou igual a 2, também deverá definir
serializeImagePulls como false.
O kubelet não iniciará se as configurações de maxParallelImagePulls forem inválidas.
Além de fornecer o binário das imagens, um registro de contêiner também pode servir um índice de imagem do contêiner. Um índice de imagem pode apontar para múltiplos manifestos da imagem para versões específicas de arquitetura de um contêiner. A ideia é que você possa ter um nome para uma imagem (por exemplo: pause, exemple/meuconteiner, kube-apiserver) e permitir que diferentes sistemas busquem o binário da imagem correta para a arquitetura de máquina que estão usando.
O próprio Kubernetes normalmente nomeia as imagens de contêiner com o sufixo -$(ARCH). Para retrocompatibilidade, gere as imagens mais antigas com sufixos. A ideia é gerar a imagem pause que tem o manifesto para todas as arquiteturas e pause-amd64 que é retrocompatível com as configurações anteriores ou arquivos YAML que podem ter codificado as imagens com sufixos.
Os registros privados podem exigir chaves para acessar as imagens deles. As credenciais podem ser fornecidas de várias maneiras:
Essas opções são explicadas com mais detalhes abaixo.
As instruções específicas para configurar as credenciais dependem do agente de execução de contêiner e do registro que você escolheu utilizar. Você deve consultar a documentação da sua solução para obter as informações mais precisas.
Para um exemplo de configuração de um registro de imagens de contêiner privado, veja a tarefa Realizar download de uma Imagem a partir de um Registro Privado. Esse exemplo utiliza um registro privado no Docker Hub.
Você pode configurar o kubelet para invocar um binário de plugin a fim de buscar dinamicamente as credenciais de registro para uma imagem de contêiner. Essa é a maneira mais robusta e versátil de obter credenciais para registros privados, mas também exige uma configuração no nível do kubelet para ser habilitada.
Veja Configurar um provedor de credenciais de imagem no kubelet para mais detalhes.
A interpretação do config.json varia entre a implementação original do Docker
e a interpretação feita pelo Kubernetes. No Docker, as chaves em auths podem especificar apenas URLs raiz,
enquanto o Kubernetes permite URLs com glob e também caminhos com correspondência por prefixo.
A única limitação é que os padrões glob (*) devem incluir o ponto (.) para cada subdomínio.
A quantidade de subdomínios correspondentes deve ser igual à quantidade de padrões glob (*.), por exemplo:
*.kubernetes.io não corresponderá a kubernetes.io, mas corresponderá a abc.kubernetes.io*.*.kubernetes.io não corresponderá a abc.kubernetes.io, mas corresponderá a abc.def.kubernetes.ioprefix.*.io corresponderá a prefix.kubernetes.io*-good.kubernetes.io corresponderá a prefix-good.kubernetes.ioIsso significa que um config.json como este é válido:
{
"auths": {
"my-registry.io/images": { "auth": "…" },
"*.my-registry.io/images": { "auth": "…" }
}
}
As operações de pull de imagem agora passarão as credenciais para o agente de execução de contêiner via CRI para cada padrão válido. Por exemplo, os seguintes nomes de imagem de contêiner corresponderiam com sucesso:
my-registry.io/imagesmy-registry.io/images/my-imagemy-registry.io/images/another-imagesub.my-registry.io/images/my-imageMas não:
a.sub.my-registry.io/images/my-imagea.b.sub.my-registry.io/images/my-imageO kubelet realiza downloads de imagem de forma sequencial para cada credencial encontrada.
Isso significa que múltiplas entradas no config.json para caminhos diferentes também são possíveis:
{
"auths": {
"my-registry.io/images": {
"auth": "…"
},
"my-registry.io/images/subpath": {
"auth": "…"
}
}
}
Se agora um contêiner especificar uma imagem my-registry.io/images/subpath/my-image
para ser baixada, o kubelet tentará fazer o download utilizando ambas as fontes de autenticação, caso uma delas falhe.
Por padrão, o kubelet tenta realizar um "pull" para cada imagem do registro especificado.
No entanto, se a propriedade imagePullPolicy do contêiner for definida como IfNotPresent ou Never,
em seguida, uma imagem local é usada (preferencial ou exclusivamente, respectivamente).
Se você quiser usar imagens pré-obtidas como um substituto para a autenticação do registro, você deve garantir que todos os nós no cluster tenham as mesmas imagens pré-obtidas.
Isso pode ser usado para pré-carregar certas imagens com o intuíto de aumentar a velocidade ou como uma alternativa para autenticação em um registro privado.
Todos os pods terão permissão de leitura a quaisquer imagens pré-obtidas.
O Kubernetes oferece suporte à especificação de chaves de registro de imagem de contêiner em um Pod.
Todos os imagePullSecrets devem estar no mesmo namespace que o Pod.
Os Secrets referenciados devem ser do tipo kubernetes.io/dockercfg ou kubernetes.io/dockerconfigjson.
Você precisa saber o nome de usuário, a senha do registro, o endereço de e-mail do cliente para autenticação no registro, além do nome do host. Execute o seguinte comando, substituindo os valores em letras maiúsculas pelos apropriados:
kubectl create secret docker-registry <name> \
--docker-server=DOCKER_REGISTRY_SERVER \
--docker-username=DOCKER_USER \
--docker-password=DOCKER_PASSWORD \
--docker-email=DOCKER_EMAIL
Se você já tem um arquivo de credenciais do Docker, em vez de usar o comando acima, você pode importar o arquivo de credenciais como um Kubernetes Secrets. Criar um segredo com base nas credenciais Docker existentes explica como configurar isso.
Isso é particularmente útil se você estiver usando vários registros privados de contêineres, como kubectl create secret docker-registry cria um Segredo que
só funciona com um único registro privado.
Agora, você pode criar Pods que referenciam esse Secret adicionando uma seção imagePullSecrets
na definição do Pod. Cada item no array imagePullSecrets pode referenciar apenas um Secret
no mesmo namespace.
Por exemplo:
cat <<EOF > pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: foo
namespace: awesomeapps
spec:
containers:
- name: foo
image: janedoe/awesomeapp:v1
imagePullSecrets:
- name: myregistrykey
EOF
cat <<EOF >> ./kustomization.yaml
resources:
- pod.yaml
EOF
Isso precisa ser feito para cada pod que está usando um registro privado.
No entanto, a configuração deste campo pode ser automatizada definindo o imagePullSecrets em um recurso de ServiceAccount.
Verifique Adicionar ImagePullSecrets a uma conta de serviço para obter instruções detalhadas.
Você pode usar isso em conjunto com um .docker / config.json por nó. As credenciais
serão mescladas.
Existem várias soluções para configurar registros privados. Aqui estão alguns casos de uso comuns e soluções sugeridas.
imagePullSecrets.Se precisar de acesso a vários registros, você pode criar um segredo para cada registro.
Em versões mais antigas do Kubernetes, o kubelet tinha uma integração direta com as credenciais de provedores de nuvem. Isso permitia buscar dinamicamente as credenciais para registros de imagens.
Havia três implementações embutidas do provedor de credenciais do kubelet: ACR (Azure Container Registry), ECR (Elastic Container Registry) e GCR (Google Container Registry).
Para mais informações sobre o mecanismo legado, consulte a documentação da versão do Kubernetes que você está utilizando. As versões do Kubernetes da v1.26 até a v1.35 não incluem mais esse mecanismo legado, portanto, você precisará:
imagePullSecrets e pelo menos um SecretEssa página descreve os recursos disponíveis para contêineres no ambiente de contêiner.
O ambiente de contêiner do Kubernetes fornece recursos importantes para contêineres:
O hostname de um contêiner é o nome do Pod em que o contêiner está executando.
Isso é disponibilizado através do comando hostname ou da função gethostname chamada na libc.
O nome do Pod e o Namespace são expostos como variáveis de ambiente através de um mecanismo chamado downward API.
Variáveis de ambiente definidas pelo usuário a partir da definição do Pod também são disponíveis para o contêiner, assim como qualquer variável de ambiente especificada estáticamente na imagem Docker.
Uma lista de todos os serviços que estão executando quando um contêiner foi criado é disponibilizada para o contêiner como variáveis de ambiente. Essas variáveis de ambiente são compatíveis com a funcionalidade docker link do Docker.
Para um serviço nomeado foo que mapeia para um contêiner nomeado bar, as seguintes variáveis são definidas:
FOO_SERVICE_HOST=<o host em que o serviço está executando>
FOO_SERVICE_PORT=<a porta em que o serviço está executando>
Serviços possuem endereço IP dedicado e são disponibilizados para o contêiner via DNS, se possuírem DNS addon habilitado.
Kubernetes v1.20 [stable]
Essa página descreve o recurso RuntimeClass e a seleção do mecanismo do agente de execução.
RuntimeClass é uma funcionalidade para selecionar as configurações do agente de execução do contêiner. A configuração do agente de execução de contêineres é usada para executar os contêineres de um Pod.
Você pode configurar um RuntimeClass diferente entre os diferentes Pods para prover um equilíbrio entre performance versus segurança. Por exemplo, se parte de sua carga de trabalho necessita de um alto nível de garantia de segurança da informação, você pode optar em executar esses Pods em um agente de execução que usa virtualização de hardware. Você então terá o benefício do isolamento extra de um agente de execução alternativo, ao custo de uma latência adicional.
Você pode ainda usar um RuntimeClass para executar diferentes Pods com o mesmo agente de execução de contêineres mas com diferentes configurações.
As configurações disponíveis através do RuntimeClass sáo dependentes da implementação do Container Runtime Interface (Container runtime interface (CRI)). Veja a documentação correspondente abaixo para a sua implementação CRI para verificar como configurar.
As configurações possuem um nome handler correspondente, referenciado pelo RuntimeClass.
Esse nome deve ser um valor DNS 1123 válido (letras, números e o carácter -).
As etapas de configuração no passo 1 devem todas estar associadas a um nome para o campo handler
que identifica a configuração. Para cada um, crie o objeto RuntimeClass correspondente.
O recurso RuntimeClass atualmente possui apenas 2 campos significativos: o nome do RuntimeClass
(metadata.name) e o agente (handler). A definição do objeto se parece conforme a seguir:
apiVersion: node.k8s.io/v1 # RuntimeClass é definido no grupo de API node.k8s.io
kind: RuntimeClass
metadata:
name: myclass # O nome que o RuntimeClass será chamado como
# RuntimeClass é um recurso global, e não possui namespace.
handler: myconfiguration # Nome da configuração CRI correspondente
O nome de um objeto RuntimeClass deve ser um nome de subdomínio DNS válido.
Uma vez que as classes de execução estão configuradas no cluster, usar elas é relativamente
simples. Especifique um runtimeClassName na especificação do Pod. Por exemplo:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
runtimeClassName: myclass
# ...
Isso irá instruir o kubelet a usar o RuntimeClass nomeado acima (myclass) para esse Pod. Se
o nome do RuntimeClass não existir, ou o CRI não puder executar a solicitação, o Pod entrará na fase
final Failed. Procure por um
evento correspondente
para uma mensagem de erro.
Se nenhum runtimeClassName for especificado, o RuntimeHandler padrão será utilizado, que é equivalente
ao comportamento quando a funcionalidade de RuntimeClass está desativada.
Para maiores detalhes de configuração dos agentes de execução CRI, veja instalação do CRI.
O CRI dockershim embutido no Kubernetes não suporta outros agentes de execução.
Agentes de execução são configurados através da configuração do containerd em
/etc/containerd/config.toml. Agentes válidos são configurados sob a seção de runtimes:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.${HANDLER_NAME}]
Veja a documentação de configuração do containerd para maiores detalhes: https://github.com/containerd/containerd/blob/main/docs/cri/config.md
Agentes de execução são configurados através da configuração do CRI-O em /etc/crio/crio.conf.
Agentes válidos são configurados na seção crio.runtime
table:
[crio.runtime.runtimes.${HANDLER_NAME}]
runtime_path = "${PATH_TO_BINARY}"
Veja a documentação de configuração do CRI-O para maiores detalhes.
Kubernetes v1.16 [beta]
Ao especificar o campo scheduling para um RuntimeClass, você pode colocar limites e
garantir que os Pods executando dentro de uma RuntimeClass sejam associados a nós que
suportem eles. Se o scheduling não estiver configurado, assume-se que esse RuntimeClass
é suportado por todos os nós.
Para garantir que os Pods sejam executados em um nó que suporte um RuntimeClass específico,
aquele conjunto de nós deve possuir uma marca/label padrão que é selecionado pelo campo
runtimeclass.scheduling.nodeSelector. O nodeSelector do RuntimeClass é combinado com o
nodeSelector do Pod em tempo de admissão, obtendo a intersecção do conjunto de nós selecionado
por cada. Se existir um conflito, o pod será rejeitado.
Se os nós suportados possuírem marcação de restrição para prevenir outros Pods com uma
classe de execução diferente de executar no nó, você pode adicionar o campo tolerations
ao objeto RuntimeClass. Assim como com o nodeSelector, o tolerations é combinado com
o campo tolerations do Pod em tempo de admissão, efetivamente pegando a intersecção do
conjunto de nós aplicáveis para cada.
Para saber mais sobre a configuração de seleção de nós e tolerâncias, veja Associando Pods a Nós.
Kubernetes v1.18 [beta]
Você pode especificar os recursos extra que estão associados à execução de um Pod. Declarar esses recursos extra permite ao cluster (incluindo o agendador/scheduler de pods) contabilizar por esses recursos quando estiver decidindo sobre Pods e recursos. Para usar a contabilização desses recursos extras, você deve estar com o feature gate PodOverhead habilitado (ele já está habilitado por padrão).
Os recursos extras utilizados são especificados no objeto RuntimeClass através do campo overhead.
Ao usar esses campos, você especifica o uso extra de recursos necessários para executar
Pods utilizando-se desse Runtimeclass e assim contabilizar esses recursos para o Kubernetes.
Essa página descreve como os contêineres gerenciados pelo kubelet podem usar a estrutura de hook de ciclo de vida do contêiner para executar código acionado por eventos durante seu ciclo de vida de gerenciamento.
Análogo a muitas estruturas de linguagem de programação que tem hooks de ciclo de vida de componentes, como angular, o Kubernetes fornece aos contêineres hooks de ciclo de vida. Os hooks permitem que os contêineres estejam cientes dos eventos em seu ciclo de vida de gerenciamento e executem código implementado em um manipulador quando o hook de ciclo de vida correspondente é executado.
Existem dois hooks que são expostos para os contêiners:
PostStart
Este hook é executado imediatamente após um contêiner ser criado. Entretanto, não há garantia que o hook será executado antes do ENTRYPOINT do contêiner. Nenhum parâmetro é passado para o manipulador.
PreStop
Esse hook é chamado imediatamente antes de um contêiner ser encerrado devido a uma solicitação de API ou um gerenciamento de evento como liveness/startup probe failure, preemption, resource contention e outros.
Uma chamada ao hook PreStop falha se o contêiner já está em um estado finalizado ou concluído e o hook deve ser concluído antes que o sinal TERM seja enviado para parar o contêiner. A contagem regressiva do período de tolerância de término do Pod começa antes que o hook PreStop seja executado, portanto, independentemente do resultado do manipulador, o contêiner será encerrado dentro do período de tolerância de encerramento do Pod. Nenhum parâmetro é passado para o manipulador.
Uma descrição mais detalhada do comportamento de término pode ser encontrada em Término de Pods.
Os contêineres podem acessar um hook implementando e registrando um manipulador para esse hook. Existem dois tipos de manipuladores de hooks que podem ser implementados para contêineres:
pre-stop.sh, dentro dos cgroups e Namespaces do contêiner.Quando um hook de gerenciamento de ciclo de vida do contêiner é chamado, o sistema de gerenciamento do Kubernetes executa o manipulador de acordo com a ação do hook, httpGet e tcpSocket são executados pelo processo kubelet e exec é executado pelo contêiner.
As chamadas do manipulador do hook são síncronas no contexto do Pod que contém o contêiner.
Isso significa que para um hook PostStart, o ENTRYPOINT do contêiner e o hook disparam de forma assíncrona.
No entanto, se o hook demorar muito para ser executado ou travar, o contêiner não consegue atingir o estado running.
Os hooks PreStop não são executados de forma assíncrona a partir do sinal para parar o contêiner, o hook precisa finalizar a sua execução antes que o sinal TERM possa ser enviado.
Se um hook PreStop travar durante a execução, a fase do Pod será Terminating e permanecerá até que o Pod seja morto após seu terminationGracePeriodSeconds expirar. Esse período de tolerância se aplica ao tempo total necessário
para o hook PreStopexecutar e para o contêiner parar normalmente.
Se por exemplo, o terminationGracePeriodSeconds é 60, e o hook leva 55 segundos para ser concluído, e o contêiner leva 10 segundos para parar normalmente após receber o sinal, então o contêiner será morto antes que possa parar
normalmente, uma vez que o terminationGracePeriodSeconds é menor que o tempo total (55 + 10) que é necessário para que essas duas coisas aconteçam.
Se um hook PostStart ou PreStop falhar, ele mata o contêiner.
Os usuários devem tornar seus hooks o mais leve possíveis. Há casos, no entanto, em que comandos de longa duração fazem sentido, como ao salvar o estado antes de parar um contêiner.
A entrega do hook é destinada a acontecer pelo menos uma vez,
o que quer dizer que um hook pode ser chamado várias vezes para qualquer evento,
como para PostStart ou PreStop.
Depende da implementação do hook lidar com isso corretamente.
Geralmente, apenas entregas únicas são feitas. Se, por exemplo, um receptor de hook HTTP estiver inativo e não puder receber tráfego, não há tentativa de reenviar. Em alguns casos raros, no entanto, pode ocorrer uma entrega dupla. Por exemplo, se um kubelet reiniciar no meio do envio de um hook, o hook pode ser reenviado depois que o kubelet voltar a funcionar.
Os logs para um manipulador de hook não são expostos em eventos de Pod.
Se um manipulador falhar por algum motivo, ele transmitirá um evento.
Para PostStart é o evento FailedPostStartHook e para PreStop é o evento
FailedPreStopHook.
Você pode ver esses eventos executando kubectl describe pod <nome_do_pod>.
Aqui está um exemplo de saída de eventos da execução deste comando:
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {default-scheduler } Normal Scheduled Successfully assigned test-1730497541-cq1d2 to gke-test-cluster-default-pool-a07e5d30-siqd
1m 1m 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Pulling pulling image "test:1.0"
1m 1m 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Created Created container with docker id 5c6a256a2567; Security:[seccomp=unconfined]
1m 1m 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Pulled Successfully pulled image "test:1.0"
1m 1m 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Started Started container with docker id 5c6a256a2567
38s 38s 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Killing Killing container with docker id 5c6a256a2567: PostStart handler: Error executing in Docker Container: 1
37s 37s 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Killing Killing container with docker id 8df9fdfd7054: PostStart handler: Error executing in Docker Container: 1
38s 37s 2 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} Warning FailedSync Error syncing pod, skipping: failed to "StartContainer" for "main" with RunContainerError: "PostStart handler: Error executing in Docker Container: 1"
1m 22s 2 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Warning FailedPostStartHook
O modelo de rede do Kubernetes é construído a partir de várias partes:
Cada pod em um cluster recebe seu próprio endereço IP exclusivo em todo o cluster.
localhost.A rede de pods (também chamada de rede do cluster) gerencia a comunicação entre pods. Ela garante que (exceto por segmentação de rede intencional):
Todos os pods podem se comunicar com todos os outros pods, estejam eles no mesmo nó ou em nós diferentes. Os pods podem se comunicar entre si diretamente, sem o uso de proxies ou tradução de endereços (NAT).
No Windows, esta regra não se aplica a pods de rede do host.
Agentes em um nó (como daemons do sistema ou kubelet) podem se comunicar com todos os pods naquele nó.
A API de Service permite que você forneça um endereço IP ou hostname estável (de longa duração) para um serviço implementado por um ou mais pods de backend, onde os pods individuais que compõem o serviço podem mudar ao longo do tempo.
O Kubernetes gerencia automaticamente objetos EndpointSlice para fornecer informações sobre os pods atualmente oferecendo suporte a um Service.
Uma implementação de proxy de serviço monitora o conjunto de objetos Service e EndpointSlice, e programa a camada de dados para rotear o tráfego de serviço para seus backends, usando APIs do sistema operacional ou provedor de nuvem para interceptar ou reescrever pacotes.
A API de Gateway (ou sua predecessora, Ingress) permite que você torne Services acessíveis a clientes que estão fora do cluster.
type: LoadBalancer
da API Service, ao usar um Provedor de Nuvem compatível.NetworkPolicy é uma API embutida do Kubernetes que permite controlar o tráfego entre pods, ou entre pods e o mundo externo.
Em sistemas de contêineres mais antigos, não havia conectividade automática entre contêineres em hosts diferentes, e por isso era frequentemente necessário criar explicitamente links entre contêineres, ou mapear portas de contêineres para portas do host para torná-los acessíveis por contêineres em outros hosts. Isso não é necessário no Kubernetes; o modelo do Kubernetes é que os pods podem ser tratados de forma muito semelhante a VMs ou hosts físicos das perspectivas de alocação de portas, nomenclatura, descoberta de serviços, balanceamento de carga, configuração de aplicações e migração.
Apenas algumas partes deste modelo são implementadas pelo próprio Kubernetes. Para as outras partes, o Kubernetes define as APIs, mas a funcionalidade correspondente é fornecida por componentes externos, alguns dos quais são opcionais:
A configuração do namespace de rede do pod é gerenciada por software de nível de sistema que implementa a Interface de Agente de Execução de Contêiner.
A própria rede de pods é gerenciada por uma implementação de rede de pods. No Linux, a maioria dos agentes de execução de contêineres usa a Interface de Rede de Contêineres (CNI) para interagir com a implementação de rede de pods, então essas implementações são frequentemente chamadas de plugins CNI.
O Kubernetes fornece uma implementação padrão de proxy de serviço, chamada kube-proxy, mas algumas implementações de rede de pods usam seu próprio proxy de serviço que é mais fortemente integrado com o restante da implementação.
NetworkPolicy geralmente também é implementado pela implementação de rede de pods. (Algumas implementações de rede de pods mais simples não implementam NetworkPolicy, ou um administrador pode optar por configurar a rede de pods sem suporte a NetworkPolicy. Nestes casos, a API ainda estará presente, mas não terá efeito.)
Existem muitas implementações de Gateway API, algumas das quais são específicas para ambientes de nuvem particulares, algumas mais focadas em ambientes "bare metal", e outras mais genéricas.
O tutorial Conectando Aplicações com Services permite que você aprenda sobre Services e rede do Kubernetes com um exemplo prático.
Conectividade do Cluster explica como configurar a rede para o seu cluster, e também fornece uma visão geral das tecnologias envolvidas.
No Kubernetes, um Service é uma forma abstrata de expor uma aplicação que está executando em um conjunto de Pods como um serviço de rede.
Um objetivo fundamental dos Services no Kubernetes é que você não precise modificar sua aplicação existente para usar um mecanismo de descoberta de serviços desconhecido. Você pode executar código em Pods, seja um código projetado para um mundo nativo em nuvem, ou uma aplicação mais antiga que você containerizou. Você usa um Service para tornar esse conjunto de Pods disponível na rede para que os clientes possam interagir com ele.
Se você usa um Deployment para executar sua aplicação, esse Deployment pode criar e destruir Pods dinamicamente. De um momento para o outro, você não sabe quantos desses Pods estão funcionando e íntegros; você pode nem mesmo saber como esses Pods íntegros são nomeados. Os Pods do Kubernetes são criados e destruídos para corresponder ao estado desejado do seu cluster. Pods são recursos efêmeros (você não deve esperar que um Pod individual seja confiável e durável).
Cada Pod obtém seu próprio endereço IP (o Kubernetes espera que os plugins de rede garantam isso). Para um determinado Deployment no seu cluster, o conjunto de Pods em execução em um momento no tempo pode ser diferente do conjunto de Pods executando essa aplicação um momento depois.
Isso leva a um problema: se algum conjunto de Pods (chame-os de "backends") fornece funcionalidade para outros Pods (chame-os de "frontends") dentro do seu cluster, como os frontends descobrem e mantêm o controle de qual endereço IP conectar, para que o frontend possa usar a parte backend da carga de trabalho?
Entram os Services.
A API Service, parte do Kubernetes, é uma abstração para ajudá-lo a expor grupos de Pods em uma rede. Cada objeto Service define um conjunto lógico de endpoints (geralmente esses endpoints são Pods) junto com uma política sobre como tornar esses pods acessíveis.
Por exemplo, considere um backend de processamento de imagens sem estado que está em execução com 3 réplicas. Essas réplicas são fungíveis—os frontends não se importam com qual backend eles usam. Embora os Pods reais que compõem o conjunto de backend possam mudar, os clientes frontend não devem precisar estar cientes disso, nem devem precisar manter o controle do conjunto de backends por conta própria.
A abstração Service permite esse desacoplamento.
O conjunto de Pods direcionado por um Service geralmente é determinado por um seletor que você define. Para aprender sobre outras maneiras de definir endpoints de Service, consulte Services sem seletores.
Se sua carga de trabalho fala HTTP, você pode optar por usar um Ingress para controlar como o tráfego web alcança essa carga de trabalho. Ingress não é um tipo de Service, mas atua como o ponto de entrada para o seu cluster. Um Ingress permite que você consolide suas regras de roteamento em um único recurso, para que você possa expor múltiplos componentes da sua carga de trabalho, executando separadamente no seu cluster, atrás de um único ponto de entrada.
O Gateway API para Kubernetes fornece capacidades extras além de Ingress e Service. Você pode adicionar Gateway ao seu cluster - é uma família de APIs de extensão, implementadas usando CustomResourceDefinitions - e então usá-las para configurar o acesso a serviços de rede que estão em execução no seu cluster.
Se você puder usar as APIs do Kubernetes para descoberta de serviços na sua aplicação, você pode consultar o servidor de API para EndpointSlices correspondentes. O Kubernetes atualiza os EndpointSlices para um Service sempre que o conjunto de Pods em um Service muda.
Para aplicações não nativas, o Kubernetes oferece maneiras de colocar uma porta de rede ou balanceador de carga entre sua aplicação e os Pods de backend.
De qualquer forma, sua carga de trabalho pode usar esses mecanismos de descoberta de Services para encontrar o destino ao qual deseja se conectar.
Um Service é um objeto
(da mesma forma que um Pod ou um ConfigMap é um objeto). Você pode criar,
visualizar ou modificar definições de Service usando a API do Kubernetes. Normalmente
você usa uma ferramenta como kubectl para fazer essas chamadas para a API.
Por exemplo, suponha que você tenha um conjunto de Pods que escutam na porta TCP 9376
e são rotulados como app.kubernetes.io/name=MyApp. Você pode definir um Service para
publicar esse ponto de entrada TCP:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app.kubernetes.io/name: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
Aplicar esse manifesto cria um novo Service chamado "my-service" com o
tipo de Service ClusterIP padrão. O Service
direciona para a porta TCP 9376 em qualquer Pod com o rótulo app.kubernetes.io/name: MyApp.
O Kubernetes atribui a este Service um endereço IP (o IP do cluster), que é usado pelo mecanismo de endereço IP virtual. Para mais detalhes sobre esse mecanismo, leia IPs Virtuais e Proxies de Service.
O controlador para esse Service verifica continuamente por Pods que correspondam ao seu seletor, e então faz quaisquer atualizações necessárias ao conjunto de EndpointSlices para o Service.
O nome de um objeto Service deve ser um nome de rótulo RFC 1035 válido.
port de entrada para uma targetPort. Por padrão e
por conveniência, a targetPort é definida com o mesmo valor do campo port.Kubernetes v1.34 [alpha](desabilitado por padrão)O feature gate RelaxedServiceNameValidation permite que nomes de objetos Service comecem com um dígito. Quando este feature gate está habilitado, os nomes de objetos Service devem ser nomes de rótulo RFC 1123 válidos.
Definições de porta em Pods têm nomes, e você pode referenciar esses nomes no
atributo targetPort de um Service. Por exemplo, podemos vincular a targetPort
do Service à porta do Pod da seguinte maneira:
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app.kubernetes.io/name: proxy
spec:
containers:
- name: nginx
image: nginx:stable
ports:
- containerPort: 80
name: http-web-svc
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app.kubernetes.io/name: proxy
ports:
- name: name-of-service-port
protocol: TCP
port: 80
targetPort: http-web-svc
Isso funciona mesmo se houver uma mistura de Pods no Service usando um único nome configurado, com o mesmo protocolo de rede disponível através de diferentes números de porta. Isso oferece muita flexibilidade para implantar e evoluir seus Services. Por exemplo, você pode alterar os números de porta que os Pods expõem na próxima versão do seu software de backend, sem quebrar os clientes.
O protocolo padrão para Services é TCP; você também pode usar qualquer outro protocolo suportado.
Como muitos Services precisam expor mais de uma porta, o Kubernetes suporta
múltiplas definições de porta para um único Service.
Cada definição de porta pode ter o mesmo protocol, ou um diferente.
Services mais comumente abstraem o acesso a Pods do Kubernetes graças ao seletor, mas quando usados com um conjunto correspondente de objetos EndpointSlices e sem um seletor, o Service pode abstrair outros tipos de backends, incluindo aqueles que são executados fora do cluster.
Por exemplo:
Em qualquer um desses cenários, você pode definir um Service sem especificar um seletor para corresponder aos Pods. Por exemplo:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
Como este Service não tem seletor, os objetos EndpointSlice correspondentes não são criados automaticamente. Você pode mapear o Service para o endereço de rede e porta onde ele está sendo executado, adicionando um objeto EndpointSlice manualmente. Por exemplo:
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: my-service-1 # por convenção, use o nome do Service
# como um prefixo para o nome do EndpointSlice
labels:
# Você deve definir o rótulo "kubernetes.io/service-name".
# Defina seu valor para corresponder ao nome do Service
kubernetes.io/service-name: my-service
addressType: IPv4
ports:
- name: http # deve corresponder ao nome da porta do service definida acima
appProtocol: http
protocol: TCP
port: 9376
endpoints:
- addresses:
- "10.4.5.6"
- addresses:
- "10.1.2.3"
Quando você cria um objeto EndpointSlice para um Service, você pode
usar qualquer nome para o EndpointSlice. Cada EndpointSlice em um namespace deve ter um
nome único. Você vincula um EndpointSlice a um Service definindo o
rótulo kubernetes.io/service-name
nesse EndpointSlice.
Os IPs de endpoint não devem ser: loopback (127.0.0.0/8 para IPv4, ::1/128 para IPv6), ou link-local (169.254.0.0/16 e 224.0.0.0/24 para IPv4, fe80::/64 para IPv6).
Os endereços IP de endpoint não podem ser os IPs de cluster de outros Services do Kubernetes, porque o kube-proxy não suporta IPs virtuais como destino.
Para um EndpointSlice que você criar por conta própria, ou no seu próprio código,
você também deve escolher um valor para usar no rótulo
endpointslice.kubernetes.io/managed-by.
Se você criar seu próprio código de controlador para gerenciar EndpointSlices, considere usar um
valor similar a "my-domain.example/name-of-controller". Se você estiver usando uma
ferramenta de terceiros, use o nome da ferramenta em letras minúsculas e altere espaços e outras
pontuações para traços (-).
Se as pessoas estiverem usando diretamente uma ferramenta como kubectl para gerenciar EndpointSlices,
use um nome que descreva esse gerenciamento manual, como "staff" ou
"cluster-admins". Você deve
evitar usar o valor reservado "controller", que identifica EndpointSlices
gerenciados pela própria camada de gerenciamento do Kubernetes.
Acessar um Service sem seletor funciona da mesma forma que se tivesse um seletor. No exemplo de um Service sem seletor, o tráfego é roteado para um dos dois endpoints definidos no manifesto EndpointSlice: uma conexão TCP para 10.1.2.3 ou 10.4.5.6, na porta 9376.
kubectl port-forward service/<service-name> forwardedPort:servicePort onde o service não tem
seletor falharão devido a essa restrição. Isso impede que o servidor de API do Kubernetes
seja usado como um proxy para endpoints aos quais o solicitante pode não estar autorizado a acessar.Um Service ExternalName é um caso especial de Service que não possui
seletores e usa nomes DNS em vez disso. Para mais informações, consulte a
seção ExternalName.
Kubernetes v1.21 [stable]
EndpointSlices são objetos que representam um subconjunto (uma fatia) dos endpoints de rede de suporte para um Service.
Seu cluster Kubernetes rastreia quantos endpoints cada EndpointSlice representa. Se houver tantos endpoints para um Service que um limite seja atingido, então o Kubernetes adiciona outro EndpointSlice vazio e armazena novas informações de endpoint lá. Por padrão, o Kubernetes cria um novo EndpointSlice assim que os EndpointSlices existentes contêm pelo menos 100 endpoints. O Kubernetes não cria o novo EndpointSlice até que um endpoint extra precise ser adicionado.
Consulte EndpointSlices para mais informações sobre esta API.
Kubernetes v1.33 [deprecated]
A API EndpointSlice é a evolução da antiga API Endpoints. A API Endpoints descontinuada tem vários problemas em relação ao EndpointSlice:
Devido a isso, é recomendado que todos os clientes usem a API EndpointSlice em vez de Endpoints.
O Kubernetes limita o número de endpoints que podem caber em um único objeto Endpoints. Quando há mais de 1000 endpoints de suporte para um Service, o Kubernetes trunca os dados no objeto Endpoints. Como um Service pode ser vinculado a mais de um EndpointSlice, o limite de 1000 endpoints de suporte afeta apenas a API Endpoints legada.
Nesse caso, o Kubernetes seleciona no máximo 1000 endpoints de backend possíveis para armazenar
no objeto Endpoints, e define uma
anotação no Endpoints:
endpoints.kubernetes.io/over-capacity: truncated.
A camada de gerenciamento também remove essa anotação se o número de Pods de backend cair abaixo de 1000.
O tráfego ainda é enviado para os backends, mas qualquer mecanismo de balanceamento de carga que dependa da API Endpoints legada envia tráfego apenas para no máximo 1000 dos endpoints de suporte disponíveis.
O mesmo limite da API significa que você não pode atualizar manualmente um Endpoints para ter mais de 1000 endpoints.
Kubernetes v1.20 [stable]
O campo appProtocol fornece uma maneira de especificar um protocolo de aplicação para
cada porta do Service. Isso é usado como uma dica para implementações oferecerem
comportamento mais rico para protocolos que elas entendem.
O valor deste campo é espelhado pelos objetos
Endpoints e EndpointSlice correspondentes.
Este campo segue a sintaxe de rótulo padrão do Kubernetes. Valores válidos são um dos seguintes:
Nomes prefixados definidos pela implementação, como mycompany.com/my-custom-protocol.
Nomes prefixados definidos pelo Kubernetes:
| Protocolo | Descrição |
|---|---|
kubernetes.io/h2c |
HTTP/2 sobre cleartext conforme descrito na RFC 7540 |
kubernetes.io/ws |
WebSocket sobre cleartext conforme descrito na RFC 6455 |
kubernetes.io/wss |
WebSocket sobre TLS conforme descrito na RFC 6455 |
Para alguns Services, você precisa expor mais de uma porta. O Kubernetes permite que você configure múltiplas definições de porta em um objeto Service. Ao usar múltiplas portas para um Service, você deve dar nomes a todas as suas portas para que estas sejam inequívocas. Por exemplo:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app.kubernetes.io/name: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
- name: https
protocol: TCP
port: 443
targetPort: 9377
Assim como os nomes do Kubernetes em geral, os nomes de portas
devem conter apenas caracteres alfanuméricos em minúsculas e -. Os nomes de portas também devem
começar e terminar com um caractere alfanumérico.
Por exemplo, os nomes 123-abc e web são válidos, mas 123_abc e -web não são.
Para algumas partes da sua aplicação (por exemplo, frontends) você pode querer expor um Service em um endereço IP externo, acessível de fora do seu cluster.
Os tipos de Service do Kubernetes permitem que você especifique que tipo de Service você deseja.
Os valores de type disponíveis e seus comportamentos são:
ClusterIPtype para um Service.
Você pode expor o Service para a internet pública usando um
Ingress ou um
Gateway.NodePortNodePort).
Para disponibilizar a porta do nó, o Kubernetes configura um endereço IP do cluster,
o mesmo que se você tivesse solicitado um Service do type: ClusterIP.LoadBalancerExternalNameexternalName (por exemplo,
para o nome de host api.foo.bar.example). O mapeamento configura o servidor
DNS do seu cluster para retornar um registro CNAME com esse valor de nome de host externo.
Nenhum tipo de proxy é configurado.O campo type na API Service é projetado como funcionalidade aninhada - cada nível
adiciona ao anterior. No entanto, há uma exceção a este design aninhado. Você pode
definir um Service LoadBalancer
desabilitando a alocação de NodePort do balanceador de carga.
type: ClusterIPEste tipo de Service padrão atribui um endereço IP de um pool de endereços IP que seu cluster reservou para esse propósito.
Vários dos outros tipos de Service são construídos sobre o tipo ClusterIP como
fundação.
Se você definir um Service que tenha o .spec.clusterIP definido como "None", então
o Kubernetes não atribui um endereço IP. Consulte headless Services
para mais informações.
Você pode especificar seu próprio endereço IP do cluster como parte de uma requisição de
criação de Service. Para fazer isso, defina o campo .spec.clusterIP. Por exemplo, se você
já tem uma entrada DNS existente que deseja reutilizar, ou sistemas legados
que estão configurados para um endereço IP específico e difíceis de reconfigurar.
O endereço IP que você escolher deve ser um endereço IPv4 ou IPv6 válido dentro do
intervalo CIDR service-cluster-ip-range que está configurado para o servidor de API.
Se você tentar criar um Service com um valor de clusterIP inválido, o servidor de API
retornará um código de status HTTP 422 para indicar que há um problema.
Leia evitando conflitos para aprender como o Kubernetes ajuda a reduzir o risco e o impacto de dois Services diferentes tentando usar o mesmo endereço IP.
type: NodePortSe você definir o campo type como NodePort, a camada de gerenciamento do Kubernetes
aloca uma porta de um intervalo especificado pela flag --service-node-port-range (padrão: 30000-32767).
Cada nó faz proxy dessa porta (o mesmo número de porta em cada Node) para o seu Service.
Seu Service reporta a porta alocada no campo .spec.ports[*].nodePort.
Usar um NodePort lhe dá a liberdade de configurar sua própria solução de balanceamento de carga, configurar ambientes que não são totalmente suportados pelo Kubernetes, ou até mesmo expor diretamente os endereços IP de um ou mais nós.
Para um Service do tipo node port, o Kubernetes aloca adicionalmente uma porta (TCP, UDP ou
SCTP para corresponder ao protocolo do Service). Cada nó no cluster se configura
para escutar nessa porta atribuída e encaminhar o tráfego para um dos endpoints prontos
associados a esse Service. Você poderá contatar o Service type: NodePort
de fora do cluster, conectando-se a qualquer nó usando o protocolo apropriado
(por exemplo: TCP), e a porta apropriada (conforme atribuída a esse Service).
Se você deseja um número de porta específico, pode especificar um valor no campo nodePort.
A camada de gerenciamento alocará essa porta para você ou reportará que
a transação da API falhou.
Isso significa que você precisa cuidar de possíveis conflitos de porta por conta própria.
Você também precisa usar um número de porta válido, que esteja dentro do intervalo configurado
para uso de NodePort.
Aqui está um exemplo de manifesto para um Service do type: NodePort que especifica
um valor NodePort (30007, neste exemplo):
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
app.kubernetes.io/name: MyApp
ports:
- port: 80
# Por padrão e por conveniência, a `targetPort` é definida com
# o mesmo valor do campo `port`.
targetPort: 80
# Campo opcional
# Por padrão e por conveniência, a camada de gerenciamento do Kubernetes
# alocará uma porta de um intervalo (padrão: 30000-32767)
nodePort: 30007
A política para atribuir portas a services NodePort se aplica tanto aos cenários de atribuição automática quanto de atribuição manual. Quando um usuário deseja criar um service NodePort que usa uma porta específica, a porta de destino pode entrar em conflito com outra porta que já foi atribuída.
Para evitar este problema, o intervalo de portas para services NodePort é dividido em duas faixas. A atribuição dinâmica de portas usa a faixa superior por padrão, e pode usar a faixa inferior uma vez que a faixa superior tenha sido esgotada. Os usuários podem então alocar da faixa inferior com menor risco de conflito de porta.
type: NodePortVocê pode configurar nós no seu cluster para usar um endereço IP específico para servir services de node port. Você pode querer fazer isso se cada nó estiver conectado a múltiplas redes (por exemplo: uma rede para tráfego de aplicação, e outra rede para tráfego entre nós e a camada de gerenciamento).
Se você deseja especificar endereço(s) IP particular(es) para fazer proxy da porta, você pode definir a
flag --nodeport-addresses para o kube-proxy ou o campo equivalente nodePortAddresses
do arquivo de configuração do kube-proxy
para bloco(s) de IP particular(es).
Esta flag recebe uma lista delimitada por vírgulas de blocos de IP (por exemplo, 10.0.0.0/8, 192.0.2.0/25)
para especificar intervalos de endereços IP que o kube-proxy deve considerar como locais para este nó.
Por exemplo, se você iniciar o kube-proxy com a flag --nodeport-addresses=127.0.0.0/8,
o kube-proxy seleciona apenas a interface de loopback para Services NodePort.
O padrão para --nodeport-addresses é uma lista vazia.
Isso significa que o kube-proxy deve considerar todas as interfaces de rede disponíveis para NodePort.
(Isso também é compatível com versões anteriores do Kubernetes.)
<NodeIP>:spec.ports[*].nodePort e .spec.clusterIP:spec.ports[*].port.
Se a flag --nodeport-addresses para o kube-proxy ou o campo equivalente
no arquivo de configuração do kube-proxy estiver definida, <NodeIP> seria um
endereço IP de nó filtrado (ou possivelmente endereços IP).type: LoadBalancerEm provedores de nuvem que suportam balanceadores de carga externos, definir o campo type
como LoadBalancer provisiona um balanceador de carga para o seu Service.
A criação real do balanceador de carga acontece de forma assíncrona, e
informações sobre o balanceador provisionado são publicadas no campo
.status.loadBalancer do Service.
Por exemplo:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app.kubernetes.io/name: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
clusterIP: 10.0.171.239
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 192.0.2.127
O tráfego do balanceador de carga externo é direcionado aos Pods de backend. O provedor de nuvem decide como é feito o balanceamento de carga.
Para implementar um Service do type: LoadBalancer, o Kubernetes normalmente começa
fazendo as alterações que são equivalentes a você solicitar um Service com
type: NodePort. O componente cloud-controller-manager então configura o balanceador de
carga externo para encaminhar o tráfego para essa porta de nó atribuída.
Você pode configurar um Service com balanceamento de carga para omitir a atribuição de uma porta de nó, desde que a implementação do provedor de nuvem suporte isso.
Alguns provedores de nuvem permitem que você especifique o loadBalancerIP. Nesses casos, o balanceador de carga é criado
com o loadBalancerIP especificado pelo usuário. Se o campo loadBalancerIP não for especificado,
o balanceador de carga é configurado com um endereço IP efêmero. Se você especificar um loadBalancerIP
mas seu provedor de nuvem não suportar a funcionalidade, o campo loadbalancerIP que você
definiu é ignorado.
O campo .spec.loadBalancerIP para um Service foi descontinuado no Kubernetes v1.24.
Este campo foi subespecificado e seu significado varia entre as implementações. Ele também não pode suportar rede dual-stack. Este campo pode ser removido em uma versão futura da API.
Se você está integrando com um provedor que suporta especificar o(s) endereço(s) IP do balanceador de carga para um Service via uma anotação (específica do provedor), você deve mudar para fazer isso.
Se você está escrevendo código para uma integração de balanceador de carga com o Kubernetes, evite usar este campo. Você pode integrar com Gateway em vez de Service, ou pode definir suas próprias anotações (específicas do provedor) no Service que especificam o detalhe equivalente.
As verificações de integridade do balanceador de carga são críticas para aplicações modernas. Elas são usadas para
determinar para qual servidor (máquina virtual ou endereço IP) o balanceador de carga deve
despachar o tráfego. As APIs do Kubernetes não definem como as verificações de integridade devem ser
implementadas para balanceadores de carga gerenciados pelo Kubernetes, em vez disso, são os provedores de nuvem
(e as pessoas implementando código de integração) que decidem sobre o comportamento. As
verificações de integridade do balanceador de carga são extensivamente usadas no contexto de suportar o
campo externalTrafficPolicy para Services.
Kubernetes v1.26 [stable](habilitado por padrão)Por padrão, para Services do tipo LoadBalancer, quando há mais de uma porta definida, todas as portas devem ter o mesmo protocolo, e o protocolo deve ser um que seja suportado pelo provedor de nuvem.
O feature gate MixedProtocolLBService (habilitado por padrão para o kube-apiserver a partir da v1.24) permite o uso de
protocolos diferentes para Services do tipo LoadBalancer, quando há mais de uma porta definida.
Kubernetes v1.24 [stable]
Você pode opcionalmente desabilitar a alocação de node port para um Service do type: LoadBalancer, definindo
o campo spec.allocateLoadBalancerNodePorts como false. Isso deve ser usado apenas para implementações de balanceador de carga
que roteiam tráfego diretamente para Pods em vez de usar node ports. Por padrão, spec.allocateLoadBalancerNodePorts
é true e Services do tipo LoadBalancer continuarão a alocar node ports. Se spec.allocateLoadBalancerNodePorts
for definido como false em um Service existente com node ports alocados, esses node ports não serão desalocados automaticamente.
Você deve remover explicitamente a entrada nodePorts em cada porta do Service para desalocar esses node ports.
Kubernetes v1.24 [stable]
Para um Service com type definido como LoadBalancer, o campo .spec.loadBalancerClass
permite que você use uma implementação de balanceador de carga diferente do padrão do provedor de nuvem.
Por padrão, .spec.loadBalancerClass não está definido e um Service do
tipo LoadBalancer usa a implementação de balanceador de carga padrão do provedor de nuvem se o
cluster estiver configurado com um provedor de nuvem usando a flag de componente
--cloud-provider.
Se você especificar .spec.loadBalancerClass, presume-se que uma implementação de balanceador de carga
que corresponda à classe especificada esteja observando os Services.
Qualquer implementação de balanceador de carga padrão (por exemplo, a fornecida pelo
provedor de nuvem) ignorará Services que tenham este campo definido.
spec.loadBalancerClass pode ser definido apenas em um Service do tipo LoadBalancer.
Uma vez definido, não pode ser alterado.
O valor de spec.loadBalancerClass deve ser um identificador no estilo de rótulo,
com um prefixo opcional como "internal-vip" ou "example.com/internal-vip".
Nomes sem prefixo são reservados para usuários finais.
Kubernetes v1.32 [stable](habilitado por padrão)Para um Service do type: LoadBalancer, um controlador pode definir .status.loadBalancer.ingress.ipMode.
O .status.loadBalancer.ingress.ipMode especifica como o IP do balanceador de carga se comporta.
Ele pode ser especificado apenas quando o campo .status.loadBalancer.ingress.ip também estiver especificado.
Existem dois valores possíveis para .status.loadBalancer.ingress.ipMode: "VIP" e "Proxy".
O valor padrão é "VIP", significando que o tráfego é entregue ao nó
com o destino definido para o IP e porta do balanceador de carga.
Existem dois casos ao definir isso como "Proxy", dependendo de como o balanceador de carga
do provedor de nuvem entrega o tráfego:
Implementações de Service podem usar esta informação para ajustar o roteamento de tráfego.
Em um ambiente misto, às vezes é necessário rotear o tráfego de Services dentro do mesmo bloco de endereço de rede (virtual).
Em um ambiente DNS split-horizon, você precisaria de dois Services para poder rotear tanto o tráfego externo quanto o interno para seus endpoints.
Para definir um balanceador de carga interno, adicione uma das seguintes anotações ao seu Service dependendo do provedor de serviço de nuvem que você está usando:
Select one of the tabs.
metadata:
name: my-service
annotations:
networking.gke.io/load-balancer-type: "Internal"
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-scheme: "internal"
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/azure-load-balancer-internal: "true"
metadata:
name: my-service
annotations:
service.kubernetes.io/ibm-load-balancer-cloud-provider-ip-type: "private"
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/openstack-internal-load-balancer: "true"
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/cce-load-balancer-internal-vpc: "true"
metadata:
annotations:
service.kubernetes.io/qcloud-loadbalancer-internal-subnetid: subnet-xxxxx
metadata:
annotations:
service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type: "intranet"
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/oci-load-balancer-internal: true
type: ExternalNameServices do tipo ExternalName mapeiam um Service para um nome DNS, não para um seletor típico como
my-service ou cassandra. Você especifica esses Services com o parâmetro spec.externalName.
Esta definição de Service, por exemplo, mapeia
o Service my-service no namespace prod para my.database.example.com:
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
Um Service do type: ExternalName aceita uma string de endereço IPv4,
mas trata essa string como um nome DNS composto por dígitos,
não como um endereço IP (a internet, no entanto, não permite tais nomes em DNS).
Services com nomes externos que se assemelham a endereços IPv4
não são resolvidos por servidores DNS.
Se você deseja mapear um Service diretamente para um endereço IP específico, considere usar headless Services.
Ao procurar o host my-service.prod.svc.cluster.local, o Service DNS do cluster
retorna um registro CNAME com o valor my.database.example.com. Acessar
my-service funciona da mesma forma que outros Services, mas com a
diferença crucial de que o redirecionamento acontece no nível DNS em vez de via proxy ou
encaminhamento. Se você decidir posteriormente mover seu banco de dados para dentro do seu cluster, você
pode iniciar seus Pods, adicionar seletores ou endpoints apropriados, e alterar o
type do Service.
Você pode ter problemas ao usar ExternalName para alguns protocolos comuns, incluindo HTTP e HTTPS. Se você usar ExternalName, então o nome do host usado pelos clientes dentro do seu cluster é diferente do nome que o ExternalName referencia.
Para protocolos que usam nomes de host, essa diferença pode levar a erros ou respostas inesperadas.
Requisições HTTP terão um cabeçalho Host: que o servidor de origem não reconhece;
servidores TLS não serão capazes de fornecer um certificado correspondente ao nome do host ao qual o cliente se conectou.
Às vezes você não precisa de balanceamento de carga e um único IP de Service. Neste
caso, você pode criar o que são chamados de headless Services, especificando explicitamente
"None" para o endereço IP do cluster (.spec.clusterIP).
Você pode usar um headless Service para fazer interface com outros mecanismos de descoberta de serviços, sem estar vinculado à implementação do Kubernetes.
Para headless Services, um IP de cluster não é alocado, o kube-proxy não manipula esses Services, e não há balanceamento de carga ou proxy feito pela plataforma para eles.
Um headless Service permite que um cliente se conecte a qualquer Pod que preferir, diretamente. Headless Services não
configuram rotas e encaminhamento de pacotes usando
endereços IP virtuais e proxies; em vez disso, Headless Services reportam os
endereços IP de endpoint dos Pods individuais via registros DNS internos, servidos através do
serviço DNS do cluster.
Para definir um headless Service, você cria um Service com .spec.type definido como ClusterIP (que também é o padrão para type),
e você adicionalmente define .spec.clusterIP como None.
O valor de string None é um caso especial e não é o mesmo que deixar o campo .spec.clusterIP não definido.
Como o DNS é configurado automaticamente depende se o Service tem seletores definidos:
Para headless Services que definem seletores, o controlador de endpoints cria EndpointSlices na API do Kubernetes, e modifica a configuração DNS para retornar registros A ou AAAA (endereços IPv4 ou IPv6) que apontam diretamente para os Pods que sustentam o Service.
Para headless Services que não definem seletores, a camada de gerenciamento não cria objetos EndpointSlice. No entanto, o sistema DNS procura e configura um dos seguintes:
type: ExternalName.ExternalName.
Quando você define um headless Service sem seletor, a port deve
corresponder à targetPort.
Para clientes em execução dentro do seu cluster, o Kubernetes suporta dois modos principais de encontrar um Service: variáveis de ambiente e DNS.
Quando um Pod é executado em um Node, o kubelet adiciona um conjunto de variáveis de ambiente
para cada Service ativo. Ele adiciona as variáveis {SVCNAME}_SERVICE_HOST e {SVCNAME}_SERVICE_PORT,
onde o nome do Service está em maiúsculas e os traços são convertidos em sublinhados.
Por exemplo, o Service redis-primary que expõe a porta TCP 6379 e recebeu
o endereço IP de cluster 10.0.0.11, produz as seguintes variáveis de
ambiente:
REDIS_PRIMARY_SERVICE_HOST=10.0.0.11
REDIS_PRIMARY_SERVICE_PORT=6379
REDIS_PRIMARY_PORT=tcp://10.0.0.11:6379
REDIS_PRIMARY_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_PRIMARY_PORT_6379_TCP_PROTO=tcp
REDIS_PRIMARY_PORT_6379_TCP_PORT=6379
REDIS_PRIMARY_PORT_6379_TCP_ADDR=10.0.0.11
Quando você tem um Pod que precisa acessar um Service, e você está usando o método de variável de ambiente para publicar a porta e o IP do cluster para os Pods clientes, você deve criar o Service antes dos Pods clientes existirem. Caso contrário, esses Pods clientes não terão suas variáveis de ambiente preenchidas.
Se você usar apenas DNS para descobrir o IP do cluster para um Service, você não precisa se preocupar com esse problema de ordenação.
O Kubernetes também suporta e fornece variáveis que são compatíveis com a funcionalidade
"legacy container links" do Docker
Engine. Você pode ler makeLinkVariables
para ver como isso é implementado no Kubernetes.
Você pode (e quase sempre deveria) configurar um serviço DNS para o seu cluster Kubernetes usando um complemento.
Um servidor DNS com reconhecimento de cluster, como o CoreDNS, observa a API do Kubernetes em busca de novos Services e cria um conjunto de registros DNS para cada um. Se o DNS foi habilitado em todo o seu cluster, então todos os Pods devem ser capazes automaticamente de resolver Services por seu nome DNS.
Por exemplo, se você tem um Service chamado my-service em um
namespace my-ns do Kubernetes, a camada de gerenciamento e o Service DNS atuando juntos
criam um registro DNS para my-service.my-ns. Os Pods no namespace my-ns
devem ser capazes de encontrar o service fazendo uma busca de nome por my-service
(my-service.my-ns também funcionaria).
Pods em outros namespaces devem qualificar o nome como my-service.my-ns. Esses nomes
resolverão para o IP do cluster atribuído ao Service.
O Kubernetes também suporta registros DNS SRV (Service) para portas nomeadas. Se o
Service my-service.my-ns tiver uma porta chamada http com o protocolo definido como
TCP, você pode fazer uma consulta DNS SRV para _http._tcp.my-service.my-ns para descobrir
o número da porta para http, bem como o endereço IP.
O servidor DNS do Kubernetes é a única maneira de acessar Services ExternalName.
Você pode encontrar mais informações sobre resolução ExternalName em
DNS para Services e Pods.
Leia IPs Virtuais e Proxies de Service que explica o mecanismo que o Kubernetes fornece para expor um Service com um endereço IP virtual.
Você pode definir os campos .spec.internalTrafficPolicy e .spec.externalTrafficPolicy
para controlar como o Kubernetes roteia o tráfego para backends íntegros ("prontos").
Consulte Políticas de Tráfego para mais detalhes.
Kubernetes v1.33 [stable](habilitado por padrão)O campo .spec.trafficDistribution fornece outra maneira de influenciar o
roteamento de tráfego dentro de um Service do Kubernetes. Enquanto as políticas de tráfego focam em garantias
semânticas estritas, a distribuição de tráfego permite que você expresse preferências
(como rotear para endpoints topologicamente mais próximos). Isso pode ajudar a otimizar
desempenho, custo ou confiabilidade. No Kubernetes 1.35, o
seguinte valor de campo é suportado:
PreferCloseKubernetes v1.35 [stable](habilitado por padrão)No Kubernetes 1.35, dois valores adicionais estão
disponíveis (a menos que o feature gate
PreferSameTrafficDistribution esteja
desabilitado):
PreferSameZonePreferClose que é mais claro sobre a semântica pretendida.PreferSameNodeSe o campo não for definido, a implementação aplicará sua estratégia de roteamento padrão.
Consulte Distribuição de Tráfego para mais detalhes.
Se você quiser garantir que as conexões de um cliente específico sejam passadas para o mesmo Pod a cada vez, você pode configurar afinidade de sessão baseada no endereço IP do cliente. Leia afinidade de sessão para saber mais.
Se houver IPs externos que roteiam para um ou mais nós do cluster, os Services do Kubernetes
podem ser expostos nesses externalIPs. Quando o tráfego de rede chega ao cluster, com
o IP externo (como IP de destino) e a porta correspondente a esse Service, regras e rotas
que o Kubernetes configurou garantem que o tráfego seja roteado para um dos endpoints
desse Service.
Quando você define um Service, você pode especificar externalIPs para qualquer
tipo de Service.
No exemplo abaixo, o Service chamado "my-service" pode ser acessado por clientes usando TCP,
em "198.51.100.32:80" (calculado a partir de .spec.externalIPs[] e .spec.ports[].port).
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app.kubernetes.io/name: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 49152
externalIPs:
- 198.51.100.32
externalIPs; estes são de responsabilidade
do administrador do cluster.Service é um recurso de nível superior na API REST do Kubernetes. Você pode encontrar mais detalhes sobre o objeto da API Service.
Saiba mais sobre Services e como eles se encaixam no Kubernetes:
Para mais contexto, leia o seguinte:
Kubernetes v1.19 [stable]
Um objeto da API (do inglês "Application Programming Interface") que gerencia o acesso externo aos serviços em um cluster, normalmente HTTP.
Um Ingress pode fornecer balanceamento de carga, terminação SSL e hospedagem virtual baseada em nomes.
Para fins de clareza, este guia define os seguintes termos:
O Ingress expõe rotas HTTP e HTTPS de fora do cluster para um serviço dentro do cluster. O roteamento do tráfego é controlado por regras definidas no recurso Ingress.
Aqui está um exemplo simples em que o Ingress envia todo o seu tráfego para um serviço:
Figura. Ingress
Um Ingress pode ser configurado para fornecer URLs acessíveis externamente aos serviços, balanceamento de carga de tráfego, terminação SSL/TLS e oferecer hospedagem virtual baseada em nome. Um controlador Ingress é responsável por atender o Ingress, geralmente com um balanceador de carga, embora também possa configurar seu roteador de borda ou frontends adicionais para ajudar a lidar com o tráfego.
Um Ingress não expõe portas ou protocolos arbitrários. Normalmente se usa um serviço do tipo Service.Type=NodePort ou Service.Type=LoadBalancer para expor serviços à Internet que não sejam HTTP e HTTPS.
Você deve ter um controlador Ingress para satisfazer um Ingress. Apenas a criação de um recurso Ingress não tem efeito.
Você pode precisar instalar um controlador Ingress. Você pode escolher entre vários controladores Ingress.
Idealmente, todos os controladores Ingress devem se encaixar na especificação de referência. Na realidade, os vários controladores Ingress operam de forma ligeiramente diferente.
Um exemplo mínimo do recurso Ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
spec:
ingressClassName: nginx-example
rules:
- http:
paths:
- path: /testpath
pathType: Prefix
backend:
service:
name: test
port:
number: 80
Um Ingress precisa dos campos apiVersion, kind, metadata e spec.
O nome de um objeto Ingress deve ser um nome de subdomínio DNS válido.
Para obter informações gerais sobre como trabalhar com arquivos de configuração, consulte como instalar aplicações, como configurar contêineres e como gerenciar recursos.
O Ingress frequentemente usa anotações para configurar opções dependendo do controlador Ingress.
Diferentes controladores Ingress suportam diferentes anotações.
Revise a documentação do seu controlador Ingress escolhido para saber quais anotações são suportadas.
A especificação Ingress tem todas as informações necessárias para configurar um balanceador de carga ou servidor proxy. Mais importante ainda, ele contém uma lista de regras correspondentes a todas as solicitações recebidas. O recurso Ingress suporta apenas regras para direcionar o tráfego HTTP(S).
Se o ingressClassName for omitido, uma classe Ingress padrão deve ser definida.
Existem alguns controladores Ingress que funcionam sem a definição de uma IngressClass padrão.
Recomenda-se especificar a IngressClass padrão, conforme mostrado abaixo.
Cada regra HTTP contém as seguintes informações:
/testpath), cada um com um backend associado definido com um service.name e um service.port.name ou service.port.number.
Tanto o host quanto o caminho devem corresponder ao conteúdo de uma solicitação recebida antes que o balanceador de carga direcione o tráfego para o serviço referenciado.Um defaultBackend geralmente é configurado em um controlador Ingress para atender a quaisquer solicitações que não correspondam a um caminho na especificação.
Um Ingress sem regras envia todo o tráfego para um único backend padrão e .spec.defaultBackend é o backend que deve lidar com as solicitações nesse caso.
O defaultBackend é convencionalmente uma opção de configuração do controlador Ingress e não é especificado em seus recursos Ingress.
Se nenhum .spec.rules for especificado, o .spec.defaultBackend deve ser especificado.
Se o defaultBackend não for definido, o tratamento de solicitações que não correspondem a nenhuma das regras ficará a cargo do controlador de Ingress (consulte a documentação do seu controlador de Ingress para descobrir como ele lida com esse caso).
Se nenhum dos hosts ou caminhos corresponder à solicitação HTTP nos objetos Ingress, o tráfego será roteado para o seu backend padrão.
Um Resource backend é um ObjectRef para outro recurso Kubernetes dentro do mesmo namespace que o objeto Ingress.
Um Resource é uma configuração mutuamente exclusiva com o serviço, e a validação irá falhar se ambos forem especificados.
Um uso comum para um Resource backend é inserir dados em um backend de armazenamento de objetos com ativos estáticos.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-resource-backend
spec:
defaultBackend:
resource:
apiGroup: k8s.example.com
kind: StorageBucket
name: static-assets
rules:
- http:
paths:
- path: /icons
pathType: ImplementationSpecific
backend:
resource:
apiGroup: k8s.example.com
kind: StorageBucket
name: icon-assets
Depois de criar o Ingress acima, você pode visualizá-lo com o seguinte comando:
kubectl describe ingress ingress-resource-backend
Name: ingress-resource-backend
Namespace: default
Address:
Default backend: APIGroup: k8s.example.com, Kind: StorageBucket, Name: static-assets
Rules:
Host Path Backends
---- ---- --------
*
/icons APIGroup: k8s.example.com, Kind: StorageBucket, Name: icon-assets
Annotations: <none>
Events: <none>
Cada caminho no Ingress deve ter um tipo de caminho correspondente.
Os caminhos que não incluem um pathType explícito falharão na validação.
Existem três tipos de caminho suportados:
ImplementationSpecific: Com esse tipo de caminho, a correspondência depende da IngressClass. As implementações podem tratar isso como um pathType separado ou tratá-lo de forma idêntica aos tipos de caminho Prefix ou Exact.Exact: Corresponde exatamente ao caminho da URL podendo ser case-sensitive.Prefix: Corresponde com base em um prefixo de caminho de URL dividido por /. A correspondência faz distinção entre maiúsculas e minúsculas e é feita em um caminho, elemento por elemento. Um elemento de caminho refere-se à lista de labels no caminho dividido pelo separador /. Uma solicitação é uma correspondência para o caminho p se cada p for um prefixo elementar de p do caminho da solicitação./foo/bar corresponde a /foo/bar/baz, mas não corresponde a /foo/barbaz).| Tipos | Caminho(s) | Caminho(s) de solicitação | Correspondências? |
|---|---|---|---|
| Prefix | / |
(todos os caminhos) | Sim |
| Exact | /foo |
/foo |
Sim |
| Exact | /foo |
/bar |
Não |
| Exact | /foo |
/foo/ |
Não |
| Exact | /foo/ |
/foo |
Não |
| Prefix | /foo |
/foo, /foo/ |
Sim |
| Prefix | /foo/ |
/foo, /foo/ |
Sim |
| Prefix | /aaa/bb |
/aaa/bbb |
Não |
| Prefix | /aaa/bbb |
/aaa/bbb |
Sim |
| Prefix | /aaa/bbb/ |
/aaa/bbb |
Sim, ignora a barra final |
| Prefix | /aaa/bbb |
/aaa/bbb/ |
Sim, combina com a barra final |
| Prefix | /aaa/bbb |
/aaa/bbb/ccc |
Sim, corresponde ao subcaminho |
| Prefix | /aaa/bbb |
/aaa/bbbxyz |
Não, não corresponde ao prefixo da string |
| Prefix | /, /aaa |
/aaa/ccc |
Sim, corresponde ao prefixo /aaa |
| Prefix | /, /aaa, /aaa/bbb |
/aaa/bbb |
Sim, corresponde ao prefixo /aaa/bbb |
| Prefix | /, /aaa, /aaa/bbb |
/ccc |
Sim, corresponde ao prefixo / |
| Prefix | /aaa |
/ccc |
Não, usa o backend padrão |
| Mixed | /foo (Prefix), /foo (Exact) |
/foo |
Sim, prefere o exact |
Em alguns casos, vários caminhos dentro de uma entrada corresponderão a uma solicitação. Nesses casos, a precedência será dada primeiro ao caminho correspondente mais longo. Se dois caminhos ainda estiverem iguais, a precedência será dada aos caminhos com um tipo de caminho exato sobre o tipo de caminho de prefixo.
Os hosts podem ter correspondências precisas (por exemplo, “foo.bar.com”) ou um curinga (por exemplo, “*.foo.com”).
Correspondências precisas exigem que o cabeçalho do host HTTP corresponda ao campo host.
As correspondências curinga exigem que o cabeçalho do host HTTP seja igual ao sufixo da regra curinga.
| Host | Host header | Corresponde? |
|---|---|---|
*.foo.com |
bar.foo.com |
Correspondências baseadas no sufixo compartilhado |
*.foo.com |
baz.bar.foo.com |
Sem correspondência, o curinga cobre apenas um único rótulo DNS |
*.foo.com |
foo.com |
Sem correspondência, o curinga cobre apenas um único rótulo DNS |
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-wildcard-host
spec:
rules:
- host: "foo.bar.com"
http:
paths:
- pathType: Prefix
path: "/bar"
backend:
service:
name: service1
port:
number: 80
- host: "*.foo.com"
http:
paths:
- pathType: Prefix
path: "/foo"
backend:
service:
name: service2
port:
number: 80
Os Ingress podem ser implementados por diferentes controladores, muitas vezes com diferentes configurações. Cada Ingress deve especificar uma classe, uma referência a um recurso IngressClass que contém uma configuração adicional, incluindo o nome do controlador que deve implementar a classe.
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: external-lb
spec:
controller: example.com/ingress-controller
parameters:
apiGroup: k8s.example.com
kind: IngressParameters
name: external-lb
O campo .spec.parameters de uma classe Ingress permite que você faça referência a outro recurso que fornece a configuração relacionada a essa classe Ingress.
O tipo específico de parâmetros a serem usados depende do controlador Ingress que você especificar no campo .spec.controller da classe Ingress.
Dependendo do seu controlador Ingress, os parâmetros definidos em todo o cluster ou apenas para um namespace poderão ser utilizados.
O escopo padrão para os parâmetros da classe Ingress é em todo o cluster.
Se você definir o campo .spec.parameters e não definir .spec.parameters.scope, ou se você definir .spec.parameters.scope como Cluster, então a classe Ingress se refere a um recurso com escopo de cluster.
O kind (em combinação com o apiGroup) dos parâmetros refere-se a uma API com escopo de cluster (possivelmente um recurso personalizado), e o name dos parâmetros identifica um recurso específico com escopo de cluster para essa API.
Por exemplo:
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: external-lb-1
spec:
controller: example.com/ingress-controller
parameters:
# Os parâmetros para esta classe Ingress são especificados em um
# ClusterIngressParameter (grupo de API k8s.example.net) nomeado
# "external-config-1". Esta definição diz ao Kubernetes para
# procurar um recurso de parâmetro com escopo de cluster.
scope: Cluster
apiGroup: k8s.example.net
kind: ClusterIngressParameter
name: external-config-1
Kubernetes v1.23 [stable]
Se você definir o campo .spec.parameters e definir .spec.parameters.scope como Namespace, a classe Ingress terá como referência um recurso com escopo de namespace.
Você também deve definir o campo namespace dentro de .spec.parameters para o namespace que contém os parâmetros que deseja usar.
O campo kind (em combinação com o campo apiGroup) dos parâmetros refere-se a uma API com namespace (por exemplo: ConfigMap), e o campo name dos parâmetros identifica um recurso específico no namespace que você especificou no campo namespace.
Os parâmetros com escopo de namespace ajudam o operador de cluster a delegar o controle sobre a configuração (por exemplo: configurações do balanceador de carga, definição de gateway API) que é usada para uma carga de trabalho. Se você usou um parâmetro com escopo de cluster, então:
A própria API do IngressClass é sempre com escopo de cluster.
Aqui está um exemplo de uma classe Ingress que se refere a parâmetros com namespace:
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: external-lb-2
spec:
controller: example.com/ingress-controller
parameters:
# The parameters for this IngressClass are specified in an
# IngressParameter (API group k8s.example.com) named "external-config",
# that's in the "external-configuration" namespace.
scope: Namespace
apiGroup: k8s.example.com
kind: IngressParameter
namespace: external-configuration
name: external-config
Antes que o recurso IngressClass e o campo ingressClassName fossem adicionados no Kubernetes 1.18, as classes Ingress foram especificadas com uma anotação kubernetes.io/ingress.class no Ingress.
Esta anotação nunca foi formalmente definida, mas foi amplamente apoiada pelos controladores Ingress.
O campo ingressClassName mais recente no Ingress é um substituto para essa anotação, mas não é um equivalente direto.
Embora a anotação tenha sido geralmente usada para fazer referência ao nome do controlador Ingress que deve implementar o Ingress, o campo é uma referência a um recurso IngressClass que contém a configuração Ingress adicional, incluindo o nome do controlador Ingress.
Você pode marcar uma classe Ingress específica como padrão para o seu cluster.
Definir a anotação ingressclass.kubernetes.io/is-default-class como true em um recurso IngressClass garantirá que novos Ingress sem um campo ingressClassName especificado sejam atribuídos a esta ingressClassName padrão.
ingressClassName especificado.
Você pode resolver isso garantindo que no máximo uma classe Ingress seja marcada como padrão no seu cluster.IngressClass padrão.
É recomendável especificar a IngressClass padrão:
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
labels:
app.kubernetes.io/component: controller
name: example-class
annotations:
ingressclass.kubernetes.io/is-default-class: "true"
spec:
controller: k8s.io/example-class
No Kubernetes existem conceitos que permitem expor um único serviço (veja alternativas). Você também pode fazer isso com um Ingress especificando um backend padrão sem regras.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
spec:
defaultBackend:
service:
name: test
port:
number: 80
Se você criá-lo usando kubectl apply -f, você deve ser capaz de visualizar o estado do Ingress que você adicionou:
kubectl get ingress test-ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
test-ingress external-lb * 203.0.113.123 80 59s
Onde 203.0.113.123 é o IP alocado pelo controlador Ingress para satisfazer o Ingress.
<pending>.Uma configuração de fanout roteia o tráfego de um único endereço IP para mais de um serviço, com base na URI HTTP que está sendo solicitada. Um Ingress permite que você mantenha o número de balanceadores de carga no mínimo. Por exemplo, uma configuração como:
Figura. Ingress Fan Out
exigiria um Ingress como:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: simple-fanout-example
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
pathType: Prefix
backend:
service:
name: service1
port:
number: 4200
- path: /bar
pathType: Prefix
backend:
service:
name: service2
port:
number: 8080
Quando você cria o Ingress com kubectl apply -f:
kubectl describe ingress simple-fanout-example
Name: simple-fanout-example
Namespace: default
Address: 178.91.123.132
Default backend: default-http-backend:80 (10.8.2.3:8080)
Rules:
Host Path Backends
---- ---- --------
foo.bar.com
/foo service1:4200 (10.8.0.90:4200)
/bar service2:8080 (10.8.0.91:8080)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 22s loadbalancer-controller default/test
O controlador Ingress fornece um balanceador de carga específico de implementação que satisfaz o Ingress, desde que os serviços (service1, service2) existam.
Quando tiver feito isso, você pode ver o endereço do balanceador de carga no campo Address.
Os hosts virtuais baseados em nomes suportam o roteamento de tráfego HTTP para vários nomes de host no mesmo endereço IP.
Figura. Hospedagem de host virtual baseado em nome
O Ingress a seguir diz ao balanceador de carga de apoio para rotear solicitações com base no Host header.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: foo.bar.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service1
port:
number: 80
- host: bar.foo.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service2
port:
number: 80
Se você criar um recurso de Ingress sem nenhum host definido nas regras, qualquer tráfego da web para o endereço IP do seu controlador de Ingress pode ser correspondido sem que seja necessário um host virtual baseado em nome.
Por exemplo, o Ingress a seguir roteia o tráfego solicitado para first.bar.com para service1, second.bar.com para service2 e qualquer tráfego cujo cabeçalho de host de solicitação não corresponda a first.bar.com e second.bar.com para service3.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: name-virtual-host-ingress-no-third-host
spec:
rules:
- host: first.bar.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service1
port:
number: 80
- host: second.bar.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service2
port:
number: 80
- http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service3
port:
number: 80
Você pode configurar o uso de TLS no Ingress especificando um Secret que contém uma chave privada e um certificado TLS.
O recurso Ingress suporta apenas uma única porta TLS, 443, e assume a terminação TLS no ponto de entrada (o tráfego para o Serviço e seus Pods não está criptografado o que é inseguro).
Se a seção de configuração TLS em um Ingress especificar hosts diferentes, eles serão multiplexados na mesma porta de acordo com o nome do host especificado através da extensão SNI TLS (desde que o controlador Ingress suporte SNI).
O objeto Secret do tipo TLS deve conter chaves chamadas tls.crt e tls.key que contêm o certificado e a chave privada a ser usada para TLS.
Por exemplo:
apiVersion: v1
kind: Secret
metadata:
name: testsecret-tls
namespace: default
data:
tls.crt: base64 encoded cert
tls.key: base64 encoded key
type: kubernetes.io/tls
Fazer referência a esse segredo em um Ingress diz ao controlador Ingress para proteger o canal do cliente para o balanceador de carga usando TLS.
Você precisa ter certeza de que o objeto Secret do tipo TLS que você criou é originário de um certificado que contém um Nome Comum (Common
Name, CN), também conhecido como Nome de Domínio Totalmente Qualificado (Fully Qualified Domain Name, FQDN), tal como https-example.foo.com.
tls precisam corresponder explicitamente ao host na seção rules.apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-example-ingress
spec:
tls:
- hosts:
- https-example.foo.com
secretName: testsecret-tls
rules:
- host: https-example.foo.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service1
port:
number: 80
Um controlador Ingress é inicializado com algumas configurações de política de balanceamento de carga que se aplicam a todos os Ingress, como o algoritmo de balanceamento de carga, esquema de peso de backend e outros. Conceitos mais avançados de balanceamento de carga (por exemplo, sessões persistentes, pesos dinâmicos) ainda não estão expostos através do Ingress. Em vez disso, você pode obter esses recursos através do balanceador de carga usado para um serviço.
Também vale a pena notar que, embora as verificações de integridade não sejam expostas diretamente através do Ingress, existem conceitos paralelos no Kubernetes, como readiness probes, que permitem alcançar o mesmo resultado final. Revise a documentação específica do controlador para ver como eles lidam com as verificações de integridade (por exemplo: GCE).
Para atualizar um Ingress existente para adicionar um novo Host, você pode atualizá-lo editando o recurso:
kubectl describe ingress test
Name: test
Namespace: default
Address: 178.91.123.132
Default backend: default-http-backend:80 (10.8.2.3:8080)
Rules:
Host Path Backends
---- ---- --------
foo.bar.com
/foo service1:80 (10.8.0.90:80)
Annotations: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 35s loadbalancer-controller default/test
kubectl edit ingress test
Isso abre um editor com a configuração existente no formato YAML. Para incluir o novo host modifique:
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
service:
name: service1
port:
number: 80
path: /foo
pathType: Prefix
- host: bar.baz.com
http:
paths:
- backend:
service:
name: service2
port:
number: 80
path: /foo
pathType: Prefix
..
Depois de salvar suas alterações, o kubectl atualizará o recurso no servidor API, que diz ao controlador Ingress para reconfigurar o balanceador de carga.
Verifique isso:
kubectl describe ingress test
Name: test
Namespace: default
Address: 178.91.123.132
Default backend: default-http-backend:80 (10.8.2.3:8080)
Rules:
Host Path Backends
---- ---- --------
foo.bar.com
/foo service1:80 (10.8.0.90:80)
bar.baz.com
/foo service2:80 (10.8.0.91:80)
Annotations: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 45s loadbalancer-controller default/test
Você pode alcançar o mesmo resultado invocando kubectl replace -f em um arquivo Ingress YAML modificado.
Técnicas para distribuir o tráfego entre domínios de falha diferem entre os provedores de nuvem. Verifique a documentação do controlador Ingress para obter detalhes relevantes.
Você pode expor um serviço de várias maneiras que não envolve diretamente o recurso Ingress:
Se você deseja controlar o fluxo do tráfego de rede no nível do endereço IP ou de portas TCP e UDP
(camadas OSI 3 e 4) então você deve considerar usar Políticas de rede (NetworkPolicies) do Kubernetes para aplicações
no seu cluster. NetworkPolicy é um objeto focado em aplicações/experiência do desenvolvedor
que permite especificar como é permitido a um pod
comunicar-se com várias "entidades" de rede.
As entidades que um Pod pode se comunicar são identificadas através de uma combinação dos 3 identificadores à seguir:
Quando definimos uma política de rede baseada em pod ou namespace, utiliza-se um selector para especificar qual tráfego é permitido de e para o(s) Pod(s) que correspondem ao seletor.
Quando uma política de redes baseada em IP é criada, nós definimos a política baseada em blocos de IP (faixas CIDR).
As políticas de rede são implementadas pelo plugin de redes. Para usar
uma política de redes, você deve usar uma solução de redes que suporte o objeto NetworkPolicy.
A criação de um objeto NetworkPolicy sem um controlador que implemente essas regras não tem efeito.
Por padrão, pods não são isolados; eles aceitam tráfego de qualquer origem.
Os pods tornam-se isolados ao existir uma NetworkPolicy que selecione eles. Uma vez que
exista qualquer NetworkPolicy no namespace selecionando um pod em específico, aquele pod
irá rejeitar qualquer conexão não permitida por qualquer NetworkPolicy. (Outros pod no mesmo
namespace que não são selecionados por nenhuma outra NetworkPolicy irão continuar aceitando
todo tráfego de rede.)
As políticas de rede não conflitam; elas são aditivas. Se qualquer política selecionar um pod, o pod torna-se restrito ao que é permitido pela união das regras de entrada/saída de tráfego definidas nas políticas. Assim, a ordem de avaliação não afeta o resultado da política.
Para o fluxo de rede entre dois pods ser permitido, tanto a política de saída no pod de origem e a política de entrada no pod de destino devem permitir o tráfego. Se a política de saída na origem, ou a política de entrada no destino negar o tráfego, o tráfego será bloqueado.
Veja a referência NetworkPolicy para uma definição completa do recurso.
Uma NetworkPolicy de exemplo é similar ao abaixo:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
Campos obrigatórios: Assim como todas as outras configurações do Kubernetes, uma NetworkPolicy
necessita dos campos apiVersion, kind e metadata. Para maiores informações sobre
trabalhar com arquivos de configuração, veja
Configurando contêineres usando ConfigMap,
e Gerenciamento de objetos.
spec: A spec contém todas as informações necessárias para definir uma política de redes em um namespace.
podSelector: Cada NetworkPolicy inclui um podSelector que seleciona o grupo de pods
que a política se aplica. A política acima seleciona os pods com a label "role=db". Um podSelector
vazio seleciona todos os pods no namespace.
policyTypes: Cada NetworkPolicy inclui uma lista de policyTypes que pode incluir Ingress,
Egress ou ambos. O campo policyTypes indica se a política se aplica ao tráfego de entrada
com destino aos pods selecionados, o tráfego de saída com origem dos pods selecionados ou ambos.
Se nenhum policyType for definido então por padrão o tipo Ingress será sempre utilizado, e o
tipo Egress será configurado apenas se o objeto contiver alguma regra de saída. (campo egress a seguir).
ingress: Cada NetworkPolicy pode incluir uma lista de regras de entrada permitidas através do campo ingress.
Cada regra permite o tráfego que corresponde simultaneamente às sessões from (de) e ports (portas).
A política de exemplo acima contém uma regra simples, que corresponde ao tráfego em uma única porta,
de uma das três origens definidas, sendo a primeira definida via ipBlock, a segunda via namespaceSelector e
a terceira via podSelector.
egress: Cada política pode incluir uma lista de regras de regras de saída permitidas através do campo egress.
Cada regra permite o tráfego que corresponde simultaneamente às sessões to (para) e ports (portas).
A política de exemplo acima contém uma regra simples, que corresponde ao tráfego destinado a uma
porta em qualquer destino pertencente à faixa de IPs em 10.0.0.0/24.
Então a NetworkPolicy acima:
Isola os pods no namespace "default" com a label "role=db" para ambos os tráfegos de entrada e saída (se eles ainda não estavam isolados)
(Regras de entrada/ingress) permite conexões para todos os pods no namespace "default" com a label "role=db" na porta TCP 6379 de:
(Regras de saída/egress) permite conexões de qualquer pod no namespace "default" com a label "role=db" para a faixa de destino 10.0.0.0/24 na porta TCP 5978.
Veja o tutorial Declarando uma política de redes para mais exemplos.
to e fromExistem quatro tipos de seletores que podem ser especificados nas sessões ingress.from ou
egress.to:
podSelector: Seleciona Pods no mesmo namespace que a política de rede foi criada, e que deve ser permitido origens no tráfego de entrada ou destinos no tráfego de saída.
namespaceSelector: Seleciona namespaces para o qual todos os Pods devem ser permitidos como origens no caso de tráfego de entrada ou destino no tráfego de saída.
namespaceSelector e podSelector: Uma entrada to/from única que permite especificar
ambos namespaceSelector e podSelector e seleciona um conjunto de Pods dentro de um namespace.
Seja cuidadoso em utilizar a sintaxe YAML correta; essa política:
...
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
podSelector:
matchLabels:
role: client
...
contém um único elemento from permitindo conexões de Pods com a label role=client em
namespaces com a label user=alice. Mas essa política:
...
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
- podSelector:
matchLabels:
role: client
...
contém dois elementos no conjunto from e permite conexões de Pods no namespace local com
a label role=client, OU de qualquer outro Pod em qualquer outro namespace que tenha
a label user=alice.
Quando estiver em dúvida, utilize o comando kubectl describe para verificar como o
Kubernetes interpretou a política.
ipBlock: Isso seleciona um conjunto particular de faixas de IP a serem permitidos como origens no caso de entrada ou destinos no caso de saída. Devem ser considerados IPs externos ao cluster, uma vez que os IPs dos Pods são efêmeros e imprevisíveis.
Os mecanismos de entrada e saída do cluster geralmente requerem que os IPs de origem ou destino
sejam reescritos. Em casos em que isso aconteça, não é definido se deve acontecer antes ou
depois do processamento da NetworkPolicy que corresponde a esse tráfego, e o comportamento
pode ser diferente para cada plugin de rede, provedor de nuvem, implementação de Service, etc.
No caso de tráfego de entrada, isso significa que em alguns casos você pode filtrar os pacotes
de entrada baseado no IP de origem atual, enquanto que em outros casos o IP de origem que
a NetworkPolicy atua pode ser o IP de um LoadBalancer ou do Nó em que o Pod está executando.
No caso de tráfego de saída, isso significa que conexões de Pods para Services que são reescritos
para IPs externos ao cluster podem ou não estar sujeitos a políticas baseadas no campo ipBlock.
Por padrão, se nenhuma política existir no namespace, então todo o tráfego de entrada e saída é permitido de e para os pods nesse namespace. Os exemplos a seguir permitem a você mudar o comportamento padrão nesse namespace.
Você pode criar uma política padrão de isolamento para um namespace criando um objeto NetworkPolicy
que seleciona todos os pods mas não permite o tráfego de entrada para esses pods.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
podSelector: {}
policyTypes:
- Ingress
Isso garante que mesmo pods que não são selecionados por nenhuma outra política de rede ainda serão isolados. Essa política não muda o comportamento padrão de isolamento de tráfego de saída nesse namespace.
Se você deseja permitir todo o tráfego de todos os pods em um namespace (mesmo que políticas que sejam adicionadas faça com que alguns pods sejam tratados como "isolados"), você pode criar uma política que permite explicitamente todo o tráfego naquele namespace.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-ingress
spec:
podSelector: {}
ingress:
- {}
policyTypes:
- Ingress
Você pode criar uma política de isolamento de saída padrão para um namespace criando uma política de redes que selecione todos os pods, mas não permita o tráfego de saída a partir de nenhum desses pods.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
spec:
podSelector: {}
policyTypes:
- Egress
Isso garante que mesmo pods que não são selecionados por outra política de rede não seja permitido tráfego de saída. Essa política não muda o comportamento padrão de tráfego de entrada.
Caso você queira permitir todo o tráfego de todos os pods em um namespace (mesmo que políticas sejam adicionadas e cause com que alguns pods sejam tratados como "isolados"), você pode criar uma política explicita que permite todo o tráfego de saída no namespace.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-egress
spec:
podSelector: {}
egress:
- {}
policyTypes:
- Egress
Você pode criar uma política padrão em um namespace que previne todo o tráfego de entrada E saída criando a política a seguir no namespace.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Isso garante que mesmo pods que não são selecionados por nenhuma outra política de redes não possuam permissão de tráfego de entrada ou saída.
Kubernetes v1.21 [alpha]
Ao escrever uma política de redes, você pode selecionar uma faixa de portas ao invés de uma
porta única, utilizando-se do campo endPort conforme a seguir:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: multi-port-egress
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 32000
endPort: 32768
A regra acima permite a qualquer Pod com a label "role=db" no namespace default de se comunicar
com qualquer IP na faixa 10.0.0.0/24 através de protocolo TCP, desde que a porta de destino
esteja na faixa entre 32000 e 32768.
As seguintes restrições aplicam-se ao se utilizar esse campo:
endPort
no cluster, você (ou o seu administrador do cluster) deve habilitar o feature gate NetworkPolicyEndPort no kube-apiserver com a flag --feature-gates=NetworkPolicyEndPort=true,....endPort deve ser igual ou maior ao valor do campo port.endPort só pode ser definido se o campo port também for definido.port e endPort devem ser números.endPort na especificação da política de redes.Kubernetes 1.21 [beta]
A camada de gerenciamento do Kubernetes configura uma label imutável kubernetes.io/metadata.name em
todos os namespaces, uma vez que o feature gate esteja habilitado por padrão.
O valor dessa label é o nome do namespace.
Enquanto que um objeto NetworkPolicy não pode selecionar um namespace pelo seu nome através de
um campo específico, você pode utilizar essa label padrão para selecionar um namespace pelo seu nome.
NetworkPolicies (ao menos por enquanto!)Por enquanto no Kubernetes 1.35 as funcionalidades a seguir não existem mas você pode conseguir implementar de forma alternativa utilizando componentes do Sistema Operacional (como SELinux, OpenVSwitch, IPtables, etc) ou tecnologias da camada 7 OSI (Ingress controllers, implementações de service mesh) ou ainda admission controllers. No caso do assunto "segurança de redes no Kubernetes" ser novo para você, vale notar que as histórias de usuário a seguir ainda não podem ser implementadas:
Services pelo seu nome (você pode, contudo, selecionar pods e namespaces por seus labels o que torna-se uma solução de contorno viável).NetworkPolicies são "negar por padrão e conforme a necessidade, deve-se adicionar regras que permitam o tráfego).Disponibilize serviços de rede usando um mecanismo de configuração extensível, orientado a funções e com reconhecimento de protocolo. O Gateway API é um complemento contendo tipos de objetos da API que fornecem provisionamento dinâmico de infraestrutura e roteamento avançado de tráfego.
Os seguintes princípios moldaram o design e a arquitetura do Gateway API:
O Gateway API possui quatro tipos de API estáveis:
GatewayClass: Define um conjunto de gateways com configuração comum e gerenciados por um controlador que implementa a classe.
Gateway: Define uma instância de infraestrutura de manipulação de tráfego, como um balanceador de carga em nuvem.
HTTPRoute: Define regras específicas de HTTP para mapear o tráfego de um ponto de entrada do Gateway para uma representação de endpoints de rede de backend. Esses endpoints geralmente são representados como um Service.
GRPCRoute: Define regras específicas de gRPC para mapear o tráfego de um ponto de entrada do Gateway para uma representação de endpoints de rede de backend. Esses endpoints geralmente são representados como um Service.
O Gateway API é organizado em diferentes tipos de API que possuem relacionamentos interdependentes para suportar
a natureza orientada a funções das organizações. Um objeto Gateway está associado a exatamente um GatewayClass;
o GatewayClass descreve o controlador de gateway responsável por gerenciar Gateways desta classe.
Um ou mais tipos de rota, como HTTPRoute, são então associados aos Gateways. Um Gateway pode filtrar as rotas
que podem ser anexadas aos seus listeners, formando um modelo de confiança bidirecional com as rotas.
A figura a seguir ilustra os relacionamentos dos três tipos estáveis do Gateway API:
Gateways podem ser implementados por diferentes controladores, frequentemente com diferentes configurações. Um Gateway deve referenciar uma GatewayClass que contenha o nome do controlador que implementa a classe.
Um exemplo mínimo de GatewayClass:
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: example-class
spec:
controllerName: example.com/gateway-controller
Neste exemplo, um controlador que implementou o Gateway API está configurado para gerenciar GatewayClasses
com o nome de controlador example.com/gateway-controller. Gateways desta classe serão gerenciados pelo
controlador da implementação.
Consulte a referência de GatewayClass para uma definição completa deste tipo de API.
Um Gateway descreve uma instância de infraestrutura de manipulação de tráfego. Ele define um endpoint de rede que pode ser usado para processar o tráfego, ou seja, filtragem, balanceamento, divisão, etc. para backends como um Service. Por exemplo, um Gateway pode representar um balanceador de carga em nuvem ou um servidor proxy dentro do cluster que está configurado para aceitar tráfego HTTP.
Um exemplo mínimo de Gateway:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: example-gateway
spec:
gatewayClassName: example-class
listeners:
- name: http
protocol: HTTP
port: 80
Neste exemplo, uma instância de infraestrutura de manipulação de tráfego é programada para escutar o tráfego HTTP
na porta 80. Como o campo addresses não está especificado, um endereço ou nome de host é atribuído
ao Gateway pelo controlador da implementação. Este endereço é usado como um endpoint de rede para
processar o tráfego de endpoints de rede de backend definidos nas rotas.
Consulte a referência de Gateway para uma definição completa deste tipo de API.
O tipo HTTPRoute especifica o comportamento de roteamento de requisições HTTP de um ouvinte do Gateway para endpoints de rede de backend. Para um backend do tipo Service, uma implementação pode representar o endpoint de rede de backend como um IP do Service ou os EndpointSlices subjacentes do Service. Um HTTPRoute representa a configuração que é aplicada à implementação subjacente do Gateway. Por exemplo, definir um novo HTTPRoute pode resultar na configuração de rotas de tráfego adicionais em um balanceador de carga em nuvem ou servidor proxy dentro do cluster.
Um exemplo mínimo de HTTPRoute:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: example-httproute
spec:
parentRefs:
- name: example-gateway
hostnames:
- "www.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /login
backendRefs:
- name: example-svc
port: 8080
Neste exemplo, o tráfego HTTP do Gateway example-gateway com o cabeçalho Host: definido como www.example.com
e o caminho da requisição especificado como /login será roteado para o Service example-svc na porta 8080.
Consulte a referência de HTTPRoute para uma definição completa deste tipo de API.
O tipo GRPCRoute especifica o comportamento de roteamento de requisições gRPC de um ouvinte do Gateway para endpoints de rede de backend. Para um backend do tipo Service, uma implementação pode representar o endpoint de rede de backend como um IP do Service ou os EndpointSlices subjacentes do Service. Um GRPCRoute representa a configuração que é aplicada à implementação subjacente do Gateway. Por exemplo, definir um novo GRPCRoute pode resultar na configuração de rotas de tráfego adicionais em um balanceador de carga em nuvem ou servidor proxy dentro do cluster.
Gateways que suportam GRPCRoute são obrigados a suportar HTTP/2 sem uma atualização inicial do HTTP/1, portanto, o tráfego gRPC tem o fluxo garantido adequadamente.
Um exemplo mínimo de GRPCRoute:
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: example-grpcroute
spec:
parentRefs:
- name: example-gateway
hostnames:
- "svc.example.com"
rules:
- backendRefs:
- name: example-svc
port: 50051
Neste exemplo, o tráfego gRPC do Gateway example-gateway com o host definido como svc.example.com
será direcionado para o serviço example-svc na porta 50051 do mesmo namespace.
O GRPCRoute permite a correspondência de serviços gRPC específicos, conforme o seguinte exemplo:
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: example-grpcroute
spec:
parentRefs:
- name: example-gateway
hostnames:
- "svc.example.com"
rules:
- matches:
- method:
service: com.example
method: Login
backendRefs:
- name: foo-svc
port: 50051
Neste caso, o GRPCRoute corresponderá a qualquer tráfego para svc.example.com e aplicará suas regras de roteamento para encaminhar o tráfego para o backend correto. Como há apenas uma correspondência especificada, somente requisições para o método com.example.User.Login para svc.example.com serão encaminhadas. RPCs de qualquer outro método não serão correspondidos por esta Rota.
Consulte a referência de GRPCRoute para uma definição completa deste tipo de API.
Aqui está um exemplo simples de tráfego HTTP sendo roteado para um Service usando um Gateway e um HTTPRoute:
Neste exemplo, o fluxo de requisição para um Gateway implementado como um proxy reverso é:
http://www.example.comO Gateway API cobre um amplo conjunto de funcionalidades e é amplamente implementado. Esta combinação requer definições e testes de conformidade claros para garantir que a API forneça uma experiência consistente onde quer que seja usada.
Consulte a documentação de conformidade para entender detalhes como canais de lançamento, níveis de suporte e execução de testes de conformidade.
O Gateway API é o sucessor da API Ingress. No entanto, ele não inclui o tipo Ingress. Como resultado, é necessária uma conversão única dos seus recursos Ingress existentes para recursos do Gateway API.
Consulte o guia de migração do ingress para detalhes sobre como migrar recursos Ingress para recursos do Gateway API.
Em vez de os recursos do Gateway API serem implementados nativamente pelo Kubernetes, as especificações são definidas como Recursos Personalizados suportados por uma ampla variedade de implementações. Instale os CRDs do Gateway API ou siga as instruções de instalação da sua implementação selecionada. Após instalar uma implementação, use o guia Getting Started para ajudá-lo a começar rapidamente a trabalhar com o Gateway API.
Consulte a especificação da API para detalhes adicionais de todos os tipos do Gateway API.
Os arquivos em disco em um contêiner são efêmeros, o que apresenta alguns problemas para
aplicações não triviais quando executadas em contêineres. Um problema é a perda de arquivos
quando um contêiner quebra. O kubelet reinicia o contêiner, mas em um estado limpo. Um segundo
problema ocorre ao compartilhar arquivos entre contêineres que são executados juntos em
um Pod. A abstração de volume
do Kubernetes resolve ambos os problemas. Sugere-se familiaridade com Pods .
Docker tem um conceito de volumes, embora seja um pouco mais simples e menos gerenciado. Um volume Docker é um diretório em disco ou em outro contêiner. O Docker oferece drivers de volume, mas a funcionalidade é um pouco limitada.
O Kubernetes suporta muitos tipos de volumes. Um Pod é capaz de utilizar qualquer quantidade de tipos de volumes simultaneamente. Os tipos de volume efêmeros têm a mesma vida útil do pod, mas os volumes persistentes existem além da vida útil de um pod. Quando um pod deixa de existir, o Kubernetes destrói volumes efêmeros; no entanto, o Kubernetes não destrói volumes persistentes. Para qualquer tipo de volume em um determinado pod, os dados são preservados entre as reinicializações do contêiner.
Em sua essência, um volume é um diretório, eventualmente com alguns dados dentro dele, que é acessível aos contêineres de um Pod. Como esse diretório vem a ser, o meio que o suporta e o conteúdo do mesmo são determinados pelo tipo particular de volume utilizado.
Para utilizar um volume, especifique os volumes que serão disponibilizados para o Pod em .spec.volumes e declare onde montar esses volumes dentro dos contêineres em .spec.containers[*].volumeMounts. Um processo em um contêiner enxerga uma visualização do sistema de arquivos composta pelo do conteúdo inicial da imagem do contêiner mais os volumes (se definidos) montados dentro do contêiner. O processo enxerga um sistema de arquivos raiz que inicialmente corresponde ao conteúdo da imagem do contêiner. Qualquer gravação dentro dessa hierarquia do sistema de arquivos, se permitida, afetará o que esse processo enxerga quando ele executa um acesso subsequente ao sistema de arquivos. Os volumes são montados nos caminhos especificados dentro da imagem. Para cada contêiner definido em um Pod, você deve especificar independentemente onde montar cada volume utilizado pelo contêiner.
Volumes não podem ser montados dentro de outros volumes (mas você pode consultar Utilizando subPath para um mecanismo relacionado). Além disso, um volume não pode conter um link físico para qualquer outro dado em um volume diferente.
Kubernetes suporta vários tipos de volumes.
Um volume awsElasticBlockStore monta um volume EBS da Amazon Web Services (AWS) em seu pod. Ao contrário do emptyDirque é apagado quando um pod é removido, o conteúdo de um volume EBS é preservado e o volume é desmontado. Isto significa que um volume EBS pode ser previamente populado com dados e que os dados podem ser compartilhados entre Pods.
aws ec2 create-volume ou pela API da AWS antes que você consiga utilizá-lo.Existem algumas restrições ao utilizar um volume awsElasticBlockStore:
Antes de poder utilizar um volume EBS com um pod, precisa criá-lo.
aws ec2 create-volume --availability-zone=eu-west-1a --size=10 --volume-type=gp2
Certifique-se de que a zona corresponde à mesma zona em que criou o cluster. Verifique se o tamanho e o tipo de volume EBS são adequados para a sua utilização.
apiVersion: v1
kind: Pod
metadata:
name: test-ebs
spec:
containers:
- image: registry.k8s.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-ebs
name: test-volume
volumes:
- name: test-volume
# Esse volume AWS EBS já deve existir.
awsElasticBlockStore:
volumeID: "<volume id>"
fsType: ext4
Se o volume EBS estiver particionado, é possível informar o campo opcional partition: "<partition em number>" para especificar em que partição deve ser montado.
Kubernetes v1.25 [stable]
Quando o recurso CSIMigration para awsElasticBlockStore está habilitado, todas as operações de plugin do tipo in-tree são redirecionadas para o driver Cointainer Storage Interface (CSI) ebs.csi.aws.com. Para usar esse recurso, o driver CSI AWS EBS deve estar instalado no cluster.
Kubernetes v1.17 [alpha]
Para desabilitar o carregamento do plugin de armazenamento awsElasticBlockStore pelo gerenciador de controladores e pelo kubelet, defina a flag InTreePluginAWSUnregister como true.
Kubernetes v1.19 [deprecated]
O tipo de volume azureDisk monta um Disco de Dados Microsoft Azure em um pod.
Para obter mais detalhes, consulte plugin de volume azureDisk.
Kubernetes v1.24 [stable]
Quando o recurso CSIMigration para azureDisk está habilitado, todas as operações de plugin do tipo in-tree são redirecionadas para o Driver de Cointêiner Storage Interface (CSI) disk.csi.azure.com. Para utilizar este recurso, o Driver CSI Azure Disk deve estar instalado no cluster.
Kubernetes v1.21 [alpha]
Para desabilitar o carregamento do plugin de armazenamento azureDisk pelo gerenciador de controladores e pelo kubelet, defina a flag InTreePluginAzureDiskUnregister como true.
Kubernetes v1.21 [deprecated]
O tipo de volume azureFile monta um volume de arquivo Microsoft Azure (SMB 2.1 e 3.0) em um pod.
Para obter mais detalhes, consulte plugin de volume azureFile.
Kubernetes v1.26 [stable]
Quando o recurso CSIMigration para azureFile está habilitado, todas as operações de plugin do tipo in-tree são redirecionadas para o Driver de Cointainer Storage Interface (CSI) file.csi.azure.com. Para utilizar este recurso, o Driver CSI do Azure Disk deve estar instalado no cluster e as feature gates CSIMigration e CSIMigrationAzureFile devem estar habilitadas.
O driver de CSI do Azure File não oferece suporte ao uso do mesmo volume por fsgroups diferentes, se a migração de CSI Azurefile estiver habilitada, o uso do mesmo volume por fsgroups diferentes não será suportado.
Kubernetes v1.21 [alpha]
Para desabilitar o carregamento do plugin de armazenamento azureFile pelo gerenciador de controladores e pelo kubelet, defina a flag InTreePluginAzureFileUnregister como true.
Um volume cephfs permite que um volume CephFS existente seja montado no seu Pod. Ao contrário do emptyDir que é apagado quando um pod é removido, o conteúdo de um volume cephfs é preservado e o volume é simplesmente desmontado. Isto significa que um volume cephfs pode ser previamente populado com dados e que os dados podem ser compartilhados entre os Pods. O volume cephfs pode ser montado por vários gravadores simultaneamente.
Consulte o exemplo CephFS para mais detalhes.
Kubernetes v1.18 [deprecated]
O tipo de volume cinder é utilizado para montar o volume do OpenStack Cinder no seu pod.
apiVersion: v1
kind: Pod
metadata:
name: test-cinder
spec:
containers:
- image: registry.k8s.io/test-webserver
name: test-cinder-container
volumeMounts:
- mountPath: /test-cinder
name: test-volume
volumes:
- name: test-volume
# Esse volume OpenStack já deve existir.
cinder:
volumeID: "<volume id>"
fsType: ext4
Kubernetes v1.24 [stable]
O recurso CSIMigration para o Cinder é ativado por padrão no Kubernetes 1.21. Ele redireciona todas as operações de plugin do tipo in-tree para o Driver de Cointainer Storage Interface (CSI) cinder.csi.openstack.org. O Driver CSI OpenStack Cinder tem de estar instalado no cluster. Você pode desativar a migração Cinder CSI para o seu cluster definindo a feature gate CSIMigrationOpenStack como false. Se você desativar o recurso CSIMigrationOpenStack, o plugin de volume in-tree do Cinder assume a responsabilidade por todos os aspectos do gerenciamento de armazenamento de volume do Cinder.
Um ConfigMap oferece uma forma de injetar dados de configuração em Pods. Os dados armazenados em um ConfigMap podem ser referenciados em um volume de tipo configMap e depois consumidos por aplicações conteinerizadas executadas em um pod.
Ao referenciar um ConfigMap, você informa o nome do ConfigMap no volume. Pode personalizar o caminho utilizado para uma entrada específica no ConfigMap. A seguinte configuração mostra como montar o log-config do ConfigMap em um Pod chamado configmap-pod:
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod
spec:
containers:
- name: test
image: busybox:1.28
command: ['sh', '-c', 'echo "The app is running!" && tail -f /dev/null']
volumeMounts:
- name: config-vol
mountPath: /etc/config
volumes:
- name: config-vol
configMap:
name: log-config
items:
- key: log_level
path: log_level.conf
O ConfigMap log-config é montado como um volume e todos os conteúdos armazenados em sua entrada log_level são montados no Pod através do caminho /etc/config/log_level.conf. Observe que esse caminho é derivado do volume mountPathe do path configurado com log_level.
É preciso criar um ConfigMap antes de usá-lo.
Um ConfigMap é sempre montado como readOnly.
Um contêiner que utiliza ConfigMap através de um ponto de montagem com a propriedade subPath não receberá atualizações deste ConfigMap.
Os dados de texto são expostos como arquivos utilizando a codificação de caracteres UTF-8. Para outras codificações de caracteres, use binaryData.
Um volume downwardAPI disponibiliza dados da downward API para as aplicações. Ele monta um diretório e grava os dados solicitados em arquivos de texto sem formatação.
subPath não receberá atualizações desta downward API.Consulte o exemplo de downward API para obter mais detalhes.
Um volume emptyDir é criado pela primeira vez quando um Pod é atribuído a um nó e existe enquanto esse Pod estiver sendo executado nesse nó. Como o nome diz, o volume emptyDir está inicialmente vazio. Todos os contêineres no Pod podem ler e gravar os mesmos arquivos no volume emptyDir, embora esse volume possa ser montado no mesmo caminho ou em caminhos diferentes em cada contêiner. Quando um Pod é removido de um nó por qualquer motivo, os dados no emptyDir são eliminados permanentemente.
emptyDir são mantidos em caso de falha do contêiner.Alguns usos para um emptyDir são:
Dependendo do seu ambiente, os volumes emptyDir são armazenados em qualquer mídia que componha o nó, como disco ou SSD, ou armazenamento de rede. No entanto, se você definir o campo emptyDir.medium como "Memory", o Kubernetes monta um tmpfs (sistema de arquivos com suporte de RAM) para você. Embora o tmpfs seja muito rápido, tenha em atenção que, ao contrário dos discos, o tmpfs é limpo na reinicialização do nó e quaisquer arquivos que grave consomem o limite de memória do seu contêiner.
SizeMemoryBackedVolumes estiver habilitada, é possível especificar um tamanho para volumes mantidos em memória. Se nenhum tamanho for especificado, os volumes mantidos em memória são dimensionados para 50% da memória em um host Linux.apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: registry.k8s.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
sizeLimit: 500Mi
Um tipo de volume fc permite que um volume de armazenamento de fibre channel existente seja montado em um Pod. Você pode especificar um ou vários WWNs usando o parâmetro targetWWNs em sua configuração de volume. Se forem especificados vários WWNs, o targetWWNs espera que esses WWNs sejam de conexões multipath.
Flocker é um gerenciador de volumes de dados de contêineres em cluster de código aberto. O Flocker oferece gerenciamento e orquestração de volumes de dados suportados por uma variedade de backends de armazenamento.
Um volume flocker permite que um conjunto de dados Flocker seja montado em um Pod. Se o conjunto de dados ainda não existir no Flocker, ele precisará ser criado primeiro com o CLI do Flocker ou usando a API do Flocker. Se o conjunto de dados já existir, ele será anexado pelo Flocker ao nó que o pod está escalonado. Isto significa que os dados podem ser compartilhados entre os Pods, conforme necessário.
Consulte exemplo do Flocker para obter mais detalhes.
Kubernetes v1.17 [deprecated]
Um volume gcePersistentDisk monta um disco persistente (PD) do Google Compute Engine (GCE) no seu Pod. Ao contrário do emptyDir que é apagado quando um pod é removido, o conteúdo de um PD é preservado e o volume é simplesmente desmontado. Isto significa que um PD pode ser previamente populado com dados e que os dados podem ser compartilhados entre os Pods.
gcloud, ou via GCE API ou via UI antes de poder utilizá-lo.Existem algumas restrições ao utilizar um gcePersistentDisk:
Uma característica do disco persistente GCE é o acesso simultâneo somente leitura a um disco persistente. Um volume gcePersistentDisk permite que vários consumidores montem simultaneamente um disco persistente como somente leitura. Isto significa que é possível alimentar previamente um PD com o seu conjunto de dados e, em seguida, disponibilizá-lo em paralelo a quantos Pods necessitar. Infelizmente, os PDs só podem ser montados por um único consumidor no modo de leitura e escrita. Não são permitidos gravadores simultâneos.
O uso de um disco persistente GCE com um Pod controlado por um ReplicaSet falhará, a menos que o PD seja somente leitura ou a contagem de réplica seja 0 ou 1.
Antes de poder utilizar um disco persistente GCE com um Pod, é necessário criá-lo.
gcloud compute disks create --size=500GB --zone=us-central1-a my-data-disk
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: registry.k8s.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
# Esse Disco Persistente (PD) GCE já deve existir.
gcePersistentDisk:
pdName: my-data-disk
fsType: ext4
O recurso de Discos persistentes regionais permite a criação de discos persistentes que estão disponíveis em duas zonas dentro da mesma região. Para usar esse recurso, o volume deve ser provisionado como PersistentVolume; referenciar o volume diretamente a partir de um pod não é uma configuração suportada.
O provisionamento dinâmico é possível usando uma StorageClass para GCE PD. Antes de criar um PersistentVolume, você deve criar o disco persistente:
gcloud compute disks create --size=500GB my-data-disk
--region us-central1
--replica-zones us-central1-a,us-central1-b
apiVersion: v1
kind: PersistentVolume
metadata:
name: test-volume
spec:
capacity:
storage: 400Gi
accessModes:
- ReadWriteOnce
gcePersistentDisk:
pdName: my-data-disk
fsType: ext4
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
# failure-domain.beta.kubernetes.io/zone deve ser usado para versões anteriores à 1.21
- key: topology.kubernetes.io/zone
operator: In
values:
- us-central1-a
- us-central1-b
Kubernetes v1.25 [stable]
Quando o recurso CSIMigration para o GCE PD é habilitado, todas as operações de plugin do plugin in-tree existente são redirecionadas para o Driver de Cointainer Storage Interface (CSI) pd.csi.storage.gke.io. Para utilizar este recurso, o Driver CSI GCE PD deve ser instalado no cluster e os recursos beta CSIMigration e CSIMigrationGCE devem estar habilitados.
Kubernetes v1.21 [alpha]
Para desabilitar o carregamento do plugin de armazenamento gcePersistentDisk pelo gerenciador de controladores e pelo kubelet, defina a flag InTreePluginGCEUnregister como true.
gitRepo foi descontinuado. Para provisionar um contêiner com um repositório git , monte um EmptyDir em um InitContainer que clone o repositório usando git, depois monte o EmptyDir no contêiner do Pod.Um volume gitRepo é um exemplo de um plugin de volume. Este plugin monta um diretório vazio e clona um repositório git neste diretório para que seu Pod utilize.
Aqui está um exemplo de um volume gitRepo:
apiVersion: v1
kind: Pod
metadata:
name: server
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /mypath
name: git-volume
volumes:
- name: git-volume
gitRepo:
repository: "git@somewhere:me/my-git-repository.git"
revision: "22f1d8406d464b0c0874075539c1f2e96c253775"
O Kubernetes 1.27 não inclui um tipo de volume glusterfs.
O driver de armazenamento in-tree GlusterFS foi descontinuado na versão v1.25 do Kubernetes e, em seguida, removido totalmente na versão v1.26.
Os volumes HostPath apresentam muitos riscos de segurança e é uma prática recomendada evitar o uso de HostPaths quando possível. Quando um volume HostPath precisa ser usado, ele deve ser definido com escopo apenas para o arquivo ou diretório necessário e montado como ReadOnly.
Se você restringir o acesso do HostPath a diretórios específicos através da AdmissionPolicy, a propriedade volumeMounts DEVE obrigatoriamente usar pontos de montagem readOnly para que a política seja eficaz.
Um volume hostPath monta um arquivo ou diretório do sistema de arquivos do nó do host em seu Pod. Isto não é algo de que a maioria dos Pods irá precisar, mas oferece uma poderosa alternativa de escape para algumas aplicações.
Por exemplo, alguns usos para um hostPath são:
hostPath apontando para /var/lib/dockerhostPath apontando para /syshostPath deve existir antes de o Pod ser executado, se deve ser criado e como deve existirAlém da propriedade obrigatória path , você pode opcionalmente definir um type para um volume hostPath.
Os valores suportados para o campo type são:
| Valor | Comportamento |
|---|---|
| A string vazia (padrão) é para compatibilidade com versões anteriores, o que significa que nenhuma verificação será executada antes de montar o volume hostPath. | |
DirectoryOrCreate |
Se nada existir no caminho indicado, um diretório vazio será criado lá, conforme necessário, com permissão definida para 0755, tendo o mesmo grupo e propriedade com a Kubelet. |
Directory |
Um diretório deve existir no caminho indicado |
FileOrCreate |
Se não houver nada no caminho indicado, um arquivo vazio será criado lá, conforme necessário, com permissão definida para 0644, tendo o mesmo grupo e propriedade com Kubelet. |
File |
Um arquivo deve existir no caminho indicado |
Socket |
Um socket UNIX deve existir no caminho indicado |
CharDevice |
Deve existir um dispositivo de caracteres no caminho indicado |
BlockDevice |
Deve existir um dispositivo de bloco no caminho indicado |
Tenha cuidado ao utilizar este tipo de volume, porque:
hostPathapiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: registry.k8s.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
# localização do diretório no host
path: /data
# este campo é opcional
type: Directory
FileOrCreate não cria o diretório onde ficará arquivo. Se o caminho de diretório do arquivo montado não existir, o pod não será iniciado. Para garantir que esse modo funcione, você pode tentar montar diretórios e arquivos separadamente, como mostrado em configuração FileOrCreate.apiVersion: v1
kind: Pod
metadata:
name: test-webserver
spec:
containers:
- name: test-webserver
image: registry.k8s.io/test-webserver:latest
volumeMounts:
- mountPath: /var/local/aaa
name: mydir
- mountPath: /var/local/aaa/1.txt
name: myfile
volumes:
- name: mydir
hostPath:
# Certifique-se de que o diretório foi criado.
path: /var/local/aaa
type: DirectoryOrCreate
- name: myfile
hostPath:
path: /var/local/aaa/1.txt
type: FileOrCreate
Um volume iscsi permite que um volume iSCSI (SCSI sobre IP) existente seja montado no seu Pod. Ao contrário do emptyDir que é apagado quando um Pod é removido, o conteúdo de um volume iscsi é preservado e o volume é simplesmente desmontado. Isto significa que um volume iscsi pode ser previamente populado com dados e que os dados podem ser compartilhados entre os Pods.
Uma característica do iSCSI é que ele pode ser montado como somente leitura por vários consumidores simultaneamente. Isto significa que um volume pode ser previamente populado com seu conjunto de dados e, em seguida, ser disponibilizado em paralelo para tantos Pods quanto necessitar. Infelizmente, os volumes iSCSI só podem ser montados por um único consumidor no modo de leitura-escrita. Não são permitidos gravadores simultâneos.
Um volume local representa um dispositivo de armazenamento local montado, como um disco, partição ou diretório.
Os volumes locais só podem ser usados como um PersistentVolume criado estaticamente. O provisionamento dinâmico não é suportado.
Em comparação com volumes hostPath, os volumes local são usados de forma durável e portátil, sem escalonamento manual dos Pods para os nós. O sistema está ciente das restrições de nós do volume, observando a afinidade do nó com o PersistentVolume.
No entanto, os volumes local estão sujeitos à disponibilidade do nó que o comporta e não são adequados para todas as aplicações. Se um nó não está íntegro, então o volume local torna-se inacessível pelo pod. O pod que utiliza este volume não consegue ser executado. Os aplicativos que usam volumes local devem ser capazes de tolerar essa disponibilidade reduzida, bem como uma possível perda de dados, dependendo das caraterísticas de durabilidade do disco subjacente.
O exemplo a seguir mostra um PersistentVolume usando um volume local e nodeAffinity:
apiVersion: v1
kind: PersistentVolume
metadata:
name: example-pv
spec:
capacity:
storage: 100Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /mnt/disks/ssd1
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- example-node
É preciso definir a propriedade nodeAffinity do PersistentVolume ao utilizar volumes local. O escalonador do Kubernetes usa o PersistentVolume nodeAffinity para escalonar esses pods para o nó correto.
A propriedade volumeMode do PersistentVolume pode ser definida como "Block" (ao invés do valor padrão "Filesystem") para expor o volume local como um dispositivo de bloco bruto.
Ao usar volumes locais, é recomendável criar uma StorageClass com a propriedade volumeBindingMode definida como WaitForFirstConsumer. Para obter mais detalhes, consulte o exemplo local StorageClass. A postergação da vinculação do volume garante que a decisão de vinculação da PersistentVolumeClaim também será avaliada com quaisquer outras restrições de nós que o Pod possa ter, tais como requisitos de recursos de nós, seletores de nós, afinidade do Pod e anti afinidade do Pod.
Um provisionador estático externo pode ser executado separadamente para uma melhor gestão do ciclo de vida do volume local. Observe que este provisionador ainda não suporta o provisionamento dinâmico. Para um exemplo sobre como executar um provisionador local externo, veja o manual do usuário do provisionador local do volume.
Um volume nfs permite que um compartilhamento NFS (Network File System) existente seja montado em um Pod. Ao contrário do emptyDir que é apagado quando um Pod é removido, o conteúdo de um volume nfs é preservado e o volume é simplesmente desmontado. Isto significa que um volume NFS pode ser previamente populado com dados e que os dados podem ser compartilhados entre os Pods. O NFS pode ser montado por vários gravadores simultaneamente.
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: registry.k8s.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /my-nfs-data
name: test-volume
volumes:
- name: test-volume
nfs:
server: my-nfs-server.example.com
path: /my-nfs-volume
readOnly: true
Você deve ter seu próprio servidor NFS rodando com o compartilhamento acessível antes de poder utilizá-lo.
Note também que você não pode especificar opções de montagem NFS em uma especificação de pod. Você pode definir as opções de montagem do lado do servidor ou usar /etc/nfsmount.conf. Você também pode montar volumes NFS por meio de PersistentVolumes, que permitem definir opções de montagem.
Um volume persistentVolumeClaim é usado para montar um PersistentVolume em um Pod. PersistentVolumeClaims são uma forma de os usuários "solicitarem" armazenamento durável (como um GCE PersistentDisk ou um volume iSCSI) sem conhecerem os detalhes do ambiente de nuvem em particular.
Consulte as informações sobre PersistentVolumes para obter mais detalhes.
Um portworxVolume é uma camada de armazenamento em bloco extensível que funciona hiperconvergente com Kubernetes. O Portworx tira as impressões digitais de um armazenamento em um servidor, organiza com base nas capacidades e agrega capacidade em múltiplos servidores. Portworx funciona em máquinas virtuais ou em nós Linux bare-metal.
Um portworxVolume pode ser criado dinamicamente através do Kubernetes ou também pode ser previamente provisionado e referenciado dentro de um Pod. Aqui está um exemplo de um Pod referenciando um volume Portworx pré-provisionado:
apiVersion: v1
kind: Pod
metadata:
name: test-portworx-volume-pod
spec:
containers:
- image: registry.k8s.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /mnt
name: pxvol
volumes:
- name: pxvol
# Este volume Portworx já deve existir.
portworxVolume:
volumeID: "pxvol"
fsType: "<fs-type>"
pxvol antes de usá-lo no Pod.Um volume projetado mapeia várias fontes de volume existentes dentro do mesmo diretório. Para obter mais detalhes, consulte Volumes projetados.
Um Volume quobyte permite que um volume Quobyte existente seja montado no seu Pod.
Quobyte oferece suporte para o Container Storage Interface. CSI é o plugin recomendado para usar volumes Quobyte dentro de Kubernetes. O projeto GitHub da Quobyte tem instruções para implantar o Quobyte usando o CSI, acompanhado de exemplos.
Um volume rbd permite que um volume Rados Block Device (RBD) seja montado em seu Pod. Ao contrário do emptyDir que é apagado quando um pod é removido, o conteúdo de um volume rbd é preservado e o volume é desmontado. Isto significa que um volume RBD pode ser previamente populado com dados e que os dados podem ser compartilhados entre os Pods.
Uma caraterística do RBD é que ele pode ser montado como somente leitura por vários consumidores simultaneamente. Isto significa que um volume pode ser previamente populado com seu conjunto de dados e, em seguida, ser disponibilizado em paralelo para tantos pods quanto necessitar. Infelizmente, os volumes RBD só podem ser montados por um único consumidor no modo de leitura-escrita. Não são permitidos gravadores simultâneos.
Consulte o exemplo RBD para obter mais detalhes.
Kubernetes v1.23 [alpha]
Quando o recurso CSIMigration do RBD está ativado, redireciona todas as operações do plugin in-tree existente para o driver CSI rbd.csi.ceph.com. Para utilizar este recurso, o driver Ceph CSI deve estar instalado no cluster e as feature gates CSIMigration e csiMigrationRBD devem estar habilitadas.
Como operador do cluster Kubernetes que administra o armazenamento, aqui estão os pré-requisitos que você deve atender antes de tentar a migração para o driver CSI RBD:
rbd.csi.ceph.com), v3.5.0 ou superior, no cluster Kubernetes.clusterID é um parâmetro necessário para o driver CSI e sua operação , mas o campo in-tree StorageClass tem o parâmetro obrigatório monitors, um administrador de armazenamento Kubernetes precisa criar um clusterID baseado no hash dos monitores (ex.:#echo -n '<monitors_string>' | md5sum) no mapa de configuração do CSI e manter os monitores sob esta configuração de clusterID.adminId no Storageclass in-tree for diferente de admin, o adminSecretName mencionado no Storageclass in-tree tem que ser corrigido com o valor base64 do valor do parâmetro adminId, caso contrário esta etapa pode ser ignorada.Um volume secret é usado para passar informações sensíveis, tais como senhas, para Pods. Você pode armazenar segredos na API Kubernetes e montá-los como arquivos para serem usados por pods sem necessidade de vinculação direta ao Kubernetes. Volumes secret são mantidos pelo tmpfs (um sistema de arquivos com baseado em memória RAM) para que nunca sejam gravados em armazenamento não volátil.
readOnly.subPath não receberá atualizações deste Secret.Para obter mais detalhes, consulte Configurando Secrets.
Um volume storageos permite que um volume StorageOS existente seja montado em seu Pod.
O StorageOS funciona como um contêiner dentro de seu ambiente Kubernetes, tornando o armazenamento local ou anexado acessível a partir de qualquer nó dentro do cluster Kubernetes. Os dados podem ser replicados para a proteção contra falhas do nó. O provisionamento e a compressão podem melhorar a utilização e reduzir os custos.
Em sua essência, o StorageOS fornece armazenamento em bloco para contêineres, acessível a partir de um sistema de arquivo.
O Conteiner StorageOS requer Linux de 64 bits e não possui dependências adicionais. Uma licença para desenvolvedores está disponível gratuitamente.
O exemplo a seguir é uma configuração do Pod com StorageOS:
apiVersion: v1
kind: Pod
metadata:
labels:
name: redis
role: master
name: test-storageos-redis
spec:
containers:
- name: master
image: kubernetes/redis:v1
env:
- name: MASTER
value: "true"
ports:
- containerPort: 6379
volumeMounts:
- mountPath: /redis-master-data
name: redis-data
volumes:
- name: redis-data
storageos:
# O volume `redis-vol01` já deve existir dentro do StorageOS no namespace `default`.
volumeName: redis-vol01
fsType: ext4
Para obter mais informações sobre StorageOS, provisionamento dinâmico e PersistentVolumeClaims, consulte os exemplos do StorageOS.
Um vsphereVolume é usado para montar um volume VMDK do vSphere em seu Pod. O conteúdo de um volume é preservado quando é desmontado. Ele suporta sistemas de armazenamento de dados tanto do tipo VMFS quanto do tipo VSAN.
Para obter mais informações, consulte os exemplos vSphere volume
Escolha um dos seguintes métodos para criar um VMDK.
Primeiro acesse o ESX via ssh, depois use o seguinte comando para criar um VMDK:
vmkfstools -c 2G /vmfs/volumes/DatastoreName/volumes/myDisk.vmdk
Utilize o seguinte comando para criar um VMDK:
vmware-vdiskmanager -c -t 0 -s 40GB -a lsilogic myDisk.vmdk
apiVersion: v1
kind: Pod
metadata:
name: test-vmdk
spec:
containers:
- image: registry.k8s.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-vmdk
name: test-volume
volumes:
- name: test-volume
# This VMDK volume must already exist.
vsphereVolume:
volumePath: "[DatastoreName] volumes/myDisk"
fsType: ext4
Para obter mais informações, consulte os exemplos de volume do vSphere .
Kubernetes v1.26 [stable]
No Kubernetes 1.27, todas as operações para o tipo vsphereVolume in-tree são redirecionadas para o driver CSI csi.vsphere.vmware.com.
O driver vSphere CSI deve ser instalado no cluster. Você pode encontrar conteúdos adicionais sobre como migrar o vsphereVolume in-tree na página de documentação do VMware Migrating In-Tree vSphere Volumes to vSphere Container Storage plug-in. Se o vSphere CSI Driver não estiver instalado, as operações de volume não poderão ser executadas no PV criado com o tipo vsphereVolume in-tree.
Você deve executar o vSphere 7.0u2 ou posterior para migrar para o driver vSphere CSI.
Se você estiver executando uma versão do Kubernetes diferente da v1.27, consulte a documentação dessa versão do Kubernetes.
Os seguintes parâmetros da StorageClass do plugin integrado vsphereVolume não são suportados pelo driver CSI do vSphere:
diskformathostfailurestotolerateforceprovisioningcachereservationdiskstripesobjectspacereservationiopslimitOs volumes existentes criados usando esses parâmetros serão migrados para o driver CSI do vSphere, mas novos volumes criados pelo driver de CSI do vSphere não estarão respeitando esses parâmetros.
Kubernetes v1.19 [beta]
Para desativar o carregamento do plugin de armazenamento vsphereVolume pelo gerenciador de controladores e pelo kubelet, defina a flag InTreePluginvSphereUnregister como true. Você precisa instalar o driver csi.vsphere.vmware.com CSI em todos os nós de processamento.
Kubernetes v1.25 [beta]
O recurso CSIMigration para Portworx foi adicionado, mas desativado por padrão no Kubernetes 1.23 visto que está no estado alfa. Ele redireciona todas as operações de plugin do tipo in-tree para o Driver de Cointainer Storage Interface (CSI) pxd.portworx.com. O driver CSI Portworx deve ser instalado no cluster. Para ativar o recurso, defina CSIMigrationPortworx=true no kube-controller-manager e no kubelet.
Às vezes, é útil compartilhar um volume para múltiplos usos em um único pod. A propriedade volumeMounts[*].subPath especifica um sub caminho dentro do volume referenciado em vez de sua raiz.
O exemplo a seguir mostra como configurar um Pod com um ambiente LAMP (Linux, Apache, MySQL e PHP) usando um único volume compartilhado. Esta exemplo de configuração subPath não é recomendada para uso em produção.
O código e os ativos da aplicação PHP mapeiam para a pasta do volume html e o banco de dados MySQL é armazenado na pasta do volume mysql . Por exemplo:
apiVersion: v1
kind: Pod
metadata:
name: my-lamp-site
spec:
containers:
- name: mysql
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "rootpasswd"
volumeMounts:
- mountPath: /var/lib/mysql
name: site-data
subPath: mysql
- name: php
image: php:7.0-apache
volumeMounts:
- mountPath: /var/www/html
name: site-data
subPath: html
volumes:
- name: site-data
persistentVolumeClaim:
claimName: my-lamp-site-data
Kubernetes v1.17 [stable]
Use o campo subPathExpr para construir nomes de diretório subPath a partir de variáveis de ambiente da downward API. As propriedades subPath e subPathExpr são mutuamente exclusivas.
Neste exemplo, um Pod usa subPathExpr para criar um diretório pod1 dentro do volume hostPath /var/log/pods. O volume hostPathrecebe o nome Pod do downwardAPI. O diretório /var/log/pods/pod1 do host é montado em /logs no contêiner.
apiVersion: v1
kind: Pod
metadata:
name: pod1
spec:
containers:
- name: container1
env:
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
image: busybox:1.28
command: [ "sh", "-c", "while [ true ]; do echo 'Hello'; sleep 10; done | tee -a /logs/hello.txt" ]
volumeMounts:
- name: workdir1
mountPath: /logs
# A expansão de variáveis usa parênteses (não chaves).
subPathExpr: $(POD_NAME)
restartPolicy: Never
volumes:
- name: workdir1
hostPath:
path: /var/log/pods
A mídia de armazenamento(como Disco ou SSD) de um volume emptyDir é determinada por meio do sistema de arquivos que mantém o diretório raiz do kubelet (normalmente /var/lib/kubelet). Não há limite para quanto espaço um volume emptyDir ou hostPath podem consumir, e não há isolamento entre contêineres ou entre pods.
Para saber mais sobre como solicitar espaço usando uma especificação de recursos, consulte como gerenciar recursos.
Os plugins de volume out-of-tree incluem o Container Storage Interface (CSI) e também o FlexVolume (que foi descontinuado). Esses plugins permitem que os fornecedores de armazenamento criem plugins de armazenamento personalizados sem adicionar seu código-fonte do plugin ao repositório Kubernetes.
Anteriormente, todos os plugins de volume eram "in-tree". Os plugins "in-tree" eram construídos, vinculados, compilados e distribuídos com o código principal dos binários do Kubernetes. Isto significava que a adição de um novo sistema de armazenamento ao Kubernetes (um plugin de volume) exigia uma validação do código no repositório central de código Kubernetes.
Tanto o CSI quanto o FlexVolume permitem que os plugins de volume sejam desenvolvidos independentemente da base de código Kubernetes e implantados (instalados) nos clusters Kubernetes como extensões.
Para fornecedores de armazenamento que procuram criar um plugin de volume out-of-tree, consulte as Perguntas mais frequentes sobre plugins de volume.
O Cointainer Storage Interface (CSI) define uma interface padrão para sistemas de orquestração de contêineres (como Kubernetes) para expor sistemas de armazenamento arbitrários a suas cargas de trabalho de contêiner.
Leia a proposta de design CSI para obter mais informações.
Uma vez que um driver de volume compatível com CSI seja implantado em um cluster Kubernetes, os usuários podem usar o tipo de volume csi para anexar ou montar os volumes expostos pelo driver CSI.
Um volume csi pode ser utilizado em um Pod de três formas diferentes:
Os seguintes campos estão disponíveis para administradores de armazenamento configurarem um volume persistente de CSI:
driver: Um valor do tipo string que especifica o nome do driver de volume a ser usado. Este valor deve corresponder ao valor retornado no GetPluginInfoResponse pelo driver CSI, conforme definido na especificação CSI. Ele é usado pelo Kubernetes para identificar qual driver CSI chamar, e pelos componentes do driver CSI para identificar quais objetos PV pertencem ao driver CSI.volumeHandle: Um valor do tipo string que identifica exclusivamente o volume. Este valor deve corresponder ao valor retornado no campo volume.id em CreateVolumeResponse pelo driver CSI, conforme definido na especificação CSI. O valor é passado como volume_id em todas as chamadas para o driver de volume CSI quando se faz referência ao volume.readOnly: Um valor booleano opcional que indica se o volume deve ser "ControllerPublished" (anexado) como somente leitura. O valor padrão é false. Este valor é passado para o driver CSI através do campo readonly em ControllerPublishVolumeRequest.fsType: Se o VolumeMode do PV for Filesystem então este campo pode ser usado para especificar o sistema de arquivos que deve ser usado para montar o volume. Se o volume não tiver sido formatado e a formatação for suportada, este valor será utilizado para formatar o volume. Este valor é passado para o driver CSI através do campo VolumeCapability nas propriedades ControllerPublishVolumeRequest, NodeStageVolumeRequest e NodePublishVolumeRequest.volumeAttributes: Um mapa de valores do tipo string para string que especifica propriedades estáticas de um volume. Este mapa deve corresponder ao mapa retornado no campo volume.attributes do CreateVolumeResponse pelo driver CSI, conforme definido na especificação CSI. O mapa é passado para o driver CSI através do campo volume_context nas propriedades ControllerPublishVolumeRequest, NodeStageVolumeRequest, e NodePublishVolumeRequest.controllerPublishSecretRef: Uma referência ao objeto Secret que contém informações confidenciais para passar ao driver CSI para completar as chamadas CSI ControllerPublishVolume e ControllerUnpublishVolume. Este campo é opcional e pode estar vazio se não for necessário nenhum segredo. Se o Secret contiver mais de um segredo, todos os segredos serão passados.nodeStageSecretRef: Uma referência ao objeto Secret que contém informações confidenciais para passar ao driver de CSI para completar a chamada de CSI do NodeStageVolume. Este campo é opcional e pode estar vazio se não for necessário nenhum segredo. Se o Secret contiver mais de um segredo, todos os segredos serão passados.nodePublishSecretRef: Uma referência ao objeto Secret que contém informações confidenciais para passar ao driver de CSI para completar a chamada de CSI do NodePublishVolume. Este campo é opcional e pode estar vazio se não for necessário nenhum segredo. Se o objeto Secret contiver mais de um segredo, todos os segredos serão passados.Kubernetes v1.18 [stable]
Os fornecedores com drivers CSI externos podem implementar o suporte de volume de blocos brutos nas cargas de trabalho Kubernetes.
Você pode configurar o PersistentVolume/PersistentVolumeClaim com suporte de volume de bloco bruto , como habitualmente, sem quaisquer alterações específicas de CSI.
Kubernetes v1.25 [stable]
É possível configurar diretamente volumes CSI dentro da especificação do Pod. Os volumes especificados desta forma são efêmeros e não persistem nas reinicializações do pod. Consulte Volumes efêmeros para obter mais informações.
Para obter mais informações sobre como desenvolver um driver CSI, consulte a documentação kubernetes-csi
Kubernetes v1.25 [stable]
Quando o recurso CSIMigration está habilitado, direciona operações relacionadas a plugins in-tree existentes para plugins CSI correspondentes (que devem ser instalados e configurados). Como resultado, os operadores não precisam fazer nenhuma alteração de configuração para Storage Classes, PersistentVolumes ou PersistentVolumeClaims existentes (referindo-se aos plugins in-tree) quando a transição para um driver CSI que substitui um plugin in-tree.
As operações e características que são suportadas incluem: provisionamento/exclusão, anexação/remoção, montargem/desmontagem e redimensionamento de volumes.
Plugins in-tree que suportam CSIMigration e têm um driver CSI correspondente implementado são listados em tipos de volumes.
Os seguintes plug-ins in-tree suportam armazenamento persistente em nós do Windows:
Kubernetes v1.23 [deprecated]
O FlexVolume é uma interface de plugin out-of-tree que usa um modelo baseado em execução para fazer interface com drivers de armazenamento. Os binários do driver FlexVolume devem ser instalados em um caminho de plugin de volume predefinido em cada nó e, em alguns casos, também nos nós da camada de gerenciamento.
Os Pods interagem com os drivers do FlexVolume através do plugin de volume in-tree flexVolume. Para obter mais detalhes, consulte o documento README do FlexVolume.
O FlexVolume foi descontinuado. Usar um driver CSI out-of-tree é a maneira recomendada de integrar o armazenamento externo com Kubernetes.
Os mantenedores do driver FlexVolume devem implementar um driver CSI e ajudar a migrar usuários de drivers FlexVolume para CSI. Os usuários do FlexVolume devem mover suas cargas de trabalho para usar o driver CSI equivalente.
A propagação de montagem permite compartilhar volumes montados por um contêiner para outros contêineres no mesmo pod, ou mesmo para outros pods no mesmo nó.
A propagação de montagem de um volume é controlada pelo campo mountPropagation na propriedade containers[*].volumeMounts. Os seus valores são:
None - Este volume de montagem não receberá do host nenhuma montagem posterior que seja montada para este volume ou qualquer um de seus subdiretórios. De forma semelhante, nenhum ponto de montagem criado pelo contêiner será visível no host. Este é o modo padrão.
Este modo é igual à propagação de montagem private conforme descrito na documentação do kernel Linux
HostToContainer - Este volume de montagem receberá todas as montagens posteriores que forem montadas para este volume ou qualquer um de seus subdiretórios.
Em outras palavras, se o host montar qualquer coisa dentro do volume de montagem, o contêiner o visualizará montado ali.
Da mesma forma, se qualquer Pod com propagação de montagem Bidirectional para o mesmo volume montar qualquer coisa lá, o contêiner com propagação de montagem HostToContainer o reconhecerá.
Este modo é igual à propagação de montagem rslave conforme descrito na documentação do kernel Linux
Bidirectional - Esta montagem de volume se comporta da mesma forma que a montagem de volume HostToContainer. Além disso, todas as montagens de volume criadas pelo contêiner serão propagadas de volta ao host e a todos os contêineres de todas os pods que utilizam o mesmo volume.
Um caso de uso típico para este modo é um Pod com um driver FlexVolume ou CSI ou um Pod que precisa montar algo no host utilizando um volume hostPath.
Este modo é igual à propagação de montagem rshared conforme descrito na documentação do kernel Linux
Bidirectional pode ser perigosa. Ela pode danificar o sistema operacional do host e, portanto, ela só é permitida em contêineres privilegiados. A familiaridade com o comportamento do kernel Linux é fortemente recomendada. Além disso, quaisquer montagens de volume criadas por contêineres em pods devem ser destruídas ( desmontadas) pelos contêineres ao final.Antes que a propagação da montagem possa funcionar corretamente em algumas distribuições (CoreOS, RedHat/Centos, Ubuntu), o compartilhamento de montagem deve ser configurado corretamente no Docker como mostrado abaixo.
Edite seu arquivo de serviços systemd do Docker. Configure a propriedade MountFlags da seguinte forma:
MountFlags=shared
Ou, se a propriedade MountFlags=slaveexistir, remova-a. Em seguida, reinicie o daemon Docker:
sudo systemctl daemon-reload
sudo systemctl restart docker
Siga um exemplo de implantação do WordPress e MySQL com volumes persistentes.
Esse documento descreve o estado atual dos volumes persistentes no Kubernetes. Sugerimos que esteja familiarizado com volumes.
O gerenciamento de armazenamento é uma questão bem diferente do gerenciamento de instâncias computacionais. O subsistema PersistentVolume provê uma API para usuários e administradores que mostra de forma detalhada de como o armazenamento é provido e como ele é consumido. Para isso, nós introduzimos duas novas APIs: PersistentVolume e PersistentVolumeClaim.
Um PersistentVolume (PV) é uma parte do armazenamento dentro do cluster que tenha sido provisionada por um administrador, ou dinamicamente utilizando Classes de Armazenamento. Isso é um recurso dentro do cluster da mesma forma que um nó também é. PVs são plugins de volume da mesma forma que Volumes, porém eles têm um ciclo de vida independente de qualquer Pod que utilize um PV. Essa API tem por objetivo mostrar os detalhes da implementação do armazenamento, seja ele NFS, iSCSI, ou um armazenamento específico de um provedor de cloud pública.
Uma PersistentVolumeClaim (PVC) é uma requisição para armazenamento por um usuário. É similar a um Pod. Pods utilizam recursos do nó e PVCs utilizam recursos do PV. Pods podem solicitar níveis específicos de recursos (CPU e Memória). Claims podem solicitar tamanho e modos de acesso específicos (exemplo: montagem como ReadWriteOnce, ReadOnlyMany ou ReadWriteMany, veja Modos de Acesso).
Enquanto as PersistentVolumeClaims permitem que um usuário utilize recursos de armazenamento de forma limitada, é comum que usuários precisem de PersistentVolumes com diversas propriedades, como desempenho, para problemas diversos. Os administradores de cluster precisam estar aptos a oferecer uma variedade de PersistentVolumes que difiram em tamanho e modo de acesso, sem expor os usuários a detalhes de como esses volumes são implementados. Para necessidades como essas, temos o recurso de StorageClass.
Veja os exemplos de passo a passo de forma detalhada.
PVs são recursos dentro um cluster. PVCs são requisições para esses recursos e também atuam como uma validação da solicitação desses recursos. O ciclo de vida da interação entre PVs e PVCs funcionam da seguinte forma:
Existem duas formas de provisionar um PV: estaticamente ou dinamicamente.
O administrador do cluster cria uma determinada quantidade de PVs. Eles possuem todos os detalhes do armazenamento os quais estão atrelados, que neste caso fica disponível para utilização por um usuário dentro do cluster. Eles estão presentes na API do Kubernetes e disponíveis para utilização.
Quando nenhum dos PVs estáticos, que foram criados anteriormente pelo administrador, satisfazem os critérios de uma PersistentVolumeClaim enviado por um usuário, o cluster pode tentar realizar um provisionamento dinâmico para atender a essa PVC. Esse provisionamento é baseado em StorageClasses: a PVC deve solicitar uma classe de armazenamento e o administrador deve ter previamente criado e configurado essa classe para que o provisionamento dinâmico possa ocorrer. Requisições que solicitam a classe "" efetivamente desabilitam o provisionamento dinâmico para elas mesmas.
Para habilitar o provisionamento de armazenamento dinâmico baseado em classe de armazenamento, o administrador do cluster precisa habilitar o controle de admissão DefaultStorageClass no servidor da API. Isso pode ser feito, por exemplo, garantindo que DefaultStorageClass esteja entre aspas simples, ordenado por uma lista de valores para a flag --enable-admission-plugins, componente do servidor da API. Para mais informações sobre os comandos das flags do servidor da API, consulte a documentação kube-apiserver.
Um usuário cria, ou em caso de um provisionamento dinâmico já ter criado, uma PersistentVolumeClaim solicitando uma quantidade específica de armazenamento e um determinado modo de acesso. Um controle de loop no master monitora por novas PVCs, encontra um PV (se possível) que satisfaça os requisitos e realiza o bind. Se o PV foi provisionado dinamicamente por uma PVC, o loop sempre vai fazer o bind desse PV com essa PVC em específico. Caso contrário, o usuário vai receber no mínimo o que ele havia solicitado, porém, o volume possa exceder em relação à solicitação inicial. Uma vez realizado esse processo, PersistentVolumeClaim sempre vai ter um bind exclusivo, sem levar em conta como o isso aconteceu. Um bind entre uma PVC e um PV é um mapeamento de um para um, utilizando o ClaimRef que é um bind bidirecional entre o PersistentVolume e o PersistentVolumeClaim.
As requisições permanecerão sem bind se o volume solicitado não existir. O bind ocorrerá somente se os requisitos forem atendidos exatamente da mesma forma como solicitado. Por exemplo, um bind de uma PVC de 100 GB não ocorrerá num cluster que foi provisionado com vários PVs de 50 GB. O bind ocorrerá somente no momento em que um PV de 100 GB for adicionado.
Pods utilizam requisições como volumes. O cluster inspeciona a requisição para encontrar o volume atrelado a ela e monta esse volume para um Pod. Para volumes que suportam múltiplos modos de acesso, o usuário especifica qual o modo desejado quando utiliza essas requisições.
Uma vez que o usuário tem a requisição atrelada a um PV, ele pertence ao usuário pelo tempo que ele precisar. Usuários agendam Pods e acessam seus PVs requisitados através da seção persistentVolumeClaim no bloco volumes do Pod. Para mais detalhes sobre isso, veja Requisições como Volumes.
O propósito da funcionalidade do Objeto de Armazenamento em Proteção de Uso é garantir que as PersistentVolumeClaims (PVCs) que estejam sendo utilizadas por um Pod e PersistentVolume (PVs) que pertençam aos PVCs não sejam removidos do sistema, pois isso pode resultar numa perda de dados.
Se um usuário deleta uma PVC que está sendo utilizada por um Pod, esta PVC não é removida imediatamente. A remoção da PVC é adiada até que a PVC não esteja mais sendo utilizado por nenhum Pod. Se um administrador deleta um PV que está atrelado a uma PVC, o PV não é removido imediatamente também. A remoção do PV é adiada até que o PV não esteja mais atrelado à PVC.
Note que uma PVC é protegida quando o status da PVC é Terminating e a lista Finalizers contém kubernetes.io/pvc-protection:
kubectl describe pvc hostpath
Name: hostpath
Namespace: default
StorageClass: example-hostpath
Status: Terminating
Volume:
Labels: <none>
Annotations: volume.beta.kubernetes.io/storage-class=example-hostpath
volume.beta.kubernetes.io/storage-provisioner=example.com/hostpath
Finalizers: [kubernetes.io/pvc-protection]
...
Note que um PV é protegido quando o status da PVC é Terminating e a lista Finalizers contém kubernetes.io/pv-protection também:
kubectl describe pv task-pv-volume
Name: task-pv-volume
Labels: type=local
Annotations: <none>
Finalizers: [kubernetes.io/pv-protection]
StorageClass: standard
Status: Terminating
Claim:
Reclaim Policy: Delete
Access Modes: RWO
Capacity: 1Gi
Message:
Source:
Type: HostPath (bare host directory volume)
Path: /tmp/data
HostPathType:
Events: <none>
Quando um usuário não precisar mais utilizar um volume, ele pode deletar a PVC pela API, que, permite a recuperação do recurso. A política de recuperação para um PersistentVolume diz ao cluster o que fazer com o volume após ele ter sido liberado da sua requisição. Atualmente, volumes podem ser Retidos, Reciclados ou Deletados.
A política Retain permite a recuperação de forma manual do recurso. Quando a PersistentVolumeClaim é deletada, ela continua existindo e o volume é considerado "livre". Mas ele ainda não está disponível para outra requisição porque os dados da requisição anterior ainda permanecem no volume. Um administrador pode manualmente recuperar o volume executando os seguintes passos:
Para plugins de volume que suportam a política de recuperação Delete, a deleção vai remover o tanto o PersistentVolume do Kubernetes, quanto o armazenamento associado à infraestrutura externa, como AWS EBS, GCE PD, Azure Disk, ou Cinder volume. Volumes que foram provisionados dinamicamente herdam a política de retenção da sua StorageClass, que por padrão é Delete. O administrador precisa configurar a StorageClass de acordo com as necessidades dos usuários. Caso contrário, o PV deve ser editado ou reparado após sua criação. Veja Alterar a política de retenção de um PersistentVolume.
Recycle está depreciada. Ao invés disso, recomendamos a utilização de provisionamento dinâmico.Em caso do volume plugin ter suporte a essa operação, a política de retenção Recycle faz uma limpeza básica (rm -rf /thevolume/*) no volume e torna ele disponível novamente para outra requisição.
Contudo, um administrador pode configurar um template personalizado de um Pod reciclador utilizando a linha de comando do gerenciamento de controle do Kubernetes como descrito em referência.
O Pod reciclador personalizado deve conter a spec volume como é mostrado no exemplo abaixo:
apiVersion: v1
kind: Pod
metadata:
name: pv-recycler
namespace: default
spec:
restartPolicy: Never
volumes:
- name: vol
hostPath:
path: /any/path/it/will/be/replaced
containers:
- name: pv-recycler
image: "registry.k8s.io/busybox"
command: ["/bin/sh", "-c", "test -e /scrub && rm -rf /scrub/..?* /scrub/.[!.]* /scrub/* && test -z \"$(ls -A /scrub)\" || exit 1"]
volumeMounts:
- name: vol
mountPath: /scrub
Contudo, o caminho especificado no Pod reciclador personalizado em volumes é substituído pelo caminho do volume que está sendo reciclado.
A camada de gerenciamento pode fazer o bind de um PersistentVolumeClaims com PersistentVolumes equivalentes no cluster. Contudo, se você quer que uma PVC faça um bind com um PV específico, é preciso fazer o pré-bind deles.
Especificando um PersistentVolume na PersistentVolumeClaim, você declara um bind entre uma PVC e um PV específico. O bind ocorrerá se o PersistentVolume existir e não estiver reservado por uma PersistentVolumeClaims através do seu campo claimRef.
O bind ocorre independentemente se algum volume atender ao critério, incluindo afinidade de nó. A camada de gerenciamento verifica se a classe de armazenamento, modo de acesso e tamanho do armazenamento solicitado ainda são válidos.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: foo-pvc
namespace: foo
spec:
storageClassName: "" # Empty string must be explicitly set otherwise default StorageClass will be set
volumeName: foo-pv
...
Esse método não garante nenhum privilégio de bind no PersistentVolume. Para evitar que alguma outra PersistentVolumeClaims possa usar o PV que você especificar, você precisa primeiro reservar esse volume de armazenamento. Especifique sua PersistentVolumeClaim no campo claimRef do PV para que outras PVCs não façam bind nele.
apiVersion: v1
kind: PersistentVolume
metadata:
name: foo-pv
spec:
storageClassName: ""
claimRef:
name: foo-pvc
namespace: foo
...
Isso é útil se você deseja utilizar PersistentVolumes que possuem suas persistentVolumeReclaimPolicy configuradas para Retain, incluindo situações onde você estiver reutilizando um PV existente.
Kubernetes v1.24 [stable]
Agora, o suporte à expansão de PersistentVolumeClaims (PVCs) já é habilitado por padrão. Você pode expandir os tipos de volumes abaixo:
Você só pode expandir uma PVC se o campo da classe de armazenamento allowVolumeExpansion é true.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gluster-vol-default
provisioner: kubernetes.io/glusterfs
parameters:
resturl: "http://192.168.10.100:8080"
restusuário: ""
secretNamespace: ""
secretName: ""
allowVolumeExpansion: true
Para solicitar um volume maior para uma PVC, edite a PVC e especifique um tamanho maior. Isso irá fazer com o que volume atrelado ao respectivo PersistentVolume seja expandido. Nunca um PersistentVolume é criado para satisfazer a requisição. Ao invés disso, um volume existente é redimensionado.
Kubernetes v1.24 [stable]
O suporte à expansão de volumes CSI é habilitada por padrão, porém é necessário um driver CSI específico para suportar a expansão do volume. Verifique a documentação do driver CSI específico para mais informações.
Só podem ser redimensionados os volumes que contém os seguintes sistemas de arquivo: XFS, Ext3 ou Ext4.
Quando um volume contém um sistema de arquivo, o sistema de arquivo somente é redimensionado quando um novo Pod está utilizando a PersistentVolumeClaim no modo ReadWrite. A expansão de sistema de arquivo é feita quando um Pod estiver inicializando ou quando um Pod estiver em execução e o respectivo sistema de arquivo tenha suporte para expansão a quente.
FlexVolumes permitem redimensionamento se o RequiresFSResize do drive é configurado como true. O FlexVolume pode ser redimensionado na reinicialização do Pod.
Kubernetes v1.15 [beta]
ExpandInUsePersistentVolumes precisa ser habilitada, o que já está automático para vários clusters que possuem funcionalidades beta. Verifique a documentação feature gate para mais informações.Neste caso, você não precisa deletar e recriar um Pod ou um deployment que está sendo utilizado por uma PVC existente. Automaticamente, qualquer PVC em uso fica disponível para o Pod assim que o sistema de arquivo for expandido. Essa funcionalidade não tem efeito em PVCs que não estão em uso por um Pod ou deployment. Você deve criar um Pod que utilize a PVC antes que a expansão seja completada.
Da mesma forma que outros tipos de volumes - volumes FlexVolume também podem ser expandidos quando estiverem em uso por um Pod.
Se a expansão do respectivo armazenamento falhar, o administrador do cluster pode recuperar manualmente o estado da Persistent Volume Claim (PVC) e cancelar as solicitações de redimensionamento. Caso contrário, as tentativas de solicitação de redimensionamento ocorrerão de forma contínua pelo controlador sem nenhuma intervenção do administrador.
Retain.Retain - nenhum dado será perdido quando a PVC for recriada.claimRef da especificação do PV para que uma PVC possa fazer bind com ele. Isso deve tornar o PV Available.volumeName da PCV com o nome do PV. Isso deve fazer o bind de uma nova PVC a um PV existente.Tipos de PersistentVolume são implementados como plugins. Atualmente o Kubernetes suporta os plugins abaixo:
awsElasticBlockStore - AWS Elastic Block Store (EBS)azureDisk - Azure DiskazureFile - Azure Filecephfs - CephFS volumecinder - Cinder (OpenStack block storage)
(depreciado)csi - Container Storage Interface (CSI)fc - Fibre Channel (FC) storageflexVolume - FlexVolumeflocker - Flocker storagegcePersistentDisk - GCE Persistent Diskglusterfs - Glusterfs volumehostPath - HostPath volume
(somente para teste de nó único; ISSO NÃO FUNCIONARÁ num cluster multi-nós; ao invés disso, considere a utilização de volume local.)iscsi - iSCSI (SCSI over IP) storagelocal - storage local montados nos nós.nfs - Network File System (NFS) storagephotonPersistentDisk - Controlador Photon para disco persistente.
(Esse tipo de volume não funciona mais desde a removação do provedor de cloud correspondente.)portworxVolume - Volume Portworxquobyte - Volume Quobyterbd - Volume Rados Block Device (RBD)scaleIO - Volume ScaleIO
(depreciado)storageos - Volume StorageOSvsphereVolume - Volume vSphere VMDKCada PV contém uma spec e um status, que é a especificação e o status do volume. O nome do PersistentVolume deve ser um DNS válido.
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0003
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: slow
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: /tmp
server: 172.17.0.2
Geralmente, um PV terá uma capacidade de armazenamento específica. Isso é configurado usando o atributo capacity do PV. Veja o Modelo de Recurso do Kubernetes para entender as unidades aceitas pelo atributo capacity.
Atualmente, o tamanho do armazenamento é o único recurso que pode ser configurado ou solicitado. Os futuros atributos podem incluir IOPS, throughput, etc.
Kubernetes v1.18 [stable]
O Kubernetes suporta dois volumeModes de PersistentVolumes: Filesystem e Block.
volumeMode é um parâmetro opcional da API.
Filesystem é o modo padrão utilizado quando o parâmetro volumeMode é omitido.
Um volume com volumeMode: Filesystem é montado em um diretório nos Pods. Se o volume for de um dispositivo de bloco e ele estiver vazio, o Kubernetes cria o sistema de arquivo no dispositivo antes de fazer a montagem pela primeira vez.
Você pode configurar o valor do volumeMode para Block para utilizar um disco bruto como volume. Esse volume é apresentado num Pod como um dispositivo de bloco, sem nenhum sistema de arquivo. Esse modo é útil para prover ao Pod a forma mais rápida para acessar um volume, sem nenhuma camada de sistema de arquivo entre o Pod e o volume. Por outro lado, a aplicação que estiver rodando no Pod deverá saber como tratar um dispositivo de bloco. Veja Suporte a Volume de Bloco Bruto para um exemplo de como utilizar o volume como volumeMode: Block num Pod.
Um PersistentVolume pode ser montado num host das mais variadas formas suportadas pelo provedor. Como mostrado na tabela abaixo, os provedores terão diferentes capacidades e cada modo de acesso do PV são configurados nos modos específicos suportados para cada volume em particular. Por exemplo, o NFS pode suportar múltiplos clientes read/write, mas um PV NFS específico pode ser exportado no server como read-only. Cada PV recebe seu próprio modo de acesso que descreve suas capacidades específicas.
Os modos de acesso são:
Na linha de comando, os modos de acesso ficam abreviados:
Importante! Um volume somente pode ser montado utilizando um único modo de acesso por vez, independente se ele suportar mais de um. Por exemplo, um GCEPersistentDisk pode ser montado como ReadWriteOnce por um único nó ou ReadOnlyMany por vários nós, porém não simultaneamente.
| Plugin de Volume | ReadWriteOnce | ReadOnlyMany | ReadWriteMany |
|---|---|---|---|
| AWSElasticBlockStore | ✓ | - | - |
| AzureFile | ✓ | ✓ | ✓ |
| AzureDisk | ✓ | - | - |
| CephFS | ✓ | ✓ | ✓ |
| Cinder | ✓ | - | - |
| CSI | depende do driver | depende do driver | depende do driver |
| FC | ✓ | ✓ | - |
| FlexVolume | ✓ | ✓ | depende do driver |
| Flocker | ✓ | - | - |
| GCEPersistentDisk | ✓ | ✓ | - |
| Glusterfs | ✓ | ✓ | ✓ |
| HostPath | ✓ | - | - |
| iSCSI | ✓ | ✓ | - |
| Quobyte | ✓ | ✓ | ✓ |
| NFS | ✓ | ✓ | ✓ |
| RBD | ✓ | ✓ | - |
| VsphereVolume | ✓ | - | (funcionam quando os Pods são do tipo collocated) |
| PortworxVolume | ✓ | - | ✓ |
| ScaleIO | ✓ | ✓ | - |
| StorageOS | ✓ | - | - |
Um PV pode ter uma classe, que é especificada na configuração do atributo storageClassName com o nome da StorageClass. Um PV de uma classe específica só pode ser atrelado a requisições PVCs dessa mesma classe. Um PV sem storageClassName não possui nenhuma classe e pode ser montado somente a PVCs que não solicitem nenhuma classe em específico.
No passado, a notação volume.beta.kubernetes.io/storage-class era utilizada no lugar do atributo storageClassName. Essa notação ainda funciona. Contudo, ela será totalmente depreciada numa futura versão do Kubernetes.
Atualmente as políticas de retenção são:
rm -rf /thevolume/*)Atualmente, somente NFS e HostPath suportam reciclagem. Volumes AWS EBS, GCE PD, Azure Disk e Cinder suportam delete.
Um administrador do Kubernetes pode especificar opções de montagem adicionais quando um Volume Persistente é montado num nó.
Seguem os tipos de volumes que suportam opções de montagem.
Não há validação em relação às opções de montagem. A montagem irá falhar se houver alguma opção inválida.
No passado, a notação volume.beta.kubernetes.io/mount-options era usada no lugar do atributo mountOptions. Essa notação ainda funciona. Contudo, ela será totalmente depreciada numa futura versão do Kubernetes.
Um PV pode especificar uma afinidade de nó para definir restrições em relação ao limite de nós que podem acessar esse volume. Pods que utilizam um PV serão somente reservados para nós selecionados pela afinidade de nó.
Um volume sempre estará em um dos seguintes estados:
A CLI mostrará o nome do PV que foi atrelado à PVC
Cada PVC contém uma spec e um status, que é a especificação e estado de uma requisição. O nome de um objeto PersistentVolumeClaim precisa ser um DNS válido.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 8Gi
storageClassName: slow
selector:
matchLabels:
release: "stable"
matchExpressions:
- {key: environment, operator: In, values: [dev]}
As requisições usam as mesmas convenções que os volumes quando eles solicitam um armazenamento com um modo de acesso específico.
As requisições usam as mesmas convenções que os volumes quando eles indicam o tipo de volume, seja ele um sistema de arquivo ou dispositivo de bloco.
Assim como Pods, as requisições podem solicitar quantidades específicas de recurso. Neste caso, a solicitação é por armazenamento. O mesmo modelo de recurso vale para volumes e requisições.
Requisições podem especifiar um seletor de rótulo para posteriormente filtrar um grupo de volumes. Somente os volumes que possuam rótulos que satisfaçam os critérios do seletor podem ser atrelados à requisição. O seletor pode conter dois campos:
matchLabels - o volume deve ter um rótulo com esse valormatchExpressions - uma lista de requisitos, como chave, lista de valores e operador relacionado aos valores e chaves. São operadores válidos: In, NotIn, Exists e DoesNotExist.Todos os requisitos de matchLabels e matchExpressions, são do tipo AND - todos eles juntos devem ser atendidos.
Uma requisição pode solicitar uma classe específica através da StorageClass utilizando o atributo storageClassName. Neste caso o bind ocorrerá somente com os PVs que possuírem a mesma classe do storageClassName dos PVCs.
As PVCs não precisam necessariamente solicitar uma classe. Uma PVC com sua storageClassName configurada como "" sempre solicitará um PV sem classe, dessa forma ela sempre será atrelada a um PV sem classe (que não tenha nenhuma notação, ou seja, igual a ""). Uma PVC sem storageClassName não é a mesma coisa e será tratada pelo cluster de forma diferente, porém isso dependerá se o puglin de admissão DefaultStorageClass estiver habilitado.
storageClassName podem ser atreladas somente a PVs que atendam a esse padrão. A especificação de uma StorageClass padrão é feita através da notação storageclass.kubernetes.io/is-default-class recebendo o valor true no objeto da StorageClass. Se o administrador não especificar nenhum padrão, o cluster vai tratar a criação de uma PVC como se o plugin de admissão estivesse desabilitado. Se mais de um valor padrão for especificado, o plugin de admissão proíbe a criação de todas as PVCs.storageClassName poderão ser atreladas somente aos PVs que não possuem classe. Neste caso, as PVCs que não tiverem storageClassName são tratadas da mesma forma como as PVCs que possuem suas storageClassName configuradas como "".Dependendo do modo de instalação, uma StorageClass padrão pode ser implantada num cluster Kubernetes durante a instalação pelo addon manager.
Quando uma PVC especifica um selector para solicitar uma StorageClass, os requisitos são do tipo AND: somente um PV com a classe solicitada e com o rótulo requisitado pode ser atrelado à PVC.
selector não pode ter um PV dinamicamente provisionado.No passado, a notação volume.beta.kubernetes.io/storage-class era usada no lugar do atributo storageClassName Essa notação ainda funciona. Contudo, ela será totalmente depreciada numa futura versão do Kubernetes.
Os Pods podem ter acesso ao armazenamento utilizando a requisição como um volume. Para isso, a requisição tem que estar no mesmo namespace que o Pod. Ao localizar a requisição no namespace do Pod, o cluster passa o PersistentVolume para a requisição.
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: myclaim
Os binds dos PersistentVolumes são exclusivos e, desde que as PersistentVolumeClaims são objetos do namespace, fazer a montagem das requisições com "Muitos" nós (ROX, RWX) é possível somente para um namespace.
hostPathUm PersistentVolume do tipo hostPath utiliza um arquivo ou diretório no nó para emular um network-attached storage (NAS). Veja um exemplo de volume do tipo hostPath.
Kubernetes v1.18 [stable]
Os plugins de volume abaixo suportam volumes de bloco bruto, incluindo provisionamento dinâmico onde for aplicável:
apiVersion: v1
kind: PersistentVolume
metadata:
name: block-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
volumeMode: Block
persistentVolumeReclaimPolicy: Retain
fc:
targetWWNs: ["50060e801049cfd1"]
lun: 0
readOnly: false
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: block-pvc
spec:
accessModes:
- ReadWriteOnce
volumeMode: Block
resources:
requests:
storage: 10Gi
apiVersion: v1
kind: Pod
metadata:
name: pod-with-block-volume
spec:
containers:
- name: fc-container
image: fedora:26
command: ["/bin/sh", "-c"]
args: [ "tail -f /dev/null" ]
volumeDevices:
- name: data
devicePath: /dev/xvda
volumes:
- name: data
persistentVolumeClaim:
claimName: block-pvc
Se um usuário solicita um volume de bloco bruto através do campo volumeMode na spec da PersistentVolumeClaim, as regras de bind agora têm uma pequena diferença em relação às versões anteriores que não consideravam esse modo como parte da spec.
A tabela abaixo mostra as possíveis combinações que um usuário e um administrador pode especificar para requisitar um dispositivo de bloco bruto. A tabela indica se o volume será ou não atrelado com base nas combinações:
Matriz de bind de volume para provisionamento estático de volumes:
| PV volumeMode | PVC volumeMode | Result |
|---|---|---|
| unspecified | unspecified | BIND |
| unspecified | Block | NO BIND |
| unspecified | Filesystem | BIND |
| Block | unspecified | NO BIND |
| Block | Block | BIND |
| Block | Filesystem | NO BIND |
| Filesystem | Filesystem | BIND |
| Filesystem | Block | NO BIND |
| Filesystem | unspecified | BIND |
Kubernetes v1.20 [stable]
O snapshot de volume é suportado somente pelo plugin de volume CSI. Veja Snapshot de Volume para mais detalhes. Plugins de volume in-tree estão depreciados. Você pode consultar sobre os plugins de volume depreciados em Perguntas Frequentes sobre Plugins de Volume.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: restore-pvc
spec:
storageClassName: csi-hostpath-sc
dataSource:
name: new-snapshot-test
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
A Clonagem de Volume é possível somente com plugins de volume CSI.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: cloned-pvc
spec:
storageClassName: my-csi-plugin
dataSource:
name: existing-src-pvc-name
kind: PersistentVolumeClaim
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
Se você está criando templates ou exemplos que rodam numa grande quantidade de clusters e que precisam de armazenamento persistente, recomendamos que utilize o padrão abaixo:
Inclua objetos PersistentVolumeClaim em seu pacote de configuração (com Deployments, ConfigMaps, etc.).
Não inclua objetos PersistentVolume na configuração, pois o usuário que irá instanciar a configuração talvez não tenha permissão para criar PersistentVolume.
Dê ao usuário a opção dele informar o nome de uma classe de armazenamento quando instanciar o template.
persistentVolumeClaim.storageClassName. Isso fará com que a PVC encontre a classe de armazenamento correta se o cluster tiver a StorageClasses habilitado pelo administrador.persistentVolumeClaim.storageClassName sem nenhum valor (vazio). Isso fará com que o PV seja provisionado automaticamente no cluster para o usuário com o StorageClass padrão. Muitos ambientes de cluster já possuem uma StorageClass padrão, ou então os administradores podem criar suas StorageClass de acordo com seus critérios.Durante suas tarefas de administração, busque por PVCs que após um tempo não estão sendo atreladas, pois, isso talvez indique que o cluster não tem provisionamento dinâmico (onde o usuário deveria criar um PV que satisfaça os critérios da PVC) ou cluster não tem um sistema de armazenamento (onde usuário não pode realizar um deploy solicitando PVCs).
Esse documento destaca e consolida as melhores práticas de configuração apresentadas em todo o guia de usuário, na documentação de introdução e nos exemplos.
Este é um documento vivo. Se você pensar em algo que não está nesta lista, mas pode ser útil para outras pessoas, não hesite em criar uma issue ou submeter um PR.
Ao definir configurações, especifique a versão mais recente estável da API.
Os arquivos de configuração devem ser armazenados em um sistema de controle antes de serem enviados ao cluster. Isso permite que você reverta rapidamente uma alteração de configuração, caso necessário. Isso também auxilia na recriação e restauração do cluster.
Escreva seus arquivos de configuração usando YAML ao invés de JSON. Embora esses formatos possam ser usados alternadamente em quase todos os cenários, YAML tende a ser mais amigável.
Agrupe objetos relacionados em um único arquivo sempre que fizer sentido. Geralmente, um arquivo é mais fácil de gerenciar do que vários. Veja o guestbook-all-in-one.yaml como exemplo dessa sintaxe.
Observe também que vários comandos kubectl podem ser chamados em um diretório. Por exemplo, você pode chamar
kubectl apply em um diretório de arquivos de configuração.
Não especifique valores padrões desnecessariamente: configurações simples e mínimas diminuem a possibilidade de erros.
Coloque descrições de objetos nas anotações para permitir uma melhor análise.
Se você puder evitar, não use "naked" Pods (ou seja, se você puder evitar, pods não vinculados a um ReplicaSet ou Deployment). Os "naked" pods não serão reconfigurados em caso de falha de um nó.
Criar um Deployment, que cria um ReplicaSet para garantir que o número desejado de Pods esteja disponível e especifica uma estratégia para substituir os Pods (como RollingUpdate), é quase sempre preferível do que criar Pods diretamente, exceto para alguns cenários explícitos de restartPolicy:Never. Um Job também pode ser apropriado.
Crie o Service antes de suas cargas de trabalho de backend correspondentes (Deployments ou ReplicaSets) e antes de quaisquer cargas de trabalho que precisem acessá-lo. Quando o
Kubernetes inicia um contêiner, ele fornece variáveis de ambiente apontando para todos os Services que estavam em execução quando o contêiner foi iniciado. Por exemplo, se um Service chamado foo existe, todos os contêineres vão
receber as seguintes variáveis em seu ambiente inicial:
FOO_SERVICE_HOST=<o host em que o Service está executando>
FOO_SERVICE_PORT=<a porta em que o Service está executando>
Isso implica em um requisito de pedido - qualquer Service que um Pod quer acessar precisa ser criado antes do Pod em si, ou então as variáveis de ambiente não serão populadas. O DNS não possui essa restrição.
Um cluster add-on opcional (embora fortemente recomendado) é um servidor DNS. O
servidor DNS monitora a API do Kubernetes buscando novos Services e cria um conjunto de DNS para cada um. Se o DNS foi habilitado em todo o cluster, então todos os Pods devem ser capazes de fazer a resolução de Services automaticamente.
Não especifique um hostPort para um Pod a menos que isso seja absolutamente necessário. Quando você vincula um Pod a um hostPort, isso limita o número de lugares em que o Pod pode ser agendado, porque cada
combinação de <hostIP, hostPort, protocol> deve ser única. Se você não especificar o hostIP e protocol explicitamente, o Kubernetes vai usar 0.0.0.0 como o hostIP padrão e TCP como protocol padrão.
Se você precisa de acesso a porta apenas para fins de depuração, pode usar o apiserver proxy ou o kubectl port-forward.
Se você precisa expor explicitamente a porta de um Pod no nó, considere usar um Service do tipo NodePort antes de recorrer a hostPort.
Evite usar hostNetwork pelos mesmos motivos do hostPort.
Use headless Services (que tem um ClusterIP ou None) para descoberta de serviço quando você não precisar de um balanceador de carga kube-proxy.
{ app: myapp, tier: frontend, phase: test, deployment: v3 }. Você pode usar essas labels para selecionar os Pods apropriados para outros recursos; por exemplo, um Service que seleciona todos os Pods tier: frontend, ou todos
os componentes de app: myapp. Veja o app guestbook para exemplos dessa abordagem.Um Service pode ser feito para abranger vários Deployments, omitindo labels específicas de lançamento de seu seletor. Quando você precisar atualizar um serviço em execução sem downtime, use um Deployment.
Um estado desejado de um objeto é descrito por um Deployment, e se as alterações nesse spec forem aplicadas o controlador do Deployment altera o estado real para o estado desejado em uma taxa controlada.
Use as labels comuns do Kubernetes para casos de uso comuns.
Essas labels padronizadas enriquecem os metadados de uma forma que permite que ferramentas, incluindo kubectl e a dashboard, funcionem de uma forma interoperável.
Você pode manipular labels para depuração. Como os controladores do Kubernetes (como ReplicaSet) e Services se relacionam com os Pods usando seletor de labels, remover as labels relevantes de um Pod impedirá que ele seja considerado por um controlador ou que
seja atendido pelo tráfego de um Service. Se você remover as labels de um Pod existente, seu controlador criará um novo Pod para
substituí-lo. Essa é uma maneira útil de depurar um Pod anteriormente "ativo" em um ambiente de "quarentena". Para remover ou
alterar labels interativamente, use kubectl label.
A imagePullPolicy e tag da imagem afetam quando o kubelet tenta puxar a imagem especificada.
imagePullPolicy: IfNotPresent: a imagem é puxada apenas se ainda não estiver presente localmente.
imagePullPolicy: Always: sempre que o kubelet inicia um contêiner, ele consulta o registry da imagem do contêiner para verificar o resumo de assinatura da imagem. Se o kubelet tiver uma imagem do contêiner com o mesmo resumo de assinatura
armazenado em cache localmente, o kubelet usará a imagem em cache, caso contrário, o kubelet baixa(pulls) a imagem com o resumo de assinatura resolvido, e usa essa imagem para iniciar o contêiner.
imagePullPolicy é omitido se a tag da imagem é :latest ou se imagePullPolicy é omitido é automaticamente definido como Always. Observe que não será utilizado para ifNotPresentse o valor da tag mudar.
imagePullPolicy é omitido se uma tag da imagem existe mas não :latest: imagePullPolicy é automaticamente definido como ifNotPresent. Observe que isto não será atualizado para Always se a tag for removida ou alterada para :latest.
imagePullPolicy: Never: presume-se que a imagem exista localmente. Não é feita nenhuma tentativa de puxar a imagem.
<nome-da-imagem>:<tag> por <nome-da-imagem>@<hash> (por exemplo, image@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2). Esse resumo de assinatura identifica exclusivamente uma versão
específica de uma imagem, então isso nunca vai ser atualizado pelo Kubernetes a menos que você mude o valor do resumo de assinatura da imagem.:latest em produção, pois é mais difícil rastrear qual versão da imagem está sendo executada e mais difícil reverter adequadamente.imagePullPolicy: Always eficiente, contanto que o registro esteja acessível de forma confiável. Com o Docker, por exemplo, se a imagem já existe, a tentativa de baixar(pull) é rápida porque todas as camadas da imagem são armazenadas em cache e nenhum download de imagem é necessário.Use kubectl apply -f <directory>. Isso procura por configurações do Kubernetes em todos os arquivos .yaml, .yml em <directory> e passa isso para apply.
Use labels selectors para operações get e delete em vez de nomes de objetos específicos. Consulte as seções sobre label selectors
e usando Labels efetivamente.
Use kubectl create deployment e kubectl expose para criar rapidamente Deployments e Services de um único contêiner. Consulte Use um Service para acessar uma aplicação em um cluster para obter um exemplo.
Um ConfigMap é um objeto da API usado para armazenar dados não-confidenciais em pares chave-valor. Pods podem consumir ConfigMaps como variáveis de ambiente, argumentos de linha de comando ou como arquivos de configuração em um volume.
Um ConfigMap ajuda a desacoplar configurações vinculadas ao ambiente das imagens de contêiner, de modo a tornar aplicações mais facilmente portáveis.
Utilize um ConfigMap para manter a configuração separada do código da aplicação.
Por exemplo, imagine que você esteja desenvolvendo uma aplicação que pode ser executada
no seu computador local (para desenvolvimento) e na nuvem (para manipular tráfego real).
Você escreve código para ler a variável de ambiente chamada DATABASE_HOST.
No seu ambiente local, você configura essa variável com o valor localhost. Na nuvem, você
configura essa variável para referenciar um serviço
do Kubernetes que expõe o componente do banco de dados ao seu cluster.
Isto permite que você baixe uma imagem de contêiner que roda na nuvem e depure exatamente
o mesmo código localmente se necessário.
Um ConfigMap não foi planejado para conter grandes quantidades de dados. Os dados armazenados em um ConfigMap não podem exceder 1 MiB. Se você precisa armazenar configurações que são maiores que este limite, considere montar um volume ou utilizar um serviço separado de banco de dados ou de arquivamento de dados.
Um ConfigMap é um objeto
da API que permite o armazenamento de configurações para consumo por outros objetos. Diferentemente
de outros objetos do Kubernetes que contém um campo spec, o ConfigMap contém os campos data e
binaryData. Estes campos aceitam pares chave-valor como valores. Ambos os campos data e binaryData
são opcionais. O campo data foi pensado para conter sequências de bytes UTF-8, enquanto o campo binaryData
foi planejado para conter dados binários em forma de strings codificadas em base64.
É obrigatório que o nome de um ConfigMap seja um subdomínio DNS válido.
Cada chave sob as seções data ou binaryData pode conter quaisquer caracteres alfanuméricos,
-, _ e .. As chaves armazenadas na seção data não podem colidir com as chaves armazenadas
na seção binaryData.
A partir da versão v1.19 do Kubernetes, é possível adicionar o campo immutable a uma definição de ConfigMap
para criar um ConfigMap imutável.
Você pode escrever uma spec para um Pod que se refere a um ConfigMap e configurar o(s) contêiner(es)
neste Pod baseados em dados do ConfigMap. O Pod e o ConfigMap devem estar no mesmo
namespace.
spec de um Pod estático não pode se referir a um
ConfigMap ou a quaisquer outros objetos da API.Exemplo de um ConfigMap que contém algumas chaves com valores avulsos e outras chaves com valores semelhantes a fragmentos de arquivos de configuração:
apiVersion: v1
kind: ConfigMap
metadata:
name: game-demo
data:
# chaves com valores de propriedades; cada chave mapeia para um valor avulso
player_initial_lives: "3"
ui_properties_file_name: "user-interface.properties"
# chaves semelhantes a fragmentos de arquivos
game.properties: |
enemy.types=aliens,monsters
player.maximum-lives=5
user-interface.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
Existem quatro formas diferentes para consumo de um ConfigMap na configuração de um contêiner dentro de um Pod:
Os diferentes métodos de consumo oferecem diferentes formas de modelar os dados sendo consumidos. Para os três primeiros métodos, o kubelet utiliza os dados de um ConfigMap quando o(s) contêiner(es) do Pod são inicializados.
O quarto método envolve escrita de código para leitura do ConfigMap e dos seus dados. No entanto, como a API do Kubernetes está sendo utilizada diretamente, a aplicação pode solicitar atualizações sempre que o ConfigMap for alterado e reagir quando isso ocorre. Acessar a API do Kubernetes diretamente também permite ler ConfigMaps em outros namespaces.
Exemplo de um Pod que utiliza valores do ConfigMap game-demo para configurar um Pod:
apiVersion: v1
kind: Pod
metadata:
name: configmap-demo-pod
spec:
containers:
- name: demo
image: alpine
command: ["sleep", "3600"]
env:
# Define as variáveis de ambiente
- name: PLAYER_INITIAL_LIVES # Note que aqui a variável está definida em caixa alta,
# diferente da chave no ConfigMap.
valueFrom:
configMapKeyRef:
name: game-demo # O ConfigMap de onde esse valor vem.
key: player_initial_lives # A chave que deve ser buscada.
- name: UI_PROPERTIES_FILE_NAME
valueFrom:
configMapKeyRef:
name: game-demo
key: ui_properties_file_name
volumeMounts:
- name: config
mountPath: "/config"
readOnly: true
volumes:
# Volumes são definidos no escopo do Pod, e os pontos de montagem são definidos
# nos contêineres dentro dos pods.
- name: config
configMap:
# Informe o nome do ConfigMap que deseja montar.
name: game-demo
# Uma lista de chaves do ConfigMap para serem criadas como arquivos.
items:
- key: "game.properties"
path: "game.properties"
- key: "user-interface.properties"
path: "user-interface.properties"
ConfigMaps não diferenciam entre propriedades com valores simples ou valores complexos, que ocupam várias linhas. O importante é a forma que Pods e outros objetos consomem tais valores.
Neste exemplo, definir um volume e montar ele dentro do contêiner demo no caminho /config
cria dois arquivos: /config/game.properties e /config/user-interface.properties, embora existam
quatro chaves distintas no ConfigMap. Isso se deve ao fato de que a definição do Pod contém uma lista
items na seção volumes.
Se a lista items for omitida, cada chave do ConfigMap torna-se um arquivo cujo nome é a sua chave
correspondente, e quatro arquivos serão criados.
ConfigMaps podem ser montados como volumes de dados. ConfigMaps também podem ser utilizados por outras partes do sistema sem serem diretamente expostos ao Pod. Por exemplo, ConfigMaps podem conter dados que outras partes do sistema devem usar para configuração.
A forma mais comum de utilização de ConfigMaps é a configuração de contêineres executando em Pods no mesmo namespace. Você também pode utilizar um ConfigMap separadamente.
Por exemplo, existem complementos ou operadores que adaptam seus comportamentos de acordo com dados de um ConfigMap.
Para consumir um ConfigMap em um volume em um Pod:
.spec.volumes[]. Escolha um nome qualquer para o seu volume, e
referencie o seu objeto ConfigMap no campo
.spec.volumes[].configMap.name..spec.containers[].volumeMounts[] a cada um dos
contêineres que precisam do ConfigMap. Especifique
.spec.containers[].volumeMounts[].readOnly = true e informe no campo
.spec.containers[].volumeMounts[].mountPath um caminho de um diretório
não utilizado onde você deseja que este ConfigMap apareça.data do ConfigMap será transformado em um nome de arquivo no
diretório especificado por mountPath.Exemplo de um Pod que monta um ConfigMap em um volume:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
configMap:
name: myconfigmap
Cada ConfigMap que você deseja utilizar precisa ser referenciado em
.spec.volumes.
Se houver múltiplos contêineres no Pod, cada contêiner deve ter seu
próprio bloco volumeMounts, mas somente uma instância de .spec.volumes
é necessária por ConfigMap.
Quando um ConfigMap que está sendo consumido em um volume é atualizado, as chaves projetadas são
eventualmente atualizadas também. O Kubelet checa se o ConfigMap montado está atualizado em cada
sincronização periódica.
No entanto, o kubelet utiliza o cache local para buscar o valor atual do ConfigMap.
O tipo de cache é configurável utilizando o campo ConfigMapAndSecretChangeDetectionStrategy na
configuração do Kubelet (KubeletConfiguration).
Um ConfigMap pode ter sua propagação baseada em um watch (comportamento padrão), que é o sistema
de propagação de mudanças incrementais em objetos do Kubernetes; baseado em TTL (time to live,
ou tempo de expiração); ou redirecionando todas as requisições diretamente para o servidor da API.
Como resultado, o tempo decorrido total entre o momento em que o ConfigMap foi atualizado até o momento
quando as novas chaves são projetadas nos Pods pode ser tão longo quanto o tempo de sincronização
do kubelet somado ao tempo de propagação do cache, onde o tempo de propagação do cache depende do
tipo de cache escolhido: o tempo de propagação pode ser igual ao tempo de propagação do watch,
TTL do cache, ou zero, de acordo com cada um dos tipos de cache.
ConfigMaps que são consumidos como variáveis de ambiente não atualizam automaticamente e requerem uma reinicialização do pod.
Kubernetes v1.21 [stable]
A funcionalidade Secrets e ConfigMaps imutáveis do Kubernetes fornece uma opção para marcar Secrets e ConfigMaps individuais como imutáveis. Para clusters que utilizam ConfigMaps extensivamente (ao menos centenas de milhares de mapeamentos únicos de ConfigMaps para Pods), prevenir alterações dos seus dados traz as seguintes vantagens:
Essa funcionalidade é controlada pelo feature gate
ImmutableEphemeralVolumes. É possível criar um ConfigMap imutável adicionando o campo
immutable e marcando seu valor com true.
Por exemplo:
apiVersion: v1
kind: ConfigMap
metadata:
...
data:
...
immutable: true
Após um ConfigMap ser marcado como imutável, não é possível reverter a alteração, nem
alterar o conteúdo dos campos data ou binaryData. É possível apenas apagar e recriar
o ConfigMap. Como Pods existentes que consomem o ConfigMap em questão mantém um ponto de
montagem que continuará referenciando este objeto após a remoção, é recomendado recriar
estes pods.
Um Secret é um objeto que contém uma pequena quantidade de informação sensível, como senhas, tokens ou chaves. Este tipo de informação poderia, em outras circunstâncias, ser colocada diretamente em uma configuração de Pod ou em uma imagem de contêiner. O uso de Secrets evita que você tenha de incluir dados confidenciais no seu código.
Secrets podem ser criados de forma independente dos Pods que os consomem. Isto reduz o risco de que o Secret e seus dados sejam expostos durante o processo de criação, visualização e edição ou atualização de Pods. O Kubernetes e as aplicações que rodam no seu cluster podem também tomar outras precauções com Secrets, como por exemplo evitar a escrita de dados confidenciais em local de armazenamento persistente (não-volátil).
Secrets são semelhantes a ConfigMaps, mas foram especificamente projetados para conter dados confidenciais.
Os Secrets do Kubernetes são, por padrão, gravados não-encriptados no sistema de armazenamento de dados utilizado pelo servidor da API (etcd). Qualquer pessoa com acesso à API ou ao etcd consegue obter ou modificar um Secret. Além disso, qualquer pessoa que possui autorização para criar Pods em um namespace consegue utilizar este privilégio para ler qualquer Secret naquele namespace. Isso inclui acesso indireto, como por exemplo a permissão para criar Deployments.
Para utilizar Secrets de forma segura, siga pelo menos as instruções abaixo:
Consulte Segurança da informação para Secrets para mais detalhes.
Existem três formas principais para um Pod utilizar um Secret:
A camada de gerenciamento do Kubernetes também utiliza Secrets. Por exemplo, os Secrets de tokens de autoinicialização são um mecanismo que auxilia a automação do registro de nós.
Ao invés de utilizar um Secret para proteger dados confidenciais, você pode escolher uma maneira alternativa. Algumas das opções são:
Você pode também combinar duas ou mais destas opções, incluindo a opção de utilizar objetos do tipo Secret.
Por exemplo: implemente (ou instale) um operador que solicite tokens de sessão de curta duração a um serviço externo, e crie Secrets baseado nestes tokens. Pods rodando no seu cluster podem fazer uso de tokens de sessão, e o operador garante que estes permanecem válidos. Esta separação significa que você pode rodar Pods que não precisam ter conhecimento do mecanismo exato para geração e atualização de tais tokens de sessão.
Existem diversas formas de criar um Secret:
kubectlO nome de um Secret deve ser um subdomínio DNS válido.
Você pode especificar o campo data e/ou o campo stringData na criação de um
arquivo de configuração de um Secret. Ambos os campos data e stringData são
opcionais. Os valores das chaves no campo data devem ser strings codificadas
no formato base64. Se a conversão para base64 não for desejável, você pode
optar por informar os dados no campo stringData, que aceita strings arbitrárias
como valores.
As chaves dos campos data e stringData devem consistir de caracteres
alfanuméricos, -, _, ou .. Todos os pares chave-valor no campo stringData
são internamente combinados com os dados do campo data. Se uma chave aparece
em ambos os campos, o valor informado no campo stringData tem a precedência.
Secrets individuais são limitados a 1MiB em tamanho. Esta limitação tem por objetivo desencorajar a criação de Secrets muito grandes que possam exaurir a memória do servidor da API e do kubelet. No entanto, a criação de vários Secrets pequenos também pode exaurir a memória. Você pode utilizar uma cota de recurso a fim de limitar o número de Secrets (ou outros recursos) em um namespace.
Você pode editar um Secret existente utilizando kubectl:
kubectl edit secrets mysecret
Este comando abre o seu editor padrão configurado e permite a modificação dos
valores do Secret codificados em base64 no campo data. Por exemplo:
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file, it will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
kind: Secret
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: { ... }
creationTimestamp: 2016-01-22T18:41:56Z
name: mysecret
namespace: default
resourceVersion: "164619"
uid: cfee02d6-c137-11e5-8d73-42010af00002
type: Opaque
Este manifesto de exemplo define um Secret com duas chaves no campo data:
username and password.
Os valores são strings codificadas em formato base64. No entanto, quando um
Secret é utilizado em um Pod, o kubelet fornece os dados decodificados ao Pod
e seus contêineres.
Você pode especificar muitas chaves e valores em um Secret só, ou utilizar muitos Secrets. Escolha a opção que for mais conveniente para o caso de uso.
Secrets podem ser montados como volumes de dados ou expostos como variáveis de ambiente para serem utilizados num contêiner de um Pod. Secrets também podem ser utilizados por outras partes do sistema, sem serem diretamente expostos ao Pod. Por exemplo, Secrets podem conter credenciais que outras partes do sistema devem utilizar para interagir com sistemas externos no lugar do usuário.
Secrets montados como volumes são verificados para garantir que o nome referenciado realmente é um objeto do tipo Secret. Portanto, um Secret deve ser criado antes de quaisquer Pods que dependem deste Secret.
Se um Secret não puder ser encontrado (porque não existe, ou devido a um problema de conectividade com o servidor da API) o kubelet tenta periodicamente reiniciar aquele Pod. O kubelet também relata um evento para aquele Pod, incluindo detalhes do problema ao buscar o Secret.
Quando você define uma variável de ambiente em um contêiner baseada em um Secret, você pode especificar que o Secret em questão será opcional. O padrão é o Secret ser requerido.
Nenhum dos contêineres de um Pod irão inicializar até que todos os Secrets requeridos estejam disponíveis.
Se um Pod referencia uma chave específica em um Secret e o Secret existe, mas não possui a chave com o nome referenciado, o Pod falha durante a inicialização.
Se você deseja acessar dados de um Secret em um Pod, uma das formas de consumir esta informação é fazer com que o Kubernetes deixe o valor daquele Secret disponível como um arquivo dentro do sistema de arquivos de um ou mais dos contêineres daquele Pod.
Para configurar isso:
.spec.volumes[]. Escolha um nome qualquer para o seu volume e adicione um
campo .spec.volumes[].secret.secretName com o mesmo valor do seu objeto
Secret..spec.containers[].volumeMounts[] de cada contêiner que requer o Secret.
Especifique .spec.containers[].volumeMounts[].readOnly = true e especifique o
valor do campo .spec.containers[].volumeMounts[].mountPath com o nome de um
diretório não utilizado onde você deseja que os Secrets apareçam.data se torna um nome de
arquivo no diretório especificado em mountPath.Este é um exemplo de Pod que monta um Secret de nome mysecret em um volume:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret # configuração padrão; "mysecret" precisa existir
Cada Secret que você deseja utilizar deve ser referenciado na lista
.spec.volumes.
Se existirem múltiplos contêineres em um Pod, cada um dos contêineres
necessitará seu próprio bloco volumeMounts, mas somente um volume na lista
.spec.volumes é necessário por Secret.
Versões do Kubernetes anteriores a v1.22 criavam automaticamente credenciais para acesso à API do Kubernetes. Este mecanismo antigo era baseado na criação de Secrets com tokens que podiam então ser montados em Pods em execução. Em versões mais recentes, incluindo o Kubernetes v1.35, credenciais para acesso à API são obtidas diretamente através da API TokenRequest e são montadas em Pods utilizando um volume projetado. Os tokens obtidos através deste método possuem tempo de vida limitado e são automaticamente invalidados quando o Pod em que estão montados é removido.
Você ainda pode criar manualmente um Secret de token de service account se você precisa de um token que não expire, por exemplo. No entanto, o uso do subrecurso TokenRequest é recomendado para obtenção de um token para acesso à API ao invés do uso de Secrets de token de service account.
Você pode também controlar os caminhos dentro do volume onde as chaves do Secret
são projetadas. Você pode utilizar o campo .spec.volumes[].secret.items para
mudar o caminho de destino de cada chave:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
items:
- key: username
path: my-group/my-username
Neste caso:
username é armazenado no arquivo
/etc/foo/my-group/my-username ao invés de /etc/foo/username.password não é projetado no sistema de arquivos.Se .spec.volumes[].secret.items for utilizado, somente chaves especificadas
na lista items são projetadas. Para consumir todas as chaves do Secret, deve
haver um item para cada chave no campo items.
Se você listar as chaves explicitamente, então todas as chaves listadas precisam existir no Secret correspondente. Caso contrário, o volume não é criado.
Você pode trocar os bits de permissão POSIX de uma chave avulsa de Secret.
Se nenhuma permissão for especificada, 0644 é utilizado por padrão.
Você pode também especificar uma permissão padrão para o volume inteiro de
Secret e sobrescrever esta permissão por chave, se necessário.
Por exemplo, você pode especificar uma permissão padrão da seguinte maneira:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
volumes:
- name: foo
secret:
secretName: mysecret
defaultMode: 0400
Dessa forma, o Secret será montado em /etc/foo e todos os arquivos criados
no volume terão a permissão 0400.
defaultMode (por exemplo, 0400 em base octal equivale a
256 na base decimal).defaultMode
em octal.Dentro do contêiner que monta um volume de Secret, as chaves deste Secret aparecem como arquivos e os valores dos Secrets são decodificados do formato base64 e armazenados dentro destes arquivos.
Ao executar comandos dentro do contêiner do exemplo anterior, obteremos os seguintes resultados:
ls /etc/foo
O resultado é semelhante a:
username
password
cat /etc/foo/username
O resultado é semelhante a:
admin
cat /etc/foo/password
O resultado é semelhante a:
1f2d1e2e67df
A aplicação rodando dentro do contêiner é responsável pela leitura dos Secrets dentro dos arquivos.
Quando um volume contém dados de um Secret, e o Secret referenciado é atualizado, o Kubernetes rastreia a atualização e atualiza os dados no volume, utilizando uma abordagem de consistência eventual.
subPath não recebe
atualizações automatizadas para este Secret.O kubelet mantém um cache das chaves e valores atuais dos Secrets que são
utilizados em volumes de Pods daquele nó. Você pode configurar a forma que o
kubelet detecta diferenças dos valores armazenados em cache. O campo
configMapAndSecretDetectionStrategy na
configuração do kubelet
controla qual estratégia o kubelet usa. A estratégia padrão é Watch.
Atualizações em Secrets podem ser propagadas por um mecanismo de observação da API (estratégia padrão), baseado em cache com um tempo de expiração definido (time-to-live), ou solicitado diretamente ao servidor da API do cluster a cada iteração do ciclo de sincronização do kubelet.
Como resultado, o atraso total entre o momento em que o Secret foi atualizado até o momento em que as novas chaves são projetadas no Pod pode ser tão longo quanto a soma do tempo de sincronização do kubelet somado ao tempo de atraso de propagação do cache, onde o atraso de propagação do cache depende do tipo de cache escolhido. Seguindo a mesma ordem listada no parágrafo anterior, estes valores são: atraso de propagação via watch, tempo de expiração configurado no cache (time-to-live, ou TTL), ou zero para solicitação direta ao servidor da API.
Para utilizar um secret em uma variável de ambiente em um Pod:
env[].valueFrom.secretKeyRef.Este é um exemplo de um Pod que utiliza Secrets em variáveis de ambiente:
apiVersion: v1
kind: Pod
metadata:
name: secret-env-pod
spec:
containers:
- name: mycontainer
image: redis
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
optional: false # valor padrão; "mysecret" deve existir
# e incluir uma chave com o nome "username"
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
optional: false # valor padrão; "mysecret" deve existir
# e incluir uma chave com o nome "password"
restartPolicy: Never
Secrets utilizados para popular variáveis de ambiente através do campo envFrom
que possuem chaves consideradas inválidas para nomes de variáveis de ambiente
têm tais chaves ignoradas. O Pod irá iniciar normalmente.
Se você definir um Pod contendo um nome de variável de ambiente inválido, os
eventos de inicialização do Pod incluirão um evento com a razão
InvalidVariableNames e uma mensagem que lista as chaves inválidas ignoradas.
O exemplo abaixo demonstra um Pod que referencia um Secret chamado mysecret,
onde mysecret contém duas chaves inválidas: 1badkey and 2alsobad.
kubectl get events
O resultado é semelhante a:
LASTSEEN FIRSTSEEN COUNT NAME KIND SUBOBJECT TYPE REASON
0s 0s 1 dapi-test-pod Pod Warning InvalidEnvironmentVariableNames kubelet, 127.0.0.1 Keys [1badkey, 2alsobad] from the EnvFrom secret default/mysecret were skipped since they are considered invalid environment variable names.
Dentro de um contêiner que consome um Secret em variáveis de ambiente, as chaves do Secret aparecem como variáveis de ambiente comuns, contendo os dados do Secret decodificados do formato base64. Ao executar comandos no contêiner do exemplo anterior, obteremos os resultados abaixo:
echo $SECRET_USERNAME
O resultado é semelhante a:
admin
echo $SECRET_PASSWORD
O resultado é semelhante a:
1f2d1e2e67df
Se você deseja obter imagens de contêiner de um repositório privado, você
precisa fornecer ao kubelet uma maneira de se autenticar a este repositório.
Você pode configurar o campo imagePullSecrets para esta finalidade. Estes
Secrets são configurados a nível de Pod.
O campo imagePullSecrets de um Pod é uma lista de referências a Secrets
no mesmo namespace que o Pod.
Você pode utilizar imagePullSecrets para enviar credenciais para acesso a um
registro de contêineres ao kubelet. O kubelet utiliza essa informação para
baixar uma imagem privada no lugar do seu Pod.
Veja o campo PodSpec na
referência da API de Pods
para maiores detalhes sobre o campo imagePullSecrets.
imagePullSecretsO campo imagePullSecrets é uma lista de referências a Secrets no mesmo
namespace.
Você pode utilizar o campo imagePullSecrets para enviar um Secret que contém
uma senha para um registro de imagens de contêiner do Docker (ou outro registro
de imagens de contêiner). O kubelet utiliza essa informação para baixar uma
imagem privada no lugar do seu Pod.
Veja a API PodSpec
para mais informações sobre o campo imagePullSecrets.
imagePullSecrets manualmenteVocê pode ler sobre como especificar imagePullSecrets em um Pod na
documentação de imagens de contêiner.
imagePullSecrets para serem adicionados automaticamenteVocê pode criar manualmente imagePullSecrets e referenciá-los em uma
ServiceAccount. Quaisquer Pods criados com esta ServiceAccount, especificada
explicitamente ou por padrão, têm o campo imagePullSecrets populado com os
mesmos valores existentes na service account.
Veja adicionando imagePullSecrets a uma service account
para uma explicação detalhada do processo.
Você não pode utilizar ConfigMaps ou Secrets em Pods estáticos.
Crie um manifesto de Secret
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
USER_NAME: YWRtaW4=
PASSWORD: MWYyZDFlMmU2N2Rm
Crie o Secret no seu cluster:
kubectl apply -f mysecret.yaml
Utilize envFrom para definir todos os dados do Secret como variáveis de
ambiente do contêiner. Cada chave do Secret se torna o nome de uma variável de
ambiente no Pod.
apiVersion: v1
kind: Pod
metadata:
name: secret-test-pod
spec:
containers:
- name: test-container
image: registry.k8s.io/busybox
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- secretRef:
name: mysecret
restartPolicy: Never
Crie um Secret contendo chaves SSH:
kubectl create secret generic ssh-key-secret --from-file=ssh-privatekey=/path/to/.ssh/id_rsa --from-file=ssh-publickey=/path/to/.ssh/id_rsa.pub
O resultado é semelhante a:
secret "ssh-key-secret" created
Você também pode criar um manifesto kustomization.yaml com um campo
secretGenerator contendo chaves SSH.
Analise cuidadosamente antes de enviar suas próprias chaves SSH: outros usuários do cluster podem ter acesso a este Secret.
Como alternativa, você pode criar uma chave SSH privada representando a identidade de um serviço que você deseja que seja acessível a todos os usuários com os quais você compartilha o cluster do Kubernetes em questão. Desse modo, você pode revogar esta credencial em caso de comprometimento.
Agora você pode criar um Pod que referencia o Secret com a chave SSH e consome-o em um volume:
apiVersion: v1
kind: Pod
metadata:
name: secret-test-pod
labels:
name: secret-test
spec:
volumes:
- name: secret-volume
secret:
secretName: ssh-key-secret
containers:
- name: ssh-test-container
image: mySshImage
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
Ao rodar o comando do contêiner, as partes da chave estarão disponíveis em:
/etc/secret-volume/ssh-publickey
/etc/secret-volume/ssh-privatekey
O contêiner então pode utilizar os dados do secret para estabelecer uma conexão SSH.
Este exemplo ilustra um Pod que consome um Secret contendo credenciais de um ambiente de produção e outro Pod que consome um Secret contendo credenciais de um ambiente de testes.
Você pode criar um manifesto kustomization.yaml com um secretGenerator ou
rodar kubectl create secret.
kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11
O resultado é semelhante a:
secret "prod-db-secret" created
Você pode também criar um Secret com credenciais para o ambiente de testes.
kubectl create secret generic test-db-secret --from-literal=username=testuser --from-literal=password=iluvtests
O resultado é semelhante a:
secret "test-db-secret" created
Caracteres especiais como $, \, *, + e ! serão interpretados pelo seu
shell e precisam
de sequências de escape.
Na maioria dos shells, a forma mais fácil de gerar sequências de escape para
suas senhas é escrevê-las entre aspas simples ('). Por exemplo, se a sua senha
for S!B\*d$zDsb=, você deve executar o comando da seguinte forma:
kubectl create secret generic dev-db-secret --from-literal=username=devuser --from-literal=password='S!B\*d$zDsb='
Não é necessário gerar sequências de escape para caracteres especiais em arquivos
(utilizados com a opção --from-file).
Agora, crie os Pods:
cat <<EOF > pod.yaml
apiVersion: v1
kind: List
items:
- kind: Pod
apiVersion: v1
metadata:
name: prod-db-client-pod
labels:
name: prod-db-client
spec:
volumes:
- name: secret-volume
secret:
secretName: prod-db-secret
containers:
- name: db-client-container
image: myClientImage
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
- kind: Pod
apiVersion: v1
metadata:
name: test-db-client-pod
labels:
name: test-db-client
spec:
volumes:
- name: secret-volume
secret:
secretName: test-db-secret
containers:
- name: db-client-container
image: myClientImage
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
EOF
Adicione os Pods a um manifesto kustomization.yaml:
cat <<EOF >> kustomization.yaml
resources:
- pod.yaml
EOF
Crie todos estes objetos no servidor da API rodando o comando:
kubectl apply -k .
Ambos os contêineres terão os seguintes arquivos presentes nos seus sistemas de arquivos, com valores para cada um dos ambientes dos contêineres:
/etc/secret-volume/username
/etc/secret-volume/password
Observe como as specs para cada um dos Pods diverge somente em um campo. Isso
facilita a criação de Pods com capacidades diferentes a partir de um template
mais genérico.
Você pode simplificar ainda mais a definição básica do Pod através da utilização de duas service accounts diferentes:
prod-user com o Secret prod-db-secrettest-user com o Secret test-db-secretA especificação do Pod é reduzida para:
apiVersion: v1
kind: Pod
metadata:
name: prod-db-client-pod
labels:
name: prod-db-client
spec:
serviceAccount: prod-db-client
containers:
- name: db-client-container
image: myClientImage
Você pode fazer com que seus dados fiquem "ocultos" definindo uma chave que se
inicia com um ponto (.). Este tipo de chave representa um dotfile, ou
arquivo "oculto". Por exemplo, quando o Secret abaixo é montado em um volume,
secret-volume:
apiVersion: v1
kind: Secret
metadata:
name: dotfile-secret
data:
.secret-file: dmFsdWUtMg0KDQo=
---
apiVersion: v1
kind: Pod
metadata:
name: secret-dotfiles-pod
spec:
volumes:
- name: secret-volume
secret:
secretName: dotfile-secret
containers:
- name: dotfile-test-container
image: registry.k8s.io/busybox
command:
- ls
- "-l"
- "/etc/secret-volume"
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
Este volume irá conter um único arquivo, chamado .secret-file, e o contêiner
dotfile-test-container terá este arquivo presente no caminho
/etc/secret-volume/.secret-file.
ls -l. Você precisa utilizar ls -la para vê-los ao
listar o conteúdo de um diretório.Suponha que um programa necessita manipular requisições HTTP, executar regras de negócio complexas e então assinar mensagens com HMAC. Devido à natureza complexa da aplicação, pode haver um exploit despercebido que lê arquivos remotos no servidor e que poderia expor a chave privada para um invasor.
Esta aplicação poderia ser dividida em dois processos, separados em dois contêineres distintos: um contêiner de front-end, que manipula as interações com o usuário e a lógica de negócio, mas não consegue ver a chave privada; e um contêiner assinador, que vê a chave privada e responde a requisições simples de assinatura do front-end (por exemplo, através de rede local).
Com essa abordagem particionada, um invasor agora precisa forçar o servidor de aplicação a rodar comandos arbitrários, o que é mais difícil de ser feito do que apenas ler um arquivo presente no disco.
Ao criar um Secret, você pode especificar o seu tipo utilizando o campo type
do objeto Secret, ou algumas opções de linha de comando equivalentes no comando
kubectl, quando disponíveis. O campo type de um Secret é utilizado para
facilitar a manipulação programática de diferentes tipos de dados confidenciais.
O Kubernetes oferece vários tipos embutidos de Secret para casos de uso comuns. Estes tipos variam em termos de validações efetuadas e limitações que o Kubernetes impõe neles.
| Tipo embutido | Caso de uso |
|---|---|
Opaque |
dados arbitrários definidos pelo usuário |
kubernetes.io/service-account-token |
token de service account (conta de serviço) |
kubernetes.io/dockercfg |
arquivo ~/.dockercfg serializado |
kubernetes.io/dockerconfigjson |
arquivo ~/.docker/config.json serializado |
kubernetes.io/basic-auth |
credenciais para autenticação básica (basic auth) |
kubernetes.io/ssh-auth |
credenciais para autenticação SSH |
kubernetes.io/tls |
dados para um cliente ou servidor TLS |
bootstrap.kubernetes.io/token |
dados de token de autoinicialização |
Você pode definir e utilizar seu próprio tipo de Secret definindo o valor do
campo type como uma string não-nula em um objeto Secret (uma string em branco
é tratada como o tipo Opaque).
O Kubernetes não restringe nomes de tipos. No entanto, quando tipos embutidos são utilizados, você precisa atender a todos os requisitos daquele tipo.
Se você estiver definindo um tipo de Secret que seja para uso público, siga a
convenção e estruture o tipo de Secret para conter o seu domínio antes do nome,
separado por uma barra (/).
Por exemplo: cloud-hosting.example.net/cloud-api-credentials.
Para melhor desempenho em uma requisição get repetitiva, clientes podem criar
objetos que referenciam o Secret e então utilizar a requisição watch neste
novo objeto, requisitando o Secret novamente quando a referência mudar.
Além disso, uma API de "observação em lotes"
para permitir a clientes observar recursos individuais também foi proposta e
provavelmente estará disponível em versões futuras do Kubernetes.
Opaque é o tipo predefinido de Secret quando o campo type é omitido em um
arquivo de configuração de Secret. Quando um Secret é criado usando o comando
kubectl, você deve usar o subcomando generic para indicar que um Secret é
do tipo Opaque. Por exemplo, o comando a seguir cria um Secret vazio do tipo
Opaque:
kubectl create secret generic empty-secret
kubectl get secret empty-secret
O resultado será semelhante ao abaixo:
NAME TYPE DATA AGE
empty-secret Opaque 0 2m6s
A coluna DATA demonstra a quantidade de dados armazenados no Secret. Neste
caso, 0 significa que este objeto Secret está vazio.
Secrets do tipo kubernetes.io/service-account-token são utilizados para
armazenar um token que identifica uma service account (conta de serviço). Ao
utilizar este tipo de Secret, você deve garantir que a anotação
kubernetes.io/service-account.name contém um nome de uma service account
existente. Um controlador do Kubernetes preenche outros campos, como por exemplo
a anotação kubernetes.io/service-account.uid e a chave token no campo data
com o conteúdo do token.
O exemplo de configuração abaixo declara um Secret de token de service account:
apiVersion: v1
kind: Secret
metadata:
name: secret-sa-sample
annotations:
kubernetes.io/service-account-name: "sa-name"
type: kubernetes.io/service-account-token
data:
# Você pode incluir pares chave-valor adicionais, da mesma forma que faria com
# Secrets do tipo Opaque
extra: YmFyCg==
Ao criar um Pod, o Kubernetes automaticamente cria um Secret de service account e automaticamente atualiza o seu Pod para utilizar este Secret. O Secret de token de service account contém credenciais para acessar a API.
A criação automática e o uso de credenciais de API podem ser desativados ou substituídos se desejado. Porém, se tudo que você necessita é poder acessar o servidor da API de forma segura, este é o processo recomendado.
Veja a documentação de
ServiceAccount
para mais informações sobre o funcionamento de service accounts. Você pode
verificar também os campos automountServiceAccountToken e serviceAccountName
do Pod
para mais informações sobre como referenciar service accounts em Pods.
Você pode utilizar um dos tipos abaixo para criar um Secret que armazena credenciais para acesso a um registro de contêineres para busca de imagens:
kubernetes.io/dockercfgkubernetes.io/dockerconfigjsonO tipo kubernetes.io/dockercfg é reservado para armazenamento de um arquivo
~/.dockercfg serializado. Este arquivo é o formato legado para configuração
do utilitário de linha de comando do Docker. Ao utilizar este tipo de Secret,
é preciso garantir que o campo data contém uma chave .dockercfg cujo valor
é o conteúdo do arquivo ~/.dockercfg codificado no formato base64.
O tipo kubernetes.io/dockerconfigjson foi projetado para armazenamento de um
conteúdo JSON serializado que obedece às mesmas regras de formato que o arquivo
~/.docker/config.json. Este arquivo é um formato mais moderno para o conteúdo
do arquivo ~/.dockercfg. Ao utilizar este tipo de Secret, o conteúdo do campo
data deve conter uma chave .dockerconfigjson em que o conteúdo do arquivo
~/.docker/config.json é fornecido codificado no formato base64.
Um exemplo de um Secret do tipo kubernetes.io/dockercfg:
apiVersion: v1
kind: Secret
metadata:
name: secret-dockercfg
type: kubernetes.io/dockercfg
data:
.dockercfg: |
"<base64 encoded ~/.dockercfg file>"
stringData como alternativa.Ao criar estes tipos de Secret utilizando um manifesto (arquivo YAML), o
servidor da API verifica se a chave esperada existe no campo data e se o valor
fornecido pode ser interpretado como um conteúdo JSON válido. O servidor da API
não verifica se o conteúdo informado é realmente um arquivo de configuração do
Docker.
Quando você não tem um arquivo de configuração do Docker, ou quer utilizar o
comando kubectl para criar um Secret de registro de contêineres, você pode
rodar o comando:
kubectl create secret docker-registry secret-tiger-docker \
--docker-email=tiger@acme.example \
--docker-username=tiger \
--docker-password=pass1234 \
--docker-server=my-registry.example:5000
Esse comando cria um secret do tipo kubernetes.io/dockerconfigjson. Se você
obtiver o conteúdo do campo .data.dockerconfigjson deste novo Secret e
decodificá-lo do formato base64:
kubectl get secret secret-tiger-docker -o jsonpath='{.data.*}' | base64 -d
o resultado será equivalente a este documento JSON (que também é um arquivo de configuração válido do Docker):
{
"auths": {
"my-registry.example:5000": {
"username": "tiger",
"password": "pass1234",
"email": "tiger@acme.example",
"auth": "dGlnZXI6cGFzczEyMzQ="
}
}
}
auth no exemplo acima é codificado em base64; ele está
ofuscado mas não criptografado. Qualquer pessoa com acesso a este Secret pode
ler o conteúdo do token bearer.O tipo kubernetes.io/basic-auth é fornecido para armazenar credenciais
necessárias para autenticação básica. Ao utilizar este tipo de Secret, o campo
data do Secret deve conter as duas chaves abaixo:
username: o usuário utilizado para autenticação;password: a senha ou token para autenticação.Ambos os valores para estas duas chaves são textos codificados em formato base64.
Você pode fornecer os valores como texto simples utilizando o campo stringData
na criação do Secret.
O arquivo YAML abaixo é um exemplo de configuração para um Secret de autenticação básica:
apiVersion: v1
kind: Secret
metadata:
name: secret-basic-auth
type: kubernetes.io/basic-auth
stringData:
username: admin # required field for kubernetes.io/basic-auth
password: t0p-Secret # required field for kubernetes.io/basic-auth
O tipo de autenticação básica é fornecido unicamente por conveniência. Você pode
criar um Secret do tipo Opaque utilizado para autenticação básica. No entanto,
utilizar o tipo embutido e público de Secret (kubernetes.io/basic-auth)
auxilia outras pessoas a compreenderem o propósito do seu Secret, e define uma
convenção de expectativa de nomes de chaves
O tipo embutido também fornece verificação dos campos requeridos pelo servidor
da API.
O tipo embutido kubernetes.io/ssh-auth é fornecido para armazenamento de dados
utilizados em autenticação SSH. Ao utilizar este tipo de Secret, você deve
especificar um par de chave-valor ssh-privatekey no campo data (ou no campo
stringData) com a credencial SSH a ser utilizada.
O manifesto abaixo é um exemplo de configuração para um Secret de autenticação SSH com um par de chaves pública/privada:
apiVersion: v1
kind: Secret
metadata:
name: secret-ssh-auth
type: kubernetes.io/ssh-auth
data:
# os dados estão abreviados neste exemplo
ssh-privatekey: |
MIIEpQIBAAKCAQEAulqb/Y ...
O Secret de autenticação SSH é fornecido apenas para a conveniência do usuário.
Você pode criar um Secret do tipo Opaque para credentials utilizadas para
autenticação SSH. No entanto, a utilização do tipo embutido e público de Secret
(kubernetes.io/tls) auxilia outras pessoas a compreenderem o propósito do
seu Secret, e define uma convenção de quais chaves podem ser esperadas.
O tipo embutido também fornece verificação dos campos requeridos em uma
configuração de Secret.
known_hosts adicionado a um ConfigMap.O Kubernetes fornece o tipo embutido de Secret kubernetes.io/tls para
armazenamento de um certificado e sua chave associada que são tipicamente
utilizados para TLS.
Uma utilização comum de Secrets TLS é a configuração de encriptação em trânsito para um recurso Ingress, mas este tipo de secret pode também ser utilizado com outros recursos ou diretamente por uma carga de trabalho.
Ao utilizar este tipo de Secret, as chaves tls.key e tls.crt devem ser
informadas no campo data (ou stringData) da configuração do Secret, embora o
servidor da API não valide o conteúdo de cada uma destas chaves.
O YAML a seguir tem um exemplo de configuração para um Secret TLS:
apiVersion: v1
kind: Secret
metadata:
name: secret-tls
type: kubernetes.io/tls
data:
# os dados estão abreviados neste exemplo
tls.crt: |
MIIC2DCCAcCgAwIBAgIBATANBgkqh ...
tls.key: |
MIIEpgIBAAKCAQEA7yn3bRHQ5FHMQ ...
O tipo TLS é fornecido para a conveniência do usuário. Você pode criar um
Secret do tipo Opaque para credenciais utilizadas para o servidor e/ou
cliente TLS. No entanto, a utilização do tipo embutido auxilia a manter a
consistência dos formatos de Secret no seu projeto; o servidor da API
valida se os campos requeridos estão presentes na configuração do Secret.
Ao criar um Secret TLS utilizando a ferramenta de linha de comando kubectl,
você pode utilizar o subcomando tls conforme demonstrado no exemplo abaixo:
kubectl create secret tls my-tls-secret \
--cert=path/to/cert/file \
--key=path/to/key/file
O par de chaves pública/privada deve ser criado previamente. O certificado
de chave pública a ser utilizado no argumento --cert deve ser codificado em
formato DER conforme especificado na
seção 5.1 da RFC 7468
e deve corresponder à chave privada fornecida no argumento --key
(PKCS #8 no formato DER;
seção 11 da RFC 7468).
Um Secret kubernetes.io/tls armazena o conteúdo de chaves e certificados em formato DER codificado em base64. Se você tem familiaridade com o formato PEM para chaves privadas e certificados, o conteúdo é o mesmo do formato PEM, excluindo-se a primeira e a última linhas.
Por exemplo, para um certificado, você não inclui as linhas
--------BEGIN CERTIFICATE----- e -------END CERTIFICATE----.
Um Secret de token de autoinicialização pode ser criado especificando o tipo de
um Secret explicitamente com o valor bootstrap.kubernetes.io/token. Este tipo
de Secret é projetado para tokens utilizados durante o processo de inicialização
de nós. Este tipo de Secret armazena tokens utilizados para assinar ConfigMaps
conhecidos.
Um Secret de token de autoinicialização é normalmente criado no namespace
kube-system e nomeado na forma bootstrap-token-<id-do-token>, onde
<id-do-token> é um texto com 6 caracteres contendo a identificação do token.
No formato de manifesto do Kubernetes, um Secret de token de autoinicialização se assemelha ao exemplo abaixo:
apiVersion: v1
kind: Secret
metadata:
name: bootstrap-token-5emitj
namespace: kube-system
type: bootstrap.kubernetes.io/token
data:
auth-extra-groups: c3lzdGVtOmJvb3RzdHJhcHBlcnM6a3ViZWFkbTpkZWZhdWx0LW5vZGUtdG9rZW4=
expiration: MjAyMC0wOS0xM1QwNDozOToxMFo=
token-id: NWVtaXRq
token-secret: a3E0Z2lodnN6emduMXAwcg==
usage-bootstrap-authentication: dHJ1ZQ==
usage-bootstrap-signing: dHJ1ZQ==
Um Secret do tipo token de autoinicialização possui as seguintes chaves no campo
data:
token-id: Uma string com 6 caracteres aleatórios como identificador do
token. Requerido.token-secret: Uma string de 16 caracteres aleatórios como o conteúdo secreto
do token. Requerido.description: Uma string contendo uma descrição do propósito para o qual este
token é utilizado. Opcional.expiration: Um horário absoluto UTC no formato RFC3339 especificando quando
o token deve expirar. Opcional.usage-bootstrap-<usage>: Um conjunto de flags booleanas indicando outros
usos para este token de autoinicialização.auth-extra-groups: Uma lista separada por vírgulas de nomes de grupos que
serão autenticados adicionalmente, além do grupo system:bootstrappers.O YAML acima pode parecer confuso, já que os valores estão todos codificados em formato base64. Você pode criar o mesmo Secret utilizando este YAML:
apiVersion: v1
kind: Secret
metadata:
# Observe como o Secret é nomeado
name: bootstrap-token-5emitj
# Um Secret de token de inicialização geralmente fica armazenado no namespace
# kube-system
namespace: kube-system
type: bootstrap.kubernetes.io/token
stringData:
auth-extra-groups: "system:bootstrappers:kubeadm:default-node-token"
expiration: "2020-09-13T04:39:10Z"
# Esta identificação de token é utilizada no nome
token-id: "5emitj"
token-secret: "kq4gihvszzgn1p0r"
# Este token pode ser utilizado para autenticação
usage-bootstrap-authentication: "true"
# e pode ser utilizado para assinaturas
usage-bootstrap-signing: "true"
Kubernetes v1.21 [stable]
O Kubernetes permite que você marque Secrets (e ConfigMaps) específicos como imutáveis. Prevenir mudanças nos dados de um Secret existente tem os seguintes benefícios:
Você pode criar um Secret imutável adicionando o campo immutable com o valor
true ao manifesto do Secret. Por exemplo:
apiVersion: v1
kind: Secret
metadata:
...
data:
...
immutable: true
Você pode também atualizar qualquer Secret mutável existente para torná-lo imutável.
data. Você
pode somente apagar e recriar o Secret. Pods existentes mantém um ponto de
montagem referenciando o Secret removido - é recomendado recriar tais Pods.Embora ConfigMaps e Secrets funcionem de formas similares, o Kubernetes aplica proteções extras aos objetos Secret.
Secrets frequentemente contém valores dentro de um espectro de importância, muitos dos quais podem provocar escalações de privilégios dentro do Kubernetes (por exemplo, um token de service account) e em sistemas externos. Mesmo que uma aplicação individual possa avaliar o poder dos Secrets com os quais espera interagir, outras aplicações dentro do mesmo namespace podem tornar tais suposições inválidas.
Um Secret só é enviado a um nó se um Pod naquele nó precisa do Secret em questão.
Para montar Secrets em Pods, o kubelet armazena uma cópia dos dados dentro de um
sistema de arquivos tmpfs, de modo que os dados confidenciais não sejam
escritos em armazenamento durável. Uma vez que o Pod que dependia do Secret seja
removido, o kubelet apaga sua cópia local dos dados confidenciais do Secret.
Um Pod pode possuir vários contêineres. Por padrão, contêineres que você define têm acesso somente à ServiceAccount padrão e seu Secret relacionado. Você deve explicitamente definir variáveis de ambiente ou mapear um volume dentro de um contêiner para ter acesso a qualquer outro Secret.
Podem haver Secrets para vários Pods no mesmo nó. No entanto, somente os Secrets que um Pod requisitou estão potencialmente visíveis dentro de seus contêineres. Portanto, um Pod não tem acesso aos Secrets de outro Pod.
watch e list em Secrets dentro de um
namespace são extremamente poderosas. Evite fornecer este acesso quando
possível, já que listar Secrets permite aos clientes inspecionar os valores de
todos os Secrets naquele namespace.watch e list para listar todos
os Secrets em um cluster (utilizando a API do Kubernetes) de modo que somente
os componentes mais privilegiados e de nível de sistema possam realizar esta
ação.kubectlAo criar a especificação de um Pod, você pode opcionalmente especificar quanto de cada recurso um contêiner precisa. Os recursos mais comuns a serem especificados são CPU e memória (RAM); há outros recursos que podem ser especificados.
Quando você especifica o requerimento de recursos em um Pod, o kube-scheduler utiliza esta informação para decidir a qual nó o Pod será atribuído. Quando você especifica um limite de recurso para um contêiner, o kubelet garante o cumprimento de tais limites, de modo que o contêiner em execução não consiga utilizar uma quantidade de tal recurso além do limite especificado. O kubelet também reserva pelo menos o requerimento daquele recurso de sistema especificamente para que este contêiner utilize.
Se o nó em que um Pod está rodando tem o suficiente de um recurso específico
disponível, é possível (e permitido) a um contêiner utilizar mais do que o seu
request para aquele recurso especifica. No entanto, não é permitido a um
contêiner consumir mais do que o seu limit para um recurso.
Por exemplo, se você especificar um requerimento de memory de 256 MiB para um
contêiner, e aquele contêiner está em um Pod atribuído a um nó com 8GiB de
memória, sem outros Pods, então este contêiner pode tentar consumir mais memória
RAM.
Se você especificar um limite de memory de 4GiB para aquele contêiner, o
kubelet (e o
agente de execução de contêiner)
vão garantir o cumprimento do limite. O agente de execução impede que o contêiner
utilize mais de um recurso do que seu limite configurado. Por exemplo, quando
um processo no contêiner tenta consumir mais que o limite permitido de memória,
o núcleo do sistema encerra o processo que tentou efetuar a alocação de memória
com um erro de memória esgotada (out of memory (OOM) error).
Limites podem ser implementados de forma reativa (o sistema intervém quando uma violação ocorre) ou por garantia (o sistema previne o contêiner de exceder o limite). Diferentes agentes de execução implementam as mesmas restrições de maneiras diferentes.
CPU e memória são tipos de recursos. Um tipo de recurso possui uma unidade básica. CPU representa processamento computacional e é especificada em unidades de CPU do Kubernetes. Memória é especificada em bytes. Em cargas de trabalho Linux, você pode especificar o recurso huge pages. Huge pages são uma funcionalidade específica do Linux que permite ao núcleo do sistema operacional alocar blocos de memória muito maiores que o tamanho de página de memória padrão.
Por exemplo, em um sistema onde o tamanho da página de memória padrão é de 4 KiB,
você pode especificar um limite hugepages-2Mi: 80Mi. Se o contêiner tentar
alocar mais de 40 huge pages de 2 MiB cada, ou um total de 80 MiB, essa
alocação irá falhar.
hugepages-*.
O recurso hugepages-* difere dos recursos memory e cpu neste aspecto.CPU e memória são chamados coletivamente de recursos computacionais, ou apenas recursos. Recursos computacionais são quantidades mensuráveis que podem ser requisitadas, alocadas, e consumidas. Estes recursos diferem dos recursos de API. Recursos de API, como Pods e Services são objetos que podem ser lidos e modificados através do servidor da API do Kubernetes.
Para cada contêiner, você pode especificar limites e requerimentos de recursos, incluindo os seguintes recursos:
spec.containers[].resources.limits.cpuspec.containers[].resources.limits.memoryspec.containers[].resources.limits.hugepages-<size>spec.containers[].resources.requests.cpuspec.containers[].resources.requests.memoryspec.containers[].resources.requests.hugepages-<size>Embora você possa especificar apenas requerimentos e limites para contêineres individuais, é útil também pensar sobre os requerimentos e limites gerais de um Pod. Para um recurso em particular, um requerimento ou limite de recurso de um Pod é a soma de todos os valores dos requerimentos ou limites de um recurso daquele tipo, especificados em cada um dos contêineres daquele Pod.
Limites e requerimentos de recursos de CPU são mensurados em unidades de cpu. No Kubernetes, uma unidade de CPU é equivalente a um núcleo físico de CPU, ou um núcleo virtual, dependendo se o nó é uma máquina física ou uma máquina virtual rodando em uma máquina física.
Requerimentos fracionários são permitidos. Quando você define um contêiner cujo
valor do campo spec.containers[].resources.requests.cpu é 0.5, você está
solicitando metade da quantidade de CPU que teria sido solicitada caso o valor
fosse 1.0.
No caso de unidades de recurso de CPU, a expressão de
quantidade 0.1
é equivalente à expressão 100m, que pode ser lida como "cem milicpus", ou
"cem milinúcleos". "Milicpu" ou "milinúcleo" equivalem à milésima parte de um
núcleo ou CPU, de modo que "100m" equivalem a 10% do tempo computacional de um
processador.
Recursos de CPU são sempre especificados como uma quantidade absoluta de recurso,
nunca como uma quantidade relativa. Por exemplo, 500m de CPU representam
grosseiramente a mesma quantidade de poder computacional, independentemente do
contêiner rodar em uma máquina com processador de núcleo único, de dois núcleos
ou de 48 núcleos.
1m. Devido a isso, é útil especificar unidades de CPU menores do que
1.0 ou 1000m utilizando a notação de milicpu. Por exemplo, 5m ao invés de
0.005.Limites e requerimentos de memory são medidos em bytes. Você pode expressar
memória como um número inteiro ou como um número de ponto fixo, utilizando um
destes sufixos de
quantidade:
E, P, T, G, M, k. Você também pode utilizar os equivalentes de potência de dois:
Ei, Pi, Ti, Gi, Mi, Ki. Por exemplo, as quantidades abaixo representam, a grosso
modo, o mesmo valor:
128974848, 129e6, 129M, 128974848000m, 123Mi
Tome cuidado com os sufixos. Se você solicitar 400m de memória, esta
quantidade estará de fato requerendo o equivalente a 0,4 byte de memória. A
intenção da pessoa que fez esta requisição provavelmente era solictar 400
mebibytes (400Mi) ou 400 megabytes (400M).
O Pod seguinte tem dois contêineres. Ambos os contêineres têm um requerimento de 0,25 CPU e 64 MiB (ou 226 bytes) de memória. Cada contêiner tem um limite de 0,5 CPU e 128 MiB de memória. Você pode dizer que o Pod tem um requerimento de 0,5 CPU e 128 MiB de memória, e um limite de 1 CPU e 256 MiB de memória.
---
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: app
image: images.my-company.example/app:v4
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: log-aggregator
image: images.my-company.example/log-aggregator:v6
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
Quando você cria um Pod, o escalonador do Kubernetes seleciona um nó para que o Pod rode. Cada nó possui uma capacidade máxima para cada um dos tipos de recurso: a quantidade de CPU e memória que o nó pode fornecer aos Pods. O escalonador garante que, para cada tipo de recurso, a soma dos requerimentos de recursos dos contêineres agendados seja menor que a capacidade do nó. Note que, embora o consumo de memória ou CPU real nos nós seja muito baixo, o escalonador ainda irá se recusar a agendar um Pod em um nó se a verificação de capacidade falhar. Isso protege contra a falta de um recurso em um nó quando o consumo de recursos aumenta com o passar do tempo, como por exemplo durante o pico diário de requisições a um serviço.
Quando o kubelet inicia um contêiner como parte de um Pod, o kubelet envia as requisições e limites de memória e de CPU ao agente de execução de contêiner.
No Linux, o agente de execução de contêiner normalmente configura os cgroups que aplicam e garantem os limites que você definiu.
memory.min e memory.low.emptyDir. O kubelet considera
sistemas de arquivos tmpfs em volumes do tipo emptyDir como uso de memória
em um contêiner, ao invés de armazenamento efêmero local.Se um contêiner exceder seu requerimento de memória e o nó em que esse contêiner está rodando ficar com pouca memória no total, é provável que o Pod a que este contêiner pertence seja removido.
A um contêiner pode ou não ser permitido exceder seu limite de CPU por períodos de tempo estendidos. No entanto, agentes de execução de contêiner não encerram Pods por uso excessivo de CPU.
A fim de determinar se um contêiner não pode ser agendado ou está sendo encerrado devido a limites de recursos, consulte a seção de solução de problemas.
O kubelet relata a utilização de recursos de um Pod como parte do
status
do Pod.
Se ferramentas opcionais para monitoramento de recursos estiverem disponíveis em seu cluster, a utilização de recursos de um Pod pode ser verificada diretamente através de API de métricas ou através das suas ferramentas de monitoramento
Kubernetes v1.10 [beta]
Nós possuem armazenamento efêmero local, através de dispositivos de escrita conectados localmente ou através de RAM. "Efêmero" significa que não há garantia de longo termo com relação a durabilidade.
Pods utilizam armazenamento local efêmero para dados temporários, cache e logs.
O kubelet pode fornecer armazenamento temporário a Pods que utilizam
armazenamento local efêmero para montar volumes
do tipo emptyDir em contêineres.
O kubelet também utiliza este tipo de armazenamento para logs de contêineres a nível de nó, imagens de contêiner e camadas graváveis de contêineres em execução.
Com esta funcionalidade em fase beta, o Kubernetes permite que você rastreie, reserve e limite quanto armazenamento local efêmero um Pod pode consumir.
O Kubernetes suporta duas formas de configuração para o armazenamento local efêmero em um nó:
Nesta configuração, você armazena todos os tipos diferentes de dados locais
efêmeros (volumes do tipo emptyDir, camadas graváveis, imagens de contêiner,
logs) em um sistema de arquivos único. A forma mais efetiva de configurar o
kubelet é dedicar este sistema de arquivos aos dados do Kubernetes (kubelet).
O kubelet também escreve logs de contêiner a nível de nó e trata estes logs de maneira semelhante ao armazenamento efêmero local.
O kubelet escreve logs em arquivos dentro do seu diretório de log configurado
(/var/log por padrão) e possui um diretório base para outros dados armazenados
localmente (/var/lib/kubelet por padrão).
Normalmente, ambos os diretórios /var/lib/kubelet e /var/log encontram-se no
sistema de arquivos raiz, e o kubelet é projetado com este desenho em mente.
Seu nó pode ter tantos outros sistemas de arquivos não utilizados pelo Kubernetes quantos você desejar.
Você tem um sistema de arquivos no nó que você utiliza para dados efêmeros que
vêm de Pods em execução: logs e volumes do tipo emptyDir. Você pode utilizar
este sistema de arquivos para outros dados (por exemplo, logs de sistema não
relacionados ao Kubernetes); este sistema de arquivos pode até mesmo ser o
sistema de arquivos raiz.
O kubelet também escreve logs de contêiner a nível de nó no primeiro sistema de arquivos e os trata de forma semelhante ao armazenamento local efêmero.
Você também tem um segundo sistema de arquivos, separado, conectado a um dispositivo lógico de armazenamento distinto. Nesta configuração, o diretório que você configurou o kubelet para armazenar as camadas de imagens de contêiner e as camadas graváveis de contêineres em execução estará neste segundo sistema de arquivos.
O primeiro sistema de arquivos não armazena nenhuma camada de imagens de contêiner ou camada gravável.
Seu nó pode ter tantos outros sistemas de arquivos não utilizados pelo Kubernetes quantos você desejar.
O kubelet consegue medir quanto armazenamento local está sendo utilizado. O kubelet faz isso desde que:
LocalStorageCapacityIsolation esteja habilitado (a funcionalidade está
ligada por padrão), eSe você tiver uma configuração diferente, o kubelet não irá aplicar limites de recursos para o armazenamento local efêmero.
emptyDir que utilizem o sistema de arquivos tmpfs
como uso de memória de contêiner, ao invés de consumo de armazenamento local
efêmero.Você pode especificar o recurso ephemeral-storage para gerenciar o
armazenamento local efêmero. Cada contêiner de um Pod pode especificar um dos
valores abaixo, ou ambos:
spec.containers[].resources.limits.ephemeral-storagespec.containers[].resources.requests.ephemeral-storageLimites e requerimentos de ephemeral-storage são medidos em quantidades de
bytes. Você pode expressar armazenamento como um inteiro ou como um valor de
ponto fixo utilizando um dos seguintes sufixos: E, P, T, G, M, k. Você pode
também utilizar os equivalentes de potência de dois: Ei, Pi, Ti, Gi, Mi, Ki.
Por exemplo, as quantidades abaixo representam grosseiramente o mesmo valor:
128974848129e6129M123MiNo exemplo a seguir, o Pod tem dois contêineres. Cada contêiner tem um requerimento de 2GiB de armazenamento efêmero local. Cada contêiner tem um limite de 4GiB de armazenamento efêmero local. Portanto, o Pod tem um requerimento de 4GiB e um limite de 8GiB de armazenamento efêmero local.
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: app
image: images.my-company.example/app:v4
resources:
requests:
ephemeral-storage: "2Gi"
limits:
ephemeral-storage: "4Gi"
volumeMounts:
- name: ephemeral
mountPath: "/tmp"
- name: log-aggregator
image: images.my-company.example/log-aggregator:v6
resources:
requests:
ephemeral-storage: "2Gi"
limits:
ephemeral-storage: "4Gi"
volumeMounts:
- name: ephemeral
mountPath: "/tmp"
volumes:
- name: ephemeral
emptyDir: {}
ephemeral-storage são agendadosQuando você cria um Pod, o Kubernetes seleciona um nó para o Pod rodar. Cada nó tem uma quantidade máxima de armazenamento efêmero local que pode ser fornecida aos Pods. Para mais informações, consulte Node Allocatable.
O escalonador garante que a soma dos requerimentos de recursos dos contêineres agendados é menor que a capacidade do nó.
Se o kubelet estiver gerenciando armazenamento local efêmero como um recurso, o kubelet irá medir o consumo de armazenamento em:
emptyDir, com exceção dos volumes do tipo tmpfsSe um Pod estiver utilizando mais armazenamento efêmero do que o permitido, o kubelet irá gerar um sinal de remoção para aquele Pod.
Para isolamento a nível de contêiner, se o consumo de armazenamento de um contêiner em camadas graváveis e logs exceder seu limite de armazenamento, o kubelet irá marcar o Pod para remoção.
Para isolamento a nível de Pod, o kubelet calcula um limite de armazenamento
total para um Pod somando os limites de cada contêiner naquele Pod. Neste caso,
se a soma do consumo de armazenamento efêmero local de todas os contêineres e
também dos volumes emptyDir de um Pod exceder o limite de armazenamento total
do Pod, então o kubelet marca o Pod para remoção.
Se o kubelet não estiver medindo armazenamento efêmero local, um Pod que exeder seu limite de armazenamento local não será removido por exceder os limites de recurso de armazenamento local.
No entanto, se o espaço de um sistema de arquivos para camadas de contêiner
graváveis, logs a nível de nó, ou volumes emptyDir ficar reduzido, o nó irá
marcar a si próprio com um taint
indicando que está com armazenamento local reduzido, e esse taint dispara a
remoção de Pods que não toleram o taint em questão.
Veja as configurações suportadas para armazenamento efêmero local.
O kubelet suporta formas diferentes de medir o uso de armazenamento dos Pods:
O kubelet executa verificações agendadas, em intervalos regulares, que varrem
cada volume do tipo emptyDir, diretório de log de contêiner, e camada gravável
de contêiner.
A varredura mede quanto espaço está sendo utilizado.
Neste modo, o kubelet não rastreia descritores de arquivos abertos para arquivos removidos.
Se você (ou um contêiner) criar um arquivo dentro de um volume emptyDir, um
processo ou usuário abrir tal arquivo, e você apagar o arquivo enquanto ele
ainda estiver aberto, o nó de índice para o arquivo apagado será mantido até que
o arquivo seja fechado novamente. O kubelet, no entanto, não computa este espaço
como espaço em uso.
Quotas de projeto são uma funcionalidade a nível de sistema operacional para
gerenciamento de uso do armazenamento em sistemas de arquivos. Com o Kubernetes,
você pode habilitar quotas de projeto para o monitoramento de armazenamento em
uso. Tenha certeza que o sistema de arquivos do nó que esteja sendo utilizado em
volumes do tipo emptyDir possui suporte a quotas de projeto. Por exemplo,
os sistemas de arquivos XFS e ext4fs oferecem suporte a quotas de projeto.
O Kubernetes utiliza IDs de projeto iniciando em 1048576. Os IDs em uso estão
registrados nos diretórios /etc/projects e /etc/projid. Se os IDs de projeto
nestes intervalos forem utilizados para outros propósitos no sistema, estes IDs
de projeto deverão estar registrados nos diretórios especificados acima para que
o Kubernetes não os tente utilizar.
Quotas fornecem melhor desempenho e mais precisão do que varredura de diretórios. Quando um diretório é atribuído a um projeto, todos os arquivos criados no diretório são também criados no projeto, e o núcleo do sistema pode simplesmente manter controle de quantos blocos estão em uso por arquivos daquele projeto. Se um arquivo é criado e apagado, mas possui um descritor de arquivo aberto, ele continua a consumir espaço. O rastreio de quotas registra este espaço de forma precisa, enquanto varreduras de diretório ignoram o uso de espaço de armazenamento por arquivos apagados.
Se você deseja utilizar quotas de projeto, você deve:
Habilitar o feature gate
LocalStorageCapacityIsolationFSQuotaMonitoring=true utilizando o campo
featureGates na configuração do kubelet
ou a opção de linha de comando --feature-gates.
Garantir que o sistema de arquivos raiz (ou o sistema de arquivos opcional de tempo de execução) tem quotas de projeto habilitadas. Todos os sistemas de arquivos XFS suportam quotas de projeto. Em sistemas de arquivos ext4, você precisa habilitar a funcionalidade de rastreio de quotas de projeto enquanto o sistema de arquivos ainda não está montado.
# Para sistema de arquivos ext4, com o volume /dev/block-device não montado
sudo tune2fs -O project -Q prjquota /dev/block-device
Garanta que o sistema de arquivos raiz (ou sistema de arquivos opcional de
tempo de execução) esteja montado com quotas de projeto habilitadas. Em ambos
os sistemas XFS e ext4fs, a opção de montagem é chamada prjquota.
Recursos estendidos são nomes de recursos absolutos fora do domínio
kubernetes.io. Estes recursos permitem a operadores de cluster anunciar e a
usuários consumir recursos que não são embutidos pelo Kubernetes.
Dois passos são necessários para a utilização de recursos estendidos. Primeiramente, o operador do cluster deve anunciar um recurso estendido. Em segundo lugar, os usuários devem solicitar o recurso estendido em Pods.
Recursos estendidos a nível de nó são recursos ligados ao nó.
Veja Device Plugin para mais informações sobre como anunciar recursos gerenciados por dispositivos conectados em cada nó.
A fim de anunciar um novo recurso estendido a nível de nó, o operador do cluster
pode enviar uma requisição HTTP com o método PATCH para o servidor da API do
Kubernetes para especificar a quantidade disponível em um nó no cluster, através
do campo status.capacity. Após a realização desta operação, o campo
status.capacity do nó irá conter um novo recurso. O campo status.allocatable
é atualizado automaticamente pelo kubelet, de forma assíncrona, com o novo
recurso.
Como o escalonador utiliza o valor do campo status.allocatable do nó ao
verificar a saúde do Pod, o escalonador somente considerará o novo valor do
campo após esta atualização assíncrona. Pode haver um pequeno atraso entre a
atualização da capacidade do nó com um novo recurso e o momento em que o
primeiro Pod que requer o recurso poderá ser agendado naquele nó.
Exemplo:
Este exemplo demonstra como utilizar a ferramenta curl para criar uma
requisição HTTP que anuncia cinco recursos "example.com/foo" no nó k8s-node-1,
cujo nó da camada de gerenciamento é k8s-master.
curl --header "Content-Type: application/json-patch+json" \
--request PATCH \
--data '[{"op": "add", "path": "/status/capacity/example.com~1foo", "value": "5"}]' \
http://k8s-master:8080/api/v1/nodes/k8s-node-1/status
~1 é a codificação do caractere / no campo
path para a operação de atualização. O valor do campo path em JSON-Patch é
interpretado como um JSON-Pointer. Para maiores detalhes, veja
a seção 3 da IETF RFC 6901.Recursos estendidos a nível de cluster não são vinculados aos nós. Estes recursos são normalmente gerenciados por extensões do escalonador, que manipulam o consumo e as quotas de recursos.
Você pode especificar os recursos estendidos que são manipulados por extensões do escalonador nas configurações do kube-scheduler.
Exemplo:
A configuração abaixo para uma política do escalonador indica que o recurso estendido a nível de cluster "example.com/foo" é manipulado pelas extensões do escalonador.
ignoredByScheduler especifica que o escalonador não verifica o
recurso "example.com/foo" em seu predicado PodFitsResources.{
"kind": "Policy",
"apiVersion": "v1",
"extenders": [
{
"urlPrefix":"<extender-endpoint>",
"bindVerb": "bind",
"managedResources": [
{
"name": "example.com/foo",
"ignoredByScheduler": true
}
]
}
]
}
Usuários podem consumir recursos estendidos em especificações de Pods como CPU e memória. O escalonador controla a contagem de recursos de modo que a quantidade alocada simultaneamente a Pods não seja maior que a quantidade disponível.
O servidor da API limita as quantidades de recursos estendidos a números inteiros.
Exemplos de quantidades válidas são 3, 3000m e 3Ki. Exemplos de
quantidades inválidas são 0.5 e 1500m.
kubernetes.io, que é reservado.Para consumir um recurso estendido em um Pod, inclua o nome do recurso como uma
chave no mapa spec.containers[].resources.limits na especificação do contêiner.
request e
limit devem ser iguais se ambos estiverem presentes na especificação de um
contêiner.Um Pod só é agendado se todos os seus requerimentos de recursos forem
satisfeitos, incluindo CPU, memória e quaisquer recursos estendidos. O Pod
permanece no estado PENDING enquanto seus requerimentos de recursos não puderem
ser satisfeitos.
Exemplo:
O Pod abaixo requisita duas CPUs e um "example.com/foo" (um recurso estendido).
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: myimage
resources:
requests:
cpu: 2
example.com/foo: 1
limits:
example.com/foo: 1
Limites de ID de processo (PID) permitem à configuração de um kubelet limitar o número de PIDs que um dado Pod pode consumir. Consulte PID Limiting para mais informações.
FailedSchedulingSe o escalonador não conseguir encontrar nenhum nó que atenda aos requisitos de
recursos do Pod, este Pod permanecerá não-agendado até que um local destino
possa ser encontrado. Um Evento
é produzido cada vez que o escalonador falhar em encontrar um local para agendar
o Pod. Você pode utilizar o utilitário kubectl para ver os eventos de um Pod.
Por exemplo:
kubectl describe pod frontend | grep -A 9999999999 Events
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 23s default-scheduler 0/42 nodes available: insufficient cpu
No exemplo acima, o Pod de nome "frontend" não pôde ser agendado devido à nenhum
nó possuir CPU suficiente para suprir seu requerimento de CPU. Mensagens de erro
semelhantes a essa podem sugerir falha devido a falta de memória
(PodExceedsFreeMemory). De maneira geral, se um Pod estiver pendente com uma
mensagem deste tipo, há diversas possibilidades de solução a serem tentadas:
cpu: 1, um Pod que requisita cpu: 1.1 nunca será
agendado.Você pode verificar capacidades de nós e quantidades alocadas com o comando
kubectl describe nodes. Por exemplo:
kubectl describe nodes e2e-test-node-pool-4lw4
Name: e2e-test-node-pool-4lw4
[ ... linhas abreviadas para simplificação ...]
Capacity:
cpu: 2
memory: 7679792Ki
pods: 110
Allocatable:
cpu: 1800m
memory: 7474992Ki
pods: 110
[ ... linhas abreviadas para simplificação ...]
Non-terminated Pods: (5 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits
--------- ---- ------------ ---------- --------------- -------------
kube-system fluentd-gcp-v1.38-28bv1 100m (5%) 0 (0%) 200Mi (2%) 200Mi (2%)
kube-system kube-dns-3297075139-61lj3 260m (13%) 0 (0%) 100Mi (1%) 170Mi (2%)
kube-system kube-proxy-e2e-test-... 100m (5%) 0 (0%) 0 (0%) 0 (0%)
kube-system monitoring-influxdb-grafana-v4-z1m12 200m (10%) 200m (10%) 600Mi (8%) 600Mi (8%)
kube-system node-problem-detector-v0.1-fj7m3 20m (1%) 200m (10%) 20Mi (0%) 100Mi (1%)
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
CPU Requests CPU Limits Memory Requests Memory Limits
------------ ---------- --------------- -------------
680m (34%) 400m (20%) 920Mi (11%) 1070Mi (13%)
No exemplo anterior, você pode verificar que se um Pod requisitar mais que 1,120 CPUs ou mais que 6,23Gi de memória, tal Pod não caberá neste nó.
Ao verificar a seção "Pods", você pode observar quais Pods estão consumindo espaço neste nó.
A quantidade de recursos disponível aos Pods é menor que a capacidade do nó, pois
daemons do sistema utilizam uma parcela dos recursos disponíveis. Dentro da API
do Kubernetes, cada nó tem um campo .status.allocatable
(consulte NodeStatus
para mais detalhes).
O campo .status.allocatable descreve a quantidade de recursos que está
disponível a Pods naquele nó (por exemplo: 15 CPUs virtuais e 7538 MiB de
memória). Para mais informações sobre recursos alocáveis do nó no Kubernetes,
veja Reserve Compute Resources for System Daemons.
Você pode configurar quotas de recursos
para limitar a quantidade total de recursos que um namespace pode consumir.
O Kubernetes garante quotas para objetos em um namespace específico quando há
uma ResourceQuota naquele namespace. Por exemplo, se você atribuir namespaces
específicos a times diferentes, você pode adicionar ResourceQuotas nestes
namespaces. Criar quotas de recursos ajuda a evitar que um time utilize tanto de
um recurso que chegue a afetar outros times utilizando o mesmo cluster.
Você deve também considerar o nível de acesso fornecido aos usuários de qualquer
namespace: acesso completo para escrita permite a alguém com este acesso
remover qualquer recurso, incluindo uma configuração de ResourceQuota.
Seu contêiner pode ser terminado se faltar recursos para que este rode. Para
verificar se um contêiner está sendo terminado por chegar no limite de algum
recurso, utilize o comando kubectl describe pod no Pod em questão:
kubectl describe pod simmemleak-hra99
A saída será semelhante a:
Name: simmemleak-hra99
Namespace: default
Image(s): saadali/simmemleak
Node: kubernetes-node-tf0f/10.240.216.66
Labels: name=simmemleak
Status: Running
Reason:
Message:
IP: 10.244.2.75
Containers:
simmemleak:
Image: saadali/simmemleak:latest
Limits:
cpu: 100m
memory: 50Mi
State: Running
Started: Tue, 07 Jul 2019 12:54:41 -0700
Last State: Terminated
Reason: OOMKilled
Exit Code: 137
Started: Fri, 07 Jul 2019 12:54:30 -0700
Finished: Fri, 07 Jul 2019 12:54:33 -0700
Ready: False
Restart Count: 5
Conditions:
Type Status
Ready False
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 42s default-scheduler Successfully assigned simmemleak-hra99 to kubernetes-node-tf0f
Normal Pulled 41s kubelet Container image "saadali/simmemleak:latest" already present on machine
Normal Created 41s kubelet Created container simmemleak
Normal Started 40s kubelet Started container simmemleak
Normal Killing 32s kubelet Killing container with id ead3fb35-5cf5-44ed-9ae1-488115be66c6: Need to kill Pod
No exemplo acima, o campo Restart Count: 5 indica que o contêiner simmemleak
deste Pod foi terminado e reiniciado cinco vezes até o momento. A razão
OOMKilled demonstra que o contêiner tentou consumir mais memória do que o seu
limite.
O próximo passo neste cenário seria vasculhar e depurar o código da aplicação, procurando por vazamentos de memória. Se você determinar que a aplicação está se comportando conforme o esperado, considere aumentar o limite (e possivelmente o requerimento) de memória para aquele contêiner.
Utilize arquivos kubeconfig para organizar informações sobre clusters, usuários, namespaces e mecanismos de autenticação. A ferramenta de linha de comando kubectl faz uso dos arquivos kubeconfig para encontrar as informações necessárias para escolher e se comunicar com o serviço de API de um cluster.
kubeconfig.Por padrão, o kubectl procura por um arquivo de nome config no diretório $HOME/.kube
Você pode especificar outros arquivos kubeconfig através da variável de ambiente KUBECONFIG ou adicionando a opção --kubeconfig.
Para maiores detalhes na criação e especificação de um kubeconfig, veja o passo a passo em Configurar Acesso para Múltiplos Clusters.
Imagine que você possua inúmeros clusters, e seus usuários e componentes se autenticam de várias formas. Por exemplo:
Através de arquivos kubeconfig, você pode organizar os seus clusters, usuários, e namespaces. Você também pode definir contextos para uma fácil troca entre clusters e namespaces.
Um elemento de contexto em um kubeconfig é utilizado para agrupar parâmetros de acesso em um nome conveniente. Cada contexto possui três parâmetros: cluster, namespace, e usuário.
Por padrão, a ferramenta de linha de comando kubectl utiliza os parâmetros do contexto atual para se comunicar com o cluster.
Para escolher o contexto atual:
kubectl config use-context
A variável de ambiente KUBECONFIG possui uma lista dos arquivos kubeconfig. Para Linux e Mac, esta lista é delimitada por vírgula. No Windows, a lista é delimitada por ponto e vírgula. A variável de ambiente KUBECONFIG não é um requisito obrigatório - caso ela não exista o kubectl utilizará o arquivo kubeconfig padrão localizado no caminho $HOME/.kube/config.
Se a variável de ambiente KUBECONFIG existir, o kubectl utilizará uma configuração que é o resultado da combinação dos arquivos listados na variável de ambiente KUBECONFIG.
Para inspecionar a sua configuração atual, execute o seguinte comando:
kubectl config view
Como descrito anteriormente, a saída poderá ser resultado de um único arquivo kubeconfig, ou poderá ser o resultado da junção de vários arquivos kubeconfig.
Aqui estão as regras que o kubectl utiliza quando realiza a combinação de arquivos kubeconfig:
Se o argumento --kubeconfig está definido, apenas o arquivo especificado será utilizado. Apenas uma instância desta flag é permitida.
Caso contrário, se a variável de ambiente KUBECONFIG estiver definida, esta deverá ser utilizada como uma lista de arquivos a serem combinados, seguindo o fluxo a seguir:
current-context.
Exemplo: Se dois arquivos especificarem um red-user, use apenas os valores do primeiro red-user. Mesmo se um segundo arquivo possuir entradas não conflitantes sobre a mesma entrada red-user, estas deverão ser descartadas.Para um exemplo de definição da variável de ambiente KUBECONFIG veja Definido a variável de ambiente KUBECONFIG.
Caso contrário, utilize o arquivo kubeconfig padrão encontrado no diretório $HOME/.kube/config, sem qualquer tipo de combinação.
Determine o contexto a ser utilizado baseado no primeiro padrão encontrado, nesta ordem:
--context caso ela existir.current-context a partir da combinação dos arquivos kubeconfig.Um contexto vazio é permitido neste momento.
Determinar o cluster e o usuário. Neste ponto, poderá ou não existir um contexto. Determinar o cluster e o usuário no primeiro padrão encontrado de acordo com a ordem à seguir. Este procedimento deverá executado duas vezes: uma para definir o usuário a outra para definir o cluster.
--user ou --cluster.O usuário e o cluster poderão estar vazios neste ponto.
Determinar as informações do cluster atual a serem utilizadas. Neste ponto, poderá ou não existir informações de um cluster.
Construir cada peça de informação do cluster baseado nas opções à seguir; a primeira ocorrência encontrada será a opção vencedora:
--server, --certificate-authority, --insecure-skip-tls-verify.Determinar a informação atual de usuário a ser utilizada. Construir a informação de usuário utilizando as mesmas regras utilizadas para o caso de informações de cluster, exceto para a regra de técnica de autenticação que deverá ser única por usuário:
--client-certificate, --client-key, --username, --password, --token.user resultado da combinação de arquivos kubeconfig.Para qualquer informação que ainda estiver ausente, utilizar os valores padrão e potencialmente solicitar informações de autenticação a partir do prompt de comando.
Arquivos e caminhos referenciados em um arquivo kubeconfig são relativos à localização do arquivo kubeconfig.
Referências de arquivos na linha de comando são relativas ao diretório de trabalho vigente.
No arquivo $HOME/.kube/config, caminhos relativos são armazenados de forma relativa, e caminhos absolutos são armazenados de forma absoluta.
Esta página descreve as diferenças em como os recursos são gerenciados entre o Linux e o Windows.
Em nós Linux, cgroups são usados como uma divisão para o controle de recursos em Pods. Os contêineres são criados dentro desse limite para o isolamento de rede, processo e sistema de arquivos. As APIs de cgroup do Linux podem ser usadas para coletar estatísticas de uso de CPU, E/S e memória.
Em contraste, o Windows usa um objeto de trabalho por contêiner com um filtro de namespace do sistema para conter todos os processos em um contêiner e fornecer isolamento lógico ao hospedar. (Os objetos de trabalho são um mecanismo de isolamento de processo do Windows e são diferentes dos que o Kubernetes chama de Job).
Não há como executar um contêiner do Windows sem a filtragem de namespace. Isso significa que os privilégios do sistema não podem ser assegurados no contexto do host e, portanto, os contêineres privilegiados não estão disponíveis no Windows. Os contêineres não podem assumir uma identidade do host porque o Gerente de Conta de Segurança (Security Account Manager, ou SAM) é separado.
O Windows não possui um eliminador de processo por falta de memória como o Linux. O Windows sempre trata todas as alocações de memória do modo de usuário como virtuais e os arquivos de paginação são obrigatórios.
Os nós Windows não superdimensionam a memória para os processos. O efeito real é que o Windows não atingirá as condições de falta de memória da mesma forma que o Linux, e estará processando a página em disco em vez de estar sujeito ao encerramento por falta de memória (OOM). Se a memória for superprovisionada e toda a memória física estiver esgotada, a paginação poderá diminuir o desempenho.
O Windows pode limitar a quantidade de tempo de CPU alocado para diferentes processos, mas não pode garantir uma quantidade mínima de tempo de CPU.
No Windows, o kubelet oferece suporte a uma flag de linha de comando para definir a
prioridade do escalonador do processo kubelet:
--windows-priorityclass. Essa flag permite que o processo kubelet obtenha
mais fatias de tempo de CPU quando comparado a outros processos em execução no host do Windows.
Mais informações sobre os valores permitidos e os seus significados estão disponíveis em
classes de prioridade do Windows.
Para garantir que os Pods em execução não deixem o kubelet sem ciclos de CPU, defina essa flag como ABOVE_NORMAL_PRIORITY_CLASS ou acima.
Para contabilizar a memória e a CPU usadas pelo sistema operacional, o agente de execução de contêiner
e os processos de host do Kubernetes, como o kubelet, você pode (e deve)
reservar recursos de memória e CPU com as flags --kube-reserved e/ou --system-reserved do kubelet.
No Windows, esses valores são usados apenas para calcular o recursos
alocáveis pelo nó.
Conforme você implanta cargas de trabalho, defina a memória de recursos e os limites de CPU nos contêineres.
Isso também subtrai de NodeAllocatable e ajuda o escalonador de todo o cluster a determinar quais pods colocar em quais nós.
Alocar pods sem limites pode superprovisionar os nós do Windows e, em casos extremos, fazer com que os nós não sejam íntegros.
No Windows, uma boa prática é reservar pelo menos 2GiB de memória.
Para determinar quanta CPU reservar, identifique a densidade máxima do pod para cada nó e monitore o uso da CPU dos serviços do sistema em execução, depois escolha um valor que atenda às necessidades das suas cargas de trabalho.
Essa seção da documentação do Kubernetes busca ensinar a executar cargas de trabalho mais seguras e aspectos essenciais para a manutenção de um cluster Kubernetes seguro.
O Kubernetes é baseado em uma arquitetura cloud native e segue as boas práticas de segurança da informação para ambientes cloud native recomendadas pela CNCF.
Leia Segurança Cloud Native e Kubernetes para entender o contexto mais amplo sobre como proteger seu cluster e as aplicações que você está executando nele.
O Kubernetes inclui várias APIs e controles de segurança, além de mecanismos para definir políticas que podem fazer parte da sua estratégia de gestão da segurança da informação.
Um mecanismo de segurança fundamental para qualquer cluster Kubernetes é controlar o acesso à API do Kubernetes.
O Kubernetes espera que você configure e utilize TLS para fornecer criptografia de dados em trânsito dentro do control plane e entre o control plane e seus clientes. Você também pode habilitar a criptografia em repouso para os dados armazenados no plano de controle do Kubernetes; isso é diferente de usar criptografia em repouso para os dados das suas próprias cargas de trabalho, o que também pode ser uma boa prática.
A API Secret fornece proteção básica para valores de configuração que exigem confidencialidade.
Aplique os padrões de segurança de Pods para garantir que os Pods e seus contêineres sejam isolados de forma adequada. Você também pode usar RuntimeClasses para definir isolamento personalizado, se necessário.
As políticas de rede permitem controlar o tráfego de rede entre Pods ou entre Pods e a rede externa ao seu cluster.
Você pode implantar controles de segurança do ecossistema mais amplo para implementar controles preventivos ou de detecção em torno dos Pods, de seus contêineres e das imagens que eles executam.
Os admission controllers são plugins que interceptam requisições para a API do Kubernetes e podem validá-las ou modificá-las com base em campos específicos da requisição. Projetar esses controladores com cuidado ajuda a evitar interrupções não intencionais à medida que as APIs do Kubernetes mudam entre atualizações de versão. Para considerações de design, consulte Boas práticas para admission webhooks.
O log de auditoria do Kubernetes fornece um conjunto cronológico de registros relevantes para segurança, documentando a sequência de ações em um cluster. O cluster audita as atividades geradas por usuários, por aplicações que usam a API do Kubernetes e pelo próprio control plane.
Se você estiver executando um cluster Kubernetes em seu próprio hardware ou em um provedor de nuvem diferente, consulte sua documentação para conhecer as melhores práticas de segurança. Aqui estão links para a documentação de segurança de alguns provedores de nuvem populares:
| Provedor de IaaS | Link |
|---|---|
| Alibaba Cloud | https://www.alibabacloud.com/trust-center |
| Amazon Web Services | https://aws.amazon.com/security |
| Google Cloud Platform | https://cloud.google.com/security |
| Huawei Cloud | https://www.huaweicloud.com/intl/en-us/securecenter/overallsafety |
| IBM Cloud | https://www.ibm.com/cloud/security |
| Microsoft Azure | https://docs.microsoft.com/en-us/azure/security/azure-security |
| Oracle Cloud Infrastructure | https://www.oracle.com/security |
| Tencent Cloud | https://www.tencentcloud.com/solutions/data-security-and-information-protection |
| VMware vSphere | https://www.vmware.com/solutions/security/hardening-guides |
Você pode definir políticas de segurança usando mecanismos nativos do Kubernetes, como NetworkPolicy (controle declarativo sobre filtragem de pacotes de rede) ou ValidatingAdmissionPolicy (restrições declarativas sobre quais alterações alguém pode fazer usando a API do Kubernetes).
No entanto, você também pode contar com implementações de políticas do ecossistema mais amplo em torno do Kubernetes. O Kubernetes fornece mecanismos de extensão que permitem a esses projetos do ecossistema implementar seus próprios controles de política para revisão de código-fonte, aprovação de imagens de contêiner, controles de acesso à API, redes e muito mais.
Para mais informações sobre mecanismos de políticas e Kubernetes, consulte Políticas.
Saiba mais sobre tópicos relacionados à segurança no Kubernetes:
Entenda o contexto:
Obtenha a certificação:
Leia mais nesta seção:
Esta visão geral define um modelo para pensar sobre a segurança em Kubernetes no contexto da Segurança em Cloud Native.
Você pode pensar na segurança em camadas. Os 4C da segurança Cloud Native são a Cloud, Clusters, Contêineres e Código.
Cada camada do modelo de segurança Cloud Native é construída sobre a próxima camada mais externa. A camada de código se beneficia de uma base forte (Cloud, Cluster, Contêiner) de camadas seguras. Você não pode proteger contra padrões ruins de segurança nas camadas de base através de segurança no nível do Código.
De muitas maneiras, a Cloud (ou servidores co-localizados, ou o datacenter corporativo) é a base de computação confiável de um cluster Kubernetes. Se a camada de Cloud é vulnerável (ou configurado de alguma maneira vulnerável), então não há garantia de que os componentes construídos em cima desta base estejam seguros. Cada provedor de Cloud faz recomendações de segurança para executar as cargas de trabalho com segurança nos ambientes.
Se você estiver executando um cluster Kubernetes em seu próprio hardware ou em um provedor de nuvem diferente, consulte sua documentação para melhores práticas de segurança. Aqui estão os links para as documentações de segurança dos provedores mais populares de nuvem:
| Provedor IaaS | Link |
|---|---|
| Alibaba Cloud | https://www.alibabacloud.com/trust-center |
| Amazon Web Services | https://aws.amazon.com/security/ |
| Google Cloud Platform | https://cloud.google.com/security/ |
| Huawei Cloud | https://www.huaweicloud.com/intl/pt-br/securecenter/overallsafety |
| IBM Cloud | https://www.ibm.com/cloud/security |
| Microsoft Azure | https://docs.microsoft.com/en-us/azure/security/azure-security |
| Oracle Cloud Infrastructure | https://www.oracle.com/security/ |
| VMWare VSphere | https://www.vmware.com/solutions/security/hardening-guides |
Sugestões para proteger sua infraestrutura em um cluster Kubernetes:
| Área de Interesse para Infraestrutura Kubernetes | Recomendação |
|---|---|
| Acesso de rede ao servidor API (Control plane) | Todo o acesso ao control plane do Kubernetes publicamente na Internet não é permitido e é controlado por listas de controle de acesso à rede restritas ao conjunto de endereços IP necessários para administrar o cluster. |
| Acesso de rede aos Nós (nodes) | Os nós devem ser configurados para só aceitar conexões (por meio de listas de controle de acesso à rede) do control plane nas portas especificadas e aceitar conexões para serviços no Kubernetes do tipo NodePort e LoadBalancer. Se possível, esses nós não devem ser expostos inteiramente na Internet pública. |
| Acesso do Kubernetes à API do provedor de Cloud | Cada provedor de nuvem precisa conceder um conjunto diferente de permissões para o control plane e nós do Kubernetes. É melhor fornecer ao cluster permissão de acesso ao provedor de nuvem que segue o princípio do menor privilégio para os recursos que ele precisa administrar. A documentação do Kops fornece informações sobre as políticas e roles do IAM. |
| Acesso ao etcd | O acesso ao etcd (o armazenamento de dados do Kubernetes) deve ser limitado apenas ao control plane. Dependendo de sua configuração, você deve tentar usar etcd sobre TLS. Mais informações podem ser encontradas na documentação do etcd. |
| Encriptação etcd | Sempre que possível, é uma boa prática encriptar todas as unidades de armazenamento, mas como o etcd mantém o estado de todo o cluster (incluindo os Secrets), seu disco deve ser criptografado. |
Existem duas áreas de preocupação para proteger o Kubernetes:
Se você deseja proteger seu cluster de acesso acidental ou malicioso e adotar boas práticas de informação, leia e siga os conselhos sobre protegendo seu cluster.
Dependendo da superfície de ataque de sua aplicação, você pode querer se concentrar em tópicos específicos de segurança. Por exemplo: se você estiver executando um serviço (Serviço A) que é crítico numa cadeia de outros recursos e outra carga de trabalho separada (Serviço B) que é vulnerável a um ataque de exaustão de recursos e, por consequência, o risco de comprometer o Serviço A é alto se você não limitar os recursos do Serviço B. A tabela a seguir lista áreas de atenção na segurança e recomendações para proteger cargas de trabalho em execução no Kubernetes:
| Área de interesse para a segurança do Workload | Recomendação |
|---|---|
| Autorização RBAC (acesso à API Kubernetes) | https://kubernetes.io/docs/reference/access-authn-authz/rbac/ |
| Autenticação | https://kubernetes.io/docs/concepts/security/controlling-access/ |
| Gerenciamento de segredos na aplicação (e encriptando-os no etcd em repouso) | https://kubernetes.io/docs/concepts/configuration/secret/ https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/ |
| Garantir que os Pods atendem aos padrões de segurança do Pod | https://kubernetes.io/docs/concepts/security/pod-security-standards/#policy-instantiation |
| Qualidade de serviço (e gerenciamento de recursos de cluster) | https://kubernetes.io/docs/tasks/configure-pod-container/quality-service-pod/ |
| Políticas de Rede | https://kubernetes.io/docs/concepts/services-networking/network-policies/ |
| TLS para Kubernetes Ingress | https://kubernetes.io/docs/concepts/services-networking/ingress/#tls |
A segurança do contêiner está fora do escopo deste guia. Aqui estão recomendações gerais e links para explorar este tópico:
| Área de Interesse para Contêineres | Recomendação |
|---|---|
| Scanners de Vulnerabilidade de Contêiner e Segurança de Dependência de SO | Como parte da etapa de construção de imagem, você deve usar algum scanner em seus contêineres em busca de vulnerabilidades. |
| Assinatura Imagem e Enforcement | Assinatura de imagens de contêineres para manter um sistema de confiança para o conteúdo de seus contêineres. |
| Proibir Usuários Privilegiados | Ao construir contêineres, consulte a documentação para criar usuários dentro dos contêineres que tenham o menor nível de privilégio no sistema operacional necessário para cumprir o objetivo do contêiner. |
| Use o Contêiner em Runtime com Isolamento mais Forte | Selecione classes de contêiner runtime com o provedor de isolamento mais forte. |
O código da aplicação é uma das principais superfícies de ataque sobre a qual você tem maior controle. Embora a proteção do código do aplicativo esteja fora do tópico de segurança do Kubernetes, aqui são recomendações para proteger o código do aplicativo:
| Área de Atenção para o Código | Recomendação |
|---|---|
| Acesso só através de TLS | Se seu código precisar se comunicar por TCP, execute um handshake TLS com o cliente antecipadamente. Com exceção de alguns casos, encripte tudo em trânsito. Indo um passo adiante, é uma boa ideia encriptar o tráfego de rede entre os serviços. Isso pode ser feito por meio de um processo conhecido como mutual ou mTLS, que realiza uma verificação bilateral da comunicação mediante os certificados nos serviços. |
| Limitando intervalos de porta de comunicação | Essa recomendação pode ser um pouco autoexplicativa, mas, sempre que possível, você só deve expor as portas em seu serviço que são absolutamente essenciais para a comunicação ou coleta de métricas. |
| Segurança na Dependência de Terceiros | É uma boa prática verificar regularmente as bibliotecas de terceiros de sua aplicação em busca de vulnerabilidades de segurança. Cada linguagem de programação possui uma ferramenta para realizar essa verificação automaticamente. |
| Análise de Código Estático | A maioria das linguagens fornece uma maneira para analisar um extrato do código referente a quaisquer práticas de codificação potencialmente inseguras. Sempre que possível, você deve automatizar verificações usando ferramentas que podem verificar as bases de código em busca de erros de segurança comuns. Algumas das ferramentas podem ser encontradas em OWASP Source Code Analysis Tools. |
| Ataques de sondagem dinâmica | Existem algumas ferramentas automatizadas que você pode executar contra seu serviço para tentar alguns dos ataques mais conhecidos. Isso inclui injeção de SQL, CSRF e XSS. Uma das ferramentas de análise dinâmica mais populares é o OWASP Zed Attack proxy. |
Saiba mais sobre os tópicos de segurança do Kubernetes:
Em vez de usar PodSecurityPolicy, você pode aplicar restrições semelhantes em Pods usando um ou ambos:
Para obter um guia de migração, consulte Migre de PodSecurityPolicy para o controlador de admissão PodSecurity embutido. Para obter mais informações sobre a remoção desta API, veja Descontinuação de PodSecurityPolicy: passado, presente e futuro.
Se você não estiver executando o Kubernetes v1.35, verifique a documentação para sua versão do Kubernetes.
Esta página descreve considerações de segurança e boas práticas específicas para o sistema operacional Windows.
No Windows, os dados do Secret são escritos em texto não-encriptado no armazenamento local do nó (em comparação ao uso de tmpfs / sistemas de arquivo em memória no Linux). Como um operador do cluster, você deve tomar as duas medidas adicionais a seguir:
RunAsUsername pode ser utilizado em Pods ou contêineres com Windows para executar os processos do contêiner como usuário específico. Isto é aproximadamente equivalente a RunAsUser.
Os contêineres Windows oferecem duas contas de usuário padrão, ContainerUser e ContainerAdministrator. As diferenças entre estas duas contas de usuário são descritas em When to use ContainerAdmin and ContainerUser user accounts dentro da documentação da Microsoft Secure Windows containers.
Os usuários locais podem ser adicionados às imagens do contêiner durante o processo de criação do mesmo.
ContainerUser por padrão.ContainerAdministrator por padrão.Contêineres Windows também podem rodar como identidades do Active Directory usando Group Managed Service Accounts
Mecanismos de contexto de segurança de Pod específicos para Linux (como SELinux, AppArmor, Seccomp, ou capabilities customizados para POSIX) não são suportados nos nós com Windows.
Contêineres privilegiados não são suportados no Windows. Em vez disso, contêineres HostProcess podem ser usados no Windows para realizar muitas das tarefas realizadas por contêineres privilegiados no Linux.
Esta página fornece uma visão geral do controle de acesso à API do Kubernetes.
Usuários podem acessar a API do Kubernetes utilizando kubectl,
bibliotecas, ou executando requisições REST. Ambos, usuários humanos e
Contas de serviço do Kubernetes podem ser autorizados
a acessar à API.
Quando uma requisição chega à API, ela passa por diversos estágios,
ilustrados no seguinte diagrama:
Em um cluster Kubernetes típico, a API fica disponível na porta 443, protegida por segurança na camada de transporte (TLS). O servidor de API apresenta um certificado. Este certificado pode ser assinado utilizando uma autoridade privada de certificados (CA), ou baseado em uma infraestrutura de chave pública ligada a uma autoridade de certificados reconhecida publicamente.
Se o seu cluster utiliza uma autoridade privada de certificados, voce precisa de uma cópia do certificado
da autoridade de certificados (CA) dentro do arquivo de configuração ~/.kube/config, no lado do cliente, para que
voce possa confiar na conexão e tenha a garantia de que não há interceptação de tráfego.
O seu cliente pode apresentar o certificado de cliente TLS neste estágio.
Uma vez em que a segurança na camada de transporte (TLS) é estabelecida, a requisição HTTP move para o passo de autenticação. Isto é demonstrado no passo 1 no diagrama acima. O script de criação do cluster ou configurações de administração configuram o servidor de API para executar um ou mais módulos autenticadores.
Autenticadores são descritos em maiores detalhes em Autenticação.
A entrada para o passo de autenticação é a requisição HTTP completa; no entanto, tipicamente são verificados os cabeçalhos e/ou o certificado de cliente.
Módulos de autenticação incluem certificados de cliente, senhas, tokens simples, tokens de auto-inicialização e JSON Web Tokens (utilizados para contas de serviço).
Vários módulos de autenticação podem ser especificados, em que cada um será verificado em sequência, até que um deles tenha sucesso.
Se a requisição não pode ser autenticada, será rejeitada com o código de status HTTP 401 (não autorizado). Caso contrário, o usuário é autenticado com um "nome de usuário" específico e o nome de usuário está disponível para as etapas subsequentes para usar em suas decisões. Alguns autenticadores também fornecem as associações de grupo do usuário, enquanto outros autenticadores não o fazem.
Enquanto o Kubernetes usa nomes de usuário para decisões de controle de acesso e no registro de requisições,
ele não possui um objeto user nem armazena nomes de usuários ou outras informações sobre
usuários em sua API.
Após a requisição ser autenticada como originada de um usuário específico, a requisição deve ser autorizada. Isso é mostrado no passo 2 no diagrama.
Uma requisição deve incluir o nome do usuário requerente, a ação requisitada e o objeto afetado pela ação. A requisição é autorizada se uma política existente declarar que o usuário tem as devidas permissões para concluir a ação requisitada.
Por exemplo, se Bob possui a política abaixo, então ele somente poderá ler pods no namespace projectCaribou:
{
"apiVersion": "abac.authorization.kubernetes.io/v1beta1",
"kind": "Policy",
"spec": {
"user": "bob",
"namespace": "projectCaribou",
"resource": "pods",
"readonly": true
}
}
Se Bob fizer a seguinte requisição, a requisição será autorizada porque ele tem permissão para ler objetos no namespace projectCaribou:
{
"apiVersion": "authorization.k8s.io/v1beta1",
"kind": "SubjectAccessReview",
"spec": {
"resourceAttributes": {
"namespace": "projectCaribou",
"verb": "get",
"group": "unicorn.example.org",
"resource": "pods"
}
}
}
Se Bob fizer uma requisição para escrever (create ou update) em objetos no namespace projectCaribou, sua autorização será negada. Se Bob fizer uma requisição para ler (get) objetos em um namespace diferente, como projectFish, sua autorização será negada.
A autorização do Kubernetes requer que você use atributos comuns a REST para interagir com os sistemas de controle de acesso existentes em toda uma organização ou em todo o provedor de nuvem utilizado. É importante usar a formatação REST porque esses sistemas de controle podem interagir com outras APIs além da API do Kubernetes.
O Kubernetes oferece suporte a vários módulos de autorização, como o modo de controle de acesso baseado em atributos (ABAC), o modo de controle de acesso baseado em função (RBAC) e o modo Webhook. Quando um administrador cria um cluster, ele configura os módulos de autorização que devem ser utilizados no servidor de API. Se mais de um módulo de autorização for configurado, o Kubernetes verificará cada módulo e, se algum módulo autorizar a requisição, a requisição poderá prosseguir. Se todos os módulos negarem a requisição, a requisição será negada (com código de status HTTP 403 - Acesso Proibido).
Para saber mais sobre a autorização do Kubernetes, incluindo detalhes sobre como criar políticas usando os módulos de autorização compatíveis, consulte Visão Geral de Autorização.
Os módulos de controle de admissão são módulos de software que podem modificar ou rejeitar requisições. Além dos atributos disponíveis para os módulos de Autorização, os módulos do controlador de admissão podem acessar o conteúdo do objeto que está sendo criado ou modificado.
Os controladores de admissão atuam em requisições que criam, modificam, excluem ou age como um proxy para outro objeto. Os controladores de admissão não agem em requisições que apenas leem objetos. Quando vários controladores de admissão são configurados, eles são chamados em ordem.
Isso é mostrado como etapa 3 no diagrama.
Ao contrário dos módulos de autenticação e autorização, se algum módulo controlador de admissão rejeita, a solicitação é imediatamente rejeitada.
Além de rejeitar objetos, os controladores de admissão também podem definir valores padrão complexos para campos.
Os módulos de Controle de Admissão disponíveis são descritos em Using Admission Controllers.
Após uma requisição passar por todos os controladores de admissão, ela é validada usando as rotinas de validação para o objeto de API correspondente e, em seguida, gravados no armazenamento de objetos (mostrado como etapa 4 no diagrama).
A auditoria do Kubernetes fornece um conjunto de registros cronológicos relevantes para a segurança que documentam a sequência de ações em um cluster. O cluster audita as atividades geradas pelos usuários, pelos aplicativos que usam a API do Kubernetes e pela própria camada de gerenciamento.
Para mais informações, consulte Auditing.
A discussão anterior se aplica a requisições enviadas para a porta segura do servidor de API (o caso típico). O servidor de API pode realmente servir em 2 portas.
Por padrão, o servidor da API Kubernetes atende HTTP em 2 portas:
Porta localhost:
--insecure-bind-address.“Porta segura”:
--tls-cert-file e a chave com a flag --tls-private-key-file.--secure-port.--bind-address.Consulte mais documentação sobre autenticação, autorização e controle de acesso à API:
Você pode aprender mais sobre:
Por padrão, os cointêineres são executados com recursos computacionais ilimitados em um cluster Kubernetes. Com cotas de recursos, os administradores de cluster podem restringir o consumo e a criação de recursos baseado no namespace. Dentro de um namespace, pod ou contêiner pode haver o consumo de quantidade de CPU e memória definidos de acordo com a cota de recursos do namespace. Existe a preocupação de que um Pod ou contêiner possa monopolizar todos os recursos disponíveis, justamente por conta disso existe o conceito de Limit Range, ou intervalos de limite, que pode ser definido como uma política utilizada para a restrição de alocação de recursos (para pods ou contêineres) em um namespace.
Um LimitRange fornece restrições que podem:
O suporte ao LimitRange foi ativado por padrão desde o Kubernetes 1.10.
Um LimitRange é aplicado em um namespace específico quando há um objeto LimitRange nesse namespace.
O nome de um objeto LimitRange deve ser um nome de subdomínio DNS válido.
LimitRanger impõe padrões e limites para todos os pods e contêineres que não definem os requisitos de recursos computacionais e rastreia o uso para garantir que não exceda o mínimo, o máximo e a proporção de recursos definidos em qualquer LimitRange presente no namespace.403 FORBIDDEN e uma mensagem explicando a restrição violada.cpu e memória, os usuários deverão especificar solicitações ou limites para esses valores. Caso contrário, o sistema pode rejeitar a criação do pod.Alguns exemplos de políticas que podem ser criadas utilizando os intervalos de limite são:
Caso os limites totais do namespace sejam menores que a soma dos limites dos Pods/Contêineres, pode haver contenção por recursos. Nesse caso, os contêineres ou Pods não serão criados.
Nem a contenção nem as alterações em um LimitRange afetarão os recursos já criados.
Consulte o documento de design LimitRanger para obter mais informações.
Para exemplos de uso de limites, leia:
Quando vários usuários ou equipes compartilham um cluster com um número fixo de nós, há uma preocupação de que uma equipe possa usar mais do que é justo durante o compartilhamento de recursos.
As cotas de recursos são uma ferramenta para os administradores resolverem essa preocupação.
Uma cota de recurso, definida por um objeto ResourceQuota, fornece restrições que limitam
consumo de recursos agregados por namespace. Pode limitar a quantidade de objetos que podem
ser criado em um namespace por tipo, bem como a quantidade total de recursos computacionais que podem
ser consumidos por recursos nesse namespace.
As cotas de recursos funcionam assim:
Diferentes equipes trabalham em diferentes namespaces. Atualmente, isso é voluntário, mas o suporte para tornar isso obrigatório por meio de ACLs está planejado.
O administrador cria uma ResourceQuota para cada namespace.
Os usuários criam recursos (pods, serviços, etc.) no namespace e o sistema de cotas rastreia o uso para garantir que ele não exceda os limites de recursos definidos em um ResourceQuota.
Se a criação ou atualização de um recurso violar uma restrição de cota, a solicitação falhará com código de status HTTP 403 FORBIDDEN acompanhado de uma mensagem explicando a restrição que foi violada.
Se a cota estiver habilitada em um namespace para recursos computacionais como cpu e memória, os usuários devem especificar solicitações ou limites para esses valores; caso contrário, o sistema de cotas poderá rejeitar a criação de pods. Dica: use o controlador de admissão LimitRanger para forçar padrões para pods que não exigem recursos computacionais.
Veja o passo a passo para um exemplo de como evitar este problema.
O nome de um objeto ResourceQuota deve ser um nome do subdomínio DNS válido.
Exemplos de políticas que podem ser criadas usando namespaces e cotas são:
Caso a capacidade total do cluster seja menor que a soma das cotas dos namespaces, pode haver contenção de recursos. Isso é tratado por ordem de chegada.
Nem a contenção nem as alterações na cota afetarão os recursos já criados.
O suporte à cota de recursos é ativado por padrão para muitas distribuições do Kubernetes. Isto é
ativado quando a flag API server --enable-admission-plugins= tem ResourceQuota como
um de seus argumentos.
Uma cota de recurso é aplicada em um namespace específico quando há um ResourceQuota nesse namespace.
Você pode limitar a soma total de recursos computacionais que pode ser solicitado em um determinado namespace.
Os seguintes tipos de recursos são suportados:
| Nome do Recurso | Descrição |
|---|---|
limits.cpu |
Em todos os pods em um estado não terminal, a soma dos limites de CPU não pode exceder esse valor. |
limits.memory |
Em todos os pods em um estado não terminal, a soma dos limites de memória não pode exceder esse valor. |
requests.cpu |
Em todos os pods em um estado não terminal, a soma das solicitações da CPU não pode exceder esse valor. |
requests.memory |
Em todos os pods em um estado não terminal, a soma das solicitações de memória não pode exceder esse valor. |
hugepages-<size> |
Em todos os pods em um estado não terminal, o número de solicitações de grandes páginas do tamanho especificado não pode exceder esse valor. |
cpu |
O mesmo que requests.cpu |
memory |
O mesmo que requests.memory |
Além dos recursos mencionados acima, na versão 1.10, suporte a cotas para recursos estendidos foi adicionado.
Como o overcommit não é permitido para recursos estendidos, não faz sentido especificar tanto requests e limits para o mesmo recurso estendido em uma cota. Portanto, para recursos estendidos, apenas itens de cota com prefixo requests. é permitido por enquanto.
Tome o recurso GPU como exemplo, se o nome do recurso for nvidia.com/gpu e você quiser limitar o número total de GPUs solicitadas em um namespace para 4, você pode definir uma cota da seguinte maneira:
requests.nvidia.com/gpu: 4Veja como visualizar e definir cotas para mais informações.
Você pode limitar a soma total de recursos de armazenamento que podem ser solicitados em um determinado namespace.
Além disso, você pode limitar o consumo de recursos de armazenamento com base na classe de armazenamento associada.
| Nome do recurso | Descrição |
|---|---|
requests.storage |
Em todas as solicitações de volume persistentes, a soma das solicitações de armazenamento não pode exceder esse valor. |
persistentvolumeclaims |
O número total de PersistentVolumeClaims que podem existir no namespace. |
<storage-class-name>.storageclass.storage.k8s.io/requests.storage |
Em todas as solicitações de volume persistentes associadas ao <storage-class-name>, a soma das solicitações de armazenamento não pode exceder esse valor. |
<storage-class-name>.storageclass.storage.k8s.io/persistentvolumeclaims |
Em todas as declarações de volume persistentes associadas ao storage-class-name, o número total de declarações de volume persistente que podem existir no namespace. |
Por exemplo, se um operador deseja cotar armazenamento com classe de armazenamento gold separada da classe de armazenamento bronze, o operador pode definir uma cota da seguinte forma:
gold.storageclass.storage.k8s.io/requests.storage: 500Gibronze.storageclass.storage.k8s.io/requests.storage: 100GiNa versão 1.8, o suporte de cota para armazenamento temporário local foi adicionado como um recurso alfa:
| Nome do Recurso | Descrição |
|---|---|
requests.ephemeral-storage |
Em todos os pods no namespace, a soma das solicitações de armazenamento local efêmero não pode exceder esse valor. |
limits.ephemeral-storage |
Em todos os pods no namespace, a soma dos limites de armazenamento temporário local não pode exceder esse valor. |
ephemeral-storage |
O mesmo que requests.ephemeral-storage. |
Você pode definir cotas para o número total de determinados recursos de todos os padrões, tipos de recursos com namespace usando a seguinte sintaxe:
count/<resource>.<group> para recursos de grupos não principaiscount/<resource> para recursos do grupo principalExemplo de conjunto de recursos que os usuários podem querer colocar na cota de contagem de objetos:
count/persistentvolumeclaimscount/servicescount/secretscount/configmapscount/replicationcontrollerscount/deployments.appscount/replicasets.appscount/statefulsets.appscount/jobs.batchcount/cronjobs.batchA mesma sintaxe pode ser usada para recursos personalizados. Por exemplo, para criar uma cota em um recurso personalizado widgets no grupo de API example.com, use count/widgets.example.com.
Ao usar a cota de recurso count/*, um objeto é cobrado na cota se existir no armazenamento do servidor. Esses tipos de cotas são úteis para proteger contra o esgotamento dos recursos de armazenamento. Por exemplo, você pode desejar limitar o número de segredos em um servidor devido ao seu grande tamanho. Muitos segredos em um cluster podem
na verdade, impedir que servidores e controladores sejam iniciados. Você pode definir uma cota para projetos para proteger contra um CronJob mal configurado. CronJobs que criam muitos Jobs em um namespace podem levar a uma negação de serviço.
Também é possível fazer uma cota de contagem de objetos genéricos em um conjunto limitado de recursos. Os seguintes tipos são suportados:
| Nome do Recurso | Descrição |
|---|---|
configmaps |
O número total de ConfigMaps que podem existir no namespace. |
persistentvolumeclaims |
O número total de PersistentVolumeClaims que podem existir no namespace. |
pods |
O número total de pods em um estado não terminal que pode existir no namespace. Um pod está em um estado terminal se .status.phase in (Failed, Succeeded) for verdadeiro. |
replicationcontrollers |
O número total de ReplicationControllers que podem existir no namespace. |
resourcequotas |
O número total de ResourceQuotas que podem existir no namespace. |
services |
O número total de Serviços que podem existir no namespace. |
services.loadbalancers |
O número total de serviços do tipo LoadBalancer que podem existir no namespace. |
services.nodeports |
O número total de serviços do tipo NodePort que podem existir no namespace. |
secrets |
O número total de segredos que podem existir no namespace. |
Por exemplo, a cota de pods conta e impõe um número máximo de pods criados em um único namespace que não é terminal. Você pode querer definir uma cota podsem um namespace para evitar o caso em que um usuário cria muitos pods pequenos e esgota o fornecimento de IPs de pod do cluster.
Cada cota pode ter um conjunto associado de scopes. Uma cota só medirá o uso de um recurso se corresponder
a interseção de escopos enumerados.
Quando um escopo é adicionado à cota, ele limita o número de recursos aos quais ele dá suporte a aqueles que pertencem ao escopo. Os recursos especificados na cota fora do conjunto permitido resultam em um erro de validação.
| Escopo | Descrição |
|---|---|
Terminating |
Pods correspondentes onde .spec.activeDeadlineSeconds >= 0 |
NotTerminating |
Pods correspondentes onde .spec.activeDeadlineSeconds is nil |
BestEffort |
Pods correspondentes que tenham a qualidade de serviço de melhor esforço. |
NotBestEffort |
Pods correspondentes que não têm qualidade de serviço de melhor esforço. |
PriorityClass |
Corresponde aos pods que fazem referência à classe de prioridade especificada. |
CrossNamespacePodAffinity |
Corresponde a pods que tenham termos de (anti)afinidade de namespace cruzado. |
O escopo BestEffort restringe uma cota ao rastreamento do seguinte recurso:
podsOs escopos Termination, NotTerminate, NotBestEffort e PriorityClassrestringem uma cota para rastrear os seguintes recursos:
podscpumemoryrequests.cpurequests.memorylimits.cpulimits.memoryObserve que você não pode especificar os escopos Terminate e o NotTerminatena mesma cota, e você também não pode especificar o BestEffort eNotBestEffort na mesma cota.
O scopeSelector suporta os seguintes valores no campo operator:
InNotInExistsDoesNotExistAo usar um dos seguintes valores como o scopeName ao definir oscopeSelector, o operator deve ser Exists.
TerminatingNotTerminatingBestEffortNotBestEffortSe o operator for In ou NotIn, o campo values deve ter pelo menos um valor. Por exemplo:
scopeSelector:
matchExpressions:
- scopeName: PriorityClass
operator: In
values:
- middle
Se o operator for Exists ou DoesNotExist, o campo values NÃO deve ser especificado.
Kubernetes v1.17 [stable]
Os pods podem ser criados em uma prioridade específica. Você pode controlar o consumo de recursos do sistema de um pod com base na prioridade de um pod, usando o scopeSelector
campo na especificação de cota.
Uma cota é correspondida e consumida apenas se scopeSelector na especificação de cota selecionar o pod.
Quando a cota está no escopo da classe de prioridade usando o campo scopeSelector, objeto de cota
está restrito a rastrear apenas os seguintes recursos:
podscpumemoryephemeral-storagelimits.cpulimits.memorylimits.ephemeral-storagerequests.cpurequests.memoryrequests.ephemeral-storageEste exemplo cria um objeto de cota e o corresponde a pods em prioridades específicas. O exemplo funciona da seguinte forma:
Salve o seguinte YAML em um arquivo quota.yml.
apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-high
spec:
hard:
cpu: "1000"
memory: 200Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["high"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-medium
spec:
hard:
cpu: "10"
memory: 20Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["medium"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-low
spec:
hard:
cpu: "5"
memory: 10Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["low"]
Aplique o YAML usando kubectl create.
kubectl create -f ./quota.yml
resourcequota/pods-high created
resourcequota/pods-medium created
resourcequota/pods-low created
Verifique se a cota Used é 0 usando kubectl describe quota.
kubectl describe quota
Name: pods-high
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 1k
memory 0 200Gi
pods 0 10
Name: pods-low
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 5
memory 0 10Gi
pods 0 10
Name: pods-medium
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 10
memory 0 20Gi
pods 0 10
Crie um pod com prioridade "high". Salve o seguinte YAML em um arquivo high-priority-pod.yml.
apiVersion: v1
kind: Pod
metadata:
name: high-priority
spec:
containers:
- name: high-priority
image: ubuntu
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello; sleep 10;done"]
resources:
requests:
memory: "10Gi"
cpu: "500m"
limits:
memory: "10Gi"
cpu: "500m"
priorityClassName: high
Applique com kubectl create.
kubectl create -f ./high-priority-pod.yml
Verifique se as estatísticas "Used" para a cota de prioridade "high", pods-high foram alteradas e se
as outras duas cotas permanecem inalteradas.
kubectl describe quota
Name: pods-high
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 500m 1k
memory 10Gi 200Gi
pods 1 10
Name: pods-low
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 5
memory 0 10Gi
pods 0 10
Name: pods-medium
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 10
memory 0 20Gi
pods 0 10
Kubernetes v1.22 [beta]
Os operadores podem usar o escopo de cota CrossNamespacePodAffinity para limitar quais namespaces têm permissão para ter pods com termos de afinidade que cruzam namespaces. Especificamente, ele controla quais pods são permitidos para definir os campos namespaces ou namespaceSelector em termos de afinidade de pod.
Impedir que os usuários usem termos de afinidade entre namespaces pode ser desejável, pois um pod com restrições antiafinidade pode bloquear pods de todos os outros namespaces de ser agendado em um domínio de falha.
O uso desses operadores de escopo pode impedir certos namespaces (foo-ns no exemplo abaixo) de ter pods que usam afinidade de pod entre namespaces criando um objeto de cota de recurso nesse namespace com escopo CrossNamespaceAffinity e limite rígido de 0:
apiVersion: v1
kind: ResourceQuota
metadata:
name: disable-cross-namespace-affinity
namespace: foo-ns
spec:
hard:
pods: "0"
scopeSelector:
matchExpressions:
- scopeName: CrossNamespaceAffinity
Se os operadores quiserem proibir o uso de namespaces e namespaceSelector por padrão, e
permitir apenas para namespaces específicos, eles podem configurar CrossNamespaceAffinitycomo um recurso limitado definindo o sinalizador kube-apiserver --admission-control-config-file
para o caminho do seguinte arquivo de configuração:
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: "ResourceQuota"
configuration:
apiVersion: apiserver.config.k8s.io/v1
kind: ResourceQuotaConfiguration
limitedResources:
- resource: pods
matchScopes:
- scopeName: CrossNamespaceAffinity
Com a configuração acima, os pods podem usar namespaces e namespaceSelector apenas na afinidade do pod se o namespace em que foram criados tiver um objeto de cota de recurso com escopo CrossNamespaceAffinity e um limite rígido maior ou igual ao número de pods usando esses campos.
Esse recurso é beta e ativado por padrão. Você pode desativá-lo usando o feature gate PodAffinityNamespaceSelector no kube-apiserver e no kube-scheduler.
Ao alocar recursos computacionais, cada contêiner pode especificar uma solicitação e um valor limite para CPU ou memória. A cota pode ser configurada para cotar qualquer valor.
Se a cota tiver um valor especificado para requests.cpu ou requests.memory, ela exigirá que cada contêiner faça uma solicitação explícita para esses recursos. Se a cota tiver um valor especificado para limits.cpu ou limits.memory, em seguida exige que cada contêiner de entrada especifique um limite explícito para esses recursos.
O Kubectl é compatível com a criação, atualização e visualização de cotas:
kubectl create namespace myspace
cat <<EOF > compute-resources.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
spec:
hard:
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
requests.nvidia.com/gpu: 4
EOF
kubectl create -f ./compute-resources.yaml --namespace=myspace
cat <<EOF > object-counts.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
configmaps: "10"
persistentvolumeclaims: "4"
pods: "4"
replicationcontrollers: "20"
secrets: "10"
services: "10"
services.loadbalancers: "2"
EOF
kubectl create -f ./object-counts.yaml --namespace=myspace
kubectl get quota --namespace=myspace
NAME AGE
compute-resources 30s
object-counts 32s
kubectl describe quota compute-resources --namespace=myspace
Name: compute-resources
Namespace: myspace
Resource Used Hard
-------- ---- ----
limits.cpu 0 2
limits.memory 0 2Gi
requests.cpu 0 1
requests.memory 0 1Gi
requests.nvidia.com/gpu 0 4
kubectl describe quota object-counts --namespace=myspace
Name: object-counts
Namespace: myspace
Resource Used Hard
-------- ---- ----
configmaps 0 10
persistentvolumeclaims 0 4
pods 0 4
replicationcontrollers 0 20
secrets 1 10
services 0 10
services.loadbalancers 0 2
Kubectl also supports object count quota for all standard namespaced resources
using the syntax count/<resource>.<group>:
kubectl create namespace myspace
kubectl create quota test --hard=count/deployments.apps=2,count/replicasets.apps=4,count/pods=3,count/secrets=4 --namespace=myspace
kubectl create deployment nginx --image=nginx --namespace=myspace --replicas=2
kubectl describe quota --namespace=myspace
Name: test
Namespace: myspace
Resource Used Hard
-------- ---- ----
count/deployments.apps 1 2
count/pods 2 3
count/replicasets.apps 1 4
count/secrets 1 4
ResourceQuotas são independentes da capacidade do cluster. Eles estão expresso em unidades absolutas. Portanto, se você adicionar nós ao cluster, isso não
dá automaticamente a cada namespace a capacidade de consumir mais recursos.
Às vezes, políticas mais complexas podem ser necessárias, como:
Tais políticas podem ser implementadas usando ResourceQuotas como blocos de construção, por
escrevendo um "controlador" que observa o uso da cota e ajusta os limites rígidos da cota de cada namespace de acordo com outros sinais.
Observe que a cota de recursos divide os recursos agregados do cluster, mas não cria restrições em torno dos nós: pods de vários namespaces podem ser executados no mesmo nó.
Pode ser desejado que os pods com uma prioridade particular, por exemplo. "cluster-services", deve ser permitido em um namespace, se, e somente se, existir um objeto de cota correspondente.
Com este mecanismo, os operadores podem restringir o uso de certas classes de prioridade para um número limitado de namespaces , e nem todos poderão consumir essas classes de prioridade por padrão.
Para impor isso, a flag kube-apiserver --admission-control-config-file deve ser
usada para passar o caminho para o seguinte arquivo de configuração:
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: "ResourceQuota"
configuration:
apiVersion: apiserver.config.k8s.io/v1
kind: ResourceQuotaConfiguration
limitedResources:
- resource: pods
matchScopes:
- scopeName: PriorityClass
operator: In
values: ["cluster-services"]
Em seguida, crie um objeto de cota de recurso no namespace kube-system:
apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-cluster-services
spec:
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["cluster-services"]kubectl apply -f https://k8s.io/examples/policy/priority-class-resourcequota.yaml -n kube-system
resourcequota/pods-cluster-services created
Nesse caso, a criação de um pod será permitida se:
priorityClassName do pod não foi especificado.priorityClassName do pod é especificado com um valor diferente de cluster-services.priorityClassName do pod está definido como cluster-services, ele deve ser criado no namespace kube-system e passou na verificação de cota de recursos.Uma solicitação de criação de pod é rejeitada caso seu priorityClassName estiver definido como cluster-services e deve ser criado em um namespace diferente de kube-system.
Para dar suporte a cargas de trabalho com latência crítica e altas taxas de transferência, o Kubernetes oferece um conjunto de gerenciadores de recursos. Os gerenciadores visam coordenar e otimizar o alinhamento de recursos do nó(s) para Pods configurados com um requisito específico para CPUs, dispositivos e recursos de memória (hugepages).
O gerenciador principal, o gerenciador de topologia, é um componente do Kubelet que coordena o processo geral de gerenciamento de recursos por meio da sua política.
A configuração de gerenciadores individuais é discutida em documentos dedicados:
No Kubernetes, escalonamento refere-se à certeza de que Pods correspondam aos nós para que o Kubelet possa executá-los. Preempção é o processo de finalizar Pods com menor prioridade para que os Pods com maior prioridade possam ser escalonados nos nós. Remoção é o processo de finalização de um ou mais Pods em nós.
Disrupção do Pod é o processo pelo qual Pods ou nós são interrompidos de forma voluntária ou involuntária.
Disrupções voluntárias são iniciadas intencionalmente pelos donos das aplicações ou administradores dos clusters. Disrupções involuntárias não são intencionais e podem ser encadeadas por problemas inevitáveis como Nós com poucos recursos, ou por exclusões acidentais.
No Kubernetes, escalonamento refere-se a garantir que os Pods sejam correspondidos aos Nós para que o Kubelet possa executá-los.
Um escalonador observa Pods recém-criados que não possuem um Nó atribuído. Para cada Pod que o escalonador descobre, ele se torna responsável por encontrar o melhor Nó para execução do Pod. O escalonador chega a essa decisão de alocação levando em consideração os princípios de escalonamento descritos abaixo.
Se você quiser entender por que os Pods são alocados em um Nó específico ou se planeja implementar um escalonador personalizado, esta página ajudará você a aprender sobre escalonamento.
kube-scheduler é o escalonador padrão do Kubernetes e é executado como parte da camada de gerenciamento. O kube-scheduler é projetado para que, se você quiser e precisar, possa escrever seu próprio componente de escalonamento e usá-lo.
O kube-scheduler seleciona um Nó ideal para executar Pods recém-criados ou não escalonados (unscheduled). Como os contêineres em Pods — e os próprios Pods — podem ter diferentes requisitos, o escalonador filtra os Nós que não atendem às necessidades específicas de escalonamento do Pod. Alternativamente, a API permite que você especifique um Nó para um Pod ao criá-lo, mas isso é incomum e só é feito em casos especiais.
Em um cluster, Nós que atendem aos requisitos de escalonamento para um Pod são chamados de Nós viáveis. Se nenhum dos Nós for adequado, o Pod permanece não escalonado até que o escalonador consiga alocá-lo.
O escalonador encontra Nós viáveis para um Pod e, em seguida, executa um conjunto de funções para classificar esses Nós viáveis e escolhe o Nó com a maior pontuação entre os possíveis para executar o Pod. O escalonador então notifica o servidor de API sobre essa decisão em um processo chamado binding.
Fatores que precisam ser levados em consideração para decisões de escalonamento incluem requisitos individuais e coletivos de recursos, restrições de hardware / software / política, especificações de afinidade e anti-afinidade, localização de dados, interferência entre cargas de trabalho e assim por diante.
O kube-scheduler seleciona um Nó para o Pod em uma operação que consiste em duas etapas:
A etapa de filtragem localiza o conjunto de Nós onde é possível alocar o Pod. Por exemplo, o filtro PodFitsResources verifica se um Nó candidato possui recursos disponíveis suficientes para atender às solicitações de recursos específicas de um Pod. Após esta etapa, a lista de Nós contém quaisquer Nós adequados; frequentemente, haverá mais de um. Se a lista estiver vazia, esse Pod (ainda) não é escalonável.
Na etapa de pontuação, o escalonador classifica os Nós restantes para escolher o mais adequado. O escalonador atribui uma pontuação a cada Nó que passou na filtragem, baseando essa pontuação nas regras de pontuação ativas.
Por fim, o kube-scheduler atribui o Pod ao Nó com a classificação mais alta. Se houver mais de um Nó com pontuações iguais, o kube-scheduler seleciona um deles aleatoriamente.
Existem duas maneiras suportadas de configurar o comportamento de filtragem e pontuação do escalonador:
QueueSort, Filter, Score,
Bind, Reserve, Permit, e outros. Você também pode configurar o kube-scheduler para executar
diferentes perfis.Você pode restringir um Pod para que ele seja limitado a executar em nó(s) específicos, ou para preferir executar em nós específicos. Existem várias maneiras de fazer isso e as abordagens recomendadas utilizam seletores de rótulos para facilitar a seleção. Frequentemente, você não precisa definir nenhuma dessas restrições; o escalonador fará automaticamente uma alocação adequada (por exemplo, distribuindo seus Pods entre os nós para não alocá-los em um nó com recursos livres insuficientes). No entanto, existem algumas circunstâncias em que você pode querer controlar em qual nó o Pod será implantado, por exemplo, para garantir que um Pod seja alocado em um nó com um SSD conectado, ou para colocalizar Pods de dois serviços diferentes que se comunicam frequentemente na mesma zona de disponibilidade.
Você pode usar qualquer um dos seguintes métodos para escolher onde o Kubernetes aloca Pods específicos:
Assim como muitos outros objetos do Kubernetes, os nós possuem rótulos. Você pode anexar rótulos manualmente. O Kubernetes também preenche um conjunto padrão de rótulos em todos os nós de um cluster.
kubernetes.io/hostname pode ser o mesmo que o nome do nó em alguns ambientes
e um valor diferente em outros ambientes.Adicionar rótulos aos nós permite direcionar Pods para alocação em nós ou grupos de nós específicos. Você pode usar essa funcionalidade para garantir que Pods específicos executem apenas em nós com determinadas propriedades de isolamento, segurança ou conformidade regulatória.
Se você usar rótulos para isolamento de nós, escolha chaves de rótulos que o kubelet não possa modificar. Isso impede que um nó comprometido defina esses rótulos em si mesmo para fazer com que o escalonador aloque cargas de trabalho no nó comprometido.
O plugin de admissão NodeRestriction
impede que o kubelet defina ou modifique rótulos com o
prefixo node-restriction.kubernetes.io/.
Para utilizar esse prefixo de rótulo para isolamento de nós:
NodeRestriction.node-restriction.kubernetes.io/ aos seus nós e use esses rótulos em seus seletores de nós.
Por exemplo, example.com.node-restriction.kubernetes.io/fips=true ou example.com.node-restriction.kubernetes.io/pci-dss=true.nodeSelector é a forma recomendada mais simples de restrição de seleção de nós.
Você pode adicionar o campo nodeSelector à especificação do seu Pod e especificar os
rótulos de nós que você deseja que o nó de destino possua.
O Kubernetes aloca o Pod apenas em nós que possuem cada um dos rótulos que você
especificar.
Consulte Atribuir Pods a Nós para mais informações.
nodeSelector é a maneira mais simples de restringir Pods a nós com rótulos
específicos. Afinidade e antiafinidade expandem os tipos de restrições que você pode
definir. Alguns dos benefícios da afinidade e antiafinidade incluem:
nodeSelector apenas
seleciona nós com todos os rótulos especificados. Afinidade/antiafinidade oferece
mais controle sobre a lógica de seleção.A funcionalidade de afinidade consiste em dois tipos de afinidade:
nodeSelector, mas é mais expressiva e
permite especificar regras flexíveis.Afinidade de nó é conceitualmente similar a nodeSelector, permitindo restringir em quais nós seu
Pod pode ser alocado com base em rótulos de nós. Existem dois tipos de afinidade
de nó:
requiredDuringSchedulingIgnoredDuringExecution: O escalonador não pode
alocar o Pod a menos que a regra seja atendida. Isso funciona como nodeSelector,
mas com uma sintaxe mais expressiva.preferredDuringSchedulingIgnoredDuringExecution: O escalonador tenta
encontrar um nó que atenda à regra. Se um nó correspondente não estiver disponível, o
escalonador ainda aloca o Pod.IgnoredDuringExecution significa que se os rótulos do nó
mudarem após o Kubernetes alocar o Pod, o Pod continuará em execução.Você pode especificar afinidades de nó usando o campo .spec.affinity.nodeAffinity na
especificação do seu Pod.
Por exemplo, considere a seguinte especificação de Pod:
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- antarctica-east1
- antarctica-west1
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: another-node-label-key
operator: In
values:
- another-node-label-value
containers:
- name: with-node-affinity
image: registry.k8s.io/pause:3.8Neste exemplo, as seguintes regras se aplicam:
topology.kubernetes.io/zone e
o valor desse rótulo deve ser antarctica-east1 ou antarctica-west1.another-node-label-key e
o valor another-node-label-value.Você pode usar o campo operator para especificar um operador lógico para o Kubernetes usar ao
interpretar as regras. Você pode usar In, NotIn, Exists, DoesNotExist,
Gt e Lt.
Leia Operadores para saber mais sobre como eles funcionam.
NotIn e DoesNotExist permitem definir o comportamento de antiafinidade de nó.
Alternativamente, você pode usar taints de nó
para repelir Pods de nós específicos.
Se você especificar tanto nodeSelector quanto nodeAffinity, ambos devem ser satisfeitos
para que o Pod seja alocado em um nó.
Se você especificar múltiplos termos em nodeSelectorTerms associados a tipos de nodeAffinity,
então o Pod pode ser alocado em um nó se um dos termos especificados
puder ser satisfeito (os termos são combinados com OR).
Se você especificar múltiplas expressões em um único campo matchExpressions associado a um
termo em nodeSelectorTerms, então o Pod pode ser alocado em um nó apenas
se todas as expressões forem satisfeitas (as expressões são combinadas com AND).
Consulte Atribuir Pods a Nós usando Afinidade de Nó para mais informações.
Você pode especificar um weight (peso) entre 1 e 100 para cada instância do
tipo de afinidade preferredDuringSchedulingIgnoredDuringExecution. Quando o
escalonador encontra nós que atendem a todos os outros requisitos de alocação do Pod, o
escalonador itera por cada regra preferencial que o nó satisfaz e adiciona o
valor do weight dessa expressão a uma soma.
A soma final é adicionada à pontuação de outras funções de prioridade do nó. Nós com a maior pontuação total são priorizados quando o escalonador toma uma decisão de alocação para o Pod.
Por exemplo, considere a seguinte especificação de Pod:
apiVersion: v1
kind: Pod
metadata:
name: with-affinity-preferred-weight
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/os
operator: In
values:
- linux
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: label-1
operator: In
values:
- key-1
- weight: 50
preference:
matchExpressions:
- key: label-2
operator: In
values:
- key-2
containers:
- name: with-node-affinity
image: registry.k8s.io/pause:3.8
Se houver dois nós possíveis que correspondem à regra
preferredDuringSchedulingIgnoredDuringExecution, um com o
rótulo label-1:key-1 e outro com o rótulo label-2:key-2, o escalonador
considera o weight de cada nó e adiciona o peso às outras pontuações daquele
nó, e aloca o Pod no nó com a maior pontuação final.
kubernetes.io/os=linux.Kubernetes v1.20 [beta]
Ao configurar múltiplos perfis de alocação, você pode associar
um perfil a uma afinidade de nó, o que é útil se um perfil se aplica apenas a um conjunto específico de nós.
Para fazer isso, adicione um addedAffinity ao campo args do plugin NodeAffinity
na configuração do escalonador. Por exemplo:
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: default-scheduler
- schedulerName: foo-scheduler
pluginConfig:
- name: NodeAffinity
args:
addedAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: scheduler-profile
operator: In
values:
- foo
O addedAffinity é aplicado a todos os Pods que definem .spec.schedulerName como foo-scheduler, além da
NodeAffinity especificada no PodSpec.
Ou seja, para corresponder ao Pod, os nós precisam satisfazer o addedAffinity e
o .spec.NodeAffinity do Pod.
Como o addedAffinity não é visível para os usuários finais, seu comportamento pode ser
inesperado para eles. Use rótulos de nós que tenham uma correlação clara com o
nome do perfil do escalonador.
nodeAffinity no controlador DaemonSet.Afinidade e antiafinidade entre Pods permitem restringir em quais nós seus Pods podem ser alocados com base nos rótulos de Pods já em execução naquele nó, em vez dos rótulos do nó.
Afinidade e antiafinidade entre Pods assumem a forma "este Pod deve (ou, no caso de antiafinidade, não deve) executar em um X se esse X já estiver executando um ou mais Pods que atendem à regra Y", onde X é um domínio topológico como nó, rack, zona ou região do provedor de nuvem, ou similar, e Y é a regra que o Kubernetes tenta satisfazer.
Você expressa essas regras (Y) como seletores de rótulos com uma lista opcional associada de namespaces. Pods são objetos com namespace no Kubernetes, então rótulos de Pods também implicitamente possuem namespaces. Quaisquer seletores de rótulos para rótulos de Pods devem especificar os namespaces nos quais o Kubernetes deve procurar esses rótulos.
Você expressa o domínio topológico (X) usando uma topologyKey, que é a chave do
rótulo do nó que o sistema usa para indicar o domínio. Para exemplos, consulte
Rótulos, Anotações e Taints conhecidos.
topologyKey.
Se alguns ou todos os nós não tiverem o rótulo topologyKey especificado, isso pode levar
a comportamentos não intencionais.Similar à afinidade de nó, existem dois tipos de afinidade e antiafinidade de Pod, como segue:
requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecutionPor exemplo, você poderia usar
afinidade requiredDuringSchedulingIgnoredDuringExecution para dizer ao escalonador para
colocalizar Pods de dois serviços na mesma zona do provedor de nuvem porque eles
se comunicam muito entre si. Da mesma forma, você poderia usar
antiafinidade preferredDuringSchedulingIgnoredDuringExecution para distribuir Pods
de um serviço em múltiplas zonas do provedor de nuvem.
Para usar afinidade entre Pods, use o campo affinity.podAffinity na especificação do Pod.
Para antiafinidade entre Pods, use o campo affinity.podAntiAffinity na especificação
do Pod.
Ao alocar um novo Pod, o escalonador do Kubernetes avalia as regras de afinidade/antiafinidade do Pod no contexto do estado atual do cluster:
Restrições rígidas (Filtragem de nós):
podAffinity.requiredDuringSchedulingIgnoredDuringExecution e podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecution:
Restrições flexíveis (Pontuação):
podAffinity.preferredDuringSchedulingIgnoredDuringExecution e podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution:
Campos ignorados:
podAffinity.preferredDuringSchedulingIgnoredDuringExecution de Pods existentes:
podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution de Pods existentes:
Se o Pod atual sendo alocado é o primeiro de uma série que tem afinidade consigo mesmos, ele pode ser alocado se passar em todas as outras verificações de afinidade. Isso é determinado verificando que nenhum outro Pod no cluster corresponde ao namespace e seletor deste Pod, que o Pod corresponde aos seus próprios termos, e que o nó escolhido corresponde a todas as topologias solicitadas. Isso garante que não haverá um deadlock mesmo se todos os Pods tiverem afinidade entre Pods especificada.
Considere a seguinte especificação de Pod:
apiVersion: v1
kind: Pod
metadata:
name: with-pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S1
topologyKey: topology.kubernetes.io/zone
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S2
topologyKey: topology.kubernetes.io/zone
containers:
- name: with-pod-affinity
image: registry.k8s.io/pause:3.8
Este exemplo define uma regra de afinidade de Pod e uma regra de antiafinidade de Pod. A
regra de afinidade de Pod usa o "rígido"
requiredDuringSchedulingIgnoredDuringExecution, enquanto a regra de antiafinidade
usa o "flexível" preferredDuringSchedulingIgnoredDuringExecution.
A regra de afinidade especifica que o escalonador pode alocar o Pod de exemplo
em um nó apenas se esse nó pertencer a uma zona
específica onde outros Pods foram rotulados com security=S1.
Por exemplo, se tivermos um cluster com uma zona designada, vamos chamá-la de "Zona V",
consistindo de nós rotulados com topology.kubernetes.io/zone=V, o escalonador pode
atribuir o Pod a qualquer nó dentro da Zona V, desde que haja pelo menos um Pod dentro
da Zona V já rotulado com security=S1. Por outro lado, se não houver Pods com rótulos
security=S1 na Zona V, o escalonador não atribuirá o Pod de exemplo a nenhum nó nessa zona.
A regra de antiafinidade especifica que o escalonador deve tentar evitar alocar o Pod
em um nó se esse nó pertencer a uma zona
específica onde outros Pods foram rotulados com security=S2.
Por exemplo, se tivermos um cluster com uma zona designada, vamos chamá-la de "Zona R",
consistindo de nós rotulados com topology.kubernetes.io/zone=R, o escalonador deve evitar
atribuir o Pod a qualquer nó dentro da Zona R, desde que haja pelo menos um Pod dentro
da Zona R já rotulado com security=S2. Por outro lado, a regra de antiafinidade não impacta
a alocação na Zona R se não houver Pods com rótulos security=S2.
Para se familiarizar mais com os exemplos de afinidade e antiafinidade de Pod, consulte a proposta de projeto.
Você pode usar os valores In, NotIn, Exists e DoesNotExist no
campo operator para afinidade e antiafinidade de Pod.
Leia Operadores para saber mais sobre como eles funcionam.
Em princípio, a topologyKey pode ser qualquer chave de rótulo permitida, com as seguintes
exceções por razões de desempenho e segurança:
topologyKey vazio não é permitido tanto em
requiredDuringSchedulingIgnoredDuringExecution
quanto em preferredDuringSchedulingIgnoredDuringExecution.requiredDuringSchedulingIgnoredDuringExecution,
o controlador de admissão LimitPodHardAntiAffinityTopology limita
topologyKey a kubernetes.io/hostname. Você pode modificar ou desabilitar o
controlador de admissão se quiser permitir topologias personalizadas.Além de labelSelector e topologyKey, você pode opcionalmente especificar uma lista
de namespaces com os quais o labelSelector deve corresponder usando o
campo namespaces no mesmo nível que labelSelector e topologyKey.
Se omitido ou vazio, namespaces assume como padrão o namespace do Pod onde a
definição de afinidade/antiafinidade aparece.
Kubernetes v1.24 [stable]
Você também pode selecionar namespaces correspondentes usando namespaceSelector, que é uma consulta de rótulos sobre o conjunto de namespaces.
O termo de afinidade é aplicado aos namespaces selecionados tanto pelo namespaceSelector quanto pelo campo namespaces.
Note que um namespaceSelector vazio ({}) corresponde a todos os namespaces, enquanto uma lista namespaces nula ou vazia e
um namespaceSelector nulo correspondem ao namespace do Pod onde a regra é definida.
Kubernetes v1.33 [stable](habilitado por padrão)O campo matchLabelKeys é um campo de nível beta e está habilitado por padrão no
Kubernetes 1.35.
Quando você quiser desabilitá-lo, você deve desabilitá-lo explicitamente através do
feature gate MatchLabelKeysInPodAffinity.
O Kubernetes inclui um campo opcional matchLabelKeys para afinidade
ou antiafinidade de Pod. O campo especifica chaves para os rótulos que devem corresponder aos rótulos do Pod de entrada,
ao satisfazer a (anti)afinidade de Pod.
As chaves são usadas para buscar valores dos rótulos do Pod; esses rótulos de chave-valor são combinados
(usando AND) com as restrições de correspondência definidas usando o campo labelSelector. A filtragem
combinada seleciona o conjunto de Pods existentes que será considerado no cálculo de (anti)afinidade de Pod.
matchLabelKeys com rótulos que possam ser atualizados diretamente nos pods.
Mesmo se você editar o rótulo do pod que está especificado em matchLabelKeys diretamente (isto é, não através de um Deployment),
o kube-apiserver não reflete a atualização do rótulo no labelSelector mesclado.Um caso de uso comum é usar matchLabelKeys com pod-template-hash (definido em Pods
gerenciados como parte de um Deployment, onde o valor é único para cada revisão).
Usar pod-template-hash em matchLabelKeys permite selecionar os Pods que pertencem
à mesma revisão que o Pod de entrada, para que uma atualização gradual não quebre a afinidade.
apiVersion: apps/v1
kind: Deployment
metadata:
name: application-server
...
spec:
template:
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- database
topologyKey: topology.kubernetes.io/zone
# Apenas Pods de um determinado rollout são considerados ao calcular a afinidade de pod.
# Se você atualizar o Deployment, os Pods substitutos seguem suas próprias regras de afinidade
# (se houver alguma definida no novo template de Pod)
matchLabelKeys:
- pod-template-hash
Kubernetes v1.33 [stable](habilitado por padrão)O campo mismatchLabelKeys é um campo de nível beta e está habilitado por padrão no
Kubernetes 1.35.
Quando você quiser desabilitá-lo, você deve desabilitá-lo explicitamente através do
feature gate MatchLabelKeysInPodAffinity.
O Kubernetes inclui um campo opcional mismatchLabelKeys para afinidade
ou antiafinidade de Pod. O campo especifica chaves para os rótulos que não devem corresponder aos rótulos do Pod de entrada,
ao satisfazer a (anti)afinidade de Pod.
mismatchLabelKeys com rótulos que possam ser atualizados diretamente nos pods.
Mesmo se você editar o rótulo do pod que está especificado em mismatchLabelKeys diretamente (isto é, não através de um Deployment),
o kube-apiserver não reflete a atualização do rótulo no labelSelector mesclado.Um exemplo de caso de uso é garantir que os Pods vão para o domínio topológico (nó, zona, etc.) onde apenas Pods do mesmo locatário ou equipe são alocados. Em outras palavras, você quer evitar executar Pods de dois locatários diferentes no mesmo domínio topológico ao mesmo tempo.
apiVersion: v1
kind: Pod
metadata:
labels:
# Assume que todos os Pods relevantes têm um rótulo "tenant" definido
tenant: tenant-a
...
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
# garante que os Pods associados a este locatário sejam alocados no pool de nós correto
- matchLabelKeys:
- tenant
labelSelector: {}
topologyKey: node-pool
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
# garante que os Pods associados a este locatário não possam ser alocados em nós usados por outro locatário
- mismatchLabelKeys:
- tenant # qualquer que seja o valor do rótulo "tenant" para este Pod, impede
# a alocação em nós de qualquer pool onde qualquer Pod de um
# locatário diferente esteja em execução.
labelSelector:
# Precisamos ter o labelSelector que seleciona apenas Pods com o rótulo tenant,
# caso contrário, este Pod teria antiafinidade contra Pods de DaemonSets também, por exemplo,
# que não deveriam ter o rótulo tenant.
matchExpressions:
- key: tenant
operator: Exists
topologyKey: node-pool
Afinidade e antiafinidade entre Pods podem ser ainda mais úteis quando são usadas com coleções de nível superior, como ReplicaSets, StatefulSets, Deployments, etc. Essas regras permitem configurar que um conjunto de cargas de trabalho deve ser colocalizado na mesma topologia definida; por exemplo, preferindo alocar dois Pods relacionados no mesmo nó.
Por exemplo: imagine um cluster de três nós. Você usa o cluster para executar uma aplicação web e também um cache em memória (como Redis). Para este exemplo, assuma também que a latência entre a aplicação web e o cache em memória deve ser a mais baixa possível. Você poderia usar afinidade e antiafinidade entre Pods para colocalizar os servidores web com o cache tanto quanto possível.
No seguinte exemplo de Deployment para o cache Redis, as réplicas recebem o rótulo app=store. A
regra podAntiAffinity diz ao escalonador para evitar alocar múltiplas réplicas
com o rótulo app=store em um único nó. Isso cria cada cache em um
nó separado.
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-cache
spec:
selector:
matchLabels:
app: store
replicas: 3
template:
metadata:
labels:
app: store
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- store
topologyKey: "kubernetes.io/hostname"
containers:
- name: redis-server
image: redis:3.2-alpine
O seguinte exemplo de Deployment para os servidores web cria réplicas com o rótulo app=web-store.
A regra de afinidade de Pod diz ao escalonador para alocar cada réplica em um nó que tenha um Pod
com o rótulo app=store. A regra de antiafinidade de Pod diz ao escalonador para nunca alocar
múltiplos servidores app=web-store em um único nó.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
spec:
selector:
matchLabels:
app: web-store
replicas: 3
template:
metadata:
labels:
app: web-store
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web-store
topologyKey: "kubernetes.io/hostname"
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- store
topologyKey: "kubernetes.io/hostname"
containers:
- name: web-app
image: nginx:1.16-alpine
Criar os dois Deployments anteriores resulta no seguinte layout de cluster, onde cada servidor web é colocalizado com um cache, em três nós separados.
| node-1 | node-2 | node-3 |
|---|---|---|
| webserver-1 | webserver-2 | webserver-3 |
| cache-1 | cache-2 | cache-3 |
O efeito geral é que cada instância de cache provavelmente será acessada por um único cliente que está executando no mesmo nó. Esta abordagem visa minimizar tanto a assimetria (carga desbalanceada) quanto a latência.
Você pode ter outras razões para usar antiafinidade de Pod. Consulte o tutorial do ZooKeeper para um exemplo de um StatefulSet configurado com antiafinidade para alta disponibilidade, usando a mesma técnica deste exemplo.
nodeName é uma forma mais direta de seleção de nó do que afinidade ou
nodeSelector. nodeName é um campo na especificação do Pod. Se o campo nodeName
não estiver vazio, o escalonador ignora o Pod e o kubelet no nó nomeado
tenta alocar o Pod naquele nó. Usar nodeName sobrepõe o uso de
nodeSelector ou regras de afinidade e antiafinidade.
Algumas das limitações de usar nodeName para selecionar nós são:
nodeName é destinado para uso por escalonadores personalizados ou casos de uso avançados onde
você precisa ignorar quaisquer escalonadores configurados. Ignorar os escalonadores pode levar a
Pods com falha se os nós atribuídos ficarem sobrecarregados. Você pode usar afinidade de nó
ou o campo nodeSelector para atribuir um Pod a um nó específico sem ignorar os escalonadores.Aqui está um exemplo de uma especificação de Pod usando o campo nodeName:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
nodeName: kube-01
O Pod acima será executado apenas no nó kube-01.
Kubernetes v1.35 [beta](habilitado por padrão)nominatedNodeName pode ser usado por componentes externos para nomear um nó para um pod pendente.
Esta nomeação é de melhor esforço: ela pode ser ignorada se o escalonador determinar que o pod não pode ir para o nó nomeado.
Além disso, este campo pode ser escrito (ou sobrescrito) pelo escalonador:
nominatedNodeName é definido apenas quando o pod precisa passar pelos pontos de extensão WaitOnPermit ou PreBind.Aqui está um exemplo de um status de Pod usando o campo nominatedNodeName:
apiVersion: v1
kind: Pod
metadata:
name: nginx
...
status:
nominatedNodeName: kube-01
Você pode usar restrições de distribuição de topologia para controlar como os Pods são distribuídos pelo seu cluster entre domínios de falha como regiões, zonas, nós, ou entre quaisquer outros domínios de topologia que você definir. Você pode fazer isso para melhorar o desempenho, a disponibilidade esperada ou a utilização geral.
Leia Restrições de distribuição de topologia de Pod para saber mais sobre como elas funcionam.
Kubernetes v1.35 [beta](habilitado por padrão)Os Pods herdam os rótulos de topologia (topology.kubernetes.io/zone e topology.kubernetes.io/region) do nó atribuído se esses rótulos estiverem presentes. Esses rótulos podem então ser utilizados através da Downward API para fornecer à carga de trabalho a informação da topologia do nó.
Aqui está um exemplo de um Pod usando a Downward API para sua zona e região:
apiVersion: v1
kind: Pod
metadata:
name: pod-with-topology-labels
spec:
containers:
- name: app
image: alpine
command: ["sh", "-c", "env"]
env:
- name: MY_ZONE
valueFrom:
fieldRef:
fieldPath: metadata.labels['topology.kubernetes.io/zone']
- name: MY_REGION
valueFrom:
fieldRef:
fieldPath: metadata.labels['topology.kubernetes.io/region']
A seguir estão todos os operadores lógicos que você pode usar no campo operator para nodeAffinity e podAffinity mencionados acima.
| Operador | Comportamento |
|---|---|
In |
O valor do rótulo está presente no conjunto de strings fornecido |
NotIn |
O valor do rótulo não está contido no conjunto de strings fornecido |
Exists |
Um rótulo com esta chave existe no objeto |
DoesNotExist |
Nenhum rótulo com esta chave existe no objeto |
Os seguintes operadores só podem ser usados com nodeAffinity.
| Operador | Comportamento |
|---|---|
Gt |
O valor do campo será interpretado como um inteiro, e o inteiro resultante da interpretação do valor de um rótulo nomeado por este seletor é maior que esse inteiro |
Lt |
O valor do campo será interpretado como um inteiro, e o inteiro resultante da interpretação do valor de um rótulo nomeado por este seletor é menor que esse inteiro |
Gt e Lt não funcionarão com valores não inteiros. Se o valor fornecido
não puder ser interpretado como um inteiro, o Pod não conseguirá ser alocado. Além disso, Gt e Lt
não estão disponíveis para podAffinity.Afinidade de nó é uma propriedade dos Pods que os associa a um conjunto de nós (seja como uma preferência ou uma exigência). Taints são o oposto -- eles permitem que um nó repudie um conjunto de pods.
Tolerâncias são aplicadas em pods e permitem, mas não exigem, que os pods sejam alocados em nós com taints correspondentes.
Taints e tolerâncias trabalham juntos para garantir que pods não sejam alocados em nós inapropriados. Um ou mais taints são aplicados em um nó; isso define que o nó não deve aceitar nenhum pod que não tolera essas taints.
Você adiciona um taint a um nó utilizando kubectl taint. Por exemplo,
kubectl taint nodes node1 key1=value1:NoSchedule
define um taint no nó node1. O taint tem a chave key1, valor value1 e o efeito NoSchedule.
Isso significa que nenhum pod conseguirá ser executado no nó node1 a menos que possua uma tolerância correspondente.
Para remover o taint adicionado pelo comando acima, você pode executar:
kubectl taint nodes node1 key1=value1:NoSchedule-
Você especifica uma tolerância para um pod na especificação do Pod. Ambas as seguintes tolerâncias "correspondem" ao taint criado pelo kubectl taint acima, e assim um pod com qualquer uma delas poderia ser executado no node1:
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
tolerations:
- key: "key1"
operator: "Exists"
effect: "NoSchedule"
Aqui está um exemplo de um pod que utiliza tolerâncias:
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
tolerations:
- key: "example-key"
operator: "Exists"
effect: "NoSchedule"
O valor padrão de operator é Equal.
Uma tolerância "casa" um taint se as chaves e efeitos são os mesmos, e:
operator é Exists (no caso nenhum value deve ser especificado), ouoperator é Equal e os valores de value são iguais.Existem dois casos especiais:
Uma key vazia com o operador Exists "casa" todas as chaves, valores e efeitos, o que significa que o pod irá tolerar tudo.
Um effect vazio "casa" todos os efeitos com a chave key1.
O exemplo acima usou effect de NoSchedule. De forma alternativa, você pode usar effect de PreferNoSchedule.
Nesse efeito, o sistema tentará evitar que o pod seja alocado ao nó caso ele não tolere os taints definidos, contudo a alocação não será evitada de forma obrigatória. Pode-se dizer que o PreferNoSchedule é uma versão permissiva do NoSchedule. O terceiro tipo de effect é o NoExecute que será descrito posteriormente.
Você pode colocar múltiplos taints no mesmo nó e múltiplas tolerâncias no mesmo pod. O jeito que o Kubernetes processa múltiplos taints e tolerâncias é como um filtro: começa com todos os taints de um nó, em seguida ignora aqueles para os quais o pod tem uma tolerância relacionada; os taints restantes que não foram ignorados indicam o efeito no pod. Mais especificamente,
NoSchedule, o Kubernetes não alocará o pod naquele nóNoSchedule, mas existe pelo menos um taint não tolerado com o efeito PreferNoSchedule, o Kubernetes tentará não alocar o pod no nóNoExecute, o pod será expulso do nó (caso já esteja em execução) e não será alocado ao nó (caso ainda não esteja em execução).Por exemplo, imagine que você tem um nó com os seguintes taints
kubectl taint nodes node1 key1=value1:NoSchedule
kubectl taint nodes node1 key1=value1:NoExecute
kubectl taint nodes node1 key2=value2:NoSchedule
E um pod com duas tolerâncias:
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
Nesse caso, o pod não será alocado ao nó porque não possui uma tolerância para o terceiro taint. Porém, se ele já estiver rodando no nó quando o taint foi adicionado, não será afetado e continuará rodando, tendo em vista que o terceiro taint é o único não tolerado pelo pod.
Normalmente, se um taint com o efeito NoExecute é adicionado a um nó, qualquer pod que não o tolere será expulso imediatamente e pods que o toleram nunca serão expulsos. Contudo, uma tolerância com efeito NoExecute pode especificar de forma opcional o campo tolerationSeconds, que determina quanto tempo o pod continuará alocado ao nó depois que o taint é adicionado. Por exemplo,
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
tolerationSeconds: 3600
significa que se esse pod está sendo executado e um taint correspondente é adicionado ao nó, o pod irá continuar rodando neste nó por 3600 segundos e depois será expulso. Se o taint for removido antes desse tempo acabar, o pod não será expulso.
Taints e tolerâncias são um modo flexível de conduzir pods para fora dos nós ou expulsar pods que não deveriam estar sendo executados. Alguns casos de uso são
Nós Dedicados: Se você quiser dedicar um conjunto de nós para uso exclusivo de um conjunto específico de usuários, poderá adicionar um taint nesses nós. (digamos, kubectl taint nodes nodename dedicated=groupName:NoSchedule) e em seguida adicionar uma tolerância correspondente para seus pods (isso seria feito mais facilmente com a escrita de um controlador de admissão customizado).
Os pods com tolerância terão sua execução permitida nos nós com taints (dedicados), assim como em qualquer outro nó no cluster. Se você quiser dedicar nós a esses pods e garantir que eles usem apenas os nós dedicados, precisará adicionar uma label similar ao taint para o mesmo conjunto de nós (por exemplo, dedicated=groupName), e o controle de admissão deverá adicionar uma afinidade de nó para exigir que os pods podem ser executados apenas nos nós definidos com a label dedicated=groupName.
Nós com hardware especial: Em um cluster no qual um pequeno grupo de nós possui hardware especializado (por exemplo, GPUs), é desejável manter pods que não necessitem desse tipo de hardware fora desses nós, dessa forma o recurso estará disponível para pods que precisem do hardware especializado. Isso pode ser feito aplicando taints nos nós com o hardware especializado (por exemplo, kubectl taint nodes nodename special=true:NoSchedule or kubectl taint nodes nodename special=true:PreferNoSchedule) e aplicando uma tolerância correspondente nos pods que usam o hardware especial. Assim como no caso de uso de nós dedicados, é provavelmente mais fácil aplicar as tolerâncias utilizando um controlador de admissão.
Por exemplo, é recomendado usar Extended Resources para representar hardware especial, adicione um taint ao seus nós de hardware especializado com o nome do recurso estendido e execute o controle de admissão ExtendedResourceToleration. Agora, tendo em vista que os nós estão marcados com um taint, nenhum pod sem a tolerância será executado neles. Porém, quando você submete um pod que requisita o recurso estendido, o controlador de admissão ExtendedResourceToleration irá adicionar automaticamente as tolerâncias necessárias ao pod que irá, por sua vez, ser alocado no nó com hardware especial. Isso garantirá que esses nós de hardware especial serão dedicados para os pods que requisitarem tal recurso e você não precisará adicionar manualmente as tolerâncias aos seus pods.
Expulsões baseadas em Taint: Um comportamento de expulsão configurada por pod quando problemas existem em um nó, o qual será descrito na próxima seção.
Kubernetes v1.18 [stable]
O efeito de taint NoExecute, mencionado acima, afeta pods que já estão rodando no nó da seguinte forma
tolerationSeconds em sua especificação de tolerância, ficam alocados para sempretolerationSeconds especificado, permanecem alocados pela quantidade de tempo definidaO controlador de nó automaticamente adiciona um taint ao Nó quando certas condições se tornam verdadeiras. Os seguintes taints são embutidos:
node.kubernetes.io/not-ready: Nó não está pronto. Isso corresponde ao NodeCondition Ready com o valor "False".node.kubernetes.io/unreachable: Nó é inalcançável a partir do controlador de nó. Isso corresponde ao NodeCondition Ready com o valor "Unknown".node.kubernetes.io/memory-pressure: Nó possui pressão de memória.node.kubernetes.io/disk-pressure: Nó possui pressão de disco.node.kubernetes.io/pid-pressure: Nó possui pressão de PID.node.kubernetes.io/network-unavailable: A rede do nó está indisponível.node.kubernetes.io/unschedulable: Nó não é alocável.node.cloudprovider.kubernetes.io/uninitialized: Quando o kubelet é iniciado com um provedor de nuvem "externo", esse taint é adicionado ao nó para que ele seja marcado como não utilizável. Após o controlador do cloud-controller-manager inicializar o nó, o kubelet remove esse taint.No caso de um nó estar prestes a ser expulso, o controlador de nó ou kubelet adicionam os taints relevantes com o efeito NoExecute. Se a condição de falha retorna ao normal, o kubelet ou controlador de nó podem remover esses taints.
Você pode especificar tolerationSeconds em um Pod para definir quanto tempo ele ficará alocado em um nó que está falhando ou está sem resposta.
Por exemplo, você talvez queira manter uma aplicação com vários estados salvos localmente alocado em um nó por um longo período na ocorrência de uma divisão na rede, esperando que essa divisão se recuperará e assim a expulsão do pod pode ser evitada. A tolerância que você define para esse Pod poderia ficar assim:
tolerations:
- key: "node.kubernetes.io/unreachable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 6000
O Kubernetes automaticamente adiciona uma tolerância para node.kubernetes.io/not-ready e node.kubernetes.io/unreachable com tolerationSeconds=300, a menos que você, ou um controlador, defina essas tolerâncias explicitamente.
Essas tolerâncias adicionadas automaticamente significam que Pods podem continuar alocados aos Nós por 5 minutos após um desses problemas ser detectado.
Pods do tipo DaemonSet são criados com tolerâncias NoExecute sem a propriedade tolerationSeconds para os seguintes taints:
node.kubernetes.io/unreachablenode.kubernetes.io/not-readyIsso garante que esses pods do DaemonSet nunca sejam expulsos por conta desses problemas.
A camada de gerenciamento, usando o controlador do nó, cria taints automaticamente com o efeito NoSchedule para condições de nó.
O agendador verifica taints, não condições de nó, quando realiza suas decisões de agendamento. Isso garante que as condições de nó não afetem diretamente o agendamento.
Por exemplo, se a condição de nó DiskPressure está ativa, a camada de gerenciamento adiciona o taint node.kubernetes.io/disk-pressure e não aloca novos pods no nó afetado. Se a condição MemoryPressure está ativa, a camada de gerenciamento adiciona o taint node.kubernetes.io/memory-pressure.
Você pode ignorar condições de nó para pods recém-criados adicionando tolerâncias correspondentes. A camada de controle também adiciona a tolerância node.kubernetes.io/memory-pressure em pods que possuem uma classe de QoS diferente de BestEffort. Isso ocorre porque o Kubernetes trata pods nas classes de QoS Guaranteed ou Burstable (até mesmo pods sem requisitos de memória definidos) como se fossem capazes de lidar com pressão de memória, enquanto novos pods com BestEffort não são alocados no nó afetado.
O controlador DaemonSet adiciona automaticamente as seguintes tolerâncias de NoSchedule para todos os daemons, prevenindo que DaemonSets quebrem.
node.kubernetes.io/memory-pressurenode.kubernetes.io/disk-pressurenode.kubernetes.io/pid-pressure (1.14 ou superior)node.kubernetes.io/unschedulable (1.10 ou superior)node.kubernetes.io/network-unavailable (somente rede do host)Adicionando essas tolerâncias garante retro compatibilidade. Você também pode adicionar tolerâncias de forma arbitrária aos DaemonSets.
Kubernetes v1.18 [beta]
Quando você executa um Pod num nó, o próprio Pod usa uma quantidade de recursos do sistema. Estes recursos são adicionais aos recursos necessários para executar o(s) contêiner(s) dentro do Pod. Sobrecarga de Pod, do inglês Pod Overhead, é uma funcionalidade que serve para contabilizar os recursos consumidos pela infraestrutura do Pod para além das solicitações e limites do contêiner.
No Kubernetes, a sobrecarga de Pods é definido no tempo de admissão de acordo com a sobrecarga associada à RuntimeClass do Pod.
Quando é ativada a Sobrecarga de Pod, a sobrecarga é considerada adicionalmente à soma das solicitações de recursos do contêiner ao agendar um Pod. Semelhantemente, o kubelet incluirá a sobrecarga do Pod ao dimensionar o cgroup do Pod e ao executar a classificação de prioridade de migração do Pod em caso de drain do Node.
Terá de garantir que o Feature Gate
PodOverhead esteja ativo (está ativo por padrão a partir da versão 1.18)
em todo o cluster, e uma RuntimeClass utilizada que defina o campo overhead.
Para usar a funcionalidade PodOverhead, é necessário uma RuntimeClass que define o campo overhead.
Por exemplo, poderia usar a definição da RuntimeClass abaixo com um agente de execução de contêiner virtualizado
que use cerca de 120MiB por Pod para a máquina virtual e o sistema operacional convidado:
---
kind: RuntimeClass
apiVersion: node.k8s.io/v1beta1
metadata:
name: kata-fc
handler: kata-fc
overhead:
podFixed:
memory: "120Mi"
cpu: "250m"
As cargas de trabalho que são criadas e que especificam o manipulador RuntimeClass kata-fc irão
usar a sobrecarga de memória e cpu em conta para os cálculos da quota de recursos, agendamento de nós,
assim como dimensionamento do cgroup do Pod.
Considere executar a seguinte carga de trabalho de exemplo, test-pod:
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
runtimeClassName: kata-fc
containers:
- name: busybox-ctr
image: busybox
stdin: true
tty: true
resources:
limits:
cpu: 500m
memory: 100Mi
- name: nginx-ctr
image: nginx
resources:
limits:
cpu: 1500m
memory: 100Mi
No tempo de admissão o controlador de admissão RuntimeClass
atualiza o PodSpec da carga de trabalho de forma a incluir o overhead como descrito na RuntimeClass. Se o PodSpec já tiver este campo definido
o Pod será rejeitado. No exemplo dado, como apenas o nome do RuntimeClass é especificado, o controlador de admissão muda o Pod de forma a
incluir um overhead.
Depois do controlador de admissão RuntimeClass, pode verificar o PodSpec atualizado:
kubectl get pod test-pod -o jsonpath='{.spec.overhead}'
A saída é:
map[cpu:250m memory:120Mi]
Se for definido um ResourceQuota, a soma das requisições dos contêineres assim como o campo overhead são contados.
Quando o kube-scheduler está decidindo que nó deve executar um novo Pod, o agendador considera o overhead do pod,
assim como a soma de pedidos aos contêineres para esse Pod. Para este exemplo, o agendador adiciona as requisições e a sobrecarga, depois procura um nó com 2.25 CPU e 320 MiB de memória disponível.
Assim que um Pod é agendado a um nó, o kubelet nesse nó cria um novo cgroup para o Pod. É dentro deste Pod que o agente de execução de contêiners subjacente vai criar contêineres.
Se o recurso tiver um limite definido para cada contêiner (QoS garantida ou Burstrable QoS com limites definidos),
o kubelet definirá um limite superior para o cgroup do Pod associado a esse recurso (cpu.cfs_quota_us para CPU
e memory.limit_in_bytes de memória). Este limite superior é baseado na soma dos limites do contêiner mais o overhead
definido no PodSpec.
Para CPU, se o Pod for QoS garantida ou Burstrable QoS, o kubelet vai definir cpu.shares baseado na soma dos
pedidos ao contêiner mais o overhead definido no PodSpec.
Olhando para o nosso exemplo, verifique as requisições ao contêiner para a carga de trabalho:
kubectl get pod test-pod -o jsonpath='{.spec.containers[*].resources.limits}'
O total de requisições ao contêiner são 2000m CPU e 200MiB de memória:
map[cpu: 500m memory:100Mi] map[cpu:1500m memory:100Mi]
Verifique isto comparado ao que é observado pelo nó:
kubectl describe node | grep test-pod -B2
A saída mostra que 2250m CPU e 320MiB de memória são solicitados, que inclui PodOverhead:
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits AGE
--------- ---- ------------ ---------- --------------- ------------- ---
default test-pod 2250m (56%) 2250m (56%) 320Mi (1%) 320Mi (1%) 36m
Verifique os cgroups de memória do Pod no nó onde a carga de trabalho está em execução. No seguinte exemplo, crictl
é usado no nó, que fornece uma CLI para agentes de execução compatíveis com CRI. Isto é um
exemplo avançado para mostrar o comportamento do PodOverhead, e não é esperado que os usuários precisem verificar
cgroups diretamente no nó.
Primeiro, no nó em particular, determine o identificador do Pod:
# Execute no nó onde o Pod está agendado
POD_ID="$(sudo crictl pods --name test-pod -q)"
A partir disto, pode determinar o caminho do cgroup para o Pod:
# Execute no nó onde o Pod está agendado
sudo crictl inspectp -o=json $POD_ID | grep cgroupsPath
O caminho do cgroup resultante inclui o contêiner pause do Pod. O cgroup no nível do Pod está um diretório acima.
"cgroupsPath": "/kubepods/podd7f4b509-cf94-4951-9417-d1087c92a5b2/7ccf55aee35dd16aca4189c952d83487297f3cd760f1bbf09620e206e7d0c27a"
Neste caso especifico, o caminho do cgroup do Pod é kubepods/podd7f4b509-cf94-4951-9417-d1087c92a5b2. Verifique a configuração cgroup de nível do Pod para a memória:
# Execute no nó onde o Pod está agendado
# Mude também o nome do cgroup para combinar com o cgroup alocado ao Pod.
cat /sys/fs/cgroup/memory/kubepods/podd7f4b509-cf94-4951-9417-d1087c92a5b2/memory.limit_in_bytes
Isto é 320 MiB, como esperado:
335544320
Uma métrica kube_pod_overhead está disponível em kube-state-metrics
para ajudar a identificar quando o PodOverhead está sendo utilizado e para ajudar a observar a estabilidade das cargas de trabalho
em execução com uma sobrecarga (Overhead) definida. Esta funcionalidade não está disponível na versão 1.9 do kube-state-metrics,
mas é esperado em uma próxima versão. Os usuários necessitarão entretanto construir o kube-state-metrics a partir do código fonte.
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.
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:
Gerar Certificados descreve os passos para gerar certificados usando diferentes cadeias de ferramentas.
Ambiente de Contêineres do Kubernetes descreve o ambiente para contêineres gerenciados pelo kubelet em um nó Kubernetes.
Controle de Acesso a API do Kubernetes descreve como o Kubernetes implementa o controle de acesso para sua própria API.
Autenticação explica a autenticação no Kubernetes, incluindo as várias opções de autenticação.
Autorização é separado da autenticação e controla como as chamadas HTTP são tratadas.
Usando Controladores de Admissão explica plugins que interceptam requisições para o servidor da API Kubernetes após a autenticação e autorização.
usando Sysctl em um Cluster Kubernetes descreve a um administrador como usar a ferramenta de linha de comando sysctl para
definir os parâmetros do kernel.
Auditoria descreve como interagir com logs de auditoria do Kubernetes.
Integração com DNS descreve como resolver um nome DNS diretamente para um serviço Kubernetes.
Registro e Monitoramento da Atividade do Cluster explica como funciona o logging no Kubernetes e como implementá-lo.
Em um cluster Kubernetes, um nó pode ser desligado de forma planejada e controlada ou inesperadamente devido a razões como uma queda de energia ou algo externo. Um desligamento de nó pode levar a falhas na carga de trabalho se o nó não for drenado antes do desligamento. Um desligamento de nó pode ser controlado ou não controlado.
O kubelet tenta detectar o desligamento do sistema do nó e encerra os Pods em execução no nó.
O Kubelet garante que os Pods sigam o processo normal de encerramento de Pod durante o desligamento do nó. Durante o desligamento do nó, o kubelet não aceita novos Pods (mesmo que esses Pods já estejam vinculados ao nó).
Kubernetes v1.21 [beta](habilitado por padrão)No Linux, a funcionalidade de desligamento controlado de nó é controlada com o feature gate
GracefulNodeShutdown que está habilitado por padrão na versão 1.21.
Kubernetes v1.34 [beta](habilitado por padrão)No Windows, a funcionalidade de desligamento controlado de nó é controlada com o feature gate
WindowsGracefulNodeShutdown que foi introduzido na versão 1.32 como uma funcionalidade alfa. No Kubernetes 1.34 a funcionalidade está em Beta
e está habilitada por padrão.
O desligamento controlado de nó no Windows não pode ser cancelado.
Se o kubelet não estiver sendo executado como um serviço do Windows, ele não será capaz de definir e monitorar o evento Preshutdown, o nó terá que passar pelo procedimento de Desligamento Não Controlado de Nó mencionado acima. No caso em que a funcionalidade de desligamento controlado de nó no Windows está habilitada, mas o kubelet não está sendo executado como um serviço do Windows, o kubelet continuará em execução em vez de falhar. No entanto, ele registrará um erro indicando que precisa ser executado como um serviço do Windows.
Observe que, por padrão, ambas as opções de configuração descritas abaixo,
shutdownGracePeriod e shutdownGracePeriodCriticalPods, são definidas como zero,
portanto não ativando a funcionalidade de desligamento controlado de nó.
Para ativar a funcionalidade, ambas as opções devem ser configuradas adequadamente e
definidas com valores diferentes de zero.
Uma vez que o kubelet é notificado sobre um desligamento de nó, ele define uma condição NotReady no
Node, com o reason definido como "node is shutting down". O kube-scheduler respeita esta condição
e não aloca nenhum Pod no nó afetado; espera-se que outros agendadores de terceiros
sigam a mesma lógica. Isso significa que novos Pods não serão alocados naquele nó
e, portanto, nenhum será iniciado.
O kubelet também rejeita Pods durante a fase PodAdmission se um
desligamento de nó em andamento for detectado, de modo que mesmo Pods com uma
tolerância para
node.kubernetes.io/not-ready:NoSchedule não sejam iniciados lá.
Quando o kubelet está definindo essa condição em seu Nó via API, o kubelet também começa a encerrar quaisquer Pods que estejam em execução localmente.
Durante um desligamento controlado, o kubelet encerra os Pods em duas fases:
A funcionalidade de desligamento controlado de nó é configurada com duas
opções do KubeletConfiguration:
shutdownGracePeriod:
Especifica a duração total que o nó deve atrasar o desligamento. Esta é a duração total de tolerância para o encerramento de Pods tanto para Pods regulares quanto para Pods críticos.
shutdownGracePeriodCriticalPods:
Especifica a duração utilizada para encerrar
Pods críticos
durante um desligamento de nó. Este valor deve ser menor que shutdownGracePeriod.
Ready.
No entanto, os Pods que já iniciaram o processo de encerramento não serão restaurados pelo kubelet
e precisarão ser reagendados.Por exemplo, se shutdownGracePeriod=30s e
shutdownGracePeriodCriticalPods=10s, o kubelet atrasará o desligamento do nó em
30 segundos. Durante o desligamento, os primeiros 20 (30-10) segundos serão reservados
para encerrar gradualmente os Pods normais, e os últimos 10 segundos serão
reservados para encerrar Pods críticos.
Quando os Pods foram removidos durante o desligamento controlado do nó, eles são marcados como desligados.
Executar kubectl get pods mostra o status dos Pods removidos como Terminated.
E kubectl describe pod indica que o Pod foi removido devido ao desligamento do nó:
Reason: Terminated
Message: Pod was terminated in response to imminent node shutdown.
Kubernetes v1.24 [beta](habilitado por padrão)Para fornecer mais flexibilidade durante o desligamento controlado de nó em relação à ordenação de Pods durante o desligamento, o desligamento controlado de nó respeita a PriorityClass para Pods, desde que você tenha habilitado esta funcionalidade em seu cluster. A funcionalidade permite que administradores de cluster definam explicitamente a ordenação de Pods durante o desligamento controlado de nó com base em classes de prioridade.
A funcionalidade de Desligamento Controlado de Nó, conforme descrita acima, desliga Pods em duas fases, Pods não críticos, seguidos por Pods críticos. Se flexibilidade adicional for necessária para definir explicitamente a ordenação de Pods durante o desligamento de uma forma mais granular, o desligamento controlado baseado em prioridade de Pod pode ser usado. Quando o desligamento controlado de nó respeita as prioridades de Pod, isso torna possível fazer o desligamento controlado de nó em múltiplas fases, cada fase desligando uma classe de prioridade específica de Pods. O kubelet pode ser configurado com as fases exatas e o tempo de desligamento por fase.
Assumindo as seguintes classes de prioridade personalizadas de Pod em um cluster,
| Nome da classe de prioridade do Pod | Valor da classe de prioridade do Pod |
|---|---|
custom-class-a |
100000 |
custom-class-b |
10000 |
custom-class-c |
1000 |
regular/unset |
0 |
Dentro da configuração do kubelet
as configurações para shutdownGracePeriodByPodPriority poderiam ser assim:
| Valor da classe de prioridade do Pod | Período de desligamento |
|---|---|
| 100000 | 10 segundos |
| 10000 | 180 segundos |
| 1000 | 120 segundos |
| 0 | 60 segundos |
A configuração YAML correspondente do kubelet seria:
shutdownGracePeriodByPodPriority:
- priority: 100000
shutdownGracePeriodSeconds: 10
- priority: 10000
shutdownGracePeriodSeconds: 180
- priority: 1000
shutdownGracePeriodSeconds: 120
- priority: 0
shutdownGracePeriodSeconds: 60
A tabela acima implica que qualquer Pod com valor de priority >= 100000 terá
apenas 10 segundos para desligar, qualquer Pod com valor >= 10000 e < 100000 terá 180
segundos para desligar, qualquer Pod com valor >= 1000 e < 10000 terá 120 segundos para desligar.
Finalmente, todos os outros Pods terão 60 segundos para desligar.
Não é necessário especificar valores correspondentes a todas as classes. Por exemplo, você poderia usar estas configurações:
| Valor da classe de prioridade do Pod | Período de desligamento |
|---|---|
| 100000 | 300 segundos |
| 1000 | 120 segundos |
| 0 | 60 segundos |
No caso acima, os Pods com custom-class-b irão para o mesmo grupo
que custom-class-c para o desligamento.
Se não houver Pods em um intervalo específico, então o kubelet não espera por Pods naquele intervalo de prioridade. Em vez disso, o kubelet pula imediatamente para o próximo intervalo de valor de classe de prioridade.
Se esta funcionalidade estiver habilitada e nenhuma configuração for fornecida, então nenhuma ação de ordenação será realizada.
Usar esta funcionalidade requer habilitar o
feature gate
GracefulNodeShutdownBasedOnPodPriority e definir ShutdownGracePeriodByPodPriority na
configuração do kubelet
para a configuração desejada contendo os valores de classe de prioridade do Pod e
seus respectivos períodos de desligamento.
As métricas graceful_shutdown_start_time_seconds e graceful_shutdown_end_time_seconds
são emitidas sob o subsistema do kubelet para monitorar os desligamentos de nó.
Kubernetes v1.28 [stable](habilitado por padrão)Uma ação de desligamento de nó pode não ser detectada pelo Gerenciador de Desligamento de Nó do kubelet, seja porque o comando não aciona o mecanismo de bloqueios inibidores usado pelo kubelet ou devido a um erro do usuário, ou seja, o ShutdownGracePeriod e ShutdownGracePeriodCriticalPods não estão configurados adequadamente. Por favor, consulte a seção acima Desligamento Controlado de Nó para mais detalhes.
Quando um nó é desligado mas não detectado pelo Gerenciador de Desligamento de Nó do kubelet, os Pods que fazem parte de um StatefulSet ficarão presos no status de encerramento no nó desligado e não podem se mover para um novo nó em execução. Isso ocorre porque o kubelet no nó desligado não está disponível para excluir os Pods, então o StatefulSet não pode criar um novo Pod com o mesmo nome. Se houver volumes usados pelos Pods, os VolumeAttachments não serão excluídos do nó desligado original, então os volumes usados por esses Pods não podem ser anexados a um novo nó em execução. Como resultado, a aplicação em execução no StatefulSet não pode funcionar adequadamente. Se o nó desligado original voltar, os Pods serão excluídos pelo kubelet e novos Pods serão criados em um nó diferente em execução. Se o nó desligado original não voltar, esses Pods ficarão presos no status de encerramento no nó desligado para sempre.
Para mitigar a situação acima, um usuário pode adicionar manualmente um taint node.kubernetes.io/out-of-service
com efeito NoExecute ou NoSchedule a um Nó marcando-o como fora de serviço.
Se um Nó for marcado como fora de serviço com este taint, os Pods no nó serão excluídos forçadamente
se não houver tolerâncias correspondentes nele e as operações de desanexação de volume para os Pods encerrando no
nó acontecerão imediatamente. Isso permite que os Pods no nó fora de serviço se recuperem rapidamente
em um nó diferente.
Durante um desligamento não controlado, os Pods são encerrados em duas fases:
out-of-service correspondentes.node.kubernetes.io/out-of-service, deve ser verificado
que o nó já está em estado de desligamento ou desligado (não no meio de uma reinicialização).Em qualquer situação em que a exclusão de um Pod não tenha sido bem-sucedida por 6 minutos, o kubernetes irá
desanexar forçadamente os volumes sendo desmontados se o nó não estiver íntegro naquele instante. Qualquer
carga de trabalho ainda em execução no nó que usa um volume desanexado forçadamente causará uma
violação da
especificação CSI,
que afirma que ControllerUnpublishVolume "deve ser chamado após todas as
NodeUnstageVolume e NodeUnpublishVolume no volume serem chamadas e bem-sucedidas".
Em tais circunstâncias, os volumes no nó em questão podem encontrar corrupção de dados.
O comportamento de desanexação forçada de armazenamento é opcional; os usuários podem optar por usar a funcionalidade de "Desligamento não controlado de nó" em vez disso.
A desanexação forçada de armazenamento por tempo limite pode ser desabilitada definindo o campo de configuração
disable-force-detach-on-timeout no kube-controller-manager. Desabilitar a funcionalidade de desanexação forçada por tempo limite significa
que um volume que está hospedado em um nó que não está íntegro por mais de 6 minutos não terá
seu VolumeAttachment
associado excluído.
Após esta configuração ter sido aplicada, Pods não íntegros ainda anexados a volumes devem ser recuperados através do procedimento de Desligamento Não Controlado de Nó mencionado acima.
Saiba mais sobre o seguinte:
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.
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 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.
Certificados descreve as etapas para gerar certificados usando diferentes ferramentas.
Ambiente de Contêiner Kubernetes descreve o ambiente para contêineres gerenciados pelo Kubelet em um nó do Kubernetes.
Controlando Acesso a API Kubernetes API descreve como configurar a permissão para usuários e contas de serviço.
Autenticando explica a autenticação no Kubernetes, incluindo as várias opções de autenticação.
Autorização é separada da autenticação e controla como as chamadas HTTP são tratadas.
Usando Controladores de Admissão explica plug-ins que interceptam solicitações ao servidor da API do Kubernetes após autenticação e autorização.
Usando Sysctls em um Cluster Kubernetes descreve a um administrador como usar a ferramenta de linha de comando sysctl para definir os parâmetros do kernel.
Auditando descreve como interagir com os logs de auditoria do Kubernetes.
Integração DNS descreve como resolver um nome DNS diretamente para um serviço do Kubernetes.
Logando e monitorando a atividade de cluster explica como o log funciona no Kubernetes e como implementá-lo.
Ao usar um client para autenticação de certificado, você pode gerar certificados
manualmente através easyrsa, openssl ou cfssl.
easyrsa pode gerar manualmente certificados para o seu cluster.
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
Gerar o CA. (--batch set automatic mode. --req-cn default CN to use.)
./easyrsa --batch "--req-cn=${MASTER_IP}@`date +%s`" build-ca nopass
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
Copie pki/ca.crt, pki/issued/server.crt, e pki/private/server.key para o seu diretório.
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 pode gerar manualmente certificados para o seu cluster.
Gere um ca.key com 2048bit:
openssl genrsa -out ca.key 2048
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
Gere um server.key com 2048bit:
openssl genrsa -out server.key 2048
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
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
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
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 é outra ferramenta para geração de certificados.
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
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
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"
}
}
}
}
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>"
}]
}
Gere a chave CA (ca-key.pem) e o certificado (ca.pem):
../cfssl gencert -initca ca-csr.json | ../cfssljson -bare ca
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>"
}]
}
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
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.
Você pode usar a API certificates.k8s.io para provisionar
certificados x509 a serem usados para autenticação conforme documentado
aqui.
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:
localhost.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.
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):
Nota: Para as plataformas que suportam Pods executando na rede do host (como o Linux):
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.
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.
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.
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 é 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 é 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 é 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 é uma camada muito simples de conectividade que satisfaz os requisitos do Kubernetes. Muitas pessoas reportaram sucesso em utilizar o Flannel com o Kubernetes.
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 é 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.
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 é 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 é 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.
Design inicial do modelo de conectividade do Kubernetes e alguns planos futuros estão descritos com maiores detalhes no documento de design de redes.
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.
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.

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.
kubectl logs. Por exemplo, se houver um arquivo de 10MB, o logrotate executa a rotação e existem dois arquivos, um com 10MB de tamanho e um vazio, o kubectl logs retornará uma resposta vazia.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:
Nas máquinas com systemd, o tempo de execução do kubelet e do contêiner é 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.
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:

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ó.
Você pode usar um contêiner sidecar de uma das seguintes maneiras:
stdout.
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.

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.
kubectl logs, porque eles não são controlados pelo kubelet.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.

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.
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 é 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]
Kubernetes v1.19 [alpha]
A migração pro formato de logs estruturados é um processo em andamento. Nem todos os logs estão dessa forma na versão atual. Sendo assim, para realizar o processamento de arquivos de log, você também precisa lidar com logs não estruturados.
A formatação e serialização dos logs ainda estão sujeitas a alterações.
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"
Kubernetes v1.19 [alpha]
Algumas opções da biblioteca klog ainda não funcionam com os logs em formato JSON. Para ver uma lista completa de quais são estas, veja a documentação da ferramenta de linha de comando.
Nem todos os logs estarão garantidamente em formato JSON (como por exemplo durante o início de processos). Sendo assim, se você pretende realizar o processamento dos logs, seu código deverá saber tratar também linhas que não são JSON.
O nome dos campos e a serialização JSON ainda estão sujeitos a mudanças.
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:
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:
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.
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.
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.
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.
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.
Os usuários podem ajustar os seguintes limites para ajustar o garbage collection da imagem com os seguintes sinalizadores do kubelet:
image-gh-high-threshold, a porcentagem de uso de disco que aciona o garbage collection da imagem. O padrão é 85%.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:
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.maximum-dead-containers-per-container, número máximo de instâncias antigas a serem retidas por contêiner. O padrão é 1.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.
Alguns recursos do Garbage Collection neste documento serão substituídos pelo kubelet eviction no futuro.
Incluindo:
| Flag Existente | Nova Flag | Fundamentação |
|---|---|---|
--image-gc-high-threshold |
--eviction-hard ou --eviction-soft |
os sinais existentes de despejo podem acionar o garbage collection da imagem |
--image-gc-low-threshold |
--eviction-minimum-reclaim |
recuperações de despejo atinge o mesmo comportamento |
--maximum-dead-containers |
descontinuado quando os logs antigos forem armazenados fora do contexto do contêiner | |
--maximum-dead-containers-per-container |
descontinuado quando os logs antigos forem armazenados fora do contexto do contêiner | |
--minimum-container-ttl-duration |
descontinuado quando os logs antigos forem armazenados fora do contexto do contêiner | |
--low-diskspace-threshold-mb |
--eviction-hard ou eviction-soft |
O despejo generaliza os limites do disco para outros recursos |
--outofdisk-transition-frequency |
--eviction-pressure-transition-period |
O despejo generaliza a transição da pressão do disco para outros recursos |
Consulte Configurando a Manipulação de Recursos Insuficientes para mais detalhes.
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.
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 de séries 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
Métrica alfa → Métrica beta → 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 beta seguem um contrato de API menos rígido do que suas contrapartes estáveis. Nenhum rótulo pode ser removido de métricas beta durante sua vida útil, no entanto, rótulos podem ser adicionados enquanto a métrica estiver no estágio beta.
Métricas estáveis possuem a garantia de que não serão alteradas. Isso significa:
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. Uma métrica ultrapassada se torna uma métrica oculta após um período de tempo, com base em seu nível de estabilidade:
Para usar uma métrica oculta, você deve habilitá-la. Para mais detalhes, 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.
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. Se você quiser mostrar todas as métricas ocultas na versão anterior, pode definir a flag show-hidden-metrics-for-version para a versão anterior. Usar uma versão muito antiga não é permitido porque viola a política de descontinuação de métricas.
Por exemplo, vamos supor que a métrica A seja descontinuada na versão 1.29. A versão na qual a métrica A se torna oculta depende de seu nível de estabilidade:
A for ALFA, ela poderá ser ocultada na versão 1.29.A for BETA, ela será ocultada na versão 1.30 no mínimo. Se você estiver atualizando para a versão 1.30 e ainda precisar de A, você deve usar a opção de linha de comando --show-hidden-metrics-for-version=1.29.A for ESTÁVEL, ela será ocultada na versão 1.32 no mínimo. Se você estiver atualizando para a versão 1.32 e ainda precisar de A, você deve usar a opção de linha de comando --show-hidden-metrics-for-version=1.31.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"}
Kubernetes v1.21 [beta]
O scheduler expõe métricas opcionais que reportam 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 série temporal de métricas. Essa série temporal é etiquetada por:
cpu)cores)Uma vez que o pod alcança um estado de conclusão (sua restartPolicy está como Never ou OnFailure e está na fase Succeeded ou Failed, ou foi deletado e todos os contêineres têm 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. Elas requerem
autorização para o endpoint /metrics/resources, geralmente concedida por uma
ClusterRole com o verbo get para a URL não-recurso /metrics/resources.
No Kubernetes 1.21 você deve usar a opção
--show-hidden-metrics-for-version=1.20 para expor essas métricas de estabilidade alfa.
Kubernetes v1.34 [beta]
Como uma funcionalidade beta, o Kubernetes permite que você configure o kubelet para coletar informações de
Pressure Stall Information
(PSI) do kernel Linux para uso de CPU, memória e I/O.
As informações são coletadas no nível de nó, Pod e contêiner.
As métricas são expostas no endpoint /metrics/cadvisor com os seguintes nomes:
container_pressure_cpu_stalled_seconds_total
container_pressure_cpu_waiting_seconds_total
container_pressure_memory_stalled_seconds_total
container_pressure_memory_waiting_seconds_total
container_pressure_io_stalled_seconds_total
container_pressure_io_waiting_seconds_total
Esta funcionalidade está habilitada por padrão, ao definir o feature gate KubeletPSI. As informações também são expostas na
API Summary.
Você pode aprender como interpretar as métricas PSI em Entender Métricas PSI.
Pressure Stall Information requer:
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).
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 valores de label permitidos 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-metric-labels <metric_name>,<label_name>='<allow_value1>, <allow_value2>...', <metric_name2>,<label_name>='<allow_value1>, <allow_value2>...', ...
Por exemplo:
--allow-metric-labels number_count_metric,odd_number='1,3,5', number_count_metric,even_number='2,4,6', date_gauge_metric,weekend='Saturday,Sunday'
Além de especificar isso pela CLI, isso também pode ser feito dentro de um arquivo de configuração. Você
pode especificar o caminho para esse arquivo de configuração usando o argumento de linha de comando
--allow-metric-labels-manifest para um componente. Aqui está um exemplo do conteúdo desse arquivo de configuração:
"metric1,label2": "v1,v2,v3"
"metric2,label1": "v1,v2,v3"
Além disso, a meta-métrica cardinality_enforcement_unexpected_categorizations_total registra a
contagem de categorizações inesperadas durante a aplicação de cardinalidade, isto é, sempre que um valor de rótulo
é encontrado que não é permitido em relação às restrições da lista de permissões.
Esta página descreve o uso de proxies com Kubernetes.
Existem vários tipos diferentes de proxies que você pode encontrar usando Kubernetes:
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.
O kube proxy:
Um Proxy/Balanceador de carga na frente de servidores de API(s):
Balanceadores de carga da nuvem em serviços externos:
LoadBalancerOs 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.
Os proxies substituíram as capacidades de redirecionamento. O redirecionamento foi depreciado.
Kubernetes v1.27 [beta]
Os rastreamentos de componentes do sistema registram a latência e os relacionamentos entre as operações no cluster.
Os componentes do Kubernetes emitem rastreamentos usando o OpenTelemetry Protocol com o exportador gRPC e podem ser coletados e roteados para backends de rastreamento usando um OpenTelemetry Collector.
Os componentes do Kubernetes possuem exportadores gRPC embutidos para OTLP para exportar rastreamentos, seja com um OpenTelemetry Collector, ou sem um OpenTelemetry Collector.
Para um guia completo sobre coleta de rastreamentos e uso do coletor, consulte Getting Started with the OpenTelemetry Collector. No entanto, existem algumas coisas a serem observadas que são específicas dos componentes do Kubernetes.
Por padrão, os componentes do Kubernetes exportam rastreamentos usando o exportador grpc para OTLP na porta IANA do OpenTelemetry, 4317. Como exemplo, se o coletor estiver sendo executado como um sidecar de um componente do Kubernetes, a seguinte configuração de receptor coletará spans e os registrará na saída padrão:
receivers:
otlp:
protocols:
grpc:
exporters:
# Substitua este exportador pelo exportador do seu backend
exporters:
debug:
verbosity: detailed
service:
pipelines:
traces:
receivers: [otlp]
exporters: [debug]
Para emitir rastreamentos diretamente para um backend sem utilizar um coletor, especifique o campo endpoint no arquivo de configuração de rastreamento do Kubernetes com o endereço do backend de rastreamento desejado. Este método elimina a necessidade de um coletor e simplifica a estrutura geral.
Para configuração de cabeçalhos do backend de rastreamento, incluindo detalhes de autenticação, variáveis de ambiente podem ser usadas com OTEL_EXPORTER_OTLP_HEADERS,
consulte OTLP Exporter Configuration.
Além disso, para configuração de atributos de recurso de rastreamento, como nome do cluster Kubernetes, namespace, nome do Pod, etc.,
variáveis de ambiente também podem ser usadas com OTEL_RESOURCE_ATTRIBUTES, consulte OTLP Kubernetes Resource.
O kube-apiserver gera spans para requisições HTTP de entrada e para requisições de saída para webhooks, etcd e requisições reentrantes. Ele propaga o W3C Trace Context com requisições de saída, mas não faz uso do contexto de rastreamento anexado às requisições de entrada, pois o kube-apiserver frequentemente é um endpoint público.
Para habilitar o rastreamento, forneça ao kube-apiserver um arquivo de configuração de rastreamento
com --tracing-config-file=<caminho-para-config>. Este é um exemplo de configuração que registra
spans para 1 em 10000 requisições e usa o endpoint padrão do OpenTelemetry:
apiVersion: apiserver.config.k8s.io/v1
kind: TracingConfiguration
# valor padrão
#endpoint: localhost:4317
samplingRatePerMillion: 100
Para mais informações sobre a estrutura TracingConfiguration, consulte
API server config API (v1).
Kubernetes v1.34 [stable](habilitado por padrão)A interface CRI do kubelet e os servidores http autenticados são instrumentados para gerar spans de rastreamento. Assim como no apiserver, o endpoint e a taxa de amostragem são configuráveis. A propagação do contexto de rastreamento também é configurada. A decisão de amostragem de um span raiz é sempre respeitada. Uma taxa de amostragem de configuração de rastreamento fornecida será aplicada a spans sem um span raiz. Habilitado sem um endpoint configurado, o endereço padrão do receptor do OpenTelemetry Collector de "localhost:4317" é definido.
Para habilitar o rastreamento, aplique a configuração de rastreamento. Este é um trecho de exemplo de uma configuração do kubelet que registra spans para 1 em 10000 requisições e usa o endpoint padrão do OpenTelemetry:
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
tracing:
# valor padrão
#endpoint: localhost:4317
samplingRatePerMillion: 100
Se o samplingRatePerMillion estiver definido como um milhão (1000000), então cada
span será enviado para o exportador.
O kubelet no Kubernetes v1.35 coleta spans da coleta de lixo, rotina de sincronização de pods, bem como de cada método gRPC. O kubelet propaga o contexto de rastreamento com requisições gRPC para que agentes de execução de contêiner com instrumentação de rastreamento, como CRI-O e containerd, possam associar seus spans exportados ao contexto de rastreamento do kubelet. Os rastreamentos resultantes terão vínculos hierárquicos entre os spans do kubelet e do agente de execução de contêiner, fornecendo contexto útil ao depurar problemas do nó.
Observe que a exportação de spans sempre vem com uma pequena sobrecarga de desempenho
no lado de rede e CPU, dependendo da configuração geral do
sistema. Se houver algum problema desse tipo em um cluster que está sendo executado com
rastreamento habilitado, então mitigue o problema reduzindo o
samplingRatePerMillion ou desabilitando completamente o rastreamento removendo a
configuração.
A instrumentação de rastreamento ainda está em desenvolvimento ativo e pode mudar de várias maneiras. Isso inclui nomes de span, atributos anexados, endpoints instrumentados, etc. Até que esta funcionalidade se torne estável, não há garantias de retrocompatibilidade para a instrumentação de rastreamento.
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.
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!
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.
--max-requests-inflight sem o recurso da APF ativado.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.
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.
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.
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.
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.
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.
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.
--max-requests-inflight e
--max-mutating-requests-inflight. Já não há distinção
entre solicitações mutantes e não mutantes; se você quiser tratá-las
separadamente para um determinado recurso, faça FlowSchemas separados que correspondam ao
verbos mutantes e não mutantes, respectivamente.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.
handSize maior também
aumenta potencialmente a quantidade de latência que um único fluxo de alto tráfego
pode causar. O número máximo de solicitações enfileiradas possíveis de um
fluxo único é handSize * queueLengthLimit.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.
| HandSize | Filas | 1 elefante | 4 elefantes | 16 elefantes |
|---|---|---|---|---|
| 12 | 32 | 4.428838398950118e-09 | 0.11431348830099144 | 0.9935089607656024 |
| 10 | 32 | 1.550093439632541e-08 | 0.0626479840223545 | 0.9753101519027554 |
| 10 | 64 | 6.601827268370426e-12 | 0.00045571320990370776 | 0.49999929150089345 |
| 9 | 64 | 3.6310049976037345e-11 | 0.00045501212304112273 | 0.4282314876454858 |
| 8 | 64 | 2.25929199850899e-10 | 0.0004886697053040446 | 0.35935114681123076 |
| 8 | 128 | 6.994461389026097e-13 | 3.4055790161620863e-06 | 0.02746173137155063 |
| 7 | 128 | 1.0579122850901972e-11 | 6.960839379258192e-06 | 0.02406157386340147 |
| 7 | 256 | 7.597695465552631e-14 | 6.728547142019406e-08 | 0.0006709661542533682 |
| 6 | 256 | 2.7134626662687968e-12 | 2.9516464018476436e-07 | 0.0008895654642000348 |
| 6 | 512 | 4.116062922897309e-14 | 4.982983350480894e-09 | 2.26025764343413e-05 |
| 6 | 1024 | 6.337324016514285e-16 | 8.09060164312957e-11 | 4.517408062903668e-07 |
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.
matchingPrecedence. Se vários FlowSchemas com igual
matchingPrecedence corresponde ao mesmo pedido, aquele com menor
name lexicográfico vencerá, mas é melhor não confiar nisso e, em vez disso,
certifique-se de que dois FlowSchemas não tenham o mesmo matchingPrecedence.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.
Cada kube-apiserver mantém dois tipos de objetos de configuração APF: obrigatória e sugerida.
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.
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.
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.
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
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.
flow_schema e
priority_level foram nomeados de forma inconsistente como flowSchema e priorityLevel,
respectivamente. Se você estiver executando versões do Kubernetes v1.19 ou anteriores, você
deve consultar a documentação da sua versão.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 outime-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).
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,
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.
O Kubernetes oferece suporte a nós de trabalho que executam Linux ou Microsoft Windows.
A CNCF e sua mantenedora, a Linux Foundation, adotam uma abordagem neutra a fornecedores em relação à compatibilidade. É possível adicionar seu servidor Windows como um nó de trabalho em um cluster Kubernetes.
Você pode instalar e configurar o kubectl no Windows, independentemente do sistema operacional que você usa em seu cluster.
Se você estiver usando nós Windows, pode ler:
Ou, para uma visão geral, leia:
Aplicativos Windows constituem uma grande parte dos serviços e aplicações que rodam em muitas organizações. Contêineres Windows fornecem uma maneira de encapsular processos e empacotar dependências, facilitando o uso de práticas DevOps e seguindo padrões nativos da nuvem para aplicativos Windows.
Organizações com investimentos em aplicativos baseados em Windows e Linux não precisam procurar orquestradores separados para gerenciar suas cargas de trabalho, levando a eficiências operacionais aumentadas em suas implantações, independentemente do sistema operacional.
Para habilitar a orquestração de contêineres Windows no Kubernetes, inclua nós Windows em seu cluster Linux existente. A alocação de contêineres Windows em Pods no Kubernetes é similar à alocação de contêineres baseados em Linux.
Para executar contêineres Windows, seu cluster Kubernetes deve incluir múltiplos sistemas operacionais. Embora você possa executar a camada de gerenciamento apenas no Linux, você pode implantar nós de trabalho executando Windows ou Linux.
Nós Windows são suportados desde que o sistema operacional seja Windows Server 2022 ou Windows Server 2025.
Este documento usa o termo contêineres Windows para se referir a contêineres Windows com isolamento de processo. O Kubernetes não suporta a execução de contêineres Windows com isolamento Hyper-V.
Alguns recursos do nó estão disponíveis apenas se você usar um agente de execução de contêiner específico; outros não estão disponíveis em nós Windows, incluindo:
Nem todos os recursos de namespaces compartilhados são suportados. Veja Compatibilidade da API para mais detalhes.
Veja Compatibilidade de versão do sistema operacional Windows para detalhes sobre as versões do Windows nas quais o Kubernetes é testado.
Do ponto de vista da API e do kubectl, contêineres Windows se comportam de maneira muito semelhante aos contêineres baseados em Linux. No entanto, há algumas diferenças notáveis em funcionalidades-chave que são destacadas nesta seção.
Elementos-chave do Kubernetes funcionam da mesma forma no Windows como no Linux. Esta seção refere-se a várias abstrações de carga de trabalho e como elas se mapeiam para o Windows.
Um Pod é o bloco de construção básico do Kubernetes — a menor e mais simples unidade no modelo de objeto do Kubernetes que você cria ou implanta. Você não pode implantar contêineres Windows e Linux no mesmo Pod. Todos os contêineres em um Pod são agendados em um único Nó, onde cada Nó representa uma plataforma e arquitetura específicas. As seguintes capacidades, propriedades e eventos do Pod são suportados com contêineres Windows:
Único ou múltiplos contêineres por Pod com isolamento de processo e compartilhamento de volume
Campos de status do Pod
Verificações de readiness (prontidão), liveness (operacionalidade) e startup (inicialização)
Hooks de ciclo de vida do Contêiner postStart e preStop
ConfigMap, Secrets: como variáveis de ambiente ou volumes
Volumes emptyDir
Montagens de pipe nomeado do host
Limites de recursos
Campo Sistema Operacional:
O campo .spec.os.name deve ser definido como windows para indicar que o Pod atual usa contêineres Windows.
Se você definir o campo .spec.os.name como windows, não deve definir os seguintes campos no .spec desse Pod:
spec.hostPIDspec.hostIPCspec.securityContext.seLinuxOptionsspec.securityContext.seccompProfilespec.securityContext.fsGroupspec.securityContext.fsGroupChangePolicyspec.securityContext.sysctlsspec.shareProcessNamespacespec.securityContext.runAsUserspec.securityContext.runAsGroupspec.securityContext.supplementalGroupsspec.containers[*].securityContext.seLinuxOptionsspec.containers[*].securityContext.seccompProfilespec.containers[*].securityContext.capabilitiesspec.containers[*].securityContext.readOnlyRootFilesystemspec.containers[*].securityContext.privilegedspec.containers[*].securityContext.allowPrivilegeEscalationspec.containers[*].securityContext.procMountspec.containers[*].securityContext.runAsUserspec.containers[*].securityContext.runAsGroupNa lista acima, curingas (*) indicam todos os elementos em uma lista. Por exemplo, spec.containers[*].securityContext refere*se ao objeto SecurityContext para todos os contêineres. Se qualquer um desses campos for especificado, o Pod não será admitido pelo servidor API.
Recursos de carga de trabalho incluindo:
Veja Balanceamento de carga e Services para mais detalhes.
Pods, recursos de carga de trabalho e Services são elementos críticos para gerenciar cargas de trabalho Windows no Kubernetes. No entanto, por si só, eles não são suficientes para habilitar o gerenciamento adequado do ciclo de vida de cargas de trabalho Windows em um ambiente nativo da nuvem dinâmico.
kubectl execAlgumas opções de linha de comando do kubelet se comportam de maneira diferente no Windows, conforme descrito abaixo:
--windows-priorityclass permite definir a prioridade de agendamento do processo kubelet (veja Gerenciamento de recursos de CPU)--kube-reserved, --system-reserved e --eviction-hard atualizam NodeAllocatable--enforce-node-allocable não está implementada--kube-reserved e --system-reserved apenas subtraem de NodeAllocatable e não garantem recursos fornecidos para cargas de trabalho. Veja Gerenciamento de recursos para nós Windows para mais informações.PIDPressure não está implementadaExistem diferenças sutis na forma como as APIs do Kubernetes funcionam para o Windows devido ao SO e ao agente de execução de contêiner. Algumas propriedades de carga de trabalho foram projetadas para Linux e falham ao rodar no Windows.
Em um nível alto, esses conceitos de SO são diferentes:
/etc/groups ou /etc/passwd de volta para UID+GID. O Windows usa um identificador de segurança (SID) binário maior que é armazenado no banco de dados Windows Security Access Manager (SAM). Este banco de dados não é compartilhado entre o host e os contêineres, ou entre os contêineres.\ em vez de /. As bibliotecas Go IO normalmente aceitam ambos e simplesmente funcionam, mas quando você está definindo um caminho ou linha de comando que é interpretada dentro de um Contêiner, pode ser necessário usar \.WM_CLOSE.SERVICE_CONTROL_STOP.Códigos de saída de Contêiner seguem a mesma convenção onde 0 é sucesso e diferente de zero é falha. Os códigos de erro específicos podem diferir entre Windows e Linux. No entanto, códigos de saída passados dos componentes do Kubernetes (kubelet, kube-proxy) são inalterados.
A lista a seguir documenta as diferenças entre como as especificações de Contêiner do Pod funcionam entre Windows e Linux:
requests.cpu e requests.memory - as solicitações são subtraídas dos recursos disponíveis do nó, para que possam ser usadas para evitar o superprovisionamento de um nó. No entanto, elas não podem ser usadas para garantir recursos em um nó superprovisionado. Elas devem ser aplicadas a todos os contêineres como uma boa prática se o operador quiser evitar o superprovisionamento completamente.securityContext.allowPrivilegeEscalation - não é possível no Windows; nenhuma das capacidades está conectadasecurityContext.capabilities - capacidades POSIX não são implementadas no WindowssecurityContext.privileged - o Windows não suporta contêineres privilegiados, use contêineres HostProcess em vez dissosecurityContext.procMount - o Windows não possui um sistema de arquivos /procsecurityContext.readOnlyRootFilesystem - não é possível no Windows; acesso de gravação é necessário para que o registro e processos do sistema rodem dentro do ContêinersecurityContext.runAsGroup - não é possível no Windows, pois não há suporte para GIDsecurityContext.runAsNonRoot - esta configuração impedirá que contêineres sejam executados como ContainerAdministrator, que é o equivalente mais próximo a um usuário root no Windows.securityContext.runAsUser - use runAsUserName em vez dissosecurityContext.seLinuxOptions - não é possível no Windows, pois o SELinux é específico do LinuxterminationMessagePath - isso tem algumas limitações, pois o Windows não suporta mapeamento de arquivos únicos. O valor padrão é /dev/termination-log, que funciona porque não existe no Windows por padrão.A lista a seguir documenta as diferenças entre como as especificações de Pod funcionam entre Windows e Linux:
hostIPC e hostPID - compartilhamento de namespace do host não é possível no WindowshostNetwork - veja abaixodnsPolicy - definir o dnsPolicy do Pod como ClusterFirstWithHostNet não é suportado no Windows porque a rede do host não é fornecida. Pods sempre rodam com uma rede de Contêiner.podSecurityContext veja abaixoshareProcessNamespace - este é um recurso beta e depende de namespaces Linux que não estão implementados no Windows. O Windows não pode compartilhar namespaces de processos ou o sistema de arquivos raiz do Contêiner. Apenas a rede pode ser compartilhada.terminationGracePeriodSeconds - isso não está totalmente implementado no Docker no Windows, veja o issue no GitHub. O comportamento atual é que o processo ENTRYPOINT recebe CTRL_SHUTDOWN_EVENT, então o Windows espera 5 segundos por padrão e finalmente encerra todos os processos usando o comportamento normal de desligamento do Windows. O padrão de 5 segundos está na verdade no registro do Windows dentro do Contêiner, então pode ser substituído quando o Contêiner é construído.volumeDevices - este é um recurso beta e não está implementado no Windows. O Windows não pode anexar dispositivos de bloco bruto a pods.volumes
emptyDir, não pode definir sua fonte de volume para memory.mountPropagation para montagens de volume, pois isso não é suportado no Windows.Kubernetes v1.26 [alpha]
O kubelet agora pode solicitar que pods em execução em nós Windows usem o namespace de rede do host em vez de criar um novo namespace de rede de pod. Para habilitar essa funcionalidade, passe --feature-gates=WindowsHostNetwork=true para o kubelet.
Apenas securityContext.runAsNonRoot e securityContext.windowsOptions dos campos securityContext do Pod funcionam no Windows.
O detector de problemas do nó (veja Monitorando a integridade do nó) tem suporte preliminar para Windows. Para mais informações, visite a página do GitHub do projeto.
Em um Pod Kubernetes, um Contêiner de infraestrutura ou "pausa" é criado primeiro para hospedar o Contêiner. No Linux, os cgroups e namespaces que compõem um pod precisam de um processo para manter sua existência contínua; o processo de pausa fornece isso. Contêineres que pertencem ao mesmo pod, incluindo infraestrutura e contêineres de trabalho, compartilham um endpoint de rede comum (mesmo endereço IPv4 e/ou IPv6, mesmos espaços de porta de rede). O Kubernetes usa contêineres de pausa para permitir que contêineres de trabalho falhem ou reiniciem sem perder qualquer configuração de rede.
O detector de problemas do nó (veja Monitorando a integridade do nó) tem suporte preliminar para Windows. Para mais informações, visite a página do GitHub do projeto.
O Kubernetes mantém uma imagem multi-arquitetura que inclui suporte para Windows. Para o Kubernetes v1.35.0 a imagem de pausa recomendada é registry.k8s.io/pause:3.6. O código fonte está disponível no GitHub.
A Microsoft mantém uma imagem multi-arquitetura diferente, com suporte para Windows amd64 e Linux, que você pode encontrar como mcr.microsoft.com/oss/kubernetes/pause:3.6. Esta imagem é construída a partir do mesmo código fonte que a imagem mantida pelo Kubernetes, mas todos os binários do Windows são assinados pelo Authenticode pela Microsoft. O projeto Kubernetes recomenda usar a imagem mantida pela Microsoft se você estiver implantando em um ambiente de produção ou similar que exija binários assinados.
Você precisa instalar um agente de execução de contêiner em cada nó do cluster para que os Pods possam ser executados lá.
Os seguintes runtimes de Contêiner funcionam com Windows:
Kubernetes v1.20 [stable]
Você pode usar ContainerD 1.4.0+ como o agente de execução de contêiner para nós Kubernetes que executam Windows.
Aprenda como instalar o ContainerD em um nó Windows.
Mirantis Container Runtime (MCR) está disponível como um agente de execução de contêiner para todas as versões do Windows Server 2019 e posteriores.
Veja Instalar MCR em servidores Windows para mais informações.
Em nós Windows, aplicam-se regras estritas de compatibilidade onde a versão do SO do host deve corresponder à versão da imagem base do Contêiner. Apenas contêineres Windows com um sistema operacional de Contêiner do Windows Server 2019 são totalmente suportados.
Para o Kubernetes v1.35, a compatibilidade do sistema operacional para nós Windows (e Pods) é a seguinte:
Windows Server 2022
A política de desvio de versão do Kubernetes também se aplica.
Consulte Requisitos de hardware para o Windows Server na documentação da Microsoft para obter as informações mais atualizadas sobre requisitos mínimos de hardware. Para orientação sobre como decidir sobre recursos para nós de trabalho em produção, consulte Nós de trabalho em produção na documentação do Kubernetes.
Para otimizar os recursos do sistema, se uma interface gráfica de usuário não for necessária, pode ser preferível usar uma instalação do Windows Server que exclua a opção de instalação Windows Desktop Experience, já que esta configuração normalmente libera mais recursos do sistema.
Ao avaliar o espaço em disco para nós de trabalho Windows, observe que as imagens de Contêiner do Windows são tipicamente maiores que as imagens de Contêiner do Linux, com tamanhos de imagem de Contêiner variando de 300MB a mais de 10GB para uma única imagem. Além disso, observe que a unidade C: em contêineres Windows representa um tamanho virtual livre de 20GB por padrão, que não é o espaço consumido real, mas sim o tamanho do disco para o qual um único Contêiner pode crescer ao ocupar quando usa armazenamento local no host. Veja Contêineres no Windows - Documentação de Armazenamento de Contêiner para mais detalhes.
Sua principal fonte de ajuda para solucionar problemas em seu cluster Kubernetes deve começar com a página de Solução de Problemas.
Alguma ajuda adicional, específica para Windows, está incluída nesta seção. Logs são um elemento importante na solução de problemas no Kubernetes. Certifique-se de incluí-los sempre que buscar assistência de outros colaboradores. Siga as instruções no guia de contribuição do SIG Windows sobre coleta de logs.
Se você tiver algo que pareça um bug ou gostaria de fazer uma solicitação de recurso, siga o guia de contribuição do SIG Windows para criar uma nova issue. Você deve primeiro pesquisar na lista de issues existentes caso tenha sido relatado anteriormente e comentar com sua experiência na issue e adicionar logs adicionais. O canal SIG Windows no Slack do Kubernetes também é uma ótima maneira de obter suporte inicial e ideias de solução de problemas antes de criar um ticket.
O projeto Kubernetes fornece uma especificação de Windows Operational Readiness, acompanhada por um conjunto de testes estruturados. Este conjunto é dividido em dois conjuntos de testes, principal (core) e estendido (extended), cada um contendo categorias destinadas a testar áreas específicas. Pode ser usado para validar todas as funcionalidades de um sistema Windows e híbrido (misturado com nós Linux) com cobertura total.
Para configurar o projeto em um cluster recém-criado, consulte as instruções no guia do projeto.
A ferramenta kubeadm ajuda você a implantar um cluster Kubernetes, fornecendo a camada de gerenciamento para gerenciá-lo, e nós para executar suas cargas de trabalho.
O projeto cluster API do Kubernetes também fornece meios para automatizar a implantação de nós Windows.
Para uma explicação detalhada dos canais de distribuição do Windows, consulte a documentação da Microsoft.
Informações sobre os diferentes canais de serviço do Windows Server, incluindo seus modelos de suporte, podem ser encontradas em Canais de serviço do Windows Server.
Esta página fornece um passo a passo para executar contêineres Windows usando o Kubernetes. Esta página também destaca funcionalidades específicas do Windows dentro do Kubernetes.
É importante notar que criar e implantar serviços e cargas de trabalho no Kubernetes comporta-se de forma muito semelhante para contêineres Linux e Windows. Os comandos kubectl para interagir com o cluster são idênticos. Os exemplos nesta página são fornecidos para iniciar sua experiência com contêineres Windows.
Configurar um exemplo de implantação para executar contêineres Windows em um nó Windows.
Você deve ter acesso a um cluster Kubernetes que inclua um nó de trabalho executando Windows Server.
O exemplo de arquivo YAML abaixo implanta um aplicativo simples de servidor web executando dentro de um contêiner Windows.
Crie um manifesto chamado win-webserver.yaml com o conteúdo abaixo:
---
apiVersion: v1
kind: Service
metadata:
name: win-webserver
labels:
app: win-webserver
spec:
ports:
# a porta em que este serviço deve rodar
- port: 80
targetPort: 80
selector:
app: win-webserver
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: win-webserver
name: win-webserver
spec:
replicas: 2
selector:
matchLabels:
app: win-webserver
template:
metadata:
labels:
app: win-webserver
name: win-webserver
spec:
containers:
- name: windowswebserver
image: mcr.microsoft.com/windows/servercore:ltsc2019
command:
- powershell.exe
- -command
- "<# código retirado de https://gist.github.com/19WAS85/5424431# > ; $$listener = New-Object System.Net.HttpListener ; $$listener.Prefixes.Add('http://*:80/') ; $$listener.Start() ; $$callerCounts = @{} ; Write-Host('Listening at http://*:80/') ; while ($$listener.IsListening) { ;$$context = $$listener.GetContext() ;$$requestUrl = $$context.Request.Url ;$$clientIP = $$context.Request.RemoteEndPoint.Address ;$$response = $$context.Response ;Write-Host '' ;Write-Host('> {0}' -f $$requestUrl) ; ;$$count = 1 ;$$k=$$callerCounts.Get_Item($$clientIP) ;if ($$k -ne $$null) { $$count += $$k } ;$$callerCounts.Set_Item($$clientIP, $$count) ;$$ip=(Get-NetAdapter | Get-NetIpAddress); $$header='<html><body><H1>Windows Container Web Server</H1>' ;$$callerCountsString='' ;$$callerCounts.Keys | % { $$callerCountsString+='<p>IP {0} callerCount {1} ' -f $$ip[1].IPAddress,$$callerCounts.Item($$_) } ;$$footer='</body></html>' ;$$content='{0}{1}{2}' -f $$header,$$callerCountsString,$$footer ;Write-Output $$content ;$$buffer = [System.Text.Encoding]::UTF8.GetBytes($$content) ;$$response.ContentLength64 = $$buffer.Length ;$$response.OutputStream.Write($$buffer, 0, $$buffer.Length) ;$$response.Close() ;$$responseStatus = $$response.StatusCode ;Write-Host('< {0}' -f $$responseStatus) } ; "
nodeSelector:
kubernetes.io/os: windows
Verifique se todos os nós estão íntegros:
kubectl get nodes
Implante o serviço e monitore as atualizações do pod:
kubectl apply -f win-webserver.yaml
kubectl get pods -o wide -w
Quando o serviço for implantado corretamente, ambos os Pods serão marcados como prontos. Para sair do comando de monitoramento, pressione Ctrl+C.
Verifique se a implantação foi bem-sucedida. Para verificar:
kubectl get podscurl na porta 80 do IP do seu pod a partir do nó de plano de controle Linux para verificar uma resposta do servidor webkubectl execcurl no IP virtual do serviço (visto em kubectl get services) a partir do nó de camada de gerenciamento Linux e de pods individuaiscurl no nome do serviço com o sufixo DNS padrão do Kubernetescurl no NodePort a partir do nó de plano de controle Linux ou máquinas fora do clustercurl em IPs externos de dentro do pod usando kubectl execOs logs são um elemento importante da observabilidade; eles permitem que os usuários obtenham insights sobre o aspecto operacional das cargas de trabalho e são um componente essencial na solução de problemas. Como os contêineres Windows e as cargas de trabalho dentro de contêineres Windows se comportam de maneira diferente dos contêineres Linux, os usuários enfrentaram dificuldades na coleta de logs, limitando a visibilidade operacional.
As cargas de trabalho Windows, por exemplo, geralmente são configuradas para registrar logs no ETW (Event Tracing for Windows) ou enviar entradas para o log de eventos de aplicativos.
O LogMonitor, uma ferramenta de código aberto da Microsoft, é a maneira recomendada para monitorar as fontes de logs configuradas dentro de um contêiner Windows. O LogMonitor oferece suporte para monitorar logs de eventos, provedores ETW e logs personalizados de aplicativos, canalizando-os para o STDOUT para consumo pelo comando kubectl logs <pod>.
Siga as instruções na página do GitHub do LogMonitor para copiar seus binários e arquivos de configuração para todos os seus contêineres e adicionar os entrypoints necessários para que o LogMonitor envie seus logs para o STDOUT.
Contêineres Windows podem ser configurados para executar seus entrypoints e processos com nomes de usuário diferentes dos padrões da imagem. Saiba mais sobre isso aqui.
As cargas de trabalho em contêineres Windows podem ser configuradas para usar Contas de Serviço Gerenciadas por Grupo (GMSA). As GMSAs são um tipo específico de conta do Active Directory que fornece gerenciamento automático de senhas, gerenciamento simplificado de nomes principais de serviço (SPN) e a capacidade de delegar o gerenciamento a outros administradores em vários servidores. Contêineres configurados com uma GMSA podem acessar recursos de domínio do Active Directory externo enquanto mantêm a identidade configurada com a GMSA. Saiba mais sobre como configurar e usar GMSA para contêineres Windows aqui.
Os usuários precisam usar uma combinação de taint e selectors de nós para agendar cargas de trabalho Linux e Windows em seus respectivos nós específicos de sistema operacional. A abordagem recomendada está descrita abaixo, com o objetivo principal de não quebrar a compatibilidade com cargas de trabalho Linux existentes.
Você pode (e deve) definir .spec.os.name para cada Pod, para indicar o sistema operacional para o qual os contêineres nesse Pod foram projetados. Para Pods que executam contêineres Linux, defina .spec.os.name como linux. Para Pods que executam contêineres Windows, defina .spec.os.name como windows.
IdentifyPodOS para definir um valor para .spec.pod.os.O escalonador não utiliza o valor de .spec.os.name ao atribuir Pods a nós. Você deve usar os mecanismos normais do Kubernetes para atribuir Pods a nós para garantir que a camada de gerenciamento do seu cluster coloque os Pods em nós que estão executando o sistema operacional apropriado.
O valor de .spec.os.name não tem efeito na alocação dos Pods Windows, então taints e tolerations (ou selectors de nós) ainda são necessários para garantir que os Pods Windows sejam atribuídos aos nós Windows apropriados.
Os usuários podem garantir que contêineres Windows sejam agendados no host apropriado usando taints e tolerations. Todos os nós Kubernetes que executam o Kubernetes 1.35 têm os seguintes rótulos padrão:
Se uma especificação de Pod não especificar um nodeSelector, como "kubernetes.io/os": windows, é possível que o Pod seja agendado em qualquer host, Windows ou Linux. Isso pode ser problemático, já que um contêiner Windows só pode ser executado em Windows e um contêiner Linux só pode ser executado em Linux. A prática recomendada para o Kubernetes 1.35 é usar um nodeSelector.
No entanto, em muitos casos, os usuários têm um grande número de implantações existentes para contêineres Linux, bem como um ecossistema de configurações prontas para uso, como chart do Helm da comunidade e casos de geração programática de Pods, como com operadores. Nessas situações, você pode hesitar em fazer a alteração de configuração para adicionar campos nodeSelector a todos os Pods e modelos de Pod. A alternativa é usar taints. Como o kubelet pode definir taints durante o registro, ele pode ser facilmente modificado para adicionar automaticamente um taint ao executar apenas em Windows.
Por exemplo: --register-with-taints='os=windows:NoSchedule'
Ao adicionar um taint a todos os nós Windows, nada será agendado neles (isso inclui Pods Linux existentes). Para que um Pod Windows seja alocação em um nó Windows, ele precisará tanto do nodeSelector quanto da toleration correspondente para escolher Windows.
nodeSelector:
kubernetes.io/os: windows
node.kubernetes.io/windows-build: '10.0.20348'
tolerations:
- key: "os"
operator: "Equal"
value: "windows"
effect: "NoSchedule"
A versão do Windows Server usada por cada Pod deve corresponder à do nó. Se você quiser usar várias versões do Windows Server no mesmo cluster, deverá definir rótulos adicionais de nó e campos nodeSelector.
O Kubernetes adiciona automaticamente um rótulo, node.kubernetes.io/windows-build, para simplificar isso.
Este rótulo reflete o número principal, secundário e de build do Windows que precisam corresponder para compatibilidade. Aqui estão os valores usados para cada versão do Windows Server:
| Nome do Produto | Versão |
|---|---|
| Windows Server 2022 | 10.0.20348 |
| Windows Server 2025 | 10.0.26100 |
RuntimeClass pode ser usado para simplificar o processo de usar taints e tolerations. Um administrador de cluster pode criar um objeto RuntimeClass, que é usado para encapsular esses taints e tolerations.
Salve este arquivo como runtimeClasses.yml. Ele inclui o nodeSelector apropriado para o SO, arquitetura e versão do Windows.
---
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: windows-2019
handler: example-container-runtime-handler
scheduling:
nodeSelector:
kubernetes.io/os: 'windows'
kubernetes.io/arch: 'amd64'
node.kubernetes.io/windows-build: '10.0.20348'
tolerations:
- effect: NoSchedule
key: os
operator: Equal
value: "windows"
Execute kubectl create -f runtimeClasses.yml como administrador do cluster.
Adicione runtimeClassName: windows-2019 conforme apropriado às especificações de Pods.
Por exemplo:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: iis-2019
labels:
app: iis-2019
spec:
replicas: 1
template:
metadata:
name: iis-2019
labels:
app: iis-2019
spec:
runtimeClassName: windows-2019
containers:
- name: iis
image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
resources:
limits:
cpu: 1
memory: 800Mi
requests:
cpu: .1
memory: 300Mi
ports:
- containerPort: 80
selector:
matchLabels:
app: iis-2019
---
apiVersion: v1
kind: Service
metadata:
name: iis
spec:
type: LoadBalancer
ports:
- protocol: TCP
port: 80
selector:
app: iis-2019
O Kubernetes é altamente configurável e extensível. Como resultado, raramente existe a necessidade de criar um fork ou submeter alterações de código para o projeto Kubernetes.
Este guia descreve as opções para personalizar um cluster do Kubernetes. Este guia tem como público-alvo os operadores de clusters que desejam entender melhor como adaptar seus clusters às necessidades do seu ambiente de trabalho. Desenvolvedores que desejam tornar-se Desenvolvedores de Plataforma ou Contribuidores do Projeto Kubernetes também irão beneficiar-se deste guia como uma introdução aos pontos de extensão e padrões existentes, e suas contrapartidas e limitações.
As abordagens de personalização podem ser divididas nos grandes grupos de configuração, que envolve somente a modificação de argumentos de linha de comando, arquivos locais de configuração, ou recursos da API; e extensões, que envolve executar programas adicionais, serviços de rede adicionais, ou ambos. Este documento cobre primariamente as extensões.
Arquivos de configuração e argumentos de comando estão documentados na seção de Referência da documentação online, com uma página para cada binário:
Argumentos de comando e arquivos de configuração podem não ser sempre alteráveis em um serviço hospedado do Kubernetes ou uma distribuição com instalação gerenciada. Quando são alteráveis, geralmente são alteráveis somente pelo operador do cluster. Além disso, são suscetíveis a mudanças em versões futuras do Kubernetes, e modificá-los pode requerer a reinicialização de processos. Por essas razões, devem ser utilizados somente quando não houver outras opções.
APIs de política embutidas, como ResourceQuota, NetworkPolicy e Role-based Access Control (RBAC), são APIs embutidas do Kubernetes que fornecem configurações declarativas de políticas. APIs são tipicamente utilizáveis mesmo nos serviços hospedados do Kubernetes e com instalações gerenciadas do Kubernetes. As APIs de política embutidas seguem as mesmas convenções de outros recursos do Kubernetes, como os Pods. Quando você utiliza uma API de políticas que é estável, você se beneficia de uma política definida de suporte como outras APIs do Kubernetes. Por essas razões, as APIs de política são recomendadas antes de arquivos de configuração e de argumentos de comando quando adequadas.
Extensões são componentes de software que estendem e integram profundamente com o Kubernetes. Elas adaptam o Kubernetes para suportar novos tipos e novos modelos de hardware.
Muitos administradores de cluster utilizam uma instância hospedada ou de distribuição do Kubernetes. Esses clusters vêm com extensões pré-instaladas. Como resultado, a maioria dos usuários do Kubernetes não precisa instalar extensões e ainda menos usuários precisarão criar novas extensões.
O Kubernetes é projetado para ser automatizado através de programas cliente. Qualquer programa que lê e/ou escreve através da API do Kubernetes pode fornecer automação útil. Uma automação pode executar no cluster ou fora dele. Seguindo as orientações neste documento, você pode escrever automações altamente disponíveis e robustas. Automações geralmente funcionam em quaisquer clusters do Kubernetes, incluindo clusters hospedados e instalações gerenciadas.
Há um padrão específico para a escrita de programas cliente que funcionam bem
com o Kubernetes, denominado padrão controlador.
Controladores tipicamente leem o campo .spec de um objeto, possivelmente executam
ações, e então atualizam o campo .status do objeto.
Um controlador é um cliente da API do Kubernetes. Quando o Kubernetes é o cliente e faz uma chamada para um serviço remoto, o Kubernetes chama isso de um webhook. O serviço remoto é chamado de backend de webhook. Assim como controladores personalizados, os webhooks adicionam um ponto de falha.
No modelo webhook, o Kubernetes faz uma requisição de rede a um serviço remoto. Com o modelo alternativo de Plugin binário, o Kubernetes executa um binário (programa). Plugins binários são utilizados pelo kubelet (por exemplo, plugins de armazenamento CSI e plugins de rede CNI), e pelo kubectl (veja Estendendo o kubectl com plugins).
Este diagrama mostra os pontos de extensão em um cluster do Kubernetes e os clientes que o acessam.
Pontos de extensão do Kubernetes
Os usuários interagem com frequência com a API do Kubernetes utilizando o kubectl.
Plugins personalizam o comportamento dos clientes. Existem
extensões genéricas que podem ser aplicadas a diferentes clientes, bem como
formas específicas de estender o kubectl.
O servidor da API manipula todas as requisições. Diversos tipos de pontos de extensão no servidor da API permitem autenticar requisições ou bloqueá-las baseada no seu conteúdo, editar o conteúdo de uma requisição, e manipular a remoção de objetos. Estes pontos de extensão estão descritos na seção Extensões de Acesso de API.
O servidor da API serve diversos tipos de recursos. Tipos de recurso embutidos, como Pods, são definidos pelo projeto Kubernetes e não podem ser modificados. Consulte Extensões de API para saber mais sobre estender a API do Kubernetes.
O alocador do Kubernetes decide em qual nó alocar Pods. Há diversas formas de estender a alocação e tais formas estão descritas na seção de Extensões de Alocação.
Muito do comportamento do Kubernetes é implementado por programas chamados controladores, que são clientes do servidor da API. Controladores são frequentemente usados em conjunto com recursos personalizados. Consulte combinando novas APIs com automação e modificando recursos embutidos para saber mais.
O kubelet roda em servidores (nós) e auxilia Pods a parecerem como servidores virtuais com seus próprios IPs na rede do cluster. Plugins de Rede permitem diferentes implementações de redes de Pod.
Você pode utilizar Plugins de Dispositivo para integrar hardware personalizado ou outras instalações locais ao nó e torná-los disponíveis aos Pods rodando no seu cluster. O kubelet inclui suporte para trabalhar com estes plugins de dispositivo.
O kubelet também monta e desmonta volumes em Pods e seus contêineres. Você pode utilizar Plugins de Armazenamento para adicionar suporte a novos tipos de armazenamento e outros tipos de volume.
Se você não tem certeza de onde começar, este fluxograma pode auxiliar. Note que algumas soluções podem envolver vários tipos de extensões.
Fluxograma guia para seleção de uma abordagem de extensão
Plugins para o kubectl são binários que adicionam ou substituem funcionalidade
em comandos específicos. A ferramenta kubectl também pode integrar com os
plugins de credenciais.
Essas extensões afetam somente o ambiente local de um usuário, e portanto não podem
garantir políticas para vários dispositivos.
Se você deseja estender a ferramenta kubectl, leia Estenda o kubectl com plugins.
Considere adicionar um Recurso Personalizado ao Kubernetes se você deseja definir
novos controladores, objetos de configuração da aplicação ou outras APIs declarativas,
e gerenciá-los utilizando ferramentas do Kubernetes, como o kubectl.
Para mais informações sobre Recursos Personalizados, veja o guia de conceito Recursos Personalizados.
Você pode utilizar a Camada de Agregação da API do Kubernetes para integrar a API do Kubernetes com serviços adicionais, como um serviço de métricas.
Uma combinação de uma API de recurso personalizado e um ciclo de controle é chamado de padrão controlador. Se o seu controlador toma o lugar de um operador humano na instalação de infraestrutura baseada em um estado desejado, então o controlador pode também estar seguindo o padrão operador. O padrão operador é usado para gerenciar aplicações específicas; normalmente, essas são aplicações que mantém estado e requerem cuidado em como são gerenciadas.
Você pode também criar suas próprias APIs e ciclos de controle personalizados que gerenciam outros recursos, como armazenamento, ou para definir políticas (como uma restrição de controle de acesso).
Quando você estende a API do Kubernetes adicionando recursos personalizados, os recursos adicionados sempre caem em um novo grupo de API. Você não pode substituir ou modificar grupos de API existentes. Adicionar uma nova API não permite a você diretamente alterar o comportamento de uma API existente (como Pods), enquanto Extensões de Acesso de API permitem.
Quando uma requisição chega ao servidor da API do Kubernetes, ela é primeiro autenticada, depois é autorizada, e então é submetida a vários tipos de controle de admissão (algumas requisições não são autenticadas e recebem tratamento especial). Consulte a página Controlando Acesso à API do Kubernetes para mais informações sobre esse fluxo.
Cada uma das etapas no fluxo de autenticação/autorização do Kubernetes oferece pontos de extensão.
A Autenticação transforma cabeçalhos ou certificados em todas as requisições em um nome de usuário para o cliente efetuando a requisição.
O Kubernetes suporta diversas formas diferentes de autenticação embutida. Ele pode
ainda estar situado atrás de um proxy de autenticação, e pode enviar um token de
um cabeçalho Authorization: para um serviço remoto para verificação (um
webhook de autenticação)
se as formas embutidas não atenderem às suas necessidades.
A Autorização determina se usuários específicos podem ler, escrever, e fazer outras operações em recursos da API. Ela funciona no nível de recursos completos -- e não discrimina baseado em campos arbitrários de um objeto.
Se as opções de autorização embutidas não atenderem às suas necessidades, um webhook de autorização permite efetuar uma chamada para um código personalizado que faça uma decisão de autorização.
Após uma requisição ser autorizada, quando se tratar de uma operação de escrita, ela também passará pelas etapas de Controle de Admissão. Além das etapas embutidas, há várias extensões:
Plugins de dispositivo permitem a um nó descobrir novos recursos Node (além dos preexistentes, como cpu e memória) através de um Plugin de Dispositivo.
Os plugins de Interface de Armazenamento de Contêiner (Container Storage Interface, ou CSI) fornecem uma maneira de estender o Kubernetes com suporte a novos tipos de volumes. Os volumes podem ser suportados por um sistema de armazenamento externo durável, fornecer armazenamento efêmero, ou oferecer uma interface somente-leitura a informações utilizando um paradigma de sistema de arquivos.
O Kubernetes também inclui suporte aos plugins FlexVolume, que estão descontinuados desde a versão 1.23 (em favor do CSI).
Os plugins FlexVolume permitem aos usuários montar tipos de volumes que não são suportados nativamente pelo Kubernetes. Quando você executa um Pod que depende de armazenamento FlexVolume, o kubelet chama um plugin binário que monta o volume. A proposta de projeto arquivada do FlexVolume tem mais detalhes desta abordagem.
A seção de Perguntas Frequentes sobre Volumes do Kubernetes para Fornecedores de Armazenamento inclui informações gerais de plugins de armazenamento.
O seu cluster do Kubernetes precisa de um plugin de rede para que a rede de Pods funcione e para suportar outros aspectos do modelo de rede do Kubernetes.
Plugins de Rede permitem que o Kubernetes funcione com diferentes topologias e tecnologias de rede.
Kubernetes v1.26 [stable]
Os plugins conseguem comunicar-se com serviços externos ou utilizar arquivos locais para obter credenciais. Dessa maneira, o kubelet não precisa ter credenciais estáticas para cada registro de imagens e pode suportar diversos métodos e protocolos de autenticação.
Para detalhes de configuração de plugins, consulte Configurar um fornecedor de credenciais de imagem do kubelet.
O alocador é um tipo especial de controlador que observa Pods, e os atribui aos nós. O alocador padrão pode ser totalmente substituído, enquanto outros componentes do Kubernetes permanecem em uso, ou múltiplos alocadores podem rodar simultaneamente.
Este é um compromisso significativo e a maior parte dos usuários do Kubernetes percebem que não precisam modificar o alocador.
Você pode controlar quais plugins de alocação estão ativos ou associar conjuntos de plugins com diferentes perfis do alocador nomeados. Você pode também escrever seu próprio plugin que integra com um ou mais dos pontos de extensão do kube-scheduler.
Por fim, o componente embutido kube-scheduler suporta um
webhook
que permite a um backend HTTP remoto (extensão do alocador) filtrar e/ou
priorizar os nós que o kube-scheduler escolhe para um Pod.
Recursos personalizados são extensões da API do Kubernetes. O Kubernetes fornece duas formas de adicionar recursos personalizados ao seu cluster:
apiGroup, kind e o formato que você especificar.
A camada de gerenciamento do Kubernetes irá servir e controlar o armazenamento
do seu recurso personalizado. CRDs permitem que você crie novos tipos de recurso
para o seu cluster sem precisar escrever e executar um servidor da API personalizado.A camada de agregação permite ao Kubernetes ser estendido com APIs adicionais, para além do que é oferecido pelas APIs centrais do Kubernetes. As APIs adicionais podem ser soluções prontas tal como o catálogo de serviços, ou APIs que você mesmo desenvolva.
A camada de agregação é diferente dos Recursos Personalizados, que são uma forma de fazer o kube-apiserver reconhecer novas espécies de objetos.
A camada de agregação executa em processo com o kube-apiserver.
Até que um recurso de extensão seja registado, a camada de agregação
não fará nada. Para registar uma API, terá de adicionar um objeto APIService
que irá "reclamar" o caminho URL na API do Kubernetes. Nesta altura, a camada
de agregação procurará qualquer coisa enviada para esse caminho da API
(e.g. /apis/myextension.mycompany.io/v1/…) para o APIService registado.
A maneira mais comum de implementar o APIService é executar uma extensão do servidor API em Pods que executam no seu cluster. Se estiver a usar o servidor de extensão da API para gerir recursos no seu cluster, o servidor de extensão da API (também escrito como "extension-apiserver") é tipicamente emparelhado com um ou mais controladores. A biblioteca apiserver-builder providencia um esqueleto para ambos os servidores de extensão da API e controladores associados.
Servidores de extensão de APIs devem ter baixa latência de rede de e para o kube-apiserver. Pedidos de descoberta são necessários que façam a ida e volta do kube-apiserver em 5 segundos ou menos.
Se o seu servidor de extensão da API não puder cumprir com o requisito de latência,
considere fazer alterações que permitam atingi-lo. Pode também definir
portal de funcionalidade EnableAggregatedDiscoveryTimeout=false no kube-apiserver para desativar
a restrição de intervalo. Esta portal de funcionalidade deprecado será removido
num lançamento futuro.
Plugins de redes no Kubernetes podem ser dos seguintes tipos:
cbr0 básico usando os plugins CNI bridge e host-localO kubelet possui um plugin único padrão, e um plugin padrão comum para todo o cluster. Ele verifica o plugin quando inicia, se lembra o que encontrou, e executa o plugin selecionado em momentos oportunos dentro do ciclo de vida de um Pod (isso é verdadeiro apenas com o Docker, uma vez que o CRI gerencia seus próprios plugins de CNI). Existem dois parâmetros de linha de comando no Kubelet para se ter em mente quando usando plugins:
cni-bin-dir: O Kubelet verifica esse diretório por plugins na inicializaçãonetwork-plugin: O plugin de rede que deve ser utilizado do diretório configurado em
cni-bin-dir. Deve ser igual ao nome configurado por um plugin no diretório de plugins.
Para plugins de CNI, isso equivale ao valor cni.Além de prover a interface NetworkPlugin
para configuração da rede do pod, o plugin pode necessitar de suporte específico ao
kube-proxy.
O proxy iptables obviamente depende do iptables, e o plugin deve garantir que o
tráfego do contêiner esteja disponível para o iptables. Por exemplo, se o plugin
conecta os contêineres à Linux bridge, o plugin deve configurar a diretiva de
sysctl net/bridge/bridge-nf-call-iptables com o valor 1 para garantir que o
proxy iptables opere normalmente. Se o plugin não faz uso da Linux Bridge (mas outro
mecanismo, como Open vSwitch) ele deve garantir que o tráfego do contêiner é roteado
apropriadamente para o proxy.
Por padrão, se nenhum plugin de rede é configurado no kubelet, o plugin noop é utilizado,
que configura net/bridge/bridge-nf-call-iptables=1 para garantir que configurações simples
(como Docker com bridge Linux) operem corretamente com o proxy iptables.
O plugin de CNI é selecionado utilizando-se da opção --network-plugin=cni no início do Kubeket.
O Kubelet lê um arquivo do diretório especificado em --cni-conf-dir (padrão /etc/cni/net.d)
e usa a configuração de CNI desse arquivo para configurar a rede de cada Pod. O arquivo de
configuração do CNI deve usar a especificação de CNI,
e qualquer plugin referenciado nesse arquivo deve estar presente no diretório
--cni-bin-dir (padrão /opt/cni/bin).
Se existirem múltiplos arquivos de configuração no diretório, o kubelet usa o arquivo de configuração que vier primeiro pelo nome, em ordem alfabética.
Adicionalmente ao plugin de CNI especificado no arquivo de configuração, o Kubernetes requer
o plugin CNI padrão lo ao menos na versão 0.2.0.
O plugin de redes CNI suporta hostPort. Você pode utilizar o plugin oficial
portmap
ou usar seu próprio plugin com a funcionalidade de portMapping.
Caso você deseje habilitar o suporte a hostPort, você deve especificar
portMappings capability no seu cni-conf-dir.
Por exemplo:
{
"name": "k8s-pod-network",
"cniVersion": "0.4.0",
"plugins": [
{
"type": "calico",
"log_level": "info",
"datastore_type": "kubernetes",
"nodename": "127.0.0.1",
"ipam": {
"type": "host-local",
"subnet": "usePodCidr"
},
"policy": {
"type": "k8s"
},
"kubernetes": {
"kubeconfig": "/etc/cni/net.d/calico-kubeconfig"
}
},
{
"type": "portmap",
"capabilities": {"portMappings": true},
"externalSetMarkChain": "KUBE-MARK-MASQ"
}
]
}
Funcionalidade experimental
O plugin de rede CNI também suporta o controle de banda de entrada e saída. Você pode utilizar o plugin oficial bandwidth desenvolvido ou usar seu próprio plugin de controle de banda.
Se você habilitar o suporte ao controle de banda, você deve adicionar o plugin bandwidth
no seu arquivo de configuração de CNI (padrão /etc/cni/net.d) e garantir que o programa
exista no diretório de binários do CNI (padrão /opt/cni/bin).
{
"name": "k8s-pod-network",
"cniVersion": "0.4.0",
"plugins": [
{
"type": "calico",
"log_level": "info",
"datastore_type": "kubernetes",
"nodename": "127.0.0.1",
"ipam": {
"type": "host-local",
"subnet": "usePodCidr"
},
"policy": {
"type": "k8s"
},
"kubernetes": {
"kubeconfig": "/etc/cni/net.d/calico-kubeconfig"
}
},
{
"type": "bandwidth",
"capabilities": {"bandwidth": true}
}
]
}
Agora você pode adicionar as anotações kubernetes.io/ingress-bandwidth e
kubernetes.io/egress-bandwidth em seu pod.
Por exemplo:
apiVersion: v1
kind: Pod
metadata:
annotations:
kubernetes.io/ingress-bandwidth: 1M
kubernetes.io/egress-bandwidth: 1M
...
Kubenet é um plugin de rede muito simples, existente apenas no Linux. Ele não implementa funcionalidades mais avançadas, como rede entre nós ou políticas de rede. Ele é geralmente utilizado junto a um provedor de nuvem que configura as regras de roteamento para comunicação entre os nós, ou em ambientes com apenas um nó.
O Kubenet cria uma interface bridge no Linux chamada cbr0 e cria um par veth
para cada um dos pods com o host como a outra ponta desse par, conectado à cbr0.
Na interface no lado do Pod um endereço IP é alocado de uma faixa associada ao nó,
sendo parte de alguma configuração no nó ou pelo controller-manager. Na interface cbr0
é associado o MTU equivalente ao menor MTU de uma interface de rede do host.
Esse plugin possui alguns requisitos:
bridge, lo e host-local são obrigatórios, ao menos na
versão 0.2.0. O Kubenet buscará inicialmente esses plugins no diretório /opt/cni/bin.
Especifique a opção cni-bin-dir no kubelet para fornecer um diretório adicional
de busca. O primeiro local equivalente será o utilizado.--network-plugin=kubenet para habilitar esse plugin.--non-masquerade-cidr=<clusterCidr> para
garantir que o tráfego de IPs para fora dessa faixa seja mascarado.--pod-cidr configurada
na inicialização do kubelet, ou as opções --allocate-node-cidrs=true --cluster-cidr=<cidr>
utilizadas na inicialização do controller-manager.O MTU deve sempre ser configurado corretamente para obter-se a melhor performance de rede. Os plugins de rede geralmente tentam detectar uma configuração correta de MTU, porém algumas vezes a lógica não irá resultar em uma configuração adequada. Por exemplo, se a Docker bridge ou alguma outra interface possuir um MTU pequeno, o kubenet irá selecionar aquela MTU. Ou caso você esteja utilizando encapsulamento IPSEC, o MTU deve ser reduzido, e esse cálculo não faz parte do escopo da maioria dos plugins de rede.
Sempre que necessário, você pode configurar explicitamente o MTU com a opção network-plugin-mtu
no kubelet. Por exemplo, na AWS o MTU da eth0 geralmente é 9001 então você deve
especificar --network-plugin-mtu=9001. Se você estiver usando IPSEC você deve reduzir
o MTU para permitir o encapsulamento excedente; por exemplo: --network-plugin-mtu=8773.
Essa opção faz parte do plugin de rede. Atualmente apenas o kubenet suporta a configuração
network-plugin-mtu.
--network-plugin=cni especifica que devemos usar o plugin de redes cni com os
binários do plugin localizados em --cni-bin-dir (padrão /opt/cni/bin) e as
configurações do plugin localizadas em --cni-conf-dir (default /etc/cni/net.d).--network-plugin=kubenet especifica que iremos usar o plugin de rede kubenet
com os plugins CNI bridge, lo e host-local localizados em /opt/cni/bin ou cni-bin-dir.--network-plugin-mtu=9001 especifica o MTU a ser utilizado, atualmente apenas em uso
pelo plugin de rede kubenetOperadores são extensões de software para o Kubernetes que fazem uso de recursos personalizados para gerir aplicações e os seus componentes. Operadores seguem os princípios do Kubernetes, notavelmente o ciclo de controle.
O padrão operador tem como objetivo capturar o principal objetivo de um operador humano que está gerenciando um serviço ou conjunto de serviços. Operadores humanos que cuidam de aplicativos e serviços específicos possuem um conhecimento profundo de como o sistema deve se comportar, como implantá-lo e como reagir se houver problemas.
As pessoas que executam cargas de trabalho no Kubernetes muitas vezes gostam de usar automação para cuidar de tarefas repetitivas. O padrão do operador captura como você pode escrever código para automatizar uma tarefa além do que o próprio Kubernetes fornece.
O Kubernetes é projetado para automação. Por padrão, você tem bastante automação integrada ao núcleo do Kubernetes. Você pode usar o Kubernetes para automatizar a implantação e execução de cargas de trabalho, e pode automatizar como o Kubernetes faz isso.
O conceito de padrão operador do Kubernetes permite a extensão do comportamento sem modificar o código do próprio Kubernetes, vinculando controladores a um ou mais recursos personalizados. Os operadores são clientes da API do Kubernetes que atuam como controladores para um recurso personalizado.
Algumas das coisas que você pode automatizar usando um operador incluem:
Como seria um operador com mais detalhes? Aqui está um exemplo:
A maneira mais comum de implantar um operador é adicionar a definição personalizada de recurso (Custom Resource Definition) e o Controlador associado ao seu cluster. O Controlador normalmente é executado fora da camada de gerenciamento, assim como você executaria qualquer aplicação que rode em contêineres. Por exemplo, você pode executar o controlador no seu cluster como um Deployment.
Depois de implantar um operador, você o usaria adicionando, modificando ou excluindo o tipo de recurso que o operador usa. Seguindo o exemplo acima, você configuraria um Deployment para o próprio operador, e depois:
kubectl get SampleDB # encontrar banco de dados configurados
kubectl edit SampleDB/example-database # alterar manualmente algumas configurações
…e é isso! O Operador cuidará de aplicar as alterações, bem como manter o serviço existente em bom estado.
Se não houver um operador no ecossistema que implemente o comportamento desejado, você pode programar o seu próprio.
Você também pode implementar um operador (ou seja, um Controlador) usando qualquer linguagem/agente de execução que possa atuar como um cliente para a API do Kubernetes.
A seguir estão algumas bibliotecas e ferramentas que você pode usar para escrever seu próprio operador nativo de nuvem.