Deploy de Repositorio Local

Este tutorial mostra como deployar uma aplicacao a partir de codigo que ja esta no servidor — sem depender de um repositorio GitHub remoto. Util para:

  • Servidores sem acesso a internet
  • Projetos internos sem repositorio externo
  • Testes rapidos e prototipagem
  • Migracoes de outros sistemas de deploy

Cenario

Voce tem o codigo da aplicacao em /home/deploy/meu-app/ no servidor e quer deployar via Runner sem configurar GitHub.

Pre-requisitos

  • Runner instalado (runner init executado)
  • Docker e Traefik rodando no servidor
  • Codigo da aplicacao no servidor

Passo 1: Preparar o Diretorio

O Runner espera uma estrutura especifica. Crie o diretorio do app em /data/apps/ (ou o apps_dir configurado no config.yml):

# Criar diretorio do app
mkdir -p /data/apps/meu-app

# Copiar codigo
cp -r /home/deploy/meu-app/* /data/apps/meu-app/

Estrutura necessaria

/data/apps/meu-app/
├── .deploy.yml          # Obrigatorio
├── Dockerfile           # Se usar build mode
├── src/                 # Codigo fonte (ou dist/)
│   └── ...
├── requirements.txt     # Ou package.json, etc
└── version.json         # Opcional (para versioning)

Passo 2: Criar .deploy.yml

# /data/apps/meu-app/.deploy.yml
project: meu-app
system: sys
port: 8000

# Modo BUILD (com Dockerfile local)
build:
  context: .
  dockerfile: Dockerfile

# Sem secao github: — deploy local nao precisa
# (Nota: o bloco `github:` foi DEPRECATED em v2.16.0 mesmo para deploys remotos)

version:
  source: file              # opcional desde v2.18.2
  file: version.json
  field: version
# Desde v2.18.2, generator default emite `source: git-commit` (deploys
# auto-versionados via SHA, sem precisar `version` field em arquivo).

networks:
  - public

healthcheck:
  path: /health           # endpoint a ser implementado pela app (HTTP 2xx)
  start_period: 30s
  interval: 10s
  timeout: 5s
  retries: 3

instances:
  production:
    domain: app.meusite.com.br
    source:
      type: local      # Usa codigo local, nao git
    keep_versions: 3

Nota: sem a secao github:, o Runner nao tenta fazer git fetch. O deploy usa o codigo que ja esta em /data/apps/meu-app/.

Criar version.json

{
  "version": "1.0.0"
}

Criar Dockerfile

FROM python:3.12-slim
WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY src/ ./src/

EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "2", "main:app"]

Passo 3: Registrar Manualmente

Para deploys locais, em vez de runner add --repo, criamos o state file manualmente:

# Criar state file
cat > /opt/runner/state/meu-app.yml << 'EOF'
app_path: /data/apps/meu-app
project: meu-app
system: sys
app_type: sys
dist_branch: ""
current_version: null
status: registered
EOF

# Verificar
runner list

Alternativa: se o diretorio local tem um .git com uma branch (mesmo sem remote), voce pode usar runner add apontando para o path:

# Inicializar git local (se nao existir)
cd /data/apps/meu-app
git init
git add . && git commit -m "initial"

# Registrar (sem --token, sem remote)
# O runner detecta que nao ha remote e trata como local

Passo 4: Deploy

runner deploy meu-app -V

Output esperado:

[1/7] FETCH     Baixando codigo fonte...
  (skipped — local source, no git remote)
[2/7] PREPARE   Preparando versao v1.0.0...
[3/7] SECURITY  Verificando seguranca...
[4/7] BUILD     Building image meu-app:v1.0.0...
[5/7] CONTAINER Iniciando container...
[6/7] HEALTH    Verificando saude...
[7/7] ROUTING   Configurando Traefik...

Passo 5: Verificar

# Health check
curl -s https://app.meusite.com.br/health

# Container
docker ps | grep meu-app

# Logs
docker logs meu-app_production_v1-0-0 --tail 20

Atualizando o Deploy

Para atualizar o codigo local e redeployar:

# 1. Atualizar codigo
cp -r /home/deploy/meu-app-novo/* /data/apps/meu-app/

# 2. Atualizar versao
echo '{"version": "1.1.0"}' > /data/apps/meu-app/version.json

# 3. Redeployar
runner deploy meu-app --force

O --force e necessario porque o Runner detecta que a versao ja esta deployada (nao mudou via git). Com --force, ele rebuilda e redeploya.

Modo IMAGE (sem Dockerfile)

Se voce nao quer buildar uma imagem e prefere usar uma imagem pronta com o codigo montado via volume:

# .deploy.yml
project: meu-app
port: 80
image: caddy:2-alpine    # Imagem pronta

instances:
  production:
    domain: app.meusite.com.br
    source:
      type: local

Nesse caso o Runner monta o diretorio /data/apps/meu-app/ como volume em /app dentro do container. O codigo fica no host e hot-reload funciona se a imagem suportar.

Exemplo: Frontend Estatico (Caddy)

# Estrutura
/data/apps/meu-front/
├── .deploy.yml
├── dist/
   ├── index.html
   ├── assets/
   └── ...
└── Caddyfile
# .deploy.yml
project: meu-front
port: 80
image: caddy:2-alpine

instances:
  production:
    domain: meusite.com.br
    source:
      type: local
runner deploy meu-front
# Caddy serve os arquivos estaticos de /app/dist/

Exemplo: Worker Python (sem dominio)

Servicos que nao precisam de Traefik (workers, cron jobs):

# .deploy.yml
project: meu-worker
port: 0                   # Sem porta HTTP

build:
  context: .
  dockerfile: Dockerfile

healthcheck:
  path: ""                # Sem healthcheck HTTP

# Sem instances.production.domain — o container roda sem Traefik
# Usa ports: para bind direto se necessario
instances:
  production:
    source:
      type: local
runner deploy meu-worker
# Container roda sem Traefik, sem healthcheck HTTP
# Runner aceita "running" como sucesso

Migrar de Local para GitHub

Quando quiser migrar de deploy local para deploy via GitHub:

# 1. Criar repo no GitHub
gh repo create devborlot/meu-app --private

# 2. Push do codigo
cd /data/apps/meu-app
git init && git add . && git commit -m "initial"
git remote add origin https://github.com/devborlot/meu-app.git
git push -u origin main
git checkout -b dist && git push -u origin dist

# 3. Re-registrar a app no Runner com o repo (v2.16.0+: o repo fica
#    no state file, não mais em `github:` no .deploy.yml — esse bloco
#    foi DEPRECATED).
runner unregister meu-app
runner add --repo devborlot/meu-app --branch main --token ghp_xxxYYYzzz

A partir dai o Runner detecta pushes na dist automaticamente.

Troubleshooting

"No .deploy.yml found"

O arquivo precisa estar em /data/apps/meu-app/.deploy.yml (raiz do app dir).

"Already deployed" (sem --force)

Para redeploy local sem mudar versao:

runner deploy meu-app --force

Build falha

Testar localmente primeiro:

cd /data/apps/meu-app
docker build -t test .
docker run --rm -p 8000:8000 test
curl http://localhost:8000/health

Container sobe mas health falha

Ver guia de healthcheck. Para deploy local sem HTTP, use healthcheck.path: "" ou healthcheck.tcp: <porta>.

By Borlot.com.br on 16/04/2026