Build na VPS ou no CI: qual escolher para o deploy não derrubar a aplicação?

Ilustração comparando servidor VPS e pipeline de CI durante o processo de build

Fala aí, beleza? Se tu já viu a aplicação cair justo na hora do deploy, a culpa pode não ser do código, e sim de onde ele está sendo compilado 🙂

O cenário aqui é bem específico: app rodando em container numa VPS e o build disputando CPU e memória com ela no mesmo servidor, no momento em que tu sobe a versão nova

E por que isso derruba tudo?

Porque, segundo a documentação de limites de recursos do Docker, um container não tem limite de memória nem de CPU por padrão: ele pode usar tudo o que o agendador do kernel do host permitir

Aí entra o problema sério: no Linux, quando falta memória para funções importantes do sistema, o kernel lança um OOME (Out Of Memory Exception) e começa a matar processos

Pode ser qualquer processo, inclusive o daemon do Docker, o que pode derrubar o sistema inteiro

E se liga nesse detalhe: a prioridade OOM do daemon é ajustada, a dos containers não

Ou seja, entre o daemon e o container da tua aplicação, quem tem MAIS chance de morrer é o container, exatamente por não ter essa prioridade ajustada

Build na VPS ou no CI: diferenças em recursos, custo e risco

A diferença central é onde a compilação gasta CPU e RAM: no mesmo servidor que atende os usuários ou numa máquina separada que existe só pra isso

Os números do runner abaixo vêm da documentação dos runners hospedados do GitHub, consultada em 20/10/2026

Critério Build na VPS Build no CI (GitHub Actions)
Onde a compilação consome CPU e RAM No servidor de produção, junto com a aplicação No runner, fora da VPS
Recursos disponíveis para o build O que sobrar da VPS enquanto o app roda Runner Linux padrão: 4 CPUs, 16 GB de RAM e 14 GB de SSD em repositório público; 2 CPUs, 8 GB de RAM e 14 GB de SSD em repositório privado
Custo da compilação Já incluso no servidor que tu paga Grátis e ilimitado em repositório público; em privado consome a cota de minutos gratuitos da conta e depois é cobrado por minuto
Para onde vai o artefato Imagem local, no próprio servidor Imagem publicada no registry, como ghcr.io/NAMESPACE/IMAGE_NAME:TAG
O que a VPS precisa executar Build completo e depois subir o container Baixar a imagem pronta e subir o container
Principal risco Build e app brigando por memória, com chance de OOME Configuração do pipeline e autenticação no registry

Repara que não tem linha de tempo de build nem de uptime na tabela

Isso depende do teu projeto e eu não vou chutar número 😛

Quando faz sentido compilar direto na VPS

Compilar no servidor é aceitável quando tu sabe quanto o build consome e o host tem folga para isso sem roubar memória da aplicação

Pensa em projeto pequeno, servidor com recursos de sobra ou ambiente onde uma queda rápida no deploy não é o fim do mundo

Mesmo assim, a documentação do Docker lista, entre os cuidados contra instabilidade por falta de memória:

  • Testar a memória que a aplicação precisa antes de ir para produção
  • Rodar em hosts com recursos adequados
  • Limitar a memória do container
  • Tomar cuidado ao configurar swap no host

O terceiro item tu resolve direto no Compose

A referência de deploy do Compose aceita deploy.resources com dois blocos: limits, que é o teto, e reservations, que é o mínimo garantido

Os dois aceitam cpus (em núcleos) e memory (string de bytes, tipo 50M)

O exemplo abaixo é didático e usa os mesmos valores do exemplo da documentação, não é um teste que eu rodei:

services:
  app:
    image: minha-app:latest
    deploy:
      resources:
        limits:
          cpus: '0.50'
          memory: 50M
        reservations:
          cpus: '0.25'
          memory: 20M

Tome cuidado! Esses valores são pequenos de propósito, servem pra mostrar o formato

O número certo pra tua aplicação sai da medição, não de copiar o exemplo

Se tu sobe containers com docker run, a lógica é a mesma: a opção --cpus=<valor> define quanto da CPU disponível o container pode usar

Para memória, o Docker aceita limite rígido (hard), que o container não ultrapassa, e limite flexível (soft), e os valores aceitam os sufixos b, k, m e g

Se tu está montando esse fluxo do zero, o guia sobre hospedar Bun com Docker na VPS mostra a parte de subir a aplicação em container no servidor

Como tirar o build da VPS com GitHub Actions e registry

A ideia é simples: o runner compila, publica a imagem num registry e a VPS só baixa a imagem pronta e sobe o container

É como pedir comida pronta em vez de montar a cozinha inteira na sala onde a família está jantando haha

No runner, o trabalho fica com três actions do Docker, documentadas no repositório da docker/build-push-action:

  1. docker/setup-buildx-action prepara o Buildx, que usa o driver docker-container por padrão
  2. docker/login-action faz o login no registry
  3. docker/build-push-action faz o build e o push da imagem com Buildx (com suporte a multi-plataforma, secrets e cache remoto) e, por padrão, usa o contexto Git

Não vou fixar versão de nenhuma delas aqui, confere a major atual no repositório de cada action antes de escrever teu workflow

O destino da imagem pode ser o GitHub Container Registry, no formato ghcr.io/NAMESPACE/IMAGE_NAME:TAG

Segundo a documentação do GitHub Container Registry, dentro das Actions dá para autenticar com o registry ghcr.io, usuário github.actor e senha secrets.GITHUB_TOKEN

Caso o push falhe por permissão: o GITHUB_TOKEN precisa da permissão packages: write para publicar a imagem

permissions:
  packages: write

E na VPS?

Aí sobra pouco trabalho, que é exatamente o objetivo

