This is the multi-page printable view of this section. Click here to print.
Extendendo o Kubernetes
- 1: Extendendo a API do Kubernetes
- 2: Extensões de Computação, armazenamento e redes
- 2.1: Plugins de rede
- 3: Padrão Operador
1 - Extendendo a API do Kubernetes
1.1 - Extendendo a API do Kubernetes com a camada de agregação
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.
Camada de agregação
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.
Latência da resposta
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.
Próximos passos
- Para pôr o agregador a funcionar no seu ambiente, configure a camada de agregação.
- De seguida, configura um api-server de extensão para funcionar com a camada de agregação.
- Também, aprenda como pode estender a API do Kubernetes através do use de Definições de Recursos Personalizados.
- Leia a especificação do APIService
2 - Extensões de Computação, armazenamento e redes
2.1 - Plugins de rede
Plugins de redes no Kubernetes podem ser dos seguintes tipos:
- Plugins CNI: Aderentes à especificação Container Network Interface (CNI), desenhados para interoperabilidade.
- Kubernetes usa a versão v0.4.0 da especificação CNI.
- Plugin kubenet: Implementa o
cbr0
básico usando os plugins CNIbridge
ehost-local
Instalação
O 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 emcni-bin-dir
. Deve ser igual ao nome configurado por um plugin no diretório de plugins. Para plugins de CNI, isso equivale ao valorcni
.
Requisitos de plugins de Rede
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.
CNI
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.
Suporte a hostPort
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"
}
]
}
Suporte a controle de banda
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
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:
- Os plugins CNI padrão
bridge
,lo
ehost-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çãocni-bin-dir
no kubelet para fornecer um diretório adicional de busca. O primeiro local equivalente será o utilizado. - O kubelet deve ser executado com a opção
--network-plugin=kubenet
para habilitar esse plugin. - O Kubelet deve ainda ser executado com a opção
--non-masquerade-cidr=<clusterCidr>
para garantir que o tráfego de IPs para fora dessa faixa seja mascarado. - O nó deve possuir uma subrede associada, através da opção
--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.
Customizando o MTU (com kubenet)
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
.
Resumo de uso
--network-plugin=cni
especifica que devemos usar o plugin de redescni
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 redekubenet
com os plugins CNIbridge
,lo
ehost-local
localizados em/opt/cni/bin
oucni-bin-dir
.--network-plugin-mtu=9001
especifica o MTU a ser utilizado, atualmente apenas em uso pelo plugin de redekubenet
Próximos passos
3 - Padrão Operador
Operadores 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.
Motivação
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.
Operadores no Kubernetes
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.
Exemplo de um operador
Algumas das coisas que você pode automatizar usando um operador incluem:
- implantação sob demanda de uma aplicação
- fazer e restaurar backups do estado dessa aplicação
- lidar com atualizações do código da aplicação junto com mudanças relacionadas, como esquemas de banco de dados ou configurações adicionais
- publicar um Service para que aplicações que não suportam as APIs do Kubernetes possam descobrí-los
- simular falhas em todo ou parte do seu cluster para testar resiliência
- escolher um líder para uma aplicação distribuída sem um processo de eleição interna de membros
Como seria um operador com mais detalhes? Aqui está um exemplo:
- Um recurso personalizado (custom resource) chamado SampleDB, que você pode configurar dentro do cluster.
- Um Deployment que garante que um Pod esteja em execução contendo a parte do controlador do operador.
- Uma imagem de contêiner do código do operador.
- Código do controlador que consulta a camada de gerenciamento para descobrir quais recursos SampleDB estão configurados.
- O núcleo do Operador é o código que informa ao servidor da API como fazer com que a realidade corresponda aos recursos configurados.
- Se você adicionar um novo SampleDB, o operador configura PersistentVolumeClaims para fornecer armazenamento durável da base de dados, um StatefulSet para executar o SampleDB e um Job para lidar com a configuração inicial.
- Se você excluir um SampleDB, o operador cria um instantâneo e em seguida, garante que o StatefulSet e os Volumes também sejam removidos.
- O operador também gerencia backups regulares da base de dados. Para cada recurso SampleDB, o operador determina quando criar um Pod que pode se conectar ao banco de dados e fazer backups. Esses Pods dependeriam de um ConfigMap e/ou um Secret que tenha detalhes da conexão e credenciais do banco de dados.
- Considerando que o Operador tem como objetivo fornecer automação robusta para o recurso que gerencia, haveria código de suporte adicional. Para este exemplo, o código verifica se o banco de dados está a executando uma versão antiga e, se estiver, cria objetos Job que fazem a atualização para você.
Implantando operadores
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.
Usando um operador
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.
Escrevendo o seu próprio operador
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.
- Charmed Operator Framework
- Java Operator SDK
- Kopf (Kubernetes Operator Pythonic Framework)
- kube-rs (Rust)
- kubebuilder
- KubeOps (.NET operator SDK)
- Mast
- Metacontroller em conjunto com webhooks que você mesmo implementa
- Operator Framework
- shell-operator
Próximos passos
- Leia o whitepaper sobre operadores da CNCF
- Saiba mais sobre Custom Resources
- Encontre operadores prontos em OperatorHub.io para atender ao seu caso de uso
- Publique seu operador para outras pessoas usarem
- Leia o artigo original do CoreOS que introduziu o padrão de operador (esta é uma versão arquivada do artigo original)
- Leia um artigo do Google Cloud sobre as melhores práticas para construir operadores