Otimizando Tamanho de Imagens Docker para Kubernetes

Imagens Docker gigantes são um problema silencioso em ambientes Kubernetes. Você já parou para pensar quanto tempo e banda estão sendo gastos puxando uma imagem de 2GB para cada novo deployment? Neste post, vou compartilhar estratégias práticas para reduzir o tamanho das suas imagens sem sacrificar funcionalidade.

O que é otimização de imagens de container?

É o processo de reduzir o tamanho do arquivo (layer) de uma imagem Docker mantendo toda a funcionalidade necessária. Uma imagem menor significa pulls mais rápidos, menos consumo de armazenamento no registry e deploys mais eficientes em Kubernetes.

Por que isso importa em Kubernetes?

Em um cluster Kubernetes, você pode ter dezenas ou centenas de nodes. Quando você faz um deploy de uma nova versão, o kubelet precisa fazer o pull da imagem. Uma imagem de 500MB vs. 100MB não parece grande diferença, mas multiplique por 50 nodes e você está falando de 20GB de transferência versus 5GB.

Sem contar que imagens menores consomem menos espaço em disco nos nodes, deixam menos margem para node pressure, e tornam o scaling mais ágil.

Leia mais »

State Lock API no Kubernetes: Coordenação e Eleição de Líder

Em sistemas distribuídos, é comum precisar garantir que apenas uma instância de um serviço execute uma tarefa crítica — seja backup, sincronização de dados ou processamento de eventos. O Kubernetes oferece a State Lock API exatamente para isso: coordenação segura entre múltiplos pods.

Neste post, vamos entender como usar State Lock API, quando usá-la, compará-la com outras abordagens e implementar um exemplo prático.

O que é State Lock API?

A State Lock API do Kubernetes (via leaderelection) é um mecanismo que permite que múltiplas réplicas de um aplicativo coordenem entre si para eleger um “líder” — uma única instância responsável por executar tarefas críticas.

Ela funciona através de:

  • Recurso ConfigMap ou Lease: armazena informações sobre quem é o líder
  • Renovação periódica: o líder renova seu “lock” em intervalos regulares
  • Eleição automática: se o líder falhar, outro pod toma o lugar
Leia mais »

Novo new() com expressão inicial no Go 1.26

Neste post, vamos explorar uma mudança pequena, mas poderosa, que chegou no Go 1.26: o built-in new() agora aceita uma expressão como valor inicial. Pode parecer um detalhe, mas simplifica inicializações e abre espaço para padrões de código mais elegantes.

O que é o built-in new()?

O new() é uma função built-in que aloca memória para um tipo e retorna um ponteiro inicializado com o valor zero do tipo. Historicamente, você só podia passar um tipo para new().

Como era antes (Go 1.25 e anteriores)

Antes, se você quisesse alocar memória e inicializar com um valor específico, tinha duas opções:

// Opção 1: alocar e depois atribuir
p := new(int)
*p = 42

// Opção 2: usar composição literal com &
p := &int{42}  // Só funciona com tipos estruturados
Leia mais »

Quality of Service (QoS) no Kubernetes

Quando você coloca uma aplicação em produção no Kubernetes, uma das decisões mais importantes é como especificar os recursos que seus pods precisam. Essa escolha determina qual classe de Quality of Service (QoS) seu pod recebe — e isso impacta diretamente na sua estabilidade e custo. Neste post, vou explicar em detalhe os três níveis de QoS: Guaranteed, Burstable e BestEffort.

O que é QoS no Kubernetes?

QoS (Quality of Service) é um mecanismo que o Kubernetes usa para classificar e priorizar seus pods em relação ao uso de recursos. Quando o nó está sem memória ou CPU disponível, o Kubernetes usa a classe QoS para decidir qual pod será removido (evicted) ou compactado.

O Kubernetes define três classes de QoS:

  • BestEffort — mínima prioridade, primeira a ser removida
  • Burstable — prioridade média, removida após Guaranteed
  • Guaranteed — máxima prioridade, última a ser removida

Qual classe seu pod recebe depende de como você especifica os requests e limits de CPU e memória.

QoS BestEffort: Máxima Flexibilidade, Sem Garantias

Um pod é classificado como BestEffort quando:

  • Você não define requests nem limits de CPU ou memória
  • É a situação padrão quando você simplesmente não especifica nada
Leia mais »

O que é TinyGo?

Neste post, vou explicar o que é TinyGo, por que você deveria conhecer e como começar com um exemplo bem simples. Se você nunca ouviu falar em TinyGo ou simplesmente quer entender esse universo de programação para microcontroladores, esse post é para você.

O que é TinyGo?