O docker compose up cria e inicia os containers, o -d roda em segundo plano e o --pull controla quando baixar as imagens, aceitando always, missing ou never

docker compose up -d --pull always

Com always, o Compose busca a imagem no registry toda vez, o que casa bem com o fluxo de publicar uma tag nova a cada build

Multi-stage build: a imagem final sem as ferramentas de compilação

O multi-stage build é o que deixa essa imagem enxuta

Cada FROM no Dockerfile inicia um estágio, tu nomeia o estágio com AS e copia só o artefato com COPY --from

O esqueleto abaixo usa placeholders, porque a imagem base e o comando de build mudam de stack pra stack:

FROM <imagem-com-sdk> AS build
# instala dependências e compila aqui

FROM <imagem-de-execucao>
COPY --from=build <caminho-do-artefato> <destino>

O SDK e os arquivos intermediários ficam no primeiro estágio e não vão para a imagem final

Resultado: a VPS baixa e executa só o necessário pra rodar, nada de ferramenta de build ocupando espaço no servidor =)

Por que testar o build antes do deploy evita esse problema

Quando um app é construído com ajuda de IA, é comum pular o build local e só descobrir um erro de compilação na hora de subir pra produção

Se isso acontece bem no momento do deploy, o ideal é tratar o erro num ambiente que não seja a produção, e não deixar o build brigar por recursos com a aplicação que já está no ar

É exatamente o ponto que este artigo defende: separar onde o build roda de onde a aplicação roda evita que um problema de compilação, ou de recursos, derrube quem já está em produção

Se tu quer ver um fluxo completo de projeto full stack com IA indo até o deploy em VPS, dá uma olhada neste vídeo do canal:

Conteúdo complementar do Hora de Codar para conhecer o canal; não é uma demonstração específica desta notícia ou versão.

Veredito: qual caminho escolher para o seu perfil

Não existe resposta única, depende do repositório e da folga de memória do teu servidor

  • Repositório público com VPS enxuta: CI, sem pensar muito. O runner padrão tem 4 CPUs e 16 GB de RAM, é grátis e ilimitado nesse caso, e a VPS fica livre pra só executar
  • Repositório privado: o runner cai para 2 CPUs e 8 GB e consome a cota de minutos gratuitos, depois cobra por minuto. Pesa esse custo contra a folga de memória que a tua VPS tem durante o build
  • Build na VPS: só com limites de memória e CPU configurados e com o consumo do build medido antes. Sem isso, tu está apostando que o OOME não vai escolher o container da aplicação

Para hospedar a parte de execução, a recomendação principal da Hora de Codar é a VPS da Hostinger (aviso: este artigo contém links de afiliado da Hostinger)

O motivo é técnico: segundo a página oficial da linha VPS, consultada em 20/10/2026, ela traz virtualização KVM, acesso root completo, armazenamento NVMe SSD, processadores AMD EPYC, backups semanais automáticos e snapshot manual

O acesso root é o que te deixa instalar Docker, configurar limites e rodar o docker compose up -d --pull always do jeito que tu quiser

E o snapshot manual entra justamente antes de um deploy arriscado: tira o snapshot, sobe a versão nova e, se der ruim, tu tem um ponto de volta

Esses são recursos gerais da linha VPS, não especificação de um plano específico, então confere CPU, RAM e disco do plano antes de contratar

Próximo passo: medir a memória do build antes de mudar o pipeline

Antes de reescrever o pipeline, mede quanto o teu build atual consome de memória e CPU no servidor

Com esse número na mão, a decisão fica objetiva: se cabe com folga ao lado da aplicação, tu configura limits e reservations no Compose e segue compilando na VPS

Se não cabe, ou se fica no limite, move o build pro GitHub Actions e deixa o servidor só baixando a imagem

Pra parte de colocar o container de pé no servidor, o passo a passo de publicar Astro SSR com Docker mostra o deploy com Docker em VPS na prática

E se a medição mostrar que o teu servidor atual não tem folga nem pra executar a aplicação com tranquilidade, vale conferir a VPS para este projeto e escolher o plano com base no consumo que tu mediu, não no chute

Bora medir? Até o próximo post! 😀

Perguntas frequentes

GitHub Actions é a única forma de tirar o build da VPS?

Não, a lógica de rodar o build fora da VPS vale pra qualquer serviço de CI que publique a imagem num registry. O post usa o GitHub Actions porque é o que tem os dados oficiais de runner e custo citados aqui, mas o fluxo de build separado da execução é o mesmo em outras ferramentas

Dá pra limitar só a CPU do container sem limitar a memória?

Tecnicamente dá: –cpus e os limites de memória são opções separadas na documentação do Docker, então nada impede usar só –cpus. Mas isso não resolve o risco de OOME, porque esse problema é causado por falta de memória, não de CPU: pra mitigar o OOME, o limite que importa é o de memória


Quer aprender mais sobre inteligência artificial e programação na prática? Conheça o canal Hora de Codar no YouTube e acompanhe os próximos vídeos.

Escrito por | Matheus Battisti

Matheus Battisti
Fundador da Hora de Codar

Programador apaixonado pelo mundo das tecnologias, sempre buscando em aprender e se aprofundar em linguagens, frameworks e o que mais for necessário para executar um bom trabalho. Agora tem uma nova missão que é de passar seu conhecimento adiante para formar novos programadores e especializar mais os que já são.

Subscribe
Notify of
guest

0 Comentários
Oldest
Newest Most Voted

Formações

Formação Claude Code

Formação Claude Code

Domine Claude Code do absoluto zero até o avançado

  • 120 aulas
  • 4 projetos
  • 9h 48min

Blog | Mais populares