Hooks de despliegue
Ejecute un comando desde la imagen de su aplicación en cuatro momentos de un despliegue Git: antes y después de la construcción, antes y después del cambio de tráfico.
Qué es un hook de despliegue
Un hook de despliegue es un único comando asociado a una aplicación y a una etapa de su despliegue. sh0 lo ejecuta en un contenedor desechable iniciado desde la imagen de la aplicación, registra su salida en el log del despliegue y decide, según su código de salida, si el despliegue continúa.
Usos típicos: una migración de base de datos antes de que el tráfico llegue a la nueva versión (npm run migrate, php artisan migrate --force), una prueba rápida de la imagen recién construida, un precalentamiento de caché después del cambio.
Qué aplicaciones ejecutan hooks
Solo las aplicaciones desplegadas desde un repositorio Git ejecutan hooks. sh0 se niega a crear un hook en cualquier otra aplicación (envío de archivo con sh0 push, imagen Docker, Dockerfile pegado, archivo Compose, plantilla), porque el hook nunca se ejecutaría:
$ sh0 hooks my-site create --hook-type pre_build --command "node --version"
Error: Deploy hooks only run on git-based deploys; app 'my-site' is a 'upload' app, where hooks would never fire. Remove the hook or convert the app to a git deploy. (BAD_REQUEST)Una aplicación Git cuyo repositorio se despliega como una pila Compose tampoco ejecuta hooks: la ruta Compose sale del pipeline antes de la primera etapa de hooks.
Las cuatro etapas
La etapa decide cuándo se ejecuta el hook, en qué imagen corre, qué recibe y qué provoca un fallo:
| Etapa | Cuándo | Imagen y entradas | Si falla |
|---|---|---|---|
| pre_build | Tras la clonación, antes de construir la imagen | La imagen de la versión desplegada actualmente. Sin variables de entorno ni volúmenes. Se omite en el primer despliegue (todavía no existe ninguna imagen). | El despliegue falla. La versión anterior sigue sirviendo el tráfico. |
| post_build | Tras construir la imagen, antes de iniciar el nuevo contenedor | La nueva imagen, con las variables de entorno de la aplicación. Sin volúmenes. | El despliegue falla. La versión anterior sigue sirviendo el tráfico. |
| pre_deploy | Después de que el nuevo contenedor supere su comprobación de salud, antes de que la ruta cambie hacia él | La nueva imagen, con las variables de entorno y los volúmenes de la aplicación montados. | El despliegue falla, el nuevo contenedor se elimina y la versión anterior sigue sirviendo el tráfico. |
| post_deploy | Tras el cambio de ruta y la eliminación del contenedor anterior | La nueva imagen, con las variables de entorno y los volúmenes. | Se registra como fallo; el despliegue sigue siendo correcto (la nueva versión ya está en línea). |
pre_build, post_build o pre_deploy que falla siempre hace fallar el despliegue; un hook post_deploy que falla, nunca.Crear un hook
En el panel, abra la aplicación, luego la pestaña Hooks de despliegue, y haga clic en Crear hook. Elija el Tipo de hook, escriba el Comando y, si hace falta, el Tiempo de espera (segundos) (300 por defecto).
Desde la CLI, el tipo se indica con --hook-type (pre_build, post_build, pre_deploy, post_deploy):
$ sh0 hooks my-api create --hook-type post_build --command "id"
Deploy hook created: 949d4097-4350-48c0-9c7c-6ca3c582a51a
Type: post_build
Command: id
Timeout: 300s
$ sh0 hooks my-api list
ID Type Command Timeout Enabled
----------------------------------------------------------------------------------------------------------
281e3d14-fdca-4478-8ae3-985d4a604562 post_deploy env | grep NODE 300 Yes
1b025181-05a1-4f8e-bd6b-3a26fcb69848 post_deploy printenv PORT 300 Yes
22ee2ab3-7fc4-4714-a05d-f1dd779514f3 pre_deploy echo second 300 Yes
6f1fa1be-b188-4cc0-b277-cf5acfbe0780 pre_deploy echo first 300 Yes
949d4097-4350-48c0-9c7c-6ca3c582a51a post_build id 300 Yes
b8303249-54fe-4358-90f8-a287390c219f pre_build node --version 300 Yessh0 hooks my-api delete <id> elimina un hook. Para pausarlo sin eliminarlo, envíe PATCH /api/v1/deploy-hooks/<id> con enabled=false. La API también ofrece GET y POST /api/v1/apps/<app-id>/deploy-hooks. Crear o modificar un hook requiere el rol de desarrollador en la aplicación.
Dónde se ejecuta un hook
Nunca en el propio servidor. Cada hook obtiene un contenedor de un solo uso, iniciado desde la imagen indicada en la tabla anterior, con estas propiedades:
- Se ejecuta con el usuario sin privilegios
1000:1000, nunca como root. - El
ENTRYPOINTde la imagen se vacía: el comando se ejecuta tal cual, no como argumentos denodeonpm. - Se conecta a la red
sh0-net, así que puede alcanzar las bases de datos de la aplicación por su nombre de host interno. - Sin shell. El comando se divide por los espacios y se ejecuta directamente.
|,;,&,>,<, los acentos graves y$(se rechazan, y las comillas se pasan literalmente. Para todo lo que necesite un shell, incluya un script en su imagen y llámelo:sh scripts/migrate.sh. Las reglas completas son las de las tareas programadas; un comando está limitado a 4096 caracteres.
Un hook post_build que ejecuta id en una imagen Node.js muestra el usuario del entorno aislado:
[HOOKS] post_build hooks:
[OK] id (242ms, exit: Some(0))
stdout: uid=1000(node) gid=1000(node) groups=1000(node)Orden y tiempo de espera
Los hooks de una misma etapa se ejecutan uno tras otro, el creado más recientemente primero. Si el orden importa, cree primero el que debe ejecutarse al final, o encadene los pasos en un solo script.
Cada hook tiene su propio tiempo de espera, 300 segundos por defecto. Un hook que lo supera cuenta como fallo (Hook timed out after 5s en el log). Su contenedor no se detiene: sigue ejecutándose hasta que el comando termina por sí solo y después permanece en el servidor.
Leer los resultados
Los resultados se añaden al log de construcción del despliegue, en la pestaña Despliegues. Cada hook tiene una línea con su estado (OK, FAIL o SKIP), su duración y su código de salida, seguida de las 10 primeras líneas de su salida estándar y de error. Los secretos se ocultan en esas líneas. Log real de un primer despliegue con cinco hooks:
[HOOKS] pre_build hooks:
[SKIP] node --version (0ms, exit: None)
stderr: skipped: no app image available yet (hooks run in a container, never on the host)
[HOOKS] post_build hooks:
[OK] id (292ms, exit: Some(0))
stdout: uid=1000(node) gid=1000(node) groups=1000(node)
[HOOKS] pre_deploy hooks:
[OK] echo second (287ms, exit: Some(0))
stdout: second
[OK] echo first (295ms, exit: Some(0))
stdout: first
[HOOKS] post_deploy hooks:
[OK] printenv PORT (249ms, exit: Some(0))
stdout: 3001Cuando falla un hook bloqueante, el log termina con el error y la eliminación del nuevo contenedor. Aquí un hook pre_deploy salió con el código 3 y la versión ya en línea siguió funcionando:
[STEP 5/6] Health check passed (previous step: 8.3s)
[ERROR] Deploy hook 'node -e process.exit(3)' failed with exit code Some(3):
[WARNING] Removed the container this failed deployment had started (/sh0-17b83e1c-my-api-6abc39e3). A failed deploy leaves nothing running.En ese caso no se conserva la salida del hook fallido, ni la de los hooks de la misma etapa ejecutados antes: solo queda la línea de error.
Límites
- Un comando con un carácter prohibido se acepta al crear el hook y solo se rechaza al ejecutarse. En una etapa bloqueante el despliegue falla; en
post_deployel hook desaparece del log sin dejar rastro. Revise su comando antes de guardarlo. - Los hooks no envían notificaciones. Las alertas de sh0 y sus canales (correo, Slack, Discord, Telegram, webhook) se describen en la página de monitorización.
- Una reversión de una aplicación Git vuelve a pasar por todo el pipeline, hooks incluidos. Consulte la página de reversiones para saber qué despliega realmente una reversión.