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 initexecutado) - 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: 3Nota: 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 listAlternativa: 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 localPasso 4: Deploy
runner deploy meu-app -VOutput 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 20Atualizando 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 --forceO --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: localNesse 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: localrunner 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: localrunner deploy meu-worker
# Container roda sem Traefik, sem healthcheck HTTP
# Runner aceita "running" como sucessoMigrar 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_xxxYYYzzzA 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 --forceBuild falha
Testar localmente primeiro:
cd /data/apps/meu-app
docker build -t test .
docker run --rm -p 8000:8000 test
curl http://localhost:8000/healthContainer sobe mas health falha
Ver guia de healthcheck. Para deploy local sem
HTTP, use healthcheck.path: "" ou healthcheck.tcp: <porta>.