☕ Um Café no Bellacosa Mainframe
Gostou do conteúdo? Ajude a manter o café quente, o COBOL compilando e o mainframe acordado. 😄
☕ Pague um café ao Bellacosa

Translate

Mostrar mensagens com a etiqueta Dockerfile. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta Dockerfile. Mostrar todas as mensagens

terça-feira, 3 de janeiro de 2023

🕵️‍♂️ Tintin na Terra dos Containers — O Mistério de Docker & Kubernetes

 

Bellacosa Mainframe e os containers dockers e kubernetes

☕ Um Café no Bellacosa Mainframe

🕵️‍♂️ Tintin na Terra dos Containers — O Mistério de Docker & Kubernetes

Uma investigação entre imagens, containers, Pods, Deployments e clusters — porque até Tintin descobriria que colocar uma aplicação em produção é muito mais complicado do que embarcar no Sirius.

Caso nº 03:17 — Arquivo confidencial do Bellacosa Mainframe
Destino: Produção
Suspeitos: Docker, Kubernetes e algumas dezenas de arquivos YAML
Situação: aparentemente simples. Portanto, extremamente suspeita.

Tintin estava acostumado a situações complicadas.

Já havia enfrentado falsificadores, contrabandistas, sociedades secretas, ditadores, traficantes, cientistas excêntricos e até viajado à Lua.

Mas naquela manhã encontrou algo muito mais perigoso.

Um desenvolvedor havia pronunciado a frase:

— Na minha máquina funciona.

Milou levantou as orelhas.

Capitão Haddock largou o café.

Professor Girassol continuou mexendo em alguma coisa que provavelmente explodiria antes do almoço.

Tintin abriu seu pequeno caderno.

Novo caso.

Precisávamos descobrir como levar uma aplicação desde o notebook de um programador até produção sem depender da configuração particular daquela máquina.

E nossa investigação começaria com uma criatura chamada container.



📰 1. O estranho caso da aplicação que funcionava ontem

Imagine que nosso jovem programador COBOL decidiu aprender Python e criou uma pequena API usando FastAPI.

No computador dele tudo funciona.

Python instalado.

Bibliotecas instaladas.

Variáveis configuradas.

Banco de dados acessível.

Portas abertas.

Versões corretas.

Ele entrega o programa para Haddock.

Haddock tenta executá-lo.

Nada funciona.

— MIL MILHÕES DE MILHARES DE BIBLIOTECAS INCOMPATÍVEIS!

Eis um problema muito antigo da computação.

O programa não existe sozinho.

Ele depende de um ambiente.

No universo mainframe conhecemos isso muito bem. Um programa COBOL pode depender de determinada versão de runtime, Db2, CICS, arquivos, configurações, parâmetros, bibliotecas e permissões.

No mundo distribuído ocorre exatamente o mesmo fenômeno.

Docker ataca justamente esse problema.

Em vez de entregar apenas:

minha-aplicacao.py

tentamos empacotar:

APLICAÇÃO
   +
RUNTIME
   +
BIBLIOTECAS
   +
DEPENDÊNCIAS
   +
CONFIGURAÇÃO NECESSÁRIA

dentro de uma unidade reproduzível.

Tintin anotaria:

Pista nº 1: não transporte apenas o programa. Transporte uma descrição reproduzível de seu ambiente.



📦 2. Surge a primeira testemunha: Docker

Docker popularizou uma maneira extremamente prática de construir, distribuir e executar aplicações em containers.

Mas precisamos separar duas palavras que frequentemente aparecem misturadas:

IMAGE e CONTAINER.

Uma imagem é o artefato preparado.

Um container é uma instância executando aquela imagem.

Podemos imaginar:

Dockerfile
    │
    ▼
docker build
    │
    ▼
┌─────────────────┐
│      IMAGE      │
│ app:v1          │
└─────────────────┘
       │
       │ docker run
       ▼
┌─────────────────┐
│    CONTAINER    │
│ aplicação viva  │
└─────────────────┘

Para quem vem do mainframe, existe uma analogia didática interessante.

Imagem lembra um artefato executável versionado. Container lembra uma execução desse artefato.

Não interprete isso literalmente como LOAD MODULE = IMAGE, porque arquiteturalmente são coisas diferentes.

Mas como ponte mental funciona muito bem.

O detalhe importante é:

uma única imagem pode originar muitos containers.

Temos:

IMAGE: bellacard-api:v7

        │
        ├── Container A
        ├── Container B
        ├── Container C
        └── Container D

Agora Tintin já tinha uma pista importante.

O artefato poderia ser reproduzido.


🧾 3. O bilhete encontrado no bolso do suspeito: Dockerfile

Toda boa investigação tem um documento comprometedor.

No nosso caso:

FROM python:3.13-slim

WORKDIR /app

COPY requirements.txt .

RUN pip install -r requirements.txt

COPY . .

EXPOSE 8000

CMD ["python", "app.py"]

Esse arquivo é o Dockerfile.

Ele descreve como construir nossa imagem.

Tintin examina cada linha com a lupa.

FROM determina a imagem-base.

WORKDIR estabelece o diretório de trabalho.

COPY coloca arquivos dentro da imagem.

RUN executa comandos durante sua construção.

ENV pode definir variáveis de ambiente.

CMD estabelece o comando normalmente executado quando o container começa.

E então aparece:

EXPOSE 8000

Haddock imediatamente conclui:

— Então a porta 8000 está publicada!

Não.

EXPOSE não publica automaticamente uma porta no host.

É informação sobre a porta esperada pela aplicação. A publicação efetiva pode ser feita, por exemplo:

docker run -p 8080:8000 bellacard-api

Temos então:

HOST                  CONTAINER

localhost:8080  ───►  :8000

