🇺🇸 English version coming soon.
Na Parte 5 desta série, validamos o cluster de ponta a ponta fazendo o deploy do Nginx. Agora vamos um passo além: construir a imagem Docker de uma aplicação própria, publicá-la, colocá-la para rodar no cluster e explorar operações do dia a dia — atualização de versão, rollback e escalabilidade (manual e automática).
Como exemplo, foi utilizada uma API REST simples (myapp.war), feita em Spring Boot, apenas para fins didáticos — o processo se aplica a qualquer aplicação empacotada como imagem de container.
Criando a imagem Docker da aplicação
O primeiro passo é escrever o Dockerfile da aplicação. Neste exemplo, foi usada uma imagem base leve (alpine), com o Java 11 instalado para rodar a aplicação:
FROM alpine
WORKDIR /opt/app
RUN apk update && apk add vim openjdk11-jre
COPY runapp.sh .
CMD ash runapp.sh
Construindo a imagem
docker image build -t oregontecnologia/myapp-api:1.0.0 .
Publicando a imagem
Antes de usar a imagem no cluster, ela precisa estar disponível em algum registro — seja o Docker Hub, seja um registro privado. Se você optar por hospedar seu próprio registro on-premise (recomendado para ambientes corporativos ou sem acesso à internet), veja o artigo complementar sobre como criar um servidor de registro local.
Para publicar no Docker Hub:
docker login
username:
password:
docker push oregontecnologia/myapp-api:1.0.0
Fazendo o deploy da aplicação
Com a imagem publicada, é possível verificar o estado atual do cluster antes de prosseguir:
kubectl get pods -o wide
kubectl get deploy -o wide
Crie o Deployment diretamente pela linha de comando, apontando para a imagem publicada:
kubectl create deploy myapp-deploy --image=oregontecnologia/myapp-api:1.0.0
Diferente dos exemplos anteriores desta série (onde usamos arquivos YAML com
kubectl apply -f), aqui o Deployment é criado diretamente via linha de comando comkubectl create deploy. Ambas as abordagens são válidas — arquivos YAML são mais indicados quando você precisa versionar e reaplicar configurações de forma consistente.
Expondo a aplicação externamente
Para tornar a aplicação acessível fora do cluster, crie um Service do tipo LoadBalancer, associando um IP externo fixo:
kubectl expose deploy myapp-deploy --type=LoadBalancer --external-ip=10.0.10.100 --port=80
Em ambientes on-premise, o tipo
LoadBalancernormalmente não provisiona um balanceador automaticamente (isso é um recurso nativo de provedores de nuvem). Por isso, aqui é informado manualmente um IP externo (--external-ip) já disponível na rede local.
Removendo a aplicação
Caso precise remover o Deployment:
kubectl delete deploy myapp-deploy
Atualizando e revertendo versões da aplicação
Uma das grandes vantagens do Kubernetes é gerenciar atualizações de forma controlada, sem downtime perceptível (rolling update).
Atualizando para uma nova versão
kubectl set image deployments/myapp-deploy myapp-api=oregontecnologia/myapp-api:1.0.2 --record
Esse comando atualiza a imagem do container myapp-api dentro do Deployment para a versão 1.0.2. A flag --record registra o comando no histórico de revisões do Deployment, o que facilita identificar depois o que mudou em cada rollout.
Revertendo para a versão anterior
Se a nova versão apresentar problemas, é possível reverter rapidamente para a revisão anterior:
kubectl rollout undo deployments/myapp-deploy
Escalando a aplicação
Escalonamento manual
Para ajustar manualmente o número de réplicas em execução — por exemplo, para 3:
kubectl scale deploy myapp-deploy --replicas=3
Escalonamento automático (HPA)
Para deixar o próprio Kubernetes ajustar o número de réplicas automaticamente, com base no uso de CPU, é possível configurar um Horizontal Pod Autoscaler (HPA). No exemplo abaixo, o cluster começa com 2 réplicas e pode escalar até 10, sempre que a utilização média de CPU ultrapassar 75%:
kubectl autoscale deploy myapp-deploy --min=2 --max=10 --cpu-percent=75
Ajuste os valores de
--min,--maxe--cpu-percentconforme a capacidade real do seu cluster e o comportamento esperado da aplicação.
Para verificar o estado atual do autoscaler:
kubectl get hpa
Esse comando mostra, entre outras informações, o uso atual de CPU em relação ao alvo configurado, e o número de réplicas em execução no momento.
Para remover o autoscaler:
kubectl delete hpa myapp-deploy
Agora vamos colocar todo este processo manual em um arquivo YAML para facilitar as coisas.
Ao longo desta série, usamos diversos arquivos .yaml para criar Deployments, Services e outros objetos no cluster. Neste artigo, vamos dar um passo atrás e entender a estrutura básica desses manifestos — o que é obrigatório em todo arquivo, como descobrir a apiVersion correta e como ficam, na prática, os principais tipos de objeto que já usamos: Pod, ReplicaSet, Deployment e Service.
A estrutura mínima de um manifesto
Todo objeto do Kubernetes, independente do tipo, é descrito por um YAML com quatro campos principais:
apiVersion:
kind:
metadata:
spec:
-
apiVersion: a versão da API do Kubernetes usada para criar aquele objeto (por exemplo,
v1ouapps/v1); -
kind: o tipo de objeto que será criado (
Pod,Deployment,Service, etc.); - metadata: os metadados do objeto — nome, labels, namespace, entre outros;
- spec: a especificação propriamente dita do objeto — no caso de um Pod, por exemplo, é aqui que ficam os containers.
Como descobrir a apiVersion correta
Cada tipo de objeto (kind) pertence a uma apiVersion específica, e isso pode variar entre versões do Kubernetes. Para consultar quais recursos estão disponíveis no seu cluster e a qual API cada um pertence, use:
$ kubectl api-resources
Esse comando lista todos os recursos suportados pelo cluster, junto com o grupo de API correspondente (coluna APIVERSION) — é a fonte mais confiável para saber qual apiVersion usar em cada manifesto, já que isso pode mudar conforme a versão do Kubernetes instalada.
Atenção à indentação
YAML é um formato sensível à indentação — diferente de chaves {} ou colchetes [], a hierarquia dos dados é definida puramente pelos espaços. Por isso:
- Nunca use TAB para indentar um arquivo YAML — use sempre espaços.
- O padrão recomendado (e usado nos exemplos abaixo) é 2 espaços por nível de indentação.
-
metadataespecsão mapeamentos (chave-valor), não listas — ou seja, seus campos internos (name,labels, etc.) não devem começar com-.
Esse último ponto é um erro comum: é fácil confundir listas (que usam -) com mapeamentos simples. No exemplo de Pod abaixo, note que name e labels ficam diretamente sob metadata, sem traço.
Pod
O objeto mais básico do Kubernetes é o Pod — a menor unidade que pode ser criada e gerenciada no cluster, contendo um ou mais containers.
apiVersion: v1
kind: Pod
metadata:
name: meupod
labels:
app: meupod-label
spec:
containers:
- name: myapp-api
image: oregontecnologia/myapp-api:1.0.2
Criando o objeto: create vs apply
Existem dois comandos principais para aplicar um manifesto no cluster:
$ kubectl create -f arquivo.yaml
$ kubectl apply -f arquivo.yaml
A diferença entre eles é importante:
-
createcria o objeto apenas se ele ainda não existir — se o objeto já foi criado anteriormente, o comando retorna erro. -
applycria o objeto caso ele não exista, ou atualiza o objeto existente caso haja alguma mudança no manifesto. Por isso,applyé o comando mais usado no dia a dia, já que permite reaplicar o mesmo arquivo continuamente conforme ele evolui.
Verificando a criação
$ kubectl get pods
A flag
-o widemostra informações adicionais sobre o pod em execução, como o nó onde ele está rodando e seu IP interno.
Para ver todos os detalhes de um pod ou deployment (incluindo eventos recentes, o que ajuda bastante na hora de depurar problemas):
$ kubectl describe pod myapp-api
Ou, para um deployment:
$ kubectl describe deploy myapp-deploy
ReplicaSet
Um Pod sozinho não se recupera automaticamente se falhar. É aí que entra o ReplicaSet: um objeto responsável por garantir que um número definido de réplicas do mesmo Pod esteja sempre em execução.
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: meureplicaset
spec:
replicas: 5
selector:
matchLabels:
app: meupod-label
template:
metadata:
labels:
app: meupod-label
spec:
containers:
- name: myapp-api
image: oregontecnologia/myapp-api:1.0.2
Repare que a estrutura é um pouco mais aninhada que a do Pod: dentro de spec, temos o selector (que define quais Pods pertencem a este ReplicaSet, com base nos labels) e o template (que descreve como cada réplica do Pod deve ser criada).
Verificando a criação:
$ kubectl get replicaset
Na prática, é raro criar ReplicaSets diretamente — normalmente eles são gerenciados automaticamente por um Deployment, que veremos a seguir. Ainda assim, entender essa camada ajuda a compreender como o Kubernetes garante a disponibilidade dos Pods.
Deployment
O Deployment é a forma mais comum de rodar aplicações no Kubernetes. Ele gerencia ReplicaSets automaticamente, adicionando recursos como rolling updates e rollback — que já vimos na prática na Parte 6 desta série.
apiVersion: apps/v1
kind: Deployment
metadata:
name: meudeploy
spec:
replicas: 5
selector:
matchLabels:
app: meupod-label
template:
metadata:
labels:
app: meupod-label
spec:
containers:
- name: myapp-api
image: oregontecnologia/myapp-api:1.0.2
Note que a estrutura é praticamente idêntica à do ReplicaSet — o que faz sentido, já que um Deployment cria e gerencia ReplicaSets por trás dos panos. A diferença está no kind e nas funcionalidades adicionais que o Deployment oferece.
Verificando a criação:
$ kubectl get deploy
Service
Por fim, o Service é o objeto responsável por expor Pods de forma estável, com um endereço fixo, independente de quantas vezes os Pods sejam recriados.
apiVersion: v1
kind: Service
metadata:
name: meudservice
spec:
selector:
app: meupod-label
ports:
- port: 80
type: LoadBalancer # ClusterIP | NodePort | LoadBalancer
O campo type define como o serviço será exposto:
- ClusterIP (padrão): expõe o serviço apenas internamente, dentro do cluster;
- NodePort: expõe o serviço em uma porta fixa em todos os nós do cluster (usamos esse tipo na Parte 5, com o Nginx);
- LoadBalancer: solicita um balanceador de carga externo — em nuvem, provisionado automaticamente pelo provedor; em ambientes on-premise, normalmente requer um IP configurado manualmente ou uma solução como o MetalLB.
Verificando a criação:
$ kubectl get services
Resumo
| Objeto | Função principal |
|---|---|
| Pod | Unidade mínima de execução (um ou mais containers) |
| ReplicaSet | Garante um número fixo de réplicas de um Pod |
| Deployment | Gerencia ReplicaSets, com suporte a rolling update e rollback |
| Service | Expõe Pods de forma estável, com IP e nome fixos |
Entender essa hierarquia — Pod → ReplicaSet → Deployment, mais o Service como camada de exposição — é a base para ler (e escrever) qualquer manifesto do Kubernetes com confiança, independente da complexidade da aplicação.
Fechando o ciclo operacional
Com o deploy de uma aplicação própria, atualizações controladas, rollback e escalabilidade (manual e automática), cobrimos as operações mais comuns do dia a dia de um cluster Kubernetes on-premise. A partir daqui, o cluster está pronto não só para hospedar aplicações, mas também para operá-las de forma resiliente conforme a demanda aumenta.
Isso encerra o conteúdo mais conceitual desta série. Nos próximos artigos, seguimos explorando tópicos práticos do dia a dia de um cluster on-premise.
Nos próximos artigos da série, vamos aprofundar em temas como registro de imagens privado on-premise, armazenamento persistente e observabilidade do cluster.
Artigos relacionados:
- Adicionando e removendo worker ao cluster.
- Criando um servidor de registros para suas imagens docker.
- Renovando certificado do kubernetes.
- Addons uteis para seu kubernetes.
- Metric server
- NGinx Ingress controller
- Cert-Manager
- Portainer
- Prometheus
- Grafana
Top comments (0)