Implantar e CI/CD
cipi deploy
Cipi usa Implantador para todas as implantações. Cada implantação é atômica: uma nova versão
diretório está totalmente preparado antes do current o link simbólico é trocado, então o tráfego nunca é
interrompido.
cipi deploy e cipi deploy --rollback
abortar com uma mensagem clara de atualização antes invocando o Deployer quando um aplicativo ainda está fixado
para uma versão PHP mais antiga - troque com cipi app edit <app> --php=8.3 (ou
superior) primeiro.Implantar pipeline
Deployer e Composer são executados com o versão PHP configurada do aplicativo (por exemplo
/usr/bin/php8.5), não o padrão do sistema. Isto se aplica a cipi deploy,
cipi deploy --rollback, gatilhos de implantação do crontab, cipi sync import implanta,
e o deploy / composeraliases no usuário do aplicativo .bashrc.
- Parar trabalhadores da fila (
cipi worker stop) - Clonar repositório em
releases/N/ - Corre
composer install --no-dev(com PHP do aplicativo) - Ligação
shared/.enveshared/storage/ - Corre
artisan migrate --force - Corre
artisan optimize - Corre
artisan storage:link - Trocar
currentlink simbólico atomicamente - Reiniciar trabalhadores da fila
- Remova os lançamentos antigos (mantenha os últimos 5)
$ cipi deploy myapp # deploy latest commit $ cipi deploy myapp --rollback # instant rollback to previous release $ cipi deploy myapp --releases # list all releases with timestamps $ cipi deploy myapp --key # show the SSH deploy key $ cipi deploy myapp --webhook # show webhook URL and token $ cipi deploy myapp --unlock # remove a stuck deploy lock $ cipi deploy myapp --snapshot # v5.0+ opt-in DB dump before deploy $ cipi deploy myapp --snapshot-required # fail if snapshot cannot be taken $ cipi deploy myapp --trust-host=git.mycompany.com # trust a custom Git server fingerprint $ cipi deploy myapp --trust-host=git.mycompany.com:2222 # trust on non-standard port (also writes ~/.ssh/config)
Desde v5.0, ativar pré-implantar snapshots de banco de dados estão disponíveis através
--snapshot / --snapshot-required ou uma configuração permanente do aplicativo – consulte
Pré-implantar snapshots de banco de dados. Os aplicativos Octane usam o
laravel-octane.php Modelo do implantador (recarregar/reiniciar Octane na implantação); habilitar nó
constrói com cipi app edit <app> --node-build='…'.
cipi deploy myapp --unlock para removê-lo antes de reimplantá-lo.Pré-implantar snapshots de banco de dados
Desde v5.0, cipi deploy <app> pode despejar o banco de dados
antes o pipeline de lançamento é executado. Instantâneos caem sob
/var/log/cipi/backups/ - o mesmo caminho usado por
cipi db backup.
$ cipi deploy shop --snapshot # dump first; warn and continue on failure $ cipi deploy shop --snapshot-required # dump first; abort deploy if snapshot fails
O que acontece
- Antes de iniciar o Deployer, Cipi faz um dump do banco de dados
/var/log/cipi/backups/. - Com
--snapshot-required, um dump com falha (ou um mecanismo de banco de dados ausente) blocos a implantação. - Com
--snapshotsozinho, um dump com falha imprime um aviso e a implantação continua.
Habilitar em cada implantação
Ative-o permanentemente para um aplicativo para que cada implantação (CLI, webhook ou pipeline) tire um snapshot primeiro:
$ cipi app edit shop --predeploy-snapshot
cipi deploy --rollback restaura o anterior código liberar apenas.
Isso acontece não restaurar o banco de dados. Se você precisar do dump pré-implantação de volta, use
cipi db restore.Para fluxos de trabalho de pipeline que também arquivam shared/ para S3 antes do lançamento, consulte
Implantação segura – backup antes do lançamento.
cipi app deploy-config
Desde v5.0.3, gerencie opções de receitas duráveis do Deployer armazenadas em
apps.json e aplicado regenerando deploy.php do modelo -
uma alternativa segura para editar PHP de formato livre.
$ cipi app deploy-config myapp $ cipi app deploy-config myapp --keep-releases=5 $ cipi app deploy-config myapp --migrate --optimize --storage-link $ cipi app deploy-config myapp --no-migrate --no-optimize $ cipi app deploy-config myapp --queue-restart --horizon-terminate $ cipi app deploy-config myapp --extra-artisan=view:clear,event:cache $ cipi app deploy-config myapp --node-build='npm ci && npm run build' $ cipi app deploy-config myapp --predeploy-snapshot
DESCANSO: GET|PUT /api/apps/{name}/deploy-config (habilidade
apps-deploy-config, API 1.14+ / Cipi 5.0.3+).
MCP: AppDeployConfigShow, AppDeployConfigUpdate.
auth.json
Gerenciar o auth.json arquivo para um aplicativo. Este arquivo reside em
/home/<app>/shared/auth.json e é automaticamente vinculado a cada versão por
Implantador - exatamente como .env. Use-o para armazenar dados de credenciais estruturados (por exemplo, API
chaves, sinalizadores de recursos ou qualquer carga útil JSON) que seu aplicativo Laravel possa ler em tempo de execução.
$ cipi auth create myapp # create auth.json with initial { "users": [] } structure $ cipi auth edit myapp # open in $EDITOR (fallback: nano), validate JSON on close $ cipi auth show myapp # print contents formatted with jq $ cipi auth delete myapp # delete file (asks for confirmation) # Non-interactive (v5.0.3+) — API / scripts / GUI $ cipi auth create myapp --force $ cipi auth edit myapp --file=/tmp/auth.json $ cipi auth show myapp --json $ cipi auth delete myapp --force
DESCANSO: GET|POST|PUT|DELETE /api/apps/{name}/auth (habilidade apps-auth, API
1.14+) — Composer/estruturado JSON, distinto de HTTP Autenticação Básica.
MCP: AppAuthJsonShow, AppAuthJsonCreate,
AppAuthJsonUpdate, AppAuthJsonDelete.
Detalhes do comando
| Comando | Descrição |
|---|---|
cipi auth create <app> |
Cria shared/auth.json com a estrutura inicial
{"users":[]}, define permissões para 640 (proprietário
app:app) e acrescenta auth.json para
shared_files na configuração do Deployer do aplicativo para que ele tenha um link simbólico em todos
implantar.
|
cipi auth edit <app> |
Abre shared/auth.json em $EDITOR (volta para
nano). Após o editor fechar, valida o JSON com
jq e avisa se o arquivo está malformado.
|
cipi auth show <app> |
Imprime o conteúdo de shared/auth.json formatado com
jq.
|
cipi auth delete <app> |
Pede confirmação e depois exclui shared/auth.json e remove o
auth.json entrada de shared_files no Deployer do aplicativo
configuração.
|
Integração do implantador
cipi auth create anexa automaticamente auth.json para o
shared_files listar em /home/<app>/.deployer/deploy.phpe
cipi auth delete remove-o. Isso significa que o arquivo é tratado exatamente como
.env: persiste entre versões e nunca é substituído por uma implantação.
cipi auth operação é registrada via log_action para
auditabilidade. O AUTH seção também está listada na saída de
cipi help.
Provedores Git
Cipi está pronto para trabalhar API e GitHub mas suporta qualquer outro provedor Git que oferece suporte a chaves de implantação SSH — sem dependência de fornecedor.
Para servidores self-hosted ou Git personalizados, você precisa confiar na impressão digital do host do servidor antes
O implantador pode clonar por SSH. Use o --trust-host sinalizador para adicionar a impressão digital ao
usuário do aplicativo ~/.ssh/known_hosts automaticamente:
# show the deploy key and add it to your Git provider $ cipi deploy myapp --key # trust a custom Git server fingerprint (standard port) $ cipi deploy myapp --trust-host=git.mycompany.com # trust a custom Git server on a non-standard port # (also writes ~/.ssh/config automatically) $ cipi deploy myapp --trust-host=git.mycompany.com:2222
Host / Port entrada para o usuário do aplicativo ~/.ssh/config então
que o Deployer possa acessar o servidor sem qualquer configuração extra.
Configuração automática do Git
Se você salvar um API ou GitHub Token de acesso pessoal, Cipi
adiciona automaticamente a chave de implantação SSH e cria o webhook no repositório toda vez que você executacipi app create. Não são necessárias etapas manuais.
Salvar um token
# GitHub (fine-grained or classic PAT) $ cipi git github-token ghp_xxxxxxxxxxxxxxxxxxxx # GitLab (gitlab.com) $ cipi git gitlab-token glpat-xxxxxxxxxxxxxxxxxxxx # GitLab (self-hosted — set the URL before or after the token) $ cipi git gitlab-url https://gitlab.example.com $ cipi git gitlab-token glpat-xxxxxxxxxxxxxxxxxxxx
GitHub permissões de token
Tokens refinados (recomendados) precisam Administração e
Webhooks definido como Ler e escrever nos repositórios de destino. Tokens clássicos
preciso do repo escopo.
GitLab permissões de token
O api o escopo é o mínimo necessário — GitLab não oferece um escopo mais granular
que abrange chaves de implantação e webhooks.
Ciclo de vida automático
| Evento | O que Cipi faz automaticamente |
|---|---|
app create |
Adiciona chave de implantação + cria webhook no repositório via API. O resumo mostra "configurado automaticamente ✓" em vez de instruções manuais. |
app edit --repository=... |
Remove a chave de implantação + webhook do repositório antigo e, em seguida, adiciona-os ao novo. |
app delete |
Remove a chave de implantação + webhook do repositório antes de excluir o aplicativo. |
cipi git comandos
| Comando | Descrição |
|---|---|
cipi git status |
Mostrar status de conexão do provedor e detalhes de integração por aplicativo (ID da chave de implantação, webhook ID) |
cipi git github-token <token> |
Salve um token de acesso pessoal GitHub |
cipi git gitlab-token <token> |
Salve um token de acesso pessoal GitLab |
cipi git gitlab-url <url> |
Defina o URL base para uma instância self-hosted GitLab |
cipi git remove-github |
Remova o token GitHub armazenado |
cipi git remove-gitlab |
Remova o token GitLab e o URL armazenados |
Configuração manual (substituição)
A configuração automática é ignorada quando nenhum token é configurado, quando a chamada API falha (permissões erradas, repositório não encontrado, limite de taxa) ou quando o repositório está hospedado em um provedor diferente GitHub ou GitLab (por exemplo, Gitea, Forgejo, Bitbucket). Em todos esses casos, Cipi volta para o fluxo de trabalho manual e a criação do aplicativo prossegue normalmente.
Para configurar a chave de implantação e webhook manualmente:
# print the SSH deploy key to add to your Git provider $ cipi deploy myapp --key # print the webhook URL and token $ cipi deploy myapp --webhook # if using a custom Git server, trust the host fingerprint first $ cipi deploy myapp --trust-host=git.mycompany.com
Em seguida, adicione-os nas configurações do repositório do seu provedor:
- Implantar chave — API: Configurações → Chaves de implantação → Adicionar chave de implantação; GitLab: Configurações → Repositório → Implantar chaves
- Webhook — API: Configurações → Webhooks → Adicionar webhook;
API: Configurações → Webhooks → Adicionar novo webhook. Defina o URL da carga útil e
secreto para os valores mostrados por
cipi deploy myapp --webhook
Personalizando o script de implantação
A configuração de implantação de cada aplicativo é armazenada em:
Este arquivo é gerado automaticamente por Cipi durante app create e atualizado automaticamente quando você
altere a versão PHP ou implante o branch via cipi app edit. Você pode editá-lo para personalizar
o pipeline de implantação, mas você deve entender as implicações antes de fazer isso.
Pipeline de implantação padrão
O gerado automaticamente deploy.php executa estas tarefas em ordem:
deploy:prepare // create releases/N/ directory deploy:vendors // composer install --no-dev deploy:shared // link shared/.env and shared/storage/ artisan:migrate // php artisan migrate --force artisan:optimize // php artisan optimize artisan:storage:link // php artisan storage:link deploy:symlink // swap current → releases/N/ atomically cipi:restart-workers // supervisorctl restart myapp-* deploy:cleanup // keep last 5 releases, delete older
Adicionando tarefas personalizadas
Você pode adicionar tarefas antes ou depois de qualquer etapa. Para um exemplo completo de construção de front-end (npm install && npm run build), veja
Construindo ativos de front-end abaixo. Outros exemplos comuns:
// Run artisan db:seed after migrations after('artisan:migrate', 'artisan:db:seed'); // Clear view cache after symlink swap after('deploy:symlink', 'artisan:view:clear'); // Custom task — send a Slack notification task('notify:slack', function () { run('curl -X POST https://hooks.slack.com/... -d \'{"text":"Deployed!"}\''); }); after('deploy:symlink', 'notify:slack');
Construindo ativos de front-end (npm / Vite)
Não há dedicado cipi Sinalizador CLI para compilações de front-end (por exemplo, npm install && npm run build).
Personalização deploy.php é a abordagem apoiada e esperada - definir um
Implantador task() e prendê-lo com after() ou before(). Você não
precisa evitar isso; estender o pipeline é exatamente a finalidade do arquivo.
Cipi instalações Node.js e npm no servidor durante a configuração. Verifique se eles estão disponíveis como o usuário do aplicativo:
$ ssh myapp@your-server-ip
myapp@server:~$ node -v && npm -v
Confirmar package.json e package-lock.json para o seu repositório. Prenda a construção
depois deploy:shared então .env está vinculado (Vite lê
VITE_* variáveis de lá) e antes deploy:symlink então
ativos compilados existem na versão antes de ela ser lançada.
Anexe o bloco abaixo no inferior de
/home/myapp/.deployer/deploy.php, abaixo das definições de tarefas geradas automaticamente por Cipi:
// ── Custom: frontend build (safe zone — keep below Cipi-managed blocks) ── task('npm:build', function () { cd('{{release_path}}'); run('npm ci --no-audit --no-fund && npm run build'); }); // .env is linked → build assets → then migrations / optimize / symlink after('deploy:shared', 'npm:build');
Isso equivale a npm install && npm run build em cada implantação. Prefiro
npm ci em produção quando package-lock.json está comprometido - é mais rápido e
reproduzível. Usar npm install em vez disso, apenas se você não bloquear dependências.
Se você precisar de etapas separadas de instalação e compilação (por exemplo, para armazenar em cache node_modules entre lançamentos),
divida-os em duas tarefas:
task('npm:ci', function () {
cd('{{release_path}}');
run('npm ci --no-audit --no-fund');
});
task('npm:build', function () {
cd('{{release_path}}');
run('npm run build');
});
after('deploy:shared', 'npm:ci');
after('npm:ci', 'npm:build');
Para acelerar implantações subsequentes, você pode persistir dependências entre versões adicionando
node_modules para os diretórios compartilhados do Deployer (opcional — somente se o seu projeto suportar
isso):
add('shared_dirs', ['node_modules']);
Edite o arquivo no servidor como usuário do aplicativo e teste com cipi deploy myapp:
$ ssh myapp@your-server-ip myapp@server:~$ nano ~/.deployer/deploy.php # paste the custom tasks at the bottom, save, then as root: $ cipi deploy myapp
npm ci && npm run build em GitHub ações
ou GitLab CI antes a etapa de implantação do SSH, para que o servidor receba apenas ativos pré-construídos.
Veja CI/CD pipelines – implantação SSH.Executando comandos artisan adicionais
// Seed only in specific environments
task('artisan:db:seed', function () {
run('{{bin/php}} {{release_path}}/artisan db:seed --force');
});
cipi app edit myapp --php=X ou cipi app edit myapp --branch=X. Backup
suas personalizações ou mantê-las em uma seção claramente separada dos blocos gerenciados por Cipi. Um
O padrão seguro é colocar todas as tarefas personalizadas na parte inferior do arquivo após a tarefa padrão
definição.
Desativando uma etapa padrão
Para pular uma tarefa — por exemplo, se você lida com migrações manualmente — comente-a ou remova-a do
deploy definição de tarefa:
// Remove the migrate step from the pipeline task('deploy', [ 'deploy:prepare', 'deploy:vendors', 'deploy:shared', // 'artisan:migrate', ← disabled 'artisan:optimize', 'artisan:storage:link', 'deploy:symlink', 'cipi:restart-workers', 'deploy:cleanup', ]);
Testando suas alterações
Depois de editar deploy.php, sempre faça uma implantação de teste antes de enviar para produção:
$ cipi deploy myapp # If something goes wrong, instant rollback: $ cipi deploy myapp --rollback # If the deploy is stuck (e.g. interrupted mid-run): $ cipi deploy myapp --unlock
~/logs/deploy.log ou através
cipi app logs myapp --type=deploy. Verifique primeiro ao solucionar uma falha
implantar.
Implantar e CI/CD — Visão geral
Com Cipi, CI (construir e testar) e CD (liberação para produção) pode
ser dividido ou combinado. Em última análise, cada implantação executa o mesmo Implantador
gasoduto no servidor - clone, composer install, migrações, troca de link simbólico,
reinicialização do trabalhador. O que muda é o que desencadeia esse gasoduto.
Cipi oferece suporte a dois modelos de gatilho. Para a maioria dos aplicativos Laravel, comece com webhook + Cipi Agente caminho. Mude para um pipeline CI/CD completo quando precisar de portas, backups ou orquestração de infra-estrutura que um simples gancho não consegue expressar.
Duas maneiras de acionar uma implantação
| Webhook + Cipi Agente (recomendado) | CI/CD pipeline via SSH | |
|---|---|---|
| Gatilho | POSTs do provedor Git para /cipi/webhook ao pressionar |
GitHub Ações / GitLab execuções de trabalho de CI cipi deploy por SSH |
| Acesso ao servidor do CI | Nenhum – apenas HTTPS para o domínio do seu aplicativo | Chave SSH dedicada armazenada como segredo de CI |
| Testes pré-implantação | Execute localmente ou em um trabalho de CI separado; implantar ainda dispara no push, a menos que você desabilite o webhook | Nativo – a etapa de implantação é executada somente depois needs: test (ou equivalente) passes |
| Backup antes do lançamento | Manual ou cron no servidor | Trabalho de pipeline — consulte implantação segura |
| Visualizar/revisar aplicativos | Não é compatível imediatamente | Pipeline cria aplicativos Cipi por branch — consulte visualização ambientes |
| Complexidade de configuração | Baixo - composer require cipi/agent + um webhook |
Médio — chave SSH, segredos, fluxo de trabalho YAML |
Qual abordagem devo usar?
| Caso de uso | Abordagem recomendada | Onde ler mais |
|---|---|---|
Aplicativo Laravel único, push-to-deploy ativado main |
Webhook + Agente | Webhook configuração |
| Implantar somente se os testes de CI forem aprovados | Pipeline SSH (desativar produção webhook) | Implantação de SSH de pipeline |
| Backup de banco de dados + arquivo antes de cada versão de produção | Pipeline SSH | Implantação segura com backup |
| Alertas do Slack/Telegram sobre o resultado da implantação | Pipeline SSH | Implantar notificações |
| URL efêmero por ramificação de recursos (avaliar aplicativos) | Pipeline SSH | Visualizar ambientes |
| Implante vários aplicativos em um servidor a partir de um repositório | Ou - webhook por aplicativo ou um pipeline com paralelo cipi deploy |
Implantação de vários aplicativos |
cipi deploy myapp --unlock se um cadeado preso for deixado para trás.
Implantações automáticas — Cipi Agente e webhook
cipi-agente (cipi/agent) é um pacote Laravel que expõe
POST /cipi/webhook dentro do seu aplicativo em execução. Quando GitHub ou GitLab envia um push
evento, o agente valida a assinatura da carga útil, confirma imediatamente e enfileira uma implantação em
o servidor - sem SSH do executor de CI, não sudo, nenhuma porta de entrada aberta além de HTTPS.
Como funciona o fluxo webhook
O design separa reconhecimento rápido de HTTP de Implantador lento trabalho. Uma implantação pode levar vários minutos; Provedores Git expiram chamadas webhook HTTP após ~10 segundos. Cipi resolve isso com um arquivo de sinalização e o crontab do usuário do aplicativo.
Developer Git provider Your Laravel app (Cipi Agent) Server (app user cron)
│ │ │ │
│ git push main │ │ │
│ ───────────────────────────► │ │ │
│ │ POST /cipi/webhook │ │
│ │ (signed with secret) │ │
│ │ ───────────────────────────► │ │
│ │ │ 1. Verify CIPI_WEBHOOK_TOKEN │
│ │ │ 2. Check branch (CIPI_DEPLOY_BRANCH) │
│ │ │ 3. Write ~/.deploy-trigger │
│ │ ◄─────────────────────────── │ 4. Return 200 immediately │
│ │ │ │
│ │ │ every minute (* * * * *) │
│ │ │ ◄──────────────────────────────────────│
│ │ │ cron sees .deploy-trigger │
│ │ │ removes file, runs Deployer │
│ │ │ in background as app user │
│ │ │ │
│ │ │ clone → composer → migrate │
│ │ │ → symlink swap → workers │
O Deployer sempre é executado como o usuário do aplicativo Linux (por exemplo myapp), com o
corrigir permissões binárias e de arquivo PHP - o mesmo contexto de um manual
cipi deploy myapp. O webhook nunca é pago diretamente ao Deployer; só deixa cair o
arquivo de gatilho que o crontab de Cipi já monitora.
Pré-requisitos
| Requisito | Por que |
|---|---|
| Cipi aplicativo criado com repositório Git | A chave de implantação deve clonar o repositório — consulte Configuração automática do Git |
| Pelo menos uma implantação manual bem-sucedida | O pacote do agente deve estar presente no current lançamento antes de webhook
rota existe |
composer require cipi/agent no projeto |
Registra o /cipi/webhook validação de rota e assinatura |
| Webhook URL acessível através de HTTPS | Os provedores Git exigem uma URL pública; usar cipi ssl install primeiro |
CIPI_WEBHOOK_TOKEN em shared/.env |
Gerado automaticamente em cipi app create; compartilhado em todos os lançamentos |
Configuração passo a passo
1. Crie o aplicativo e implante uma vez manualmente para que o servidor possa clonar seu repositório:
$ cipi app create --user=myapp --domain=myapp.com \ --repository=git@github.com:you/myapp.git --branch=main --php=8.5 $ cipi deploy myapp
2. Instale o Agente Cipi em seu projeto Laravel localmente, confirme e envie:
$ composer require cipi/agent $ git add composer.json composer.lock $ git commit -m "Add Cipi Agent for webhook deploys" $ git push origin main $ cipi deploy myapp # one more manual deploy until webhook is live
3. Configure o webhook. Se você salvou um token GitHub ou GitLab, Cipi pode ter
já criei o webhook durante app create - verifique com
cipi git status. Caso contrário, recupere o URL e o segredo:
$ cipi deploy myapp --webhook
Adicione webhook em seu provedor Git:
| Provedor | URL de carga útil | Campo secreto | Eventos |
|---|---|---|---|
| GitHub | https://myapp.com/cipi/webhook |
Segredo → valor de --webhook |
Apenas o push evento |
| GitLab | https://myapp.com/cipi/webhook |
Token secreto → mesmo valor | Eventos push |
4. Restrinja ao seu branch de implantação (recomendado para produção):
CIPI_DEPLOY_BRANCH=main
Defina isso shared/.env através de cipi app env myapp. Empurra para outras filiais
receber um skipped resposta e nenhuma implantação é executada.
5. Verifique. Envie um pequeno commit para main e observe o log de implantação:
$ cipi app logs myapp --type=deploy # or on the server as the app user: $ tail -f /home/myapp/logs/deploy.log
Cerca de um minuto após a entrega de webhook, uma nova versão do Deployer deverá aparecer. Confirme o
compromisso ao vivo com php artisan cipi:status ou o saúde
verificar ponto final.
Configuração automática do Git
Quando um Token GitHub ou GitLab está configurado no servidor, Cipi
registra a chave de implantação e cria o webhook automaticamente em cada
cipi app create. O resumo do aplicativo mostra "configurado automaticamente ✓" em vez de manual
instruções. Eventos do ciclo de vida (app edit --repository, app delete) manter
chaves e webhooks sincronizados.
Solução de problemas
| Sintoma | Causa provável | Correção |
|---|---|---|
| Webhook retorna 404 | Agente ainda não implantado | Corre cipi deploy myapp depois de adicionar cipi/agent para
composer.json
|
| Webhook retorna 403/assinatura inválida | Incompatibilidade secreta | Copiar novamente o token de cipi deploy myapp --webhook nas configurações do provedor
|
| 200 OK, mas sem implantação | Filial filtrada | Verifique CIPI_DEPLOY_BRANCH corresponde ao branch empurrado |
| Implantação travada/erro de bloqueio | Implantação anterior interrompida | cipi deploy myapp --unlock então tente novamente |
| A implantação é executada duas vezes em um push | Webhook + pipeline ambos ativos | Desative um gatilho - consulte visão geral |
deploy ferramenta -
ele usa o mesmo .deploy-trigger mecanismo. Veja Cipi Agente
para verificações de integridade, MCP e recursos de anonimização.CI/CD pipelines – implantação SSH
Quando o modelo webhook não for suficiente, execute GitHub Ações ou GitLab
CI/CD jobs que fazem SSH no servidor e invocam cipi deploy. Este é o
escolha certa sempre que a implantação deve ser condicional — fechado em testes, precedido por backups,
seguido por notificações ou orquestrando novos aplicativos de visualização.
Quando você precisa de um pipeline em vez de um webhook
- Portão de qualidade - correr
php artisan test, análise estática ou front-end é compilado antes que qualquer código chegue à produção - Liberação segura - instantâneo do banco de dados e
shared/para S3 antes trocando o link simbólico (implantação segura) - Visibilidade da equipe - postar sucesso/falha no Slack ou Telegram com reversão ativada falha (implantar notificações)
- Revise aplicativos — criar ou atualizar um aplicativo Cipi completo por ramificação de recursos (visualizar ambientes)
- Monorepo para vários aplicativos - implantar
frontendeapiem paralelo após um único trabalho de teste
Para esses fluxos de trabalho, desabilitar a produção webhook (ou nunca crie um) então apenas os gatilhos do pipeline são implantados. Você ainda pode usar o agente Cipi no aplicativo para verificações de integridade e MCP.
Acesso SSH para CI
/root/.ssh/authorized_keys no servidor (ou no
cipi usuário se preferir sudo cipi deploy) e armazene o
chave privada como um segredo de CI. Nunca reutilize chaves de implantação do Git ou chaves SSH pessoais.
# on your local machine $ ssh-keygen -t ed25519 -C "ci-deploy" -f ~/.ssh/ci_deploy -N "" # copy the public key to the server $ ssh-copy-id -i ~/.ssh/ci_deploy.pub root@your-server-ip # copy the private key content → add it as a CI secret (SERVER_SSH_KEY) $ cat ~/.ssh/ci_deploy
Loja SERVER_HOST (IP do servidor ou nome do host) ao lado SERVER_SSH_KEY em seu
segredos do repositório (GitHub) ou variáveis CI/CD (GitLab).
GitHub Ações – teste e implante
Adicione a chave privada como um segredo do repositório chamado SERVER_SSH_KEY e o IP do servidor como
SERVER_HOST.
# .github/workflows/deploy.yml name: Deploy on: push: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run tests run: php artisan test deploy: runs-on: ubuntu-latest needs: test # only deploy if tests pass steps: - name: Deploy via Cipi uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SERVER_HOST }} username: cipi key: ${{ secrets.SERVER_SSH_KEY }} script: sudo cipi deploy myapp
Para reversão em caso de falha, estenda a etapa de script:
script: |
sudo cipi deploy myapp || (sudo cipi deploy myapp --rollback && exit 1)
GitLab CI/CD
Adicione a chave privada como uma variável CI/CD chamada SERVER_SSH_KEY (tipo: Arquivo) e o servidor
IP como SERVER_HOST.
# .gitlab-ci.yml
stages:
- test
- deploy
test:
stage: test
script:
- php artisan test
deploy:
stage: deploy
environment: production
only:
- main
before_script:
- apt-get install -y openssh-client
- eval $(ssh-agent -s)
- echo "$SERVER_SSH_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh
- ssh-keyscan -H $SERVER_HOST >> ~/.ssh/known_hosts
script:
- ssh root@$SERVER_HOST "cipi deploy myapp"
Com reversão em caso de falha:
script:
- ssh root@$SERVER_HOST "cipi deploy myapp || (cipi deploy myapp --rollback && exit 1)"
Implantação de vários aplicativos
Se o mesmo pipeline gerenciar vários aplicativos no mesmo servidor:
# GitHub Actions — deploy multiple apps in parallel
- name: Deploy
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: root
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
cipi deploy frontend &
cipi deploy api &
wait
Padrões avançados de pipeline
Depois que a implantação do SSH funcionar, componha estas seções em um único fluxo de trabalho de produção:
| Padrão | O que o pipeline adiciona | Guia |
|---|---|---|
| Notificações | Mensagem do Slack ou Telegram sobre sucesso, falha e reversão automática | Implantar notificações |
| Implantação segura | cipi db backup + cipi backup run antes
cipi deploy; reversão em caso de falha
|
Implantação segura com backup |
| Visualizar ambientes | Crie/atualize/exclua aplicativos Cipi por ramificação com curinga DNS + SSL | Visualizar ambientes |
Uma configuração madura típica usa o webhook para um aplicativo de teste (feedback instantâneo sobre cada empurrar) e um gasoduto para produção (testes → backup → implantar → notificar). Cada aplicativo tem seu próprio gatilho - eles nunca entram em conflito porque têm como alvo diferentes usuários do aplicativo Cipi.
Implantar notificações
Caso de uso de pipeline: o caminho webhook é implantado silenciosamente — Git retorna 200 e a equipe
só descobre se observarem os registros. Com um Pipeline SSH, adicione
etapas de notificação apóscipi deploy para transmitir sucesso, fracasso e
reversões para Slack ou Telegram. Ambos os exemplos abaixo funcionam com GitHub Actions e GitLab CI usando
apenas chamadas HTTP padrão — sem dependências extras de plataforma.
Folga
Adicione uma etapa final que poste em um webhook do Slack, independentemente do resultado da implantação. Usar
if: always() em GitHub Actions para que a notificação seja disparada em caso de sucesso e falha.
Crie um Entrada
Webhook no seu espaço de trabalho do Slack e armazene o URL como
SLACK_WEBHOOK_URL em seus segredos de CI.
# GitHub Actions — deploy + Slack notification
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy
id: deploy
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: root
key: ${{ secrets.SERVER_SSH_KEY }}
script: cipi deploy myapp
- name: Notify Slack — success
if: success()
uses: slackapi/slack-github-action@v2
with:
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
webhook-type: incoming-webhook
payload: |
{
"text": ":white_check_mark: *myapp* deployed successfully",
"attachments": [{
"color": "good",
"fields": [
{ "title": "Branch", "value": "${{ github.ref_name }}", "short": true },
{ "title": "By", "value": "${{ github.actor }}", "short": true },
{ "title": "Commit", "value": "${{ github.sha }}", "short": false }
]
}]
}
- name: Notify Slack — failure
if: failure()
uses: slackapi/slack-github-action@v2
with:
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
webhook-type: incoming-webhook
payload: |
{
"text": ":x: *myapp* deploy FAILED — rolling back",
"attachments": [{
"color": "danger",
"fields": [
{ "title": "Branch", "value": "${{ github.ref_name }}", "short": true },
{ "title": "By", "value": "${{ github.actor }}", "short": true },
{ "title": "Run", "value": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}", "short": false }
]
}]
}
- name: Rollback on failure
if: failure()
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: root
key: ${{ secrets.SERVER_SSH_KEY }}
script: cipi deploy myapp --rollback
Para CI GitLab, use curl diretamente — nenhum plugin é necessário:
# .gitlab-ci.yml — deploy stage with Slack notification
deploy:
stage: deploy
script:
- ssh root@$SERVER_HOST "cipi deploy myapp" && export DEPLOY_STATUS="success" || export DEPLOY_STATUS="failed"
- |
if [ "$DEPLOY_STATUS" = "success" ]; then
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d "{\"text\":\":white_check_mark: *myapp* deployed by $GITLAB_USER_LOGIN on \`$CI_COMMIT_REF_NAME\`\"}"
else
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d "{\"text\":\":x: *myapp* deploy FAILED — <$CI_PIPELINE_URL|view pipeline>\"}"
ssh root@$SERVER_HOST "cipi deploy myapp --rollback"
exit 1
fi
Telegrama
Crie um bot do Telegram via @BotFather, obtenha o token do bot e encontre seu ID de bate-papo/grupo.
Armazene-os como TELEGRAM_BOT_TOKEN e TELEGRAM_CHAT_ID em segredos de CI.
# GitHub Actions — deploy + Telegram notification
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy
id: deploy
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: root
key: ${{ secrets.SERVER_SSH_KEY }}
script: cipi deploy myapp
- name: Notify Telegram — success
if: success()
run: |
curl -s -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \
-d chat_id="${{ secrets.TELEGRAM_CHAT_ID }}" \
-d parse_mode="Markdown" \
-d text="✅ *myapp* deployed successfully%0ABranch: \`${{ github.ref_name }}\`%0ABy: ${{ github.actor }}"
- name: Notify Telegram — failure + rollback
if: failure()
run: |
curl -s -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \
-d chat_id="${{ secrets.TELEGRAM_CHAT_ID }}" \
-d parse_mode="Markdown" \
-d text="❌ *myapp* deploy FAILED — rolling back%0ABranch: \`${{ github.ref_name }}\`%0A[View run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})"
ssh -o StrictHostKeyChecking=no -i <(echo "${{ secrets.SERVER_SSH_KEY }}") \
root@${{ secrets.SERVER_HOST }} "cipi deploy myapp --rollback"
GitLab CI equivalente (puro curl, sem dependências extras):
# .gitlab-ci.yml — deploy stage with Telegram notification
deploy:
stage: deploy
script:
- ssh root@$SERVER_HOST "cipi deploy myapp" && RESULT="✅ deployed" || RESULT="❌ FAILED"
- |
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-d chat_id="$TELEGRAM_CHAT_ID" \
-d parse_mode="Markdown" \
-d text="*myapp* ${RESULT}%0ABranch: \`$CI_COMMIT_REF_NAME\`%0ABy: $GITLAB_USER_LOGIN"
- |
if echo "$RESULT" | grep -q "FAILED"; then
ssh root@$SERVER_HOST "cipi deploy myapp --rollback"
exit 1
fi
https://api.telegram.org/bot<TOKEN>/getUpdates e procure o
chat.id campo na resposta. Para bate-papos privados, basta enviar uma mensagem ao bot primeiro.
Implantação segura – backup antes do lançamento
Para um dump integrado logo antes da execução do Deployer (sem necessidade de estágio de pipeline), use
--snapshot / --snapshot-requiredou ativar cipi app edit <app> --predeploy-snapshot.
Caso de uso de pipeline: uma implantação webhook não pode executar uma etapa de backup antes de liberar o código —
o evento push dispara a implantação imediatamente. Em um CI/CD pipeline, adicione um
dedicado backup estágio que deve ter sucesso antes deploy começa. Um
o fluxo de trabalho de nível de produção deve sempre criar um ponto de restauração antes o novo código vai
viver. Cipi fornece dois comandos de backup complementares que mapeiam dois níveis de segurança diferentes:
# local DB snapshot — fast, on-disk, instant rollback $ cipi db backup myapp # → /var/log/cipi/backups/myapp_20260303_143012.sql.gz # S3 backup — DB dump + shared/ folder uploaded to your bucket $ cipi backup run myapp # → s3://your-bucket/cipi/myapp/2026-03-03_143015/db.sql.gz # → s3://your-bucket/cipi/myapp/2026-03-03_143015/shared.tar.gz
Usados juntos em um pipeline, eles fornecem um ponto de restauração local rápido e uma cópia fora do servidor do o banco de dados e todos os arquivos carregados. A implantação só será iniciada se ambos os backups forem bem-sucedidos.
cipi backup configure uma vez no servidor para
vincule suas credenciais S3 antes cipi backup run pode ser usado.
cipi db backup funciona sem qualquer configuração — está sempre disponível.
O que cada comando faz internamente
cipi db backup <app> chamadas
mysqldump --single-transaction --routines --triggers e compacta a saída para
/var/log/cipi/backups/<app>_<timestamp>.sql.gz. O arquivo permanece no
servidor e nunca é excluído automaticamente — adicione uma etapa de limpeza ou um cron se o espaço em disco for importante.
cipi backup run <app> faz duas coisas: despeja o banco de dados com
mariadb-dump --single-transaction em um diretório temporário e arquiva todo o
/home/<app>/shared/ pasta (que contém .env,
storage/e quaisquer arquivos enviados pelo usuário). Ambos os arquivos são então enviados para S3 sob o
caminho cipi/<app>/<timestamp>/. Os arquivos temporários são excluídos após uma operação bem-sucedida
carregar.
GitHub Ações — fluxo de trabalho de implantação seguro
# .github/workflows/deploy.yml name: Deploy on: push: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: php artisan test backup: runs-on: ubuntu-latest needs: test steps: - name: Local DB backup uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SERVER_HOST }} username: root key: ${{ secrets.SERVER_SSH_KEY }} script: cipi db backup myapp - name: S3 backup (DB + shared) uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SERVER_HOST }} username: root key: ${{ secrets.SERVER_SSH_KEY }} script: cipi backup run myapp deploy: runs-on: ubuntu-latest needs: backup # only runs if backup job succeeds steps: - name: Deploy uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SERVER_HOST }} username: root key: ${{ secrets.SERVER_SSH_KEY }} script: cipi deploy myapp - name: Rollback on failure if: failure() uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SERVER_HOST }} username: root key: ${{ secrets.SERVER_SSH_KEY }} script: | cipi deploy myapp --rollback echo "Deploy failed — rolled back to previous release"
O gráfico de trabalho impõe a ordem: test → backup → deploy. Se
qualquer trabalho falhar, os subsequentes serão ignorados. Se a etapa de implantação falhar, o
rollback A etapa é acionada automaticamente e restaura a versão anterior do Deployer.
GitLab CI/CD — pipeline de implantação segura
# .gitlab-ci.yml
stages:
- test
- backup
- deploy
variables:
APP: myapp
.ssh: &ssh
before_script:
- apt-get install -y openssh-client
- eval $(ssh-agent -s)
- echo "$SERVER_SSH_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh
- ssh-keyscan -H "$SERVER_HOST" >> ~/.ssh/known_hosts
test:
stage: test
script: php artisan test
only: [main]
backup-local:
stage: backup
<<: *ssh
only: [main]
script:
- ssh root@$SERVER_HOST "cipi db backup $APP"
backup-s3:
stage: backup
<<: *ssh
only: [main]
script:
- ssh root@$SERVER_HOST "cipi backup run $APP"
deploy:
stage: deploy
<<: *ssh
only: [main]
script:
- |
ssh root@$SERVER_HOST "
cipi deploy $APP || {
cipi deploy $APP --rollback
echo 'Deploy failed — rolled back'
exit 1
}
"
after_script:
- echo "Released → https://myapp.com"
backup-local e backup-s3 estão no mesmo estágio, então eles correm em paralelo se
você tem vários executores, reduzindo o tempo geral do pipeline. Ambos devem ter sucesso antes do
deploy fase começa.
Restaurar do backup local
Se você precisar reverter o banco de dados para o snapshot obtido logo antes da implantação:
# list available local snapshots $ ls -lh /var/log/cipi/backups/myapp_*.sql.gz # restore the most recent one $ cipi db restore myapp /var/log/cipi/backups/myapp_20260303_143012.sql.gz # also roll back the code release $ cipi deploy myapp --rollback
Restaurar do backup S3
# list available S3 snapshots for this app $ cipi backup list myapp # download the DB snapshot from S3 $ aws s3 cp s3://your-bucket/cipi/myapp/2026-03-03_143015/db.sql.gz /tmp/db.sql.gz # restore the database $ cipi db restore myapp /tmp/db.sql.gz # (optional) restore shared/ files $ aws s3 cp s3://your-bucket/cipi/myapp/2026-03-03_143015/shared.tar.gz /tmp/shared.tar.gz $ tar -xzf /tmp/shared.tar.gz -C /home/myapp/
.sql.gz arquivo para /var/log/cipi/backups/. Em uma agenda de implantação ocupada,
adicione uma limpeza cron ou mantenha apenas os últimos N arquivos:ls -t /var/log/cipi/backups/myapp_*.sql.gz | tail -n +6 | xargs rm -fEste exemplo mantém os cinco instantâneos mais recentes e exclui os mais antigos.
Ambientes de visualização (implantação por filial)
Caso de uso de pipeline: webhooks apontam para um único URL de produção - eles não podem gerar um
novo aplicativo Cipi por filial. Os ambientes de visualização exigem um CI/CD
gasoduto que faz SSH no servidor, calcula um nome de aplicativo determinístico da ramificação e
corre cipi app create ou cipi deploy de acordo. Toda não produção
branch pode obter seu próprio URL ativo - um aplicativo Laravel totalmente implantado com seu próprio banco de dados, trabalhadores e
HTTPS. Esse padrão às vezes é chamado de "aplicativos de avaliação" ou "ambientes efêmeros".
O formato da URL usa três slugs separados por hífens, para que cada ambiente seja legível e globalmente único:
https://develop-acmeco-3a1f9c2e.preview.domain.ltd https://release-1-2-3-acmeco-3a1f9c2e.preview.domain.ltd https://main-acmeco-3a1f9c2e.preview.domain.ltd
Como os identificadores são gerados
Três valores são derivados no tempo de execução do pipeline:
# branch name → lowercase, non-alphanum → hyphens, trim edges BRANCH_SLUG=$(echo "$BRANCH" | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9]/-/g; s/--*/-/g; s/^-//; s/-$//') # repo/project name → same treatment PROJECT_SLUG=$(echo "$PROJECT" | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9]/-/g') # deterministic MD5 hash — same branch always gets the same environment HASH=$(echo -n "${BRANCH_SLUG}${PROJECT_SLUG}" | md5sum | cut -c1-8) # Cipi app username: must be lowercase alphanumeric, 3–32 chars, no hyphens # hex chars (0–9, a–f) are valid; prefix "pr" ensures it starts with a letter APP_NAME="pr${HASH}" # e.g. pr3a1f9c2e # human-readable domain with wildcard base DOMAIN="${BRANCH_SLUG}-${PROJECT_SLUG}-${HASH}.${DEPLOY_WILDCARD_DOMAIN}"
Pré-requisitos (configuração única do servidor)
A gravar
*.preview.domain.ltd → <server-ip> em seu provedor DNS. Todos os subdomínios
resolver automaticamente; nenhuma alteração DNS por branch é necessária.2. Certificado curinga SSL — obtenha um certificado curinga por meio do desafio DNS-01 uma vez e instale-o no servidor. Veja o Domínios curinga seção para obter instruções. O caminho do certificado usado pelos exemplos de pipeline abaixo é
/etc/letsencrypt/live/preview.domain.ltd/.3. Acesso ao repositório — os exemplos de pipeline usam uma URL HTTPS com um nome pessoal token de acesso (PAT) incorporado, portanto, nenhuma configuração de chave de implantação SSH por aplicativo é necessária. O token só precisa leia acesso ao repositório.
GitHub Ações
Adicione estes segredos ao repositório: SERVER_HOST, SERVER_SSH_KEY,
DEPLOY_WILDCARD_DOMAIN (por exemplo preview.domain.ltd), GH_PAT (um
PAT refinado com acesso de leitura ao repositório).
# .github/workflows/preview.yml name: Preview on: push: branches-ignore: [main, master] # main branch uses your production pipeline delete: # clean up when a branch is deleted jobs: deploy: if: github.event_name == 'push' runs-on: ubuntu-latest steps: - name: Compute identifiers id: ids run: | BRANCH_SLUG=$(echo "${{ github.ref_name }}" \ | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9]/-/g; s/--*/-/g; s/^-//; s/-$//') PROJECT_SLUG=$(echo "${{ github.event.repository.name }}" \ | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9]/-/g') HASH=$(echo -n "${BRANCH_SLUG}${PROJECT_SLUG}" | md5sum | cut -c1-8) APP_NAME="pr${HASH}" DOMAIN="${BRANCH_SLUG}-${PROJECT_SLUG}-${HASH}.${{ secrets.DEPLOY_WILDCARD_DOMAIN }}" REPO="https://oauth2:${{ secrets.GH_PAT }}@github.com/${{ github.repository }}.git" echo "app_name=${APP_NAME}" >> "$GITHUB_OUTPUT" echo "domain=${DOMAIN}" >> "$GITHUB_OUTPUT" echo "repo_url=${REPO}" >> "$GITHUB_OUTPUT" - name: Create or update preview uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SERVER_HOST }} username: root key: ${{ secrets.SERVER_SSH_KEY }} script: | APP="${{ steps.ids.outputs.app_name }}" DOMAIN="${{ steps.ids.outputs.domain }}" REPO="${{ steps.ids.outputs.repo_url }}" BRANCH="${{ github.ref_name }}" WILDCARD="/etc/letsencrypt/live/${{ secrets.DEPLOY_WILDCARD_DOMAIN }}" if cipi app show "$APP" &>/dev/null; then echo "→ Updating: $APP" cipi deploy "$APP" else echo "→ Creating: $APP → $DOMAIN" cipi app create \ --user="$APP" \ --domain="$DOMAIN" \ --repository="$REPO" \ --branch="$BRANCH" \ --php=8.5 # Patch nginx to listen on 443 using the pre-installed wildcard cert awk -v cert="$WILDCARD" ' /^ listen 80;/ { print print " listen 443 ssl http2;" print " ssl_certificate " cert "/fullchain.pem;" print " ssl_certificate_key " cert "/privkey.pem;" next } { print } ' "/etc/nginx/sites-available/$APP" > /tmp/_cipi_vhost \ && mv /tmp/_cipi_vhost "/etc/nginx/sites-available/$APP" nginx -t && systemctl reload nginx cipi deploy "$APP" fi - name: Print preview URL run: | echo "" echo " Preview → https://${{ steps.ids.outputs.domain }}" echo "" cleanup: if: github.event_name == 'delete' runs-on: ubuntu-latest steps: - name: Compute identifiers id: ids run: | BRANCH_SLUG=$(echo "${{ github.event.ref }}" \ | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9]/-/g; s/--*/-/g; s/^-//; s/-$//') PROJECT_SLUG=$(echo "${{ github.event.repository.name }}" \ | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9]/-/g') HASH=$(echo -n "${BRANCH_SLUG}${PROJECT_SLUG}" | md5sum | cut -c1-8) echo "app_name=pr${HASH}" >> "$GITHUB_OUTPUT" - name: Delete preview uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SERVER_HOST }} username: root key: ${{ secrets.SERVER_SSH_KEY }} script: | APP="${{ steps.ids.outputs.app_name }}" if cipi app show "$APP" &>/dev/null; then echo "y" | cipi app delete "$APP" echo "→ Deleted: $APP" else echo "→ Not found, nothing to delete" fi
GitLab CI/CD
Adicione estas variáveis CI/CD: SERVER_HOST, SERVER_SSH_KEY (Tipo de arquivo),
DEPLOY_WILDCARD_DOMAIN, GL_TOKEN (um token de acesso de projeto/grupo com
read_repositório escopo).
# .gitlab-ci.yml stages: - preview - cleanup .ssh_setup: &ssh_setup before_script: - apt-get install -y openssh-client - eval $(ssh-agent -s) - echo "$SERVER_SSH_KEY" | tr -d '\r' | ssh-add - - mkdir -p ~/.ssh - ssh-keyscan -H "$SERVER_HOST" >> ~/.ssh/known_hosts .compute_ids: &compute_ids | BRANCH_SLUG=$(echo "$CI_COMMIT_REF_NAME" \ | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9]/-/g; s/--*/-/g; s/^-//; s/-$//') PROJECT_SLUG=$(echo "$CI_PROJECT_NAME" \ | tr '[:upper:]' '[:lower:]' \ | sed 's/[^a-z0-9]/-/g') HASH=$(echo -n "${BRANCH_SLUG}${PROJECT_SLUG}" | md5sum | cut -c1-8) APP="pr${HASH}" DOMAIN="${BRANCH_SLUG}-${PROJECT_SLUG}-${HASH}.${DEPLOY_WILDCARD_DOMAIN}" REPO="https://oauth2:${GL_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" WILDCARD="/etc/letsencrypt/live/${DEPLOY_WILDCARD_DOMAIN}" deploy-preview: stage: preview <<: *ssh_setup except: - main - master script: - *compute_ids - | ssh root@$SERVER_HOST bash -s << ENDSSH APP="$APP" DOMAIN="$DOMAIN" REPO="$REPO" BRANCH="$CI_COMMIT_REF_NAME" WILDCARD="$WILDCARD" if cipi app show "\$APP" &>/dev/null; then echo "Updating: \$APP" cipi deploy "\$APP" else echo "Creating: \$APP → \$DOMAIN" cipi app create \ --user="\$APP" \ --domain="\$DOMAIN" \ --repository="\$REPO" \ --branch="\$BRANCH" \ --php=8.5 awk -v cert="\$WILDCARD" ' /^ listen 80;/ { print print " listen 443 ssl http2;" print " ssl_certificate " cert "/fullchain.pem;" print " ssl_certificate_key " cert "/privkey.pem;" next } { print } ' "/etc/nginx/sites-available/\$APP" > /tmp/_cipi_vhost \ && mv /tmp/_cipi_vhost "/etc/nginx/sites-available/\$APP" nginx -t && systemctl reload nginx cipi deploy "\$APP" fi ENDSSH - echo "Preview → https://$DOMAIN" cleanup-preview: stage: cleanup <<: *ssh_setup only: - branches when: manual # or trigger on MR merge via rules: script: - *compute_ids - | ssh root@$SERVER_HOST " APP='$APP' if cipi app show \"\$APP\" &>/dev/null; then echo 'y' | cipi app delete \"\$APP\" fi "
cleanup-preview automaticamente quando uma solicitação de mesclagem é
mesclado adicionando um rules: bloquear que verifica
$CI_MERGE_REQUEST_EVENT_TYPE == "merge_train" ou usando um dedicado
workflow: com if: $CI_PIPELINE_SOURCE == "merge_request_event".
Notas e limites
cipi app list periodicamente e exclua visualizações obsoletas.O patch nginx SSL não é idempotente — se o pipeline for executado
cipi app create duas vezes (por exemplo, devido a uma nova tentativa), o awk patch será
aplicado novamente. O hash garante APP_NAME é determinístico, então o
if cipi app show guarda impede a criação dupla em condições normais.Evite correr
cipi ssl install em um aplicativo de visualização - ele irá
substituir a configuração do certificado curinga por um certificado Let's Encrypt por domínio que falhará (o
domínio não possui registro DNS dedicado, apenas o curinga).