Essa diferença pequena é exatamente o tipo de detalhe que transforma uma explicação introdutória em conhecimento operacional.



🌐 4. O mistério das portas

Tintin agora encontra três containers.

frontend
backend
database

Cada um possui seu próprio contexto de rede.

E aqui surge outra mudança mental importante.

Não devemos construir sistemas distribuídos supondo que cada container terá eternamente determinado endereço IP.

Containers aparecem.

Containers desaparecem.

Podem ser recriados.

É muito melhor trabalhar com nomes e mecanismos de descoberta de serviços.

Em um ambiente Docker Compose poderíamos ter:

frontend
    │
    ▼
backend:8000
    │
    ▼
postgres:5432

Isso começa a revelar algo importante.

Containerização não significa simplesmente:

“pegamos uma VM e diminuímos.”

O modelo operacional é diferente.

Containers tendem a ser descartáveis.

A aplicação precisa ser projetada levando isso em consideração.



💾 5. Milou encontra o banco de dados

Milou começa a latir para um container.

Tintin abre o container.

Encontra PostgreSQL.

Haddock reinicia a máquina.

O banco desaparece.

— BOMBARDEIOS E BACKUPS INEXISTENTES!

Tintin identifica imediatamente o problema.

Persistência.

O filesystem interno de um container não deve ser tratado ingenuamente como o lugar permanente dos dados importantes.

Precisamos separar:

COMPUTE                  DATA

container              volume/storage
 descartável            persistente

Docker oferece mecanismos como volumes e bind mounts.

Essa separação torna-se ainda mais importante quando chegarmos ao Kubernetes.

Uma aplicação pode morrer.

O Pod pode desaparecer.

O container pode ser substituído.

Mas determinados dados precisam continuar existindo.

Para quem vem de mainframe isso não deveria parecer revolucionário.

Há décadas aprendemos a separar processamento de dados persistentes.

A novidade está nas abstrações utilizadas.



🗝️ 6. O envelope secreto

Girassol encontra isto:

DB_PASSWORD=Tintin123
API_KEY=abc123

E sugere colocar tudo no GitHub.

Tintin quase derruba o café.

Variáveis de ambiente são excelentes para retirar determinadas configurações do código.

Podemos ter:

APP_ENV=production
DB_HOST=database
DB_PORT=5432

Arquivos .env também são muito convenientes durante desenvolvimento.

Mas existe uma armadilha:

tirar uma senha do código não significa que ela automaticamente ficou segura.

Um .env contendo credenciais continua sendo um arquivo contendo credenciais.

Precisa ser protegido.

Não deve simplesmente parar no repositório.

E esse problema reaparecerá no Kubernetes com os Secrets.


🧩 7. O caso ficou grande demais: Docker Compose

Tintin agora possui cinco containers:

frontend
API
agent
database
redis

Executá-los manualmente começa a parecer uma operação militar.

Então entra Docker Compose.

Podemos declarar um conjunto de serviços em um arquivo compose.yaml.

Algo conceitualmente semelhante a:

services:

  api:
    build: .
    ports:
      - "8000:8000"

  database:
    image: postgres

  redis:
    image: redis

Agora descrevemos uma pequena aplicação multi-container declarativamente.

Essa é uma das grandes virtudes do Compose.

Em vez de Haddock precisar decorar quinze comandos, declaramos como o ambiente deve ser.

Um detalhe merece atualização nos materiais mais antigos: no Compose moderno, aquele tradicional:

version: "3.8"

não é mais necessário. A documentação do Docker classifica a propriedade superior version como obsoleta e meramente informativa; o Compose moderno trabalha com a Compose Specification. (Docker Documentation)

É um belo exemplo de por que bons cursos técnicos precisam ser revisados continuamente.


🚢 8. Finalmente embarcamos a imagem

Construímos nossa aplicação:

docker build -t bellacard:v1 .

Temos uma imagem local.

Mas queremos executá-la em outro lugar.

Entram os container registries.

O fluxo conceitual torna-se:

SOURCE CODE
     │
     ▼
DOCKERFILE
     │
     ▼
BUILD
     │
     ▼
IMAGE
     │
     ▼
REGISTRY
     │
     ▼
PULL
     │
     ▼
EXECUTION

É aqui que começa uma ideia extremamente poderosa:

o artefato produzido pelo pipeline deve ser exatamente aquilo que promovemos entre ambientes.

Não queremos recompilar misteriosamente produção de maneira diferente de homologação.

Queremos artefatos versionados, rastreáveis e reproduzíveis.

O velho programador mainframe sentado no fundo da sala provavelmente começa a sorrir.

Ele já ouviu essa música antes.


🌊 9. De repente aparecem 500 containers

E aqui nossa aventura muda completamente.

Docker resolveu muito bem vários problemas relacionados a construção e execução de containers.

Mas suponha que nossa aplicação tenha:

300 containers
40 servidores
12 serviços
6 versões
3 ambientes
milhares de requisições

Quem decide onde cada workload executará?

Quem percebe que um deles morreu?

Quem cria outro?

Quem mantém determinada quantidade de réplicas?

Quem distribui tráfego?

Quem atualiza gradualmente uma versão?

Quem associa armazenamento?

Quem controla configuração?

Quem escala a aplicação?

Tintin escreve uma única palavra no caderno:

KUBERNETES


☸️ 10. Entramos no território Kubernetes

Kubernetes não é simplesmente um “Docker maior”.

Essa distinção é fundamental.

Ele é uma plataforma de orquestração de workloads containerizados.

Seu grande truque filosófico está no conceito de estado desejado.

Nós declaramos algo como:

QUERO 3 RÉPLICAS DESTA APLICAÇÃO.

O sistema observa:

DESEJADO = 3
ATUAL = 3

Tudo certo.