TinyGo é um compilador Go otimizado para ambientes com recursos limitados. Enquanto a linguagem Go tradicional foi criada para sistemas desktop, como CLIs, e servidores, como aplicações cloud, o TinyGo permite que você escreva código Go para rodar em microcontroladores e pequenos dispositivos.

A ideia é simples: leve a simplicidade e a elegância do Go para o mundo do IoT (Internet das Coisas) e sistemas embarcados.

Leia mais »

Go 1.26.2: Patches de Segurança

Go 1.26.2 foi lançado em 7 de abril com patches críticos de segurança no compilador, crypto/tls, crypto/x509, html/template e os. Neste post, vamos entender por que essa atualização é importante e como você pode acompanhar esses advisories de forma proativa.

Por que atualizar para Go 1.26.2?

Atualizar rapidamente quando patches de segurança saem é uma das coisas mais importantes que você pode fazer como engenheiro. Não estou falando de features novas — estou falando de brechas de segurança que podem comprometer toda a sua infraestrutura.

Go publica patches de segurança em ciclos regulares, e quando saem, é porque uma vulnerabilidade real foi descoberta e já está documentada. Esperar “até o próximo ciclo” é arriscar demais.

Leia mais »
goroutine leaks no go 1.26

Detectando goroutine leaks no Go 1.26

Se você já trabalhou com Go em produção, provavelmente já enfrentou aquele cenário: goroutines que ficam presas para sempre, consumindo memória sem nunca terminar. O Go 1.26 trouxe uma ferramenta experimental que ataca esse problema direto na raiz: o goroutine leak profile.

O que são goroutine leaks?

Uma goroutine leak acontece quando uma goroutine fica bloqueada permanentemente — esperando em um channel, mutex ou condition variable que nunca vai ser desbloqueado. Na prática, é memória e recursos que ficam presos sem possibilidade de liberação.

O cenário mais clássico: você cria uma goroutine que escreve em um channel sem buffer, mas a função que deveria ler esse channel retorna antes por conta de um erro. A goroutine fica ali, bloqueada para sempre.

Leia mais »

In-Place Pod Resize — redimensionando sem restart

Se você trabalha com Kubernetes em produção, sabe que ajustar recursos de CPU e memória geralmente significa recriar os pods. Neste post, vamos explorar o In-Place Pod Resize, um recurso que permite redimensionar containers sem perder o uptime.

O que é In-Place Pod Resize?

In-Place Pod Resize é uma funcionalidade do Kubernetes que permite alterar os requests e limits de CPU e memória de um container enquanto o pod continua rodando. Não há reinicialização, sem downtime, sem interrupção de conexões.

Antes dessa feature, a única forma era deletar e recriar o pod com novos valores — algo impraticável em ambientes críticos.

Por que isso importa?

Imagine este cenário: você subiu uma aplicação com 256Mi de memória, achando que era suficiente. Alguns dias depois, monitoramento mostra que está usando 400Mi, próximo ao limite. Você precisa aumentar — e rápido.

Leia mais »

Entendendo o Green Tea GC do Go 1.26

Go 1.26 trouxe uma das maiores mudanças no runtime dos últimos anos: o Green Tea garbage collector agora vem habilitado por padrão. Nesse post, vamos entender o que mudou, por que isso importa e o que esperar na prática.

O que é o Green Tea GC?

O Green Tea GC é uma reformulação do garbage collector do Go. Ele mantém a mesma abordagem mark-sweep do GC anterior, mas muda fundamentalmente a forma como os objetos são rastreados e escaneados.

A diferença principal: em vez de operar objeto por objeto espalhado pelo heap, o Green Tea trabalha no nível de páginas de memória. Ele agrupa objetos em blocos contíguos de 8 KiB chamados spans e escaneia vários objetos de uma vez dentro do mesmo span.

Leia mais »

Como Go 1.25 e 1.26 reduzem a pressão no GC

Nesse post, vamos entender uma das otimizações mais interessantes das últimas versões do Go: a capacidade do compilador de alocar slices na stack em mais cenários — sem você precisar mudar uma linha de código.

O problema: heap allocation e o GC

Em Go, cada variável precisa ser alocada em algum lugar: na stack (pilha) ou na heap. A stack é rápida — alocar e liberar memória lá é praticamente gratuito. Já a heap é gerenciada pelo garbage collector, o que tem um custo: quanto mais você aloca no heap, mais trabalho o GC tem para fazer.

O compilador do Go usa uma técnica chamada escape analysis para decidir onde cada variável vai parar. Se ele consegue provar que uma variável não vai “escapar” do escopo da função, ele a coloca na stack. Caso contrário, ela vai para o heap.

O problema é que essa análise é conservadora: em muitos casos práticos, como acumular elementos em um slice dentro de um loop, o compilador não tinha certeza se o slice ia escapar ou não e alocava no heap por precaução.

Leia mais »