Documentación/ Despliegue/ Hooks de despliegue

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:

Terminal
$ 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:

EtapaCuándoImagen y entradasSi falla
pre_buildTras la clonación, antes de construir la imagenLa 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_buildTras construir la imagen, antes de iniciar el nuevo contenedorLa 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_deployDespués de que el nuevo contenedor supere su comprobación de salud, antes de que la ruta cambie hacia élLa 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_deployTras el cambio de ruta y la eliminación del contenedor anteriorLa 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).
Warning
No existe un ajuste «fallar si hay error» por hook. Solo la etapa decide: un hook 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):

Terminal
$ 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      Yes

sh0 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 ENTRYPOINT de la imagen se vacía: el comando se ejecuta tal cual, no como argumentos de node o npm.
  • 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:

Build log
[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:

Build log
[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: 3001

Cuando 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:

Build log
[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_deploy el 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.