Um Pod desaparece:

DESEJADO = 3
ATUAL = 2

Existe divergência.

Os controladores trabalham para retornar ao estado desejado:

DESEJADO = 3
ATUAL = 3

Isso é extraordinariamente importante.

O operador deixa de pensar apenas:

“execute este comando.”

e passa também a pensar:

“este é o estado que quero manter.”

Quem conhece automação operacional, WLM e políticas em ambientes corporativos provavelmente já começou a enxergar pontes conceituais.


🏰 11. Tintin entra no cluster

Um cluster Kubernetes possui componentes de controle e nós onde workloads são executados.

De forma simplificada:

              KUBERNETES CLUSTER

        ┌─────────────────────────┐
        │      CONTROL PLANE      │
        │                         │
        │ API Server              │
        │ Scheduler               │
        │ Controller Manager      │
        │ etcd                    │
        └────────────┬────────────┘
                     │
          ───────────┼───────────
                     │
       ┌─────────────┴─────────────┐

   WORKER NODE                 WORKER NODE
   ┌──────────────┐           ┌──────────────┐
   │ kubelet      │           │ kubelet      │
   │ runtime      │           │ runtime      │
   │              │           │              │
   │ Pod Pod Pod  │           │ Pod Pod Pod  │
   └──────────────┘           └──────────────┘

O API Server é uma peça central da interface de controle.

O scheduler ajuda a decidir onde Pods serão colocados.

Os controllers observam o estado e trabalham para reconciliá-lo.

O etcd mantém dados importantes do estado do cluster.

E nos workers temos, entre outros componentes, o kubelet e um runtime de containers.


🐳 12. Haddock encontra uma pista desatualizada

Em algum velho mapa Tintin encontra:

Kubernetes → Docker

— Caso encerrado! — grita Haddock.

Não tão depressa.

Aqui existe uma atualização histórica importantíssima.

Kubernetes removeu seu dockershim integrado a partir da versão 1.24. Kubernetes moderno trabalha através da Container Runtime Interface — CRI, com runtimes compatíveis, como containerd e CRI-O; Docker Engine ainda pode ser integrado por um adaptador como cri-dockerd. (Kubernetes)

Isso não significa que imagens construídas com Docker deixaram de funcionar no Kubernetes. A própria documentação explica que usar Docker para construir imagens não cria uma dependência de Docker como runtime do cluster. (Kubernetes)

Portanto nosso mapa mental moderno é melhor representado assim:

              KUBERNETES

                 kubelet
                    │
                    ▼
                   CRI
                    │
          ┌─────────┴─────────┐
          ▼                   ▼
     containerd             CRI-O

E Docker continua extremamente útil no workflow de desenvolvimento e construção de imagens.

Pista nº 12: Docker não morreu no Kubernetes. Mudou a relação arquitetural entre eles.


📦 13. O menor quarto do hotel: Pod

Chegamos agora a uma das palavras mais importantes de Kubernetes:

Pod.

Pod é a menor unidade implantável de computação que Kubernetes gerencia.

Normalmente encontramos um container principal dentro dele, embora um Pod possa conter mais de um container quando esses processos precisam compartilhar estreitamente recursos e ciclo de vida.

Podemos imaginar:

POD
┌────────────────────────────┐
│                            │
│   Application Container    │
│                            │
│   shared networking        │
│   shared volumes/context   │
│                            │
└────────────────────────────┘

Mas existe algo fundamental:

não se apaixone pelo Pod.

Pods são substituíveis.

Podem desaparecer e serem recriados.

E por isso normalmente não administramos aplicações complexas criando Pods soltos manualmente.

Entra outra testemunha.


🧬 14. Deployment → ReplicaSet → Pods

Para uma aplicação típica, podemos declarar um Deployment.

Por exemplo:

replicas: 3

Conceitualmente:

Deployment
     │
     ▼
ReplicaSet
     │
 ┌───┼───┐
 ▼   ▼   ▼
Pod Pod Pod

Se um desaparece:

Pod ✖

o sistema trabalha para restaurar o estado desejado.

Isso também permite realizar rolling updates.

Em vez de:

VERSÃO 1
   ↓
DESLIGA TUDO
   ↓
VERSÃO 2

podemos substituir progressivamente instâncias antigas por novas.

E, quando necessário, trabalhar com mecanismos de rollback.

Haddock começa a gostar da história.

Produção sem uma gigantesca janela de “desliga tudo e reza” realmente parece civilização.


📞 15. Mas como encontramos esses Pods?

Temos outro problema.

Pods são efêmeros.

Se ficarmos distribuindo seus endereços diretamente, criamos dependências frágeis.

Entra o objeto Service.

Imagine:

CLIENTE
   │
   ▼
SERVICE
   │
 ┌─┼───────────┐
 ▼ ▼           ▼
POD A        POD B        POD C

O Service fornece uma abstração estável para alcançar determinado conjunto de Pods.

Essa é uma mudança mental importantíssima:

não procure indivíduos; procure o serviço.

Para um programador mainframe acostumado com um endpoint lógico de uma aplicação transacional, a ideia começa a soar curiosamente familiar.


🗺️ 16. ConfigMap e o documento que não deveria conter a senha

Nossa aplicação precisa saber:

LOG_LEVEL=INFO
LANGUAGE=pt_BR
FEATURE_X=true

Esses valores podem estar em um ConfigMap.

Mas temos também:

PASSWORD
TOKEN
API_KEY
CERTIFICATE

Aí entramos no território dos Secrets.

Contudo, há uma pegadinha digna dos irmãos Dupond e Dupont:

— Está em Base64, portanto está criptografado!

— Exatamente! E eu diria ainda mais: está criptografado porque está em Base64!

Errado duas vezes.

