Category: Contentores de aplicações

Esta categoria ajuda a executar programas em isolamento, evitar conflitos e fazer rollbacks. Damos prática do “approach” de contentorização doméstica.

  • Ambientes limpos e previsíveis: crie, atualize e reverta contentores com segurança e mínimo esforço

    Ambientes limpos e previsíveis: crie, atualize e reverta contentores com segurança e mínimo esforço

    Trabalhar com contentores em 2024–2025 é transformar o ciclo “build → run → atualizar → reverter” em algo previsível, limpo e observável. O objetivo não é apenas empacotar a app: é encurtar builds, fixar dependências, reduzir superfície de ataque, separar dados de runtime e manter atualizações e rollbacks como ações de baixo risco. Este guia é prático e direto. Explica como produzir imagens pequenas e repetíveis, executar com segurança e limites claros, isolar rede e segredos, atualizar sem tempo de indisponibilidade e voltar atrás em segundos quando algo foge do esperado. A linha condutora é “limpeza e ordem”: menos camadas, menos privilégios, menos surpresas.

    Imagens pequenas, reproduzíveis e fáceis de auditar

    Comece por uma base minimalista adequada à sua stack, preferindo variantes “slim”, distroless ou runtime-only para reduzir tamanho e CVEs. Congele versões de sistema e de pacotes no build para evitar variações invisíveis entre ambientes. Use multi-stage build para compilar numa imagem rica e copiar apenas binários e artefactos finais para a imagem de produção. Garanta reprodutibilidade definindo timezone, locale e ordens de cópia estáveis, e evite “apt upgrade” genérico; instale só o necessário. Crie um utilizador não root no build e defina-o como padrão na imagem final. Adicione um healthcheck simples que prove que o processo principal responde, em vez de apenas verificar se a porta está aberta. Gere e publique um SBOM junto com a imagem e integre uma etapa de scan no pipeline para bloquear bibliotecas vulneráveis antes de irem ao registo. Etiquete imagens com esquema consistente de versão e commit, adotando tags imutáveis para releases e reservando “latest” apenas para desenvolvimento local.

    Execução segura e com limites claros de recursos

    Ao executar, privilegie mínimos privilégios. Evite root, monte o sistema de ficheiros como read-only e só escreva em volumes explícitos. Remova capabilities desnecessárias e desligue a partilha do PID e IPC com o host se não precisa. Defina limites de CPU e memória compatíveis com o perfil da app, e estabeleça reservas para impedir competição agressiva em hosts partilhados. Use políticas de reinício que diferenciem falhas transitórias de crash loops, e mantenha logs a sair para stdout e stderr para coleta centralizada; não escreva logs intermináveis dentro do contentor. Para jobs de curta duração, prefira contentores efémeros que arrancam, trabalham e terminam, mantendo o host limpo de processos órfãos. Se a aplicação spawna sub-processos, confirme que o PID 1 reencaminha sinais e reaprove zumbis corretamente, garantindo shutdowns rápidos e previsíveis em deploys e reverts.

    Rede, dados persistentes e segredos fora da imagem

    Separe o tráfego entre serviços em redes virtuais internas e exponha portas ao exterior apenas no ponto de entrada. Evite publicar em 0.0.0.0 quando não é necessário e use nomes de serviço para descoberta interna, reduzindo acoplamento a IPs. Os dados pertencem a volumes, não à imagem; defina um layout simples com diretórios de escrita claros e faça backups a partir dos volumes, não do sistema de ficheiros do contentor. Para migrações de base de dados, acople o ciclo ao deploy com uma etapa controlada que execute scripts idempotentes antes de expor a nova versão. Segredos nunca devem viver em variáveis de ambiente permanentes ou em ficheiros dentro da imagem. Use mecanismos nativos de secrets e injete-os apenas em runtime, com permissões mínimas e rotação periódica. Em ambientes híbridos, isole contentores que falam com redes locais e aplique firewalls por host para conter movimentos laterais.

    Atualizações previsíveis e reversões em segundos

    Trate cada release como um conjunto versionado de imagem, configuração e migrações. Promova a mesma imagem entre ambientes, alterando apenas variáveis e endpoints, para evitar “funciona na pré, falha na prod”. Em ambientes de uma só máquina, faça rolling com duas pilhas lógicas: suba a nova pilha em portas internas, passe healthchecks, troque o tráfego através do proxy e desligue a antiga depois do período de observação. Em clusters, use rollouts com limites de replicas simultâneas, janelas de readiness e probes de liveness afinadas; canary gradual reduz risco em alterações grandes. A reversão precisa de estar ensaiada: mantenha ao menos duas versões prontas a arrancar, registe o comando de rollback no runbook e garanta que voltar atrás não tenta refazer migrações destrutivas. Evite dependências escondidas em “latest” no registo; fixe digests ou tags de release, expira artefactos antigos com política de retenção e limpe imagens não utilizadas no host para manter discos e caches saudáveis.

    Pipeline, registo e observabilidade que evitam surpresas

    Automatize o ciclo build-push-scan-assinar-implantar. Cada commit que toca código ou Dockerfile deve produzir uma imagem, gerar SBOM, passar por scans e receber assinatura de proveniência. Publique em registo privado com papéis claros de leitura e escrita, políticas de retenção e replicação entre regiões quando necessário. No arranque, exponha métricas e sirva um endpoint de health interno que reflete dependências essenciais como base de dados e filas. Consolide logs com correlação de request ID entre serviços para facilitar diagnósticos. Monitore consumo de CPU, memória e IO por contentor, alertando por tendências e não só por picos. Documente em poucas linhas como subir localmente, como parametrizar credenciais, como executar migrações e como reverter. Esta documentação viva evita “herança tribal” e reduz o tempo de recuperação quando algo falha no pior momento.

     

  • Execução previsível e segura: padronize contentores, evite conflitos e mantenha ambientes estáveis

    Execução previsível e segura: padronize contentores, evite conflitos e mantenha ambientes estáveis

    Estabilidade em contentores é resultado de previsibilidade: builds repetíveis, execução com limites claros, dependências explícitas, observabilidade simples e rotinas de manutenção que não dependem de heróis. Em 2024–2025, dá para atingir isso sem complicar: imagens pequenas e reproduzíveis, execução sem privilégios, rede e dados isolados, atualizações que não derrubam o serviço e rollbacks que cabem num comando. O objetivo deste guia é prático: padronizar ambientes, evitar conflitos e manter o host limpo, para que “arrancar e otimizar” signifique, na prática, menos incidentes e recuperação mais rápida quando algo falha.

    Imagens reprodutíveis e pequenas: menos variação, menos CVEs

    Comece pelo Dockerfile ou equivalente com multi-stage build: compilar numa imagem “cheia” e copiar só os artefactos para uma base minimal (slim, distroless ou runtime-only). Fixe versões do SO e de bibliotecas; não use comandos de atualização genéricos que variam a cada build. Defina USER não-root e mantenha o sistema de ficheiros em read-only, escrevendo apenas em volumes claramente montados. Ordene cópias e instalações para maximizar cache, documente variáveis de ambiente e escolha um único diretório de trabalho. Gere um SBOM a cada build e integre scan de vulnerabilidades no pipeline, bloqueando versões com CVEs críticos antes de subir ao registo. Etiquete imagens com esquema estável (ex.: app:1.8.2 e app:1.8.2-), usando digests em produção para evitar “latest” enganadores.

    Execução previsível: limites, sinais e isolamento

    No runtime, privilegie o mínimo de privilégios. Remova capabilities que não precisa, desligue privilégios elevados e isole PID/IPC do host. Aplique limites de CPU e memória compatíveis com o perfil real; reserve também recursos quando possível para evitar contendas. Garanta que o processo PID 1 gere sinais corretamente e “recolhe” zumbis; um init leve (tini) resolve muitos shutdowns lentos. Mantenha healthchecks que testem a app a sério (consulta a endpoint interno ou comando de verificação), em vez de apenas “porta aberta”. Redirecione logs para stdout/stderr em formato estruturado e deixe a rotação para o daemon/sidecar; não escreva logs infinitos no disco do contentor. Para jobs efémeros, use contentores que arrancam, trabalham e terminam, evitando processos órfãos e diretórios sujos.

    Rede, dados e segredos: cada coisa no seu lugar

    Trate a rede como fronteira de estabilidade. Use redes virtuais internas para comunicação entre serviços e exponha ao exterior apenas através de um proxy/reverso. Evite publicar portas em 0.0.0.0 sem necessidade e prefira nomes de serviço em vez de IPs para reduzir acoplamento. Dados são responsabilidade de volumes, não de imagens: defina caminhos de escrita explícitos, use volumes com backup e versionamento, e separe configuração de estado para facilitar rollbacks. Migrações de base devem ser idempotentes e executadas antes de expor a nova versão; se houver passos destrutivos, faça “expandir → migrar → cortar” com compatibilidade temporária. Segredos nunca vivem na imagem nem em repositórios; injete-os via mecanismos de secrets do runtime, com escopo mínimo e rotação periódica. Para diretórios temporários, monte tmpfs e limite tamanho para evitar encher discos por engano.

    Atualizações seguras e reversão em segundos

    Promova a mesma imagem entre dev, staging e produção, alterando apenas variáveis e endpoints. Em uma única máquina, faça blue/green: levante a nova pilha em portas internas, passe readiness, troque o tráfego no proxy e mantenha a antiga “em espera” por alguns minutos. Em clusters, use rollouts graduais com limites de réplicas atualizadas, janelas de readiness e backoff em falhas; canary ajuda a detectar regressões cedo. Defina tempos de terminationGracePeriod compatíveis com shutdown limpo e configure liveness só depois de ter readiness afinado, para não matar instâncias em arranques lentos. Tenha um comando de rollback documentado e testado; guardar as duas últimas versões prontas a arrancar reduz o MTTR para segundos. Evite dependências em “latest” no registo; fixe digests e implemente retenção automática para imagens antigas, além de limpeza de camadas não usadas no host.

    Observabilidade e higiene contínua: estabilidade que se renova

    Exponha métricas básicas (latência, taxa de erro, filas, uso de CPU/memória/IO) e um endpoint de health que reflete dependências essenciais. Correlacione logs com um request_id de entrada para atravessar serviços. Alerta por tendência, não só por pico: crescimento de uso de memória ou de “restarts” é sinal de fuga ou limites mal ajustados. No host, agende “prune” seguro de imagens sem referência, volumes órfãos e caches antigos; em registos privados, ative políticas de retenção e assinatura/proveniência. Documente em poucas linhas como correr localmente, como parametrizar credenciais, como executar migrações e como reverter; documentação viva reduz dependência de conhecimento tácito. Uma revisão quinzenal que passa por scans, tamanhos de imagens, tempos de arranque, taxas de falha de healthcheck e consumo médio por serviço mantém a plataforma previsível e o custo sob controlo.