Introdução
Na primeira seção do curso, você explorou um cluster Kubernetes sem modificá-lo. Aprendeu que o kubectl envia solicitações ao servidor de API e que os controladores do Kubernetes comparam continuamente o estado desejado com o estado atual.
Agora você fará suas primeiras solicitações para executar uma aplicação. Em vez de informar ao Kubernetes cada ação de baixo nível que deve ser realizada, você descreverá o resultado desejado em arquivos YAML chamados manifestos. O Kubernetes armazena as definições desses objetos e trabalha para concretizá-las.
Você começará com um único Pod, para que seja fácil visualizar a estrutura básica de um manifesto. Em seguida, definirá um Deployment que gerencia dois Pods. A comparação entre um Pod independente e Pods gerenciados por um Deployment mostrará por que os controladores de nível mais alto normalmente são preferíveis para aplicações.
Este laboratório se concentra deliberadamente na criação de cargas de trabalho. Mais adiante, você aprenderá a expor aplicações por meio de Services, depois que Pods, labels e Deployments já forem conceitos familiares.
Entender objetos declarativos do Kubernetes
Inicialização do ambiente: Este laboratório inicia um cluster Kubernetes completo para você. A configuração do plano de controle, do nó e dos componentes de rede normalmente leva 2–3 minutos. Aguarde pacientemente até que o ambiente termine de carregar antes de começar.
Nesta etapa, você relacionará o conceito de estado desejado do laboratório anterior aos manifestos do Kubernetes e preparará um espaço de trabalho para suas primeiras definições de aplicações.
Dos comandos ao estado desejado
O Kubernetes oferece dois estilos gerais de gerenciamento:
- Com um comando imperativo, você solicita diretamente uma ação, como “criar um Pod chamado
first-nginx”. - Com um manifesto declarativo, você salva a configuração desejada do objeto em um arquivo e solicita ao Kubernetes que faça o cluster corresponder a ela.
Os arquivos declarativos são valiosos porque podem ser lidos antes de uma alteração, aplicados repetidamente, comparados para identificar diferenças e armazenados em um sistema de controle de versão. Este curso dará prioridade ao estilo declarativo.
Todo objeto do Kubernetes retornado pela API possui campos importantes no nível superior:
apiVersionseleciona o grupo e a versão da API do Kubernetes.kindidentifica o tipo de objeto, comoPodouDeployment.metadatainforma a identidade do objeto, incluindo seu nome e seus labels.specdescreve o estado desejado desse objeto.statusrelata o estado observado e normalmente é preenchido pelo Kubernetes após a criação, não escrito no seu manifesto.
Isso cria um ciclo importante:
manifest spec -> API server stores desired state -> controllers act -> object status reports actual state
Preparar o diretório de manifestos
Acesse o diretório preparado para este laboratório:
cd /home/labex/project/k8s-manifests
Confirme sua localização com pwd, que significa print working directory:
pwd
/home/labex/project/k8s-manifests
Crie um pequeno arquivo de anotações registrando os quatro campos de manifesto que você usará. O comando printf escreve cada string entre aspas em uma linha separada, e > redireciona essa saída para um arquivo, substituindo-o caso já exista.
printf '%s\n' apiVersion kind metadata spec > manifest-fields.txt
Exiba o arquivo para verificá-lo:
cat manifest-fields.txt
apiVersion
kind
metadata
spec
Esse arquivo de anotações funciona como uma pequena verificação de aprendizagem: os quatro campos aparecerão nos dois manifestos que você criará a seguir.
Escrever e validar um manifesto de Pod
Nesta etapa, você escreverá um manifesto YAML para um Pod e validará sua estrutura antes de enviá-lo ao cluster.
Conhecer o Pod
Um Pod é o menor objeto implantável do Kubernetes. Um Pod oferece a um ou mais contêineres estreitamente relacionados uma identidade de rede e um contexto de armazenamento compartilhados. Na maioria dos exemplos introdutórios, cada Pod contém um único contêiner.
O Pod deste laboratório executará o NGINX, um servidor web leve. A imagem está fixada em nginx:1.27-alpine. Fixar uma versão torna o resultado mais reproduzível do que usar a tag variável latest. A imagem já foi armazenada em cache no cluster, portanto o trabalho não depende de um download da internet.
Criar o arquivo YAML
Verifique se você está no diretório de manifestos:
cd /home/labex/project/k8s-manifests
Você usará um here-document para criar o arquivo. O shell redireciona todas as linhas entre <<'EOF' e o EOF de fechamento para first-pod.yaml. Colocar o primeiro EOF entre aspas impede que o shell expanda caracteres especiais dentro do YAML.
cat <<'EOF' > first-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: first-nginx
namespace: default
labels:
app: first-nginx
spec:
containers:
- name: nginx
image: nginx:1.27-alpine
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
protocol: TCP
EOF
O YAML representa a hierarquia por meio da indentação. Use espaços de forma consistente; tabulações podem tornar o YAML inválido. Um hífen, como em - name: nginx, inicia um item de uma lista.
Leia o objeto de cima para baixo:
apiVersion: v1seleciona a API principal usada pelos Pods.kind: Poddeclara o tipo do recurso.metadata.nameatribui ao Pod o nome estávelfirst-nginx.metadata.namespace: defaultcoloca o Pod no namespace comum de aplicações do curso, em vez de um namespace do sistema.metadata.labelsassociaapp=first-nginx, que poderá ser usado posteriormente para selecionar este Pod.spec.containersé uma lista dos contêineres que o Pod deve executar.imagePullPolicy: IfNotPresentusa a imagem armazenada em cache quando ela estiver disponível.- A porta nomeada
httpusacontainerPort: 80eprotocol: TCP. Ela documenta onde o NGINX escuta dentro do contêiner; não expõe o Pod para fora do cluster.
Validar antes de criar
Use uma execução simulada no lado do cliente para analisar o arquivo sem criar o Pod. A opção -f significa file, e --dry-run=client mantém a solicitação local:
kubectl apply --dry-run=client -f first-pod.yaml
pod/first-nginx created (dry run)
As palavras dry run são essenciais: a sintaxe é válida, mas o cluster ainda não foi alterado.
Peça ao kubectl que exiba o objeto normalizado em YAML:
A opção de saída -o significa output format. Ao fornecer yaml, você solicita que o kubectl renderize o objeto analisado como YAML, em vez de imprimir apenas uma linha de resultado:
kubectl apply --dry-run=client -f first-pod.yaml -o yaml
Você verá seus campos, além dos valores padrão adicionados pelo cliente. Isso é útil para detectar problemas de indentação, nomes de campos e tipos antes de realizar uma aplicação de verdade.
Criar e inspecionar seu primeiro Pod
Nesta etapa, você aplicará o manifesto validado, observará o Kubernetes conduzir o Pod em direção ao estado desejado e inspecionará o objeto resultante.
Aplicar o manifesto
Acesse o diretório de manifestos, se necessário:
cd /home/labex/project/k8s-manifests
Aplique o arquivo sem a opção de execução simulada:
kubectl apply -f first-pod.yaml
pod/first-nginx created
O kubectl apply envia o objeto ao servidor de API. O servidor de API armazena a especificação desejada do Pod, enquanto o agendador e o kubelet trabalham juntos para executá-lo no nó.
Aguardar a disponibilidade
A criação de um Pod é assíncrona: o kubectl apply pode retornar antes que o contêiner esteja pronto. Use kubectl wait para aguardar a condição Ready do Pod. O comando termina com sucesso quando a condição se torna verdadeira ou falha após 60 segundos:
kubectl wait --for=condition=Ready pod/first-nginx --timeout=60s
pod/first-nginx condition met
Agora liste o Pod. Este laboratório repete -o wide porque cada laboratório deve poder ser usado de forma independente: -o seleciona um formato de saída, e wide acrescenta campos como o IP do Pod e o nome do nó:
kubectl get pod first-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE
first-nginx 1/1 Running ... ... ... labex-v135
READY=1/1 significa que o único contêiner está pronto, enquanto STATUS=Running representa a fase do Pod. A visualização ampla também mostra o IP do Pod e o nó ao qual ele foi atribuído. Os IPs e as idades dos Pods são valores gerados, portanto podem variar.
Inspecionar labels e propriedade
Exiba os labels do Pod:
kubectl get pod first-nginx --show-labels
Procure por app=first-nginx. Os labels são armazenados junto com o objeto e se tornarão importantes quando Deployments e Services selecionarem Pods.
Pergunte ao Kubernetes se outro objeto controla este Pod. -o jsonpath='...' extrai campos específicos em vez de imprimir o objeto inteiro. A expressão percorre metadata.ownerReferences; {"\n"} adiciona uma nova linha final para que o prompt do shell apareça na linha seguinte:
kubectl get pod first-nginx -o jsonpath='Owner: {.metadata.ownerReferences[0].kind}{"\n"}'
Owner:
O proprietário está vazio porque você criou diretamente este Pod independente. Se ele for excluído, nenhum controlador de nível superior saberá que deve substituí-lo. Você fará essa comparação com Pods gerenciados nas próximas etapas.
Verificação da etapa
Você transformou um arquivo local de estado desejado em um objeto Kubernetes em execução. A API aceitou o Pod, o agendador o atribuiu a um nó e o kubelet deixou o contêiner pronto. O Pod existe, mas nenhum controlador gerencia seu ciclo de vida.
Definir um Deployment
Nesta etapa, você definirá um Deployment que solicitará ao Kubernetes a manutenção de duas cópias de um Pod NGINX.
Por que usar um Deployment?
Um Pod independente é útil para aprendizagem, mas as aplicações geralmente precisam de um controlador. Um Deployment fornece uma quantidade desejada de réplicas e um modelo de Pod. Ele cria um ReplicaSet, que mantém a quantidade solicitada de Pods.
A cadeia de propriedade é:
Deployment -> ReplicaSet -> Pods -> containers
Se um Pod gerenciado desaparecer, o ReplicaSet perceberá que a quantidade atual de réplicas está abaixo da quantidade desejada e criará uma substituição. Em laboratórios posteriores, você usará Deployments para escalabilidade e atualizações graduais.
Criar o manifesto do Deployment
Retorne ao diretório de manifestos:
cd /home/labex/project/k8s-manifests
Crie course-web-deployment.yaml com um here-document:
cat <<'EOF' > course-web-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: course-web
labels:
app: course-web
spec:
replicas: 2
selector:
matchLabels:
app: course-web
template:
metadata:
labels:
app: course-web
spec:
containers:
- name: nginx
image: nginx:1.27-alpine
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
EOF
O Deployment usa apps/v1, a API estável para Deployments. Seu spec apresenta três campos importantes:
replicas: 2é a quantidade desejada de Pods.selector.matchLabelsidentifica os Pods gerenciados pelo Deployment.templateé o modelo usado para criar cada Pod.
O seletor e template.metadata.labels usam ambos app: course-web. Eles precisam corresponder; caso contrário, o Deployment não conseguiria identificar os Pods criados a partir de seu próprio modelo.
Validar o Deployment
Analise o manifesto sem alterar o cluster:
kubectl apply --dry-run=client -f course-web-deployment.yaml
deployment.apps/course-web created (dry run)
Use kubectl diff para comparar o manifesto com o estado atual. Um código de saída diferente de zero simplesmente significa que o objeto seria alterado; || true impede que o shell trate essa diferença esperada como uma falha:
kubectl diff -f course-web-deployment.yaml || true
Como course-web ainda não existe, a saída mostra o objeto completo como uma adição, com linhas iniciadas por +. Diferentemente de apply, diff não altera o cluster.
Implantar e inspecionar a aplicação gerenciada
Nesta etapa, você aplicará o Deployment, aguardará suas duas réplicas e inspecionará os recursos relacionados selecionados pelo label compartilhado.
Aplicar e aguardar o Deployment
Primeiro, acesse o diretório que contém o manifesto. Em seguida, aplique o estado desejado salvo; -f informa ao kubectl que ele deve ler a partir desse arquivo:
cd /home/labex/project/k8s-manifests
kubectl apply -f course-web-deployment.yaml
deployment.apps/course-web created
Aguarde a conclusão do rollout do Deployment. Um rollout é o processo de levar os Pods do Deployment ao modelo e à quantidade de réplicas desejados:
kubectl rollout status deployment/course-web --timeout=60s
deployment "course-web" successfully rolled out
Liste o Deployment:
kubectl get deployment course-web
NAME READY UP-TO-DATE AVAILABLE AGE
course-web 2/2 2 2 ...
READY=2/2 significa que as duas réplicas desejadas estão prontas. UP-TO-DATE=2 significa que ambas usam o modelo de Pod atual, e AVAILABLE=2 significa que as duas estão disponíveis.
Inspecionar os recursos relacionados
Use o seletor de labels -l app=course-web para listar os recursos relacionados:
kubectl get deployment,replicaset,pods -l app=course-web
A saída contém um Deployment, um ReplicaSet e dois Pods. Os sufixos gerados do ReplicaSet e dos Pods variarão:
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/course-web 2/2 2 2 ...
NAME DESIRED CURRENT READY AGE
replicaset.apps/course-web-... 2 2 2 ...
NAME READY STATUS RESTARTS AGE
pod/course-web-...-... 1/1 Running ... ...
pod/course-web-...-... 1/1 Running ... ...
Essa visualização confirma que as duas réplicas desejadas do Deployment se transformaram em dois Pods prontos. Na próxima etapa, você rastreará as relações de propriedade entre esses recursos.
Verificação da etapa
Você aplicou um manifesto de Deployment e aguardou que seu estado desejado fosse alcançado. O Kubernetes criou um ReplicaSet e dois Pods, e o label compartilhado app=course-web permitiu listá-los como um único grupo de aplicação.
Rastrear a propriedade dos controladores
Nesta etapa, você seguirá as referências de proprietário do Kubernetes de um Pod gerenciado até seu ReplicaSet e, depois, até o Deployment. Você também reaplicará o manifesto para observar a idempotência declarativa.
Inspecionar o proprietário de um Pod
Armazene o nome de um Pod gerado em uma variável do shell. A sintaxe NAME=$(command) é uma substituição de comando: o shell executa o comando e salva sua saída em NAME. Aqui, -l app=course-web seleciona os Pods correspondentes, e o JSONPath extrai o nome gerado do primeiro Pod:
POD_NAME=$(kubectl get pods -l app=course-web -o jsonpath='{.items[0].metadata.name}')
Imprima o nome para saber qual Pod foi selecionado:
echo "$POD_NAME"
Agora inspecione seu proprietário direto. Colocar "$POD_NAME" entre aspas passa o nome armazenado como um único argumento seguro para o comando:
kubectl get pod "$POD_NAME" -o jsonpath='Owner: {.metadata.ownerReferences[0].kind}/{.metadata.ownerReferences[0].name}{"\n"}'
Owner: ReplicaSet/course-web-...
Ao contrário do Pod independente first-nginx, um Pod gerenciado por um Deployment tem um ReplicaSet como proprietário. O próprio ReplicaSet pertence ao Deployment.
Exiba o proprietário do ReplicaSet. O primeiro comando repete o mesmo padrão de substituição de comando, desta vez armazenando um nome de ReplicaSet em RS_NAME:
RS_NAME=$(kubectl get replicaset -l app=course-web -o jsonpath='{.items[0].metadata.name}')
kubectl get replicaset "$RS_NAME" -o jsonpath='Owner: {.metadata.ownerReferences[0].kind}/{.metadata.ownerReferences[0].name}{"\n"}'
Owner: Deployment/course-web
Reaplicar o estado desejado
Aplique o mesmo manifesto novamente:
kubectl apply -f course-web-deployment.yaml
deployment.apps/course-web unchanged
unchanged demonstra uma propriedade declarativa importante: aplicar repetidamente o mesmo estado desejado é seguro. O Kubernetes só precisa agir quando a configuração desejada e a configuração atual são diferentes.
Verificação da etapa
Agora você tem um Pod independente e uma aplicação gerenciada por um Deployment. Ambos executam contêineres, mas o Deployment acrescenta uma hierarquia de controladores que mantém duas réplicas e serve de base para futuras operações de escalabilidade e atualizações graduais.
Resumo
Você passou da exploração somente leitura do cluster ao gerenciamento declarativo de aplicações. Aprendeu as funções de apiVersion, kind, metadata e spec; validou manifestos com execuções simuladas no lado do cliente; criou e inspecionou um Pod independente; e implantou duas réplicas gerenciadas por um Deployment.
Mais importante, você observou a cadeia de propriedade dos controladores, do Deployment ao ReplicaSet e deste aos Pods. Essa base de estado desejado prepara você para diagnosticar aplicações, expô-las por meio de Services, dimensionar réplicas e realizar atualizações graduais nas próximas seções do curso.