A documentação oficial é explícita: Base64 não é criptografia. Kubernetes Secrets podem ser armazenados sem criptografia por padrão; ambientes sérios precisam considerar controles como RBAC, restrição de acesso, criptografia em repouso e soluções apropriadas de gerenciamento de segredos. (Kubernetes)

Portanto:

ConfigMap
    ↓
configuração não confidencial

Secret
    ↓
informação confidencial
    ↓
+ controle de acesso
+ proteção apropriada
+ encryption at rest quando aplicável
+ gestão segura do ciclo de vida

Esse é um ponto que merece enorme atenção em qualquer treinamento.


🗄️ 17. O banco não pode desaparecer novamente

Voltamos ao problema de persistência.

No Kubernetes encontramos conceitos como:

PersistentVolume — PV

e

PersistentVolumeClaim — PVC

Didaticamente:

POD
 │
 ▼
PVC
 │
 ▼
PV
 │
 ▼
STORAGE

O PVC representa a solicitação de armazenamento feita pelo workload.

O PV representa o recurso persistente disponibilizado ao cluster, dependendo do modelo e provisionamento utilizado.

Em ambientes modernos existe ainda toda uma camada envolvendo StorageClass, provisionamento dinâmico e CSI.

Mas para nossa primeira investigação basta guardar:

Pod é descartável; dado importante não pode depender da sobrevivência daquele Pod.


🩺 18. Professor Girassol inventa três estetoscópios

Agora precisamos saber se a aplicação está saudável.

Kubernetes trabalha com probes que respondem perguntas diferentes.

Startup probe:

Você conseguiu iniciar?

Liveness probe:

Você continua vivo?

Readiness probe:

Você está pronto para receber tráfego?

Essas perguntas parecem semelhantes.

Não são.

Imagine uma aplicação Java que demora bastante para iniciar.

Ela pode estar viva, mas ainda não pronta para atender.

Ou uma aplicação pode continuar com processo existente, mas ter entrado em um estado do qual não consegue se recuperar adequadamente.

Misturar esses conceitos pode produzir exatamente o tipo de incidente que começa às...

03:17.

Pronto.

Easter egg encontrado. ☕😎


🚪 19. Tintin chega ao portão: Ingress

Agora temos serviços funcionando dentro do cluster.

Mas usuários precisam chegar até eles.

Tradicionalmente, Kubernetes utiliza Ingress para definir roteamento HTTP/HTTPS externo, associado a uma implementação/controlador.

Conceitualmente:

INTERNET
   │
   ▼
INGRESS
   │
   ├── /api ─────► Service API
   │                    │
   │                  Pods
   │
   └── /web ─────► Service WEB
                        │
                      Pods

Ingress continua sendo um conceito importante porque existem enormes ambientes usando-o.

Porém nosso curso de 2026 precisa colocar uma anotação vermelha no caderno de Tintin:

⚠️ EXISTE UM NOVO CAPÍTULO

O ecossistema Kubernetes está avançando para Gateway API como abordagem moderna e mais expressiva para networking. Em agosto de 2026, o projeto anunciou Gateway API v1.6, incluindo TCPRoute e UDPRoute no canal Standard. (Kubernetes)

Há inclusive tooling oficial para ajudar migrações de Ingress para Gateway API. (Kubernetes)

Portanto um curso atualizado deveria ensinar:

Ingress
   │
   ├── importantíssimo para ambientes existentes
   │
   └── API congelada para novos recursos
             │
             ▼
         Gateway API
        caminho moderno

Esse pequeno detalhe separa uma apostila histórica de uma formação preparada para os próximos anos.


📈 20. De repente chegam dez mil usuários

Haddock finalmente publica seu sistema.

Um usuário acessa.

Tudo funciona.

Dez acessam.

Tudo funciona.

Mil acessam.

Haddock começa a suar.

Dez mil acessam.

— ESCALABILIDADE DOS SETE MARES!

Kubernetes oferece mecanismos de escalabilidade, entre eles o Horizontal Pod Autoscaler — HPA.

Podemos pensar:

TRÁFEGO ↑
CPU ↑
MÉTRICA ↑

       │
       ▼

HPA observa
       │
       ▼

replicas: 3
       │
       ▼
replicas: 7

Quando a demanda diminui, a quantidade pode ser reduzida segundo a configuração e comportamento do autoscaler.

CPU e memória são excelentes exemplos introdutórios, embora arquiteturas reais possam utilizar outras métricas conforme a infraestrutura de métricas disponível.

Aqui encontramos uma ponte interessante com o universo mainframe.

Um profissional de WLM imediatamente perguntaria:

Qual é a política? Qual a prioridade? Qual o recurso disponível? Qual a métrica? Qual o objetivo de serviço?

Excelente.

Essa é exatamente a mentalidade que queremos preservar.

A tecnologia muda.

As boas perguntas sobrevivem.


🧠 21. Tintin monta o quadro completo

Depois de centenas de pistas espalhadas pela mesa, finalmente conseguimos enxergar nossa arquitetura.

                    INTERNET
                        │
                        ▼
              ┌──────────────────┐
              │ GATEWAY/INGRESS  │
              └────────┬─────────┘
                       │
                       ▼
                  ┌─────────┐
                  │ SERVICE │
                  └────┬────┘
                       │
              ┌────────┼────────┐
              ▼        ▼        ▼
             POD      POD      POD
              ▲        ▲        ▲
              └────────┼────────┘
                       │
                  ReplicaSet
                       ▲
                       │
                  Deployment
                       │
             desired replicas = 3


       CONFIGURAÇÃO                DADOS

        ConfigMap                   PVC
        Secrets                      │
                                     ▼
                                     PV
                                     │
                                     ▼
                                  STORAGE

E por trás disso existe o cluster:

