Déployer depuis la CI/CD
Déployer à chaque push depuis GitHub Actions ou GitLab CI/CD, avec un identifiant restreint et un job qui échoue quand le déploiement échoue.
Un pipeline fait quatre choses : installer la CLI, se connecter avec un identifiant conservé dans le système de CI, créer l'application la première fois puis la mettre à jour à chaque fois ensuite, et attendre le déploiement pour que le job échoue quand celui-ci échoue. Deux modèles prêts à l'emploi font exactement cela. Cette page les présente en entier, explique chaque partie et décrit ce qui peut mal tourner.
1. Créer un identifiant pour le pipeline
Ne réutilisez pas l'identifiant de votre propre machine. Créez-en un réservé à la CI, avec uniquement ce dont le pipeline a besoin : il pourra être révoqué sans vous déconnecter, et ne permettra rien de plus que déployer s'il fuit.
export ISOGRID_CONFIG_HOME="$(mktemp -d)"
isogrid --api https://api.isogrid.skyvault.pro login \
--scope application:create,application:write-any \
--name github-ci
Le navigateur s'ouvre sur la page d'approbation. Vérifiez l'organisation qui y est affichée : l'identifiant y est rattaché et sera refusé partout ailleurs. Approuvez, puis copiez le jeton depuis la configuration temporaire et supprimez-la :
jq -r '.contexts[].token' "$ISOGRID_CONFIG_HOME/config.json"
rm -rf "$ISOGRID_CONFIG_HOME"
Utiliser un ISOGRID_CONFIG_HOME temporaire laisse votre propre connexion
intacte. Sans cela, le nouvel identifiant remplacerait celui de
~/.isogrid/config.json pour cette adresse, et il vous faudrait
isogrid login --force pour récupérer le vôtre.
Quelles portées
| Portée | Ce que le pipeline peut faire avec |
|---|---|
application:create |
Créer l'application lors de la première exécution. |
application:write-any |
Modifier, construire et déployer toutes les applications de l'organisation. |
application:deploy-any |
Construire, déployer, démarrer et arrêter toutes les applications, sans modifier leurs paramètres. |
Les modèles créent l'application si elle n'existe pas : ils ont donc besoin de
application:create et de application:write-any. Une fois l'application
créée, vous pouvez créer un identifiant plus restreint, sans
application:create. application:deploy-any ne suffit que si le pipeline ne
passe jamais de paramètres : pas de --env-file ni de changement de branche.
Une portée n'ajoute jamais rien à ce que vous détenez. Elle est croisée avec votre propre rôle et vos groupes à chaque requête : une portée que vous ne détenez pas est ignorée sans message, et si l'on réduit vos droits, l'identifiant du pipeline est réduit aussi. Certaines choses sont interdites à un identifiant, quoi qu'il demande : la facturation, la nomination d'administrateurs, et la création ou la révocation d'identifiants. Voir Rôles, groupes de permissions et accès.
Un identifiant dure 90 jours, sauf si vous avez choisi une durée plus courte sur la page d'approbation. Notez dans votre agenda de le remplacer avant.
2. Configurer le système de CI
| Paramètre | GitHub Actions | GitLab CI/CD |
|---|---|---|
ISOGRID_TOKEN |
Secret du dépôt | Variable CI/CD, Masked (masquée) |
ISOGRID_API_URL |
Variable du dépôt, par ex. https://api.isogrid.skyvault.pro |
Variable CI/CD |
ISOGRID_APP |
Variable facultative. Par défaut, le nom du dépôt. | Variable facultative. Par défaut, le nom du projet. |
ISOGRID_CLUSTER |
Facultatif. Slug de la région ; nécessaire si plusieurs régions vous sont ouvertes. | Idem |
ISOGRID_TIER |
Facultatif. Type d'instance ; par défaut, le plus petit de la région. | Idem |
ISOGRID_NETWORK |
Facultatif. Slug du réseau ; par défaut, celui de votre organisation. | Idem |
ISOGRID_ENV_FILE |
Facultatif. Un fichier dotenv du dépôt à appliquer à chaque déploiement. | Idem |
Sur GitHub, ces réglages se trouvent sous Settings → Secrets and variables →
Actions. Sur GitLab, sous Settings → CI/CD → Variables ; marquez aussi
ISOGRID_TOKEN comme Protected (protégée) si seules les branches protégées
déploient.
La CLI lit ISOGRID_TOKEN dans l'environnement et ne l'écrit jamais sur le
disque : un pipeline qui met en cache le répertoire personnel ne transmet donc
pas le jeton aux jobs suivants.
3. Ajouter le pipeline
La CLI écrit le fichier pour vous :
isogrid ci init github --app shop --cluster eu-west # .github/workflows/isogrid-deploy.yml
isogrid ci init gitlab --app shop --cluster eu-west # .gitlab-ci.yml
isogrid ci init github --output - # print it instead
Les valeurs que vous passez (--app, --cluster, --tier, --network,
--env-file) sont écrites dans le fichier. Tout ce que vous omettez est lu dans
les variables de CI ci-dessus. Un fichier existant n'est pas écrasé sans
--force. Une fois le fichier écrit, la commande affiche les variables qu'il
reste à définir.
Vous pouvez aussi télécharger les modèles sans la CLI :
curl -fsSL https://api.isogrid.skyvault.pro/api/v1/cli/ci-templates/github -o .github/workflows/isogrid-deploy.yml
curl -fsSL https://api.isogrid.skyvault.pro/api/v1/cli/ci-templates/gitlab -o .gitlab-ci.yml
Avant la première exécution
Le dépôt doit être connecté à votre organisation et ouvert à la personne dont le
pipeline utilise l'identifiant. isogrid repos list l'affiche une fois que
c'est le cas ; la colonne YOU doit inclure create-app et deploy. Voir
Dépôts Git.
Le modèle GitHub Actions
# Deploy to ISOGrid from GitHub Actions.
#
# Save as .github/workflows/isogrid-deploy.yml (or generate it with
# `isogrid ci init github`). On every push to main, and whenever you run it by
# hand, it installs the ISOGrid CLI and either updates the application and
# deploys the pushed commit, or - the first time - creates the application.
#
# Set these in the repository (Settings -> Secrets and variables -> Actions):
#
# Secrets
# ISOGRID_TOKEN A CLI credential. Mint a narrow one for CI: run
# `isogrid login --scope application:create,application:write-any --name github-ci`
# on your machine, then copy the token from
# ~/.isogrid/config.json. Never commit it.
#
# Variables
# ISOGRID_API_URL Your platform's API, e.g. https://api.isogrid.skyvault.pro
# ISOGRID_APP Application name (default: this repository's name)
# ISOGRID_CLUSTER Region slug (optional when only one region is open to you)
# ISOGRID_TIER Instance type name (optional: the region's smallest)
# ISOGRID_NETWORK Network slug (optional: your organization's network)
# ISOGRID_ENV_FILE A dotenv file in the repository to apply (optional)
#
# The repository must already be connected to the organization through the
# ISOGrid GitHub app (`isogrid repos list` shows it once it is).
name: Deploy to ISOGrid
on:
push:
branches: [main]
workflow_dispatch:
# One deployment of a branch at a time; a newer push waits rather than racing.
concurrency:
group: isogrid-deploy-${{ github.ref }}
cancel-in-progress: false
env:
ISOGRID_API_URL: ${{ vars.ISOGRID_API_URL }}
ISOGRID_TOKEN: ${{ secrets.ISOGRID_TOKEN }}
ISOGRID_APP: ${{ vars.ISOGRID_APP || github.event.repository.name }}
ISOGRID_CLUSTER: ${{ vars.ISOGRID_CLUSTER }}
ISOGRID_TIER: ${{ vars.ISOGRID_TIER }}
ISOGRID_NETWORK: ${{ vars.ISOGRID_NETWORK }}
ISOGRID_ENV_FILE: ${{ vars.ISOGRID_ENV_FILE }}
jobs:
deploy:
runs-on: ubuntu-latest
steps:
# Only needed for ISOGRID_ENV_FILE: the platform clones the repository
# itself to build it.
- uses: actions/checkout@v4
- name: Install the ISOGrid CLI
run: |
curl -fsSL "$ISOGRID_API_URL/api/v1/cli/install.sh" | ISOGRID_INSTALL_DIR="$HOME/.local/bin" sh
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- name: Deploy
run: |
set -eu
isogrid version
ENV_ARGS=""
if [ -n "$ISOGRID_ENV_FILE" ]; then
ENV_ARGS="--env-file $ISOGRID_ENV_FILE"
fi
# --exact: an application called "api" must not be taken for "api-gateway".
if isogrid apps get "$ISOGRID_APP" --exact --json > /dev/null 2>&1; then
# Builds this exact commit and waits; the step fails if the build or
# the deployment does.
isogrid apps update "$ISOGRID_APP" \
--branch "${{ github.ref_name }}" \
$ENV_ARGS \
--deploy --ref "${{ github.sha }}" --wait
else
isogrid apps create \
--name "$ISOGRID_APP" \
--provider github \
--url "${{ github.server_url }}/${{ github.repository }}" \
--branch "${{ github.ref_name }}" \
--cluster "$ISOGRID_CLUSTER" \
--tier "$ISOGRID_TIER" \
--network "$ISOGRID_NETWORK" \
$ENV_ARGS \
--wait
fi
Le modèle GitLab CI/CD
# Deploy to ISOGrid from GitLab CI/CD.
#
# Save as .gitlab-ci.yml at the root of the project (or generate it with
# `isogrid ci init gitlab`), or merge the job into the one you have. On every
# push to the default branch, and when run by hand, it installs the ISOGrid CLI
# and either updates the application and deploys the pushed commit, or - the
# first time - creates the application.
#
# Set these under Settings -> CI/CD -> Variables:
#
# ISOGRID_TOKEN A CLI credential; mark it Masked (and Protected if only
# protected branches deploy). Mint a narrow one for CI:
# `isogrid login --scope application:create,application:write-any --name gitlab-ci`
# on your machine, then copy the token from
# ~/.isogrid/config.json. Never commit it.
# ISOGRID_API_URL Your platform's API, e.g. https://api.isogrid.skyvault.pro
#
# and optionally override the defaults below the same way (project variables
# take precedence over the values written in this file):
#
# ISOGRID_APP Application name (default: the project's name)
# ISOGRID_CLUSTER Region slug (optional when only one region is open to you)
# ISOGRID_TIER Instance type name (optional: the region's smallest)
# ISOGRID_NETWORK Network slug (optional: your organization's network)
# ISOGRID_ENV_FILE A dotenv file in the repository to apply (optional)
#
# The project must already be connected to the organization through the
# ISOGrid GitLab integration (`isogrid repos list` shows it once it is).
stages:
- deploy
variables:
ISOGRID_APP: "$CI_PROJECT_NAME"
ISOGRID_CLUSTER: ""
ISOGRID_TIER: ""
ISOGRID_NETWORK: ""
ISOGRID_ENV_FILE: ""
isogrid-deploy:
stage: deploy
image: alpine:3.20
# One deployment of a branch at a time.
resource_group: isogrid-$CI_COMMIT_REF_SLUG
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "web"
before_script:
- apk add --no-cache curl
- curl -fsSL "$ISOGRID_API_URL/api/v1/cli/install.sh" | ISOGRID_INSTALL_DIR=/usr/local/bin sh
- isogrid version
script:
- |
set -eu
ENV_ARGS=""
if [ -n "$ISOGRID_ENV_FILE" ]; then
ENV_ARGS="--env-file $ISOGRID_ENV_FILE"
fi
# --exact: an application called "api" must not be taken for "api-gateway".
if isogrid apps get "$ISOGRID_APP" --exact --json > /dev/null 2>&1; then
# Builds this exact commit and waits; the job fails if the build or
# the deployment does.
isogrid apps update "$ISOGRID_APP" \
--branch "$CI_COMMIT_REF_NAME" \
$ENV_ARGS \
--deploy --ref "$CI_COMMIT_SHA" --wait
else
isogrid apps create \
--name "$ISOGRID_APP" \
--provider gitlab \
--url "$CI_PROJECT_URL" \
--branch "$CI_COMMIT_REF_NAME" \
--cluster "$ISOGRID_CLUSTER" \
--tier "$ISOGRID_TIER" \
--network "$ISOGRID_NETWORK" \
$ENV_ARGS \
--wait
fi
--provider gitlab est indiqué explicitement : un GitLab auto-hébergé dont
l'adresse ne contient pas « gitlab » fonctionne donc aussi, et $CI_PROJECT_URL
transmet les groupes imbriqués tels quels.
Ce que fait le pipeline, étape par étape
Il installe la CLI depuis votre plateforme, en vérifiant sa somme de contrôle. La CLI et la plateforme sont toujours de la même génération, puisque l'une distribue l'autre.
Il vérifie si l'application existe avec apps get --exact. Sans --exact,
une nouvelle application appelée api serait confondue avec une application
api-gateway existante, et le pipeline déploierait la mauvaise.
Il la met à jour si elle existe. --branch fait suivre à l'application la
branche qui a été poussée. --deploy --ref <commit> construit exactement ce
commit, et non ce vers quoi pointe la branche au moment où la construction
démarre : deux push rapprochés ne peuvent donc pas déployer le code l'un de
l'autre. --env-file fusionne le fichier dans l'environnement de
l'application ; les clés retirées du fichier restent sur l'application, sauf si
vous ajoutez --replace-env.
Il la crée la première fois, à partir du dépôt qui a déclenché l'exécution.
Des valeurs vides pour --cluster, --tier et --network signifient les
valeurs par défaut.
Il attend. --wait ne rend la main qu'une fois la construction et le
déploiement terminés, et se termine avec le code 1 si l'un des deux a échoué,
y compris un déploiement ramené à la version précédente. C'est ce code de sortie
qui fait échouer le job.
Il n'exécute qu'un déploiement à la fois par branche : concurrency sur
GitHub, resource_group sur GitLab. Un second push attend le premier au lieu
d'entrer en concurrence avec lui.
Écrire le vôtre
Le cœur des deux modèles tient en cinq lignes de shell : tout système de CI capable d'exécuter un shell peut s'en servir :
curl -fsSL "$ISOGRID_API_URL/api/v1/cli/install.sh" | sh
if isogrid apps get "$APP" --exact --json > /dev/null 2>&1; then
isogrid apps update "$APP" --branch "$BRANCH" --deploy --ref "$COMMIT_SHA" --wait
else
isogrid apps create --name "$APP" --provider github --url "$REPO_URL" --branch "$BRANCH" --wait
fi
Variante : construire l'image dans la CI
Si votre pipeline construit déjà une image de conteneur, laissez-le pousser l'image dans le registre de votre organisation et faites-la déployer par la plateforme, plutôt que de la construire une seconde fois.
Créez l'application une fois, à partir de l'image :
isogrid apps create --name worker --provider registry --url acme/worker:latest --cluster eu-west
Ensuite, chaque exécution pousse un nouveau tag et fait pointer l'application dessus :
docker build -t "$REGISTRY/$NAMESPACE/worker:$COMMIT_SHA" .
docker push "$REGISTRY/$NAMESPACE/worker:$COMMIT_SHA"
isogrid apps update worker --tag "$COMMIT_SHA" --deploy --wait
Le pipeline a besoin d'identifiants de registre en plus de ISOGRID_TOKEN : un
compte robot créé depuis la page Images de la console, enregistré dans
ISOGRID_REGISTRY_USER et dans un secret ou une variable masquée
ISOGRID_REGISTRY_PASSWORD, avec ISOGRID_REGISTRY (l'hôte du registre) et
ISOGRID_NAMESPACE (votre namespace). Les deux modèles contiennent ce job, en
commentaire, à la fin du fichier. Les noms d'images doivent être en minuscules :
définissez donc ISOGRID_APP explicitement si le nom du dépôt ne l'est pas.
Quand ça ne va pas
Pendant la mise en place, faites de isogrid whoami la première commande du
job. Elle affiche à qui appartient l'identifiant, l'organisation à laquelle il
est rattaché et les permissions qui lui seront réellement accordées.
« not signed in ». ISOGRID_TOKEN est vide dans le job. Sur GitHub, un
secret n'est pas transmis aux workflows déclenchés depuis des forks. Sur GitLab,
une variable Protected n'est pas transmise aux branches non protégées.
L'identifiant a expiré ou a été révoqué. Créez-en un nouveau et remplacez le secret. Rien d'autre n'a besoin de changer.
Une erreur de permission sur apps create. L'identifiant n'a pas
application:create, ou vous ne la détenez pas vous-même. whoami indique
lequel des deux.
Une erreur de permission sur apps update. L'identifiant ne peut pas
modifier ou déployer cette application. Soit il n'a pas
application:write-any, soit il n'a que application:deploy-any et la commande
a passé un paramètre (--env-file, ou un --branch différent).
« is not a repository you have been given access to », ou « You do not have
'repo:deploy' on acme/api ». Le jeton agit en votre nom, et vous ne pouvez pas
construire depuis ce dépôt. Quelqu'un d'autre a connecté le compte par lequel il
arrive et ne vous a pas ouvert le dépôt. Demandez-lui, ou à un administrateur
s'il est parti, d'exécuter isogrid repos grant acme/api --member you@example.com --preset repo-deployer. Si le dépôt est ouvert aux
administrateurs et que vous en êtes un, créez l'identifiant en ajoutant aussi
github:manage à ses portées : c'est sur cette permission que repose l'accès
des administrateurs aux dépôts. Voir Dépôts Git.
« pinned to » une autre organisation. L'identifiant a été approuvé alors que
le navigateur affichait une autre organisation, ou ISOGRID_ORGANIZATION ou
--organization désigne une organisation à laquelle il n'est pas rattaché.
Changez d'organisation dans la console et créez de nouveau l'identifiant.
« choose a region with --cluster ». Plusieurs régions vous sont ouvertes.
Définissez ISOGRID_CLUSTER.
Le job a expiré mais le déploiement s'est terminé. --wait a abandonné
après --timeout (20 minutes par défaut) ; le déploiement a continué.
Augmentez-le avec --timeout 40m pour les constructions lentes.
Le job a échoué et le site est toujours en ligne. La nouvelle version n'est
jamais devenue saine et la précédente a été remise en place. C'est bien un échec
qui justifie de faire échouer le job. Consultez isogrid apps logs <app>.
Codes de sortie
| Code | Signification |
|---|---|
0 |
Déployé, ou rien à changer. |
1 |
Quelque chose a échoué : une erreur de l'API ou de permission, une construction échouée, un déploiement échoué ou annulé, un délai dépassé. |
2 |
La commande a été mal appelée : une option inconnue, une valeur manquante, ou un delete sans --yes. Presque toujours une erreur dans le fichier du pipeline. |