This is the multi-page printable view of this section. Click here to print.
Objetos do Kubernetes
- 1: Entendendo os objetos do Kubernetes
- 2: Nomes de objetos e IDs
- 3: Namespaces
- 4: Seletores de Campos
- 5: Versões de armazenamento
1 - Entendendo os objetos do Kubernetes
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.
Entendendo os objetos do Kubernetes
Os objetos do Kubernetes são entidades persistentes no Kubernetes. Kubernetes utiliza estas entidades para representar o estado do cluster. Especificamente, eles podem descrever:
- Quais aplicativos estão sendo executados (e em quais nós).
- Os recursos disponíveis para esses aplicativos
- As políticas acerca de como esses aplicativos se comportam, como políticas de reinicialização e tolerâncias a falhas.
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.
Especificação e status do objeto
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.
Descrevendo um objeto Kubernetes
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
Campos obrigatórios
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 stringnome,UIDe umnamespace.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.
Próximos passos
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.
2 - Nomes de objetos e IDs
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.
Nomes
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.
Nota:
Em casos em que objetos representam uma entidade física, como no caso de um Nó representando um host físico, caso o host seja recriado com o mesmo nome mas o objeto Nó não seja recriado, o Kubernetes trata o novo host como o host antigo, o que pode causar inconsistências.Abaixo estão descritos quatro tipos de restrições de nomes comumente utilizadas para recursos.
Nomes de subdomínio DNS
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:
- conter no máximo 253 caracteres
- conter somente caracteres alfanuméricos em caixa baixa, traço ('-') ou ponto ('.').
- iniciar com um caractere alfanumérico
- terminar com um caractere alfanumérico
Nomes de rótulos da RFC 1123
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:
- conter no máximo 63 caracteres
- conter somente caracteres alfanuméricos em caixa baixa ou traço ('-')
- iniciar com um caractere alfanumérico
- terminar com um caractere alfanumérico
Nomes de rótulo da RFC 1035
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:
- conter no máximo 63 caracteres
- conter somente caracteres alfanuméricos em caixa baixa ou traço ('-')
- iniciar com um caractere alfanumérico
- terminar com um caractere alfanumérico
Nomes de segmentos de caminhos
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
Nota:
Alguns tipos de recursos possuem restrições adicionais em seus nomes.UIDs
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.
Próximos passos
- Leia sobre labels no Kubernetes.
- Consulte o documento de design Identifiers and Names in Kubernetes.
3 - Namespaces
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).
Quando Utilizar Múltiplos Namespaces
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.
Nota:
Para clusters em produção, considere não utilizar o namespacedefault. Em vez disso, crie e utilize outros namespaces.Namespaces Iniciais
O Kubernetes é inicializado com quatro namespaces:
default- O Kubernetes inclui esse namespace para que você possa começar a usar seu novo cluster sem precisar criar um namespace primeiro.
kube-node-lease- Este namespace contém os objetos de Lease associados com cada node. Node leases permitem que o kubelet envie heartbeats para que a camada de gerenciamento detecte falhas nos nodes.
kube-public- Este namespace é criado automaticamente e é legível por todos os clientes (incluindo clientes não autenticados). Este namespace é reservado principalmente para uso do cluster, no caso de alguns recursos que precisem ser visíveis e legíveis publicamente por todo o cluster. O aspecto público deste namespace é apenas uma convenção, não um requisito.
kube-system- O namespace para objetos criados pelo sistema Kubernetes
Trabalhando com Namespaces
Criação e eliminação de namespaces estão descritas na documentação de namespaces do guia de administradores.
Nota:
Evite criar namespaces com o prefixokube-, já que este prefixo é reservado para namespaces do sistema Kubernetes.Visualizando namespaces
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
Preparando o namespace para uma requisição
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>
Configurando a preferência de namespaces
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:
Namespaces e DNS
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.
Aviso:
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.
Nem todos os objetos pertencem a algum Namespace
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
Rotulamento Automático
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.
Próximos passos
- Leia sobre a criação de um novo namespace.
- Leia sobre a eliminação de um namespace.
4 - Seletores de Campos
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=Pending
O 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
Nota:
Seletores de campos são essencialmente filtros de recursos. Por padrão, nenhum seletor/filtro é aplicado, de forma que todos os recursos do tipo especificado são selecionados. Isso faz com que as seguintes pesquisas utilizandokubectl sejam equivalentes: kubectl get pods e kubectl get pods --field-selector ""Campos suportados
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"
Operadores suportados
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
Seletores em cadeia
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
Múltiplos tipos de recursos
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
5 - Versões de armazenamento
O servidor de API do Kubernetes armazena objetos, contando com um armazenamento de apoio (backing store) compatível com etcd (frequentemente, o armazenamento de apoio é o próprio etcd). Cada objeto é serializado usando uma versão específica daquele tipo de API; por exemplo, a representação v1 de um ConfigMap. O Kubernetes usa o termo versão de armazenamento (storage version) para descrever como um objeto é armazenado em seu cluster.
A API do Kubernetes também depende da conversão automática; por exemplo, se você tem um HorizontalPodAutoscaler, então você pode interagir com esse HorizontalPodAutoscaler usando qualquer combinação das versões v1 e v2 da API HorizontalPodAutoscaler. O Kubernetes é responsável por converter cada chamada de API para que os clientes não vejam qual versão está realmente serializada.
Para administradores de cluster, a versão de armazenamento de um objeto é um conceito importante de se entender, pois é ela que vincula a representação da API do objeto à codificação real no backend de armazenamento. Isso pode ser importante quando as codificações binárias subjacentes do objeto importam, como na criptografia em repouso (encryption at rest), ou na descontinuação (deprecação) da API.
A mesma API pode ter várias versões de armazenamento que o servidor de API pode então converter para um schema de objeto. Um único objeto que faz parte desse recurso deve ter apenas uma versão de armazenamento a qualquer momento. Isso significa que o servidor de API está ciente das codificações binárias dos objetos e é capaz de converter entre todas as versões armazenadas e a representação da API do objeto dinamicamente.
A versão de um objeto é completamente separada da versão de armazenamento. Por
exemplo, um objeto de API v1alpha1 e v1beta1 para o mesmo Resource será
codificado da mesma forma no armazenamento, desde que a versão de armazenamento não tenha sido atualizada
entre os dois objetos.
Mapeamento da versão de armazenamento para o recurso
Cada recurso terá 1 versão de armazenamento ativa em qualquer momento, o que significa que qualquer gravação em um objeto armazenará o objeto nessa versão de armazenamento. A versão de armazenamento pode ser atualizada, no entanto, fazendo com que os objetos possam ser armazenados em versões diferentes. Um objeto será armazenado em apenas uma versão de armazenamento a qualquer momento.
As leituras do servidor de API converterão os dados armazenados na representação da API do objeto. Isso faz com que versões de armazenamento antigas possam permanecer indefinidamente, contanto que nenhuma atualização ocorra no objeto. As gravações, por outro lado, converterão o objeto armazenado para a nova representação após a atualização.
Versões de armazenamento para recursos personalizados
Recursos personalizados são definidos dinamicamente e, como tal, diferem dos tipos integrados do Kubernetes em relação à sua versão de armazenamento. Objetos integrados geralmente têm sua codificação de armazenamento definida separadamente de seus tipos de API, onde o objeto armazenado atua como um hub e a versão específica do recurso não importa, além de ser um campo no schema do objeto.
No entanto, para recursos personalizados, uma determinada versão do recurso deve ser definida como a versão de armazenamento. O schema definido por essa versão específica do recurso personalizado será usado como a codificação do recurso na camada de armazenamento. Consulte o conjunto de recursos avançados de CRD para obter informações mais detalhadas sobre a configuração e o versionamento da API.
Por exemplo, veja esta CustomResourceDefinition para crontabs:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: crontabs.example.com
spec:
group: example.com
# lista de versões suportadas por esta CustomResourceDefinition
versions:
- name: v1beta1
# Cada versão pode ser habilitada/desabilitada pela flag served.
served: true
# Uma e apenas uma versão deve ser marcada como a versão de armazenamento.
storage: true
schema:
openAPIV3Schema:
type: object
properties:
host:
type: string
port:
type: string
- name: v1
served: true
storage: false
schema:
openAPIV3Schema:
type: object
properties:
host:
type: string
port:
type: string
time:
type: string
conversion:
strategy: None
scope: Namespaced
names:
plural: crontabs
singular: crontab
kind: CronTab
shortNames:
- ct
A definição de API v1beta1 é usada como a versão de armazenamento, o que significa que qualquer
atualização ou criação de crontabs será armazenada com o schema de objeto da
API v1beta1. Neste caso, isso realmente significaria que o objeto de API v1
nunca conseguiria armazenar o campo time, pois ele não faz parte da
definição de armazenamento. Este schema é usado na camada de armazenamento como a
codificação binária do próprio objeto. Tentar definir duas versões como a versão
armazenada ao mesmo tempo é considerado inválido, pois isso significaria que dois
esquemas de dados seriam considerados formas válidas de armazenar os objetos ao mesmo tempo.
Após a modificação da versão usada para armazenamento, essa versão da API será usada para armazenar quaisquer CRs novos ou atualizados. Assistir (watch) ou obter o objeto fará com que o objeto esteja em uso, mas apenas converterá o objeto da versão de armazenamento antiga, sem afetar o objeto. Apenas a atualização ou a criação terão um efeito e usarão a versão de armazenamento recém-definida.
Como as versões de armazenamento se relacionam com a criptografia em repouso
Existem ferramentas para criptografar o armazenamento em repouso de um cluster, especialmente para os secrets do cluster. Isso adiciona uma camada adicional de proteção contra o roubo (exfiltração) de dados, já que os dados realmente armazenados no cluster são criptografados. Isso significa que o servidor de API está realmente descriptografando os dados ao recuperá-los do armazenamento. O APIServer deve ter a chave dessa versão de armazenamento para decodificar o objeto corretamente.
A versão de armazenamento, neste caso, é mais do que apenas a codificação binária do objeto. Contanto que o que está armazenado possa, de alguma forma, ser convertido no objeto da API, pode ser usado como uma versão de armazenamento.
Migrando para uma versão de armazenamento diferente
Múltiplas versões de armazenamento para um único recurso podem causar problemas para administradores de cluster. Um administrador de cluster não pode remover versões antigas de uma API para CRDs que podem não ser suportadas até ter certeza de que todos os objetos não estão mais usando a versão de armazenamento associada a elas. Com um grande número de objetos e uma visão opaca de quais são novos e quais ainda estão suportados por versões de armazenamento antigas, fica difícil saber quando uma versão pode ser removida com segurança. Se uma versão for removida prematuramente, isso pode significar ficar impossibilitado de ler o objeto por completo.
Outra questão importante é o uso de chaves de criptografia, conforme definido na seção acima. Como um recurso deve estar ativamente em uso para atualizar a versão de armazenamento, quando uma rotação de chaves é feita, tanto a chave de criptografia antiga quanto a nova chave de criptografia devem permanecer em uso até que o administrador tenha certeza de que todos os objetos foram gravados pelo menos uma vez. Isso representa riscos de segurança e problemas de usabilidade, já que uma chave não pode ser totalmente removida do uso até então.
Consulte a migração de versão de armazenamento para exemplos de como executar uma migração para garantir que todos os objetos estejam usando uma versão de armazenamento mais recente, sem intervenção manual.