CONTROL PLANE
      │
      ├── API Server
      ├── Scheduler
      ├── Controllers
      └── etcd
             │
             ▼
        WORKER NODES
             │
             ▼
           kubelet
             │
             ▼
             CRI
             │
       container runtime
             │
             ▼
            Pods

Finalmente o mistério começa a fazer sentido.


🏦 22. E onde entra o mainframe nessa aventura?

Aqui está talvez a parte mais interessante para quem está entrando nesse mundo vindo de COBOL, CICS, Db2 e z/OS.

Você não precisa apagar quarenta anos de conhecimento para aprender containers.

Muito pelo contrário.

Quem passou anos pensando em disponibilidade, processamento transacional, controle de acesso, recuperação, armazenamento, capacidade, versionamento e produção já possui uma enorme bagagem conceitual.

O segredo é não procurar equivalências literais.

Não diga:

CICS = Kubernetes
JES2 = Kubernetes
WLM = HPA
RACF = RBAC

Não são.

Mas use essas tecnologias como pontes cognitivas.

Você conhece a pergunta:

Quem pode executar isto?

Ótimo. Vamos conversar sobre RBAC.

Você conhece:

Onde os dados sobrevivem?

Excelente. Vamos falar de persistent storage.

Você pergunta:

O que acontece se esta execução morrer?

Bem-vindo ao desired state e reconciliation.

Você pergunta:

Como distribuir capacidade?

Vamos estudar scheduler, requests, limits e autoscaling.

Você pergunta:

Como colocar uma nova versão sem explodir produção?

Deployment, rolling updates, probes, observabilidade e estratégias de rollout estão esperando por você.

O veterano não chega vazio a Kubernetes.

Chega carregando décadas de perguntas extremamente úteis.


🚂 23. A viagem completa

Agora podemos reconstruir toda nossa investigação em uma única linha narrativa.

Tintin recebe:

SOURCE CODE

Cria:

Dockerfile

Produz:

IMAGE

Publica:

REGISTRY

Kubernetes referencia essa imagem.

Um:

Deployment

define o workload desejado.

Ele administra ReplicaSets que mantêm:

Pods

Esses Pods são alcançados por:

Service

Configuração chega através de mecanismos como:

ConfigMap
Secret

Dados persistentes podem utilizar:

PVC → PV → Storage

Saúde pode ser acompanhada com:

startup
readiness
liveness

Tráfego externo pode chegar através de:

Gateway API / Ingress

E escalabilidade horizontal pode envolver:

HPA

Isso já não parece uma coleção aleatória de palavras.

Parece uma arquitetura.


🔎 24. O que as excelentes ilustrações escondem

Os infográficos que iniciaram nossa investigação são ótimos para aquilo que considero a primeira passagem pelo território.

Você olha.

Reconhece os nomes.

Entende as relações.

Executa alguns comandos.

Constrói uma imagem.

Executa containers.

Cria um Compose.

Publica uma imagem.

Cria Pod.

Deployment.

Service.

PVC.

Ingress.

HPA.

Excelente.

Mas existe uma segunda passagem.

É nela que começamos a perguntar:

“Como isso funciona em produção?”

Então surgem novos personagens:

Namespaces
RBAC
ServiceAccounts
NetworkPolicy
requests/limits
taints
tolerations
affinity
anti-affinity
PodDisruptionBudget
StorageClass
CSI
Helm
Kustomize
observability
metrics
logging
tracing
GitOps
CI/CD
supply-chain security
image scanning
policy enforcement
Gateway API

E existe uma terceira passagem ainda mais interessante para nós:

Kubernetes + IBM Z + LinuxONE + OpenShift + z/OS

Aí a história deixa de ser simplesmente:

“mainframe versus cloud.”

Passa a ser:

“qual workload deve executar onde?”

Esse é um problema arquitetural muito mais adulto.


🚀 25. Bellacosa Containers 101 → 201 → 301

Eu transformaria todo esse material em uma trilha em três atos.

101 — Tintin descobre os containers: Linux essencial, Docker, imagens, containers, Dockerfile, registry, networking, volumes, environment variables, secrets e Compose.

201 — Tintin encontra Kubernetes: cluster, control plane, worker, kubectl, Pod, Deployment, ReplicaSet, Service, ConfigMap, Secret, PV/PVC, probes, requests/limits, Ingress, Gateway API e HPA.

301 — Tintin entra em produção: RBAC, namespaces, NetworkPolicy, CSI, Helm/Kustomize, observabilidade, segurança, CI/CD, GitOps, supply chain, OpenShift, LinuxONE/IBM Z e integração de workloads containerizados com serviços corporativos e z/OS.

O aluno poderia começar com:

docker run hello-world

e terminar compreendendo algo como:

Internet
   │
Gateway
   │
OpenShift/Kubernetes
   │
Containerized API
   │
MQ / REST
   │
z/OS Connect
   │
CICS
   │
COBOL
   │
Db2

Agora estamos falando a língua do Bellacosa Mainframe.


🏁 Epílogo — Tintin fecha o caderno

Depois de horas investigando containers, imagens, registries, Pods, Deployments, Services, Secrets e clusters, Capitão Haddock finalmente perguntou:

— Então Kubernetes substitui o mainframe?

Tintin fechou o caderno.

Milou olhou para Haddock.

Professor Girassol fingiu não ouvir.

E um velho programador COBOL sentado no canto começou a rir.

Porque essa era a pergunta errada.

Mainframes resolvem determinados problemas extraordinariamente bem.

Containers resolvem outros.

Kubernetes resolve um problema importantíssimo de orquestração e gerenciamento de workloads containerizados em escala.

E arquiteturas modernas podem combinar esses mundos.

A verdadeira habilidade do arquiteto não é escolher uma tecnologia para vencer uma guerra imaginária.

É saber onde cada workload pertence, como conectá-lo aos demais e como operar o conjunto com segurança, disponibilidade e previsibilidade.

Tintin guardou a lupa.

Haddock terminou o café.

Milou finalmente encontrou o container desaparecido.

E o veterano COBOL abriu um terminal e digitou:

kubectl get pods

Havia três.

bellacard-7f84c      Running
bellacard-2b17d      Running
bellacard-91a2e      Running

Deployment desejava três.

Produção tinha três.

Por alguns preciosos minutos, o universo estava em equilíbrio.

Até o telefone tocar.

Eram 03:17.

— Tintin... caiu produção.

Ele pegou o sobretudo.

— Milou, estamos diante de um novo caso.

☕ Bellacosa Mainframe — porque a tecnologia muda, mas produção continua encontrando maneiras criativas de acordar alguém de madrugada.




segunda-feira, 28 de janeiro de 2019

Docker e Kubernetes Muito Além do docker run e do kubectl apply

 

Bellacosa Mainframe apresenta docker e kubernetes

☕ Um Café no Bellacosa Mainframe

Docker e Kubernetes Muito Além do docker run e do kubectl apply

O Que Todo Programador COBOL Padawan Precisa Saber Sobre Containers, Orquestração, DevOps, Cloud, IBM Z e Como os Grandes Bancos Executam Milhares de Aplicações Sem Parar um Segundo

"O programador COBOL do século XXI não precisa abandonar o Mainframe. Precisa entender como o Mainframe conversa com o restante do mundo."


Introdução

Durante muitos anos, aprender informática significava instalar programas diretamente no computador.

Você colocava um CD.

Executava o instalador.

Clicava em "Avançar".

Esperava alguns minutos.

Pronto.

O software estava instalado.

O problema era que esse software passava a depender completamente daquele computador.

Se outro computador tivesse uma versão diferente do Windows...

Outra biblioteca...

Outro Java...

Outra configuração regional...

Outro driver...

Era comum ouvir uma frase que se tornou quase uma piada entre programadores.

"Na minha máquina funciona."

Essa frase custou bilhões de dólares para empresas no mundo inteiro.

Ela representa horas perdidas de suporte técnico, atrasos em projetos, ambientes inconsistentes, servidores quebrados e implantações malsucedidas.

Foi justamente para resolver esse problema que nasceu uma das tecnologias mais importantes da computação moderna: Docker.

Poucos anos depois surgiu outro desafio.

Tudo funcionava muito bem com um único container.

Mas e quando uma empresa possui:

  • 500 servidores;

  • 8.000 containers;

  • centenas de microsserviços;

  • milhões de clientes conectados simultaneamente?

Quem decide onde cada aplicação será executada?

Quem reinicia automaticamente uma aplicação que falhou?

Quem distribui a carga?

Quem aumenta automaticamente a quantidade de servidores durante a Black Friday?

Quem reduz essa infraestrutura durante a madrugada?

Essa resposta chama-se Kubernetes.

Hoje praticamente todas as grandes empresas utilizam Docker e Kubernetes de alguma forma.

Google.

Netflix.

Spotify.

Amazon.

IBM.

Microsoft.

Nubank.

Itaú.

Bradesco.

Santander.

BB.

Caixa.

E centenas de outras instituições financeiras.

Mas existe uma forma muito mais fácil de compreender tudo isso.

Vamos esquecer a nuvem por alguns minutos.

Vamos olhar para Docker e Kubernetes com os olhos de um Programador COBOL Padawan.


Antes do Docker

Imagine que você acabou de desenvolver um programa COBOL.

Você compilou.

Gerou o Load Module.

Tudo funcionou.

Agora outra equipe precisa executar exatamente o mesmo programa em outro ambiente.

Só que existe um problema.

O compilador é diferente.

As bibliotecas são diferentes.

O sistema operacional possui outra versão.

O banco de dados foi atualizado.

A variável de ambiente mudou.

O timezone é outro.

O locale também.

De repente...

O programa deixa de funcionar.

Não porque o código esteja errado.

Mas porque o ambiente mudou.

Foi exatamente esse problema que Docker resolveu.


O conceito mais importante

Docker não foi criado para substituir máquinas virtuais.

Nem servidores.

Nem sistemas operacionais.

Ele nasceu para encapsular uma aplicação junto com tudo aquilo que ela precisa para funcionar.

Imagine uma caixa.

Dentro dessa caixa existe:

  • sua aplicação;

  • bibliotecas;

  • dependências;

  • arquivos de configuração;

  • variáveis de ambiente;

  • versões corretas das ferramentas;

  • tudo pronto para execução.

Essa caixa recebe o nome de Container.


Uma analogia com o Mainframe

Imagine um programa COBOL.

Primeiro temos:

Programa Fonte

Depois:

Compilação

Depois:

Link Edit

Depois:

Load Module

Quando executamos:

//STEP01 EXEC PGM=PAGAMENT

O programa entra em execução.

Docker segue exatamente essa filosofia.

Você cria uma Imagem.

Depois executa essa imagem.

A imagem nunca muda.

Quem muda é a instância dela.

Essa instância chama-se Container.


Imagem não é Container

Este talvez seja o primeiro conceito que todo iniciante precisa aprender.

Muitas pessoas confundem.

Uma imagem é apenas um modelo.

Ela não está executando.

É semelhante a um Load Module armazenado em uma Load Library.

Já o container é o programa em execução.

Da mesma forma que um mesmo programa COBOL pode ser executado por vários JOBs simultaneamente, uma única imagem Docker pode originar diversos containers independentes.


O Dockerfile: o "JCL" do Mundo Docker

Se existe algo que lembra um JCL dentro do universo Docker, esse algo é o Dockerfile.

Ele descreve todas as etapas necessárias para construir uma imagem.

Exemplo:

FROM eclipse-temurin:21

WORKDIR /app

COPY . .

RUN mvn clean package

CMD ["java","-jar","app.jar"]

Observe que ele não executa imediatamente.

Ele apenas descreve como construir o ambiente.

É muito parecido com um procedimento documentando todas as etapas para gerar um executável.


Build: construindo a imagem

Quando executamos:

docker build -t banco-api .

Estamos dizendo:

"Leia o Dockerfile e construa uma imagem chamada banco-api."

Nada está rodando ainda.

Estamos apenas fabricando nosso executável.

É como executar uma compilação COBOL.


Run: finalmente executando

Agora sim.

docker run banco-api

A imagem transforma-se em um container.

O programa começa a executar.

Se executarmos novamente:

docker run banco-api

Outro container será criado.

A imagem continua exatamente igual.


Docker Client e Docker Daemon

Muita gente acredita que o comando docker faz todo o trabalho.

Na realidade, ele é apenas o cliente.

Quem realmente administra tudo é o Docker Daemon.

Quando digitamos:

docker ps

O terminal envia uma solicitação ao Daemon.

É o Daemon que lista os containers.

Quando digitamos:

docker stop

Quem encerra o container é o Daemon.

Quando criamos imagens.

Volumes.

Redes.

Quem faz tudo é ele.

O cliente apenas envia comandos.


Docker Hub: a "Load Library" da Internet

Imagine uma gigantesca biblioteca contendo milhões de programas prontos.

Ubuntu.

Debian.

PostgreSQL.

MySQL.

Redis.

MongoDB.

Nginx.

Apache.

Python.

Node.js.

Java.

Tudo disponível.

Esse repositório chama-se Docker Hub.

Ao executar:

docker pull postgres

Você baixa uma imagem pronta.

É semelhante a copiar um Load Module certificado para sua biblioteca de execução.


Volumes: onde moram os dados?

Aqui encontramos um dos erros mais comuns dos iniciantes.

Containers devem ser descartáveis.

Podem morrer.

Podem ser recriados.

Podem desaparecer.

Então onde ficam os dados?

Em um Volume.

Imagine um banco PostgreSQL.

Os dados nunca ficam dentro do container.

Eles ficam em um armazenamento externo.

O container pode ser destruído.

Os dados continuam intactos.

Para um programador COBOL, pense em um programa acessando um VSAM ou um Db2.

O programa pode terminar.

Os dados continuam armazenados.


Redes Docker

Outro conceito interessante.

Cada container recebe um endereço IP interno.

Docker cria uma rede virtual.

Aplicações podem conversar entre si.

Imagine:

Container WEB

↓

Container API

↓

Container Db2

↓

Container Redis

Cada um executando separadamente.

Mas todos conectados pela mesma rede.


Bridge, Host e Overlay

O driver Bridge é o padrão.

Ele cria uma rede privada.

Host elimina esse isolamento e utiliza diretamente a rede do servidor.

Overlay conecta containers distribuídos em vários servidores diferentes.

É justamente esse último que se torna extremamente importante quando entramos no universo Kubernetes.


O problema que Docker não resolve

Agora imagine um banco digital.

Existem:

  • 3.000 APIs;

  • 800 microsserviços;

  • 12.000 containers;

  • centenas de servidores Linux.

Docker sabe criar containers.

Mas não sabe decidir em qual servidor cada aplicação deverá executar.

Também não sabe reiniciar automaticamente aplicações que falharam.

Não sabe fazer escalabilidade automática.

Não sabe distribuir carga.

Não sabe realizar atualizações sem indisponibilidade.

É aqui que entra Kubernetes.


Kubernetes: o maestro da orquestra

Docker fabrica músicos.

Kubernetes rege a orquestra.

Ele observa milhares de containers simultaneamente.

Decide onde executar cada um.

Monitora falhas.

Redistribui carga.

Executa atualizações.

Realiza rollback.

Mantém sempre o ambiente funcionando.


O Control Plane

O cérebro do Kubernetes recebe esse nome.

Ele não executa aplicações.

Ele apenas toma decisões.

É semelhante a uma central de controle.

Tudo passa por ele.


API Server

Toda comunicação acontece através dele.

Quando executamos:

kubectl apply -f deployment.yaml

Na realidade estamos falando com o API Server.

Ele recebe a solicitação.

Valida.

Armazena.

Distribui.


etcd: a memória do cluster

O Kubernetes precisa lembrar de tudo.

Quantos Pods existem.

Quais aplicações estão instaladas.

Quem possui acesso.

Quais Secrets foram criados.

Tudo isso fica armazenado no etcd.

Ele funciona como um banco de dados extremamente rápido.


Scheduler

Imagine cinco servidores disponíveis.

Qual deles possui CPU suficiente?

Qual possui memória livre?

Qual atende às restrições?

Quem decide?

Scheduler.

Ele analisa dezenas de parâmetros antes de escolher o melhor destino.


Worker Nodes

São os servidores que realmente executam os containers.

Podemos ter:

Node 1

Node 2

Node 3

Node 4

Node 5

Todos trabalhando simultaneamente.


Pods: a menor unidade

Muitos acreditam que Kubernetes executa containers.

Na verdade, ele executa Pods.

Um Pod normalmente contém um container.

Mas pode conter vários.

Eles compartilham rede.

Compartilham armazenamento.

Compartilham ciclo de vida.


Deployments

Suponha que desejamos dez Pods.

Criamos um Deployment.

Ele monitora continuamente.

Se um Pod morrer.

Outro nasce automaticamente.

Sem intervenção humana.


ReplicaSets

O Deployment utiliza ReplicaSets.

Sua missão é simples.

Garantir que o número desejado de Pods permaneça constante.


Services

Pods mudam constantemente.

São criados.

Destruídos.

Reiniciados.

Logo, seus endereços IP mudam.

Não podemos depender deles.

Criamos então um Service.

Ele fornece:

  • endereço fixo;

  • DNS;

  • balanceamento de carga.

As aplicações conversam com o Service.

Jamais diretamente com o Pod.


ConfigMaps

Imagine alterar a URL do banco de dados.

Você precisaria recompilar toda a aplicação?

Não.

Basta modificar um ConfigMap.

Ele armazena configurações externas.


Secrets

Senhas jamais devem ficar escritas no código.

Secrets armazenam:

  • senhas;

  • certificados;

  • tokens;

  • chaves de API.

Tudo de forma protegida.


Rolling Update

Uma das maiores vantagens do Kubernetes.

Imagine atualizar um sistema bancário.

Antigamente seria necessário interromper o serviço.

Hoje não.

O Kubernetes substitui Pods gradualmente.

Usuários praticamente não percebem.


Rollback

A atualização apresentou defeito?

Em segundos retornamos para a versão anterior.

Tudo automaticamente.


Auto Scaling

Imagine um PIX viralizando durante uma promoção.

O número de acessos dispara.

Kubernetes identifica o aumento.

Cria novos Pods.

Quando a demanda diminui.

Remove os Pods excedentes.

Tudo sem intervenção humana.


Onde entra o IBM Z?

Aqui está um ponto que muitos profissionais desconhecem.

Docker e Kubernetes não vieram substituir o Mainframe.

Vieram complementá-lo.

Hoje é extremamente comum encontrar arquiteturas como:

Aplicativo Mobile

↓

API Gateway

↓

Kubernetes

↓

Microsserviços Java

↓

IBM MQ

↓

z/OS Connect

↓

CICS

↓

COBOL

↓

Db2

Observe que o COBOL continua executando exatamente onde sempre esteve.

A diferença é que agora ele conversa com aplicações modernas executando em containers.


O papel do OpenShift

A Red Hat, empresa pertencente à IBM, criou o OpenShift.

Ele utiliza Kubernetes como base.

Mas adiciona recursos corporativos.

Autenticação.

Segurança.

Monitoramento.

Registro de imagens.

Pipelines CI/CD.

Console gráfico.

Integração com IBM Z.

É hoje uma das plataformas mais utilizadas em ambientes financeiros.


O futuro do Programador COBOL

Existe um enorme equívoco no mercado.

Muitos imaginam que aprender Docker significa abandonar COBOL.

Na realidade acontece exatamente o contrário.

Quanto mais modernas ficam as arquiteturas, maior é a necessidade de integrar sistemas novos com sistemas legados.

O conhecimento em COBOL passa a ter ainda mais valor quando combinado com:

  • Docker;

  • Kubernetes;

  • Git;

  • DevOps;

  • APIs REST;

  • OpenShift;

  • IBM MQ;

  • z/OS Connect;

  • observabilidade;

  • automação.

O profissional deixa de ser apenas um programador.

Passa a ser um engenheiro de software capaz de compreender toda a cadeia de processamento.


Conclusão

Docker e Kubernetes representam uma mudança profunda na maneira como desenvolvemos, distribuímos e operamos aplicações.

Docker resolveu um problema antigo: garantir que uma aplicação funcione da mesma forma em qualquer ambiente, empacotando código, bibliotecas e dependências em containers leves, portáveis e reproduzíveis.

Kubernetes levou essa ideia a um novo patamar, automatizando a implantação, a recuperação de falhas, o balanceamento de carga, as atualizações e a escalabilidade de milhares de containers distribuídos por diversos servidores.

Para o Programador COBOL Padawan, esses conceitos não são estranhos. Eles dialogam diretamente com ideias já conhecidas do universo IBM Mainframe: a disciplina do JCL, a confiabilidade do z/OS, a persistência do Db2 e do VSAM, a automação do IBM Z Workload Scheduler, a integração via IBM MQ e a alta disponibilidade que sempre caracterizou os grandes ambientes corporativos.

O mundo da tecnologia não está abandonando o Mainframe; está construindo uma ponte entre décadas de confiabilidade e as novas arquiteturas baseadas em microsserviços, containers e computação em nuvem. Entender Docker e Kubernetes é aprender a atravessar essa ponte.

O COBOL continua processando bilhões de transações diariamente. A diferença é que, agora, muitas dessas transações começam em um aplicativo móvel, passam por APIs executadas em containers orquestrados pelo Kubernetes e chegam ao IBM Z com a mesma robustez e segurança que sustentam o mercado financeiro há mais de meio século.

E talvez essa seja a maior lição deste café no Bellacosa Mainframe: as tecnologias mudam, as ferramentas evoluem, mas os princípios da boa engenharia de software — padronização, automação, confiabilidade e simplicidade — permanecem os mesmos. Quem domina esses princípios estará preparado para programar tanto no legado quanto no futuro.


Vagner Renato Bellacosa, IBM Champion e especialista em IBM Mainframe
IBM Z17 SYSTEM ONLINE
Sobre o autor

Vagner Renato Bellacosa

IBM Champion 2026 • Especialista em IBM Mainframe

Vagner Renato Bellacosa trabalha com IBM Mainframe desde 1988 , é IBM Champion e especialista em COBOL, CICS, Db2, z/OS e IBM Z. Compartilha experiências profissionais, conhecimento técnico, história da computação e práticas do universo mainframe para aproximar novas gerações das tecnologias que sustentam empresas, bancos e governos ao redor do mundo.

IBM Champion IBM Z COBOL CICS Db2 z/OS Mainframe desde 1988
GitHub LinkedIn
Inicializando conteúdo...