feat(infra): Terraform provisionne la VM, GitHub Actions continue de déployer
Le seul Terraform du dépôt installait un cluster k3s que rien ne consomme, et sa racine ne passait même pas `terraform init` : depuis Terraform 1.x, un provisioner `destroy` impose que tout le bloc `connection` ne lise que `self`, et celui du module k3s lisait `var.*`. Il est corrigé en batissant la connexion sur `triggers`, où ne figurent que l'adresse, le port, l'utilisateur et le chemin de la clé : jamais la clé ni un mot de passe. `environments/vm-eni` provisionne la machine qui porte la recette et la production : Docker et le plugin Compose, `scripts/provision-host.sh`, puis l'enregistrement du runner. Rien n'y construit d'image ni ne lance de conteneur, et un `apply` n'interrompt pas la stack qui tourne. Le déploiement continu ne bouge pas : `deploy.yml` reste le seul chemin de livraison. `environments/dev` devient `k3s-cible`, parce qu'il provisionnait un cluster et pas un environnement applicatif, et que `rec` et `prod` vivent sur la même machine. `environments/prod`, dossier vide, disparaît. `infra.yml` formate et valide chaque racine à chaque push : c'est l'absence d'un tel job qui a laissé ce Terraform cassé sans que rien ne le dise. La boucle parcourt `environments/*`, une racine ajoutée est couverte sans y toucher. ADR 0010 pour la frontière entre provisionnement et livraison, et la doc d'architecture alignée dessus.
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
# Pourquoi : Terraform provisionne la machine, GitHub Actions la deploie (ADR 0010). Rien ici ne
|
||||
# construit d'image ni ne lance de conteneur : la livraison reste portee par `deploy.yml` et
|
||||
# `make stack-up`, et un `apply` n'interrompt pas la stack qui tourne.
|
||||
# Piege : seul le bloc `triggers` d'un `null_resource` atterrit dans le state. Ni le jeton du
|
||||
# runner ni la cle SSH n'y figurent, et ne doivent jamais y etre ajoutes pour forcer un rejeu.
|
||||
# Contrainte : pas de provisioner `destroy` sur le runner. Il imposerait une connexion ne lisant
|
||||
# que `self`, donc le chemin de la cle SSH dans le state, et `svc.sh uninstall` ne desinscrit pas
|
||||
# le runner cote GitHub : le retrait reste manuel, depuis les parametres du depot.
|
||||
# Ref : ADR 0009 pour les deux environnements, `scripts/provision-host.sh` pour leur contenu.
|
||||
|
||||
locals {
|
||||
sudo = var.ssh_user == "root" ? "" : "sudo "
|
||||
en_tant_que = "${var.ssh_user == "root" ? "" : "sudo "}runuser -u ${var.proprietaire} --"
|
||||
provisionneur = "${path.root}/../../../../scripts/provision-host.sh"
|
||||
runner_archive = "actions-runner-linux-x64-${var.runner_version}.tar.gz"
|
||||
}
|
||||
|
||||
resource "null_resource" "docker_engine" {
|
||||
triggers = {
|
||||
hote = var.ssh_host
|
||||
user = var.proprietaire
|
||||
}
|
||||
|
||||
connection {
|
||||
type = "ssh"
|
||||
host = var.ssh_host
|
||||
port = var.ssh_port
|
||||
user = var.ssh_user
|
||||
private_key = file(pathexpand(var.ssh_private_key_path))
|
||||
timeout = "5m"
|
||||
}
|
||||
|
||||
provisioner "remote-exec" {
|
||||
inline = [
|
||||
<<-EOT
|
||||
set -eu
|
||||
id ${var.proprietaire} >/dev/null 2>&1 || {
|
||||
echo "l'utilisateur ${var.proprietaire} n'existe pas sur la machine" >&2
|
||||
exit 1
|
||||
}
|
||||
command -v docker >/dev/null || ${local.sudo}sh -c 'curl -fsSL https://get.docker.com | sh'
|
||||
${local.sudo}systemctl enable --now docker
|
||||
${local.sudo}usermod -aG docker ${var.proprietaire}
|
||||
${local.sudo}docker compose version
|
||||
EOT
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# `provision-host.sh` verifie lui-meme docker, compose et la sortie HTTPS, puis prepare un clone
|
||||
# par environnement, son `.env` et son certificat. Il est rejouable : un `.env` existant n'est
|
||||
# jamais reecrit, un certificat present jamais regenere.
|
||||
resource "null_resource" "environnements" {
|
||||
depends_on = [null_resource.docker_engine]
|
||||
|
||||
triggers = {
|
||||
script = filesha256(local.provisionneur)
|
||||
racine = var.racine
|
||||
depot = var.depot_url
|
||||
}
|
||||
|
||||
connection {
|
||||
type = "ssh"
|
||||
host = var.ssh_host
|
||||
port = var.ssh_port
|
||||
user = var.ssh_user
|
||||
private_key = file(pathexpand(var.ssh_private_key_path))
|
||||
timeout = "5m"
|
||||
}
|
||||
|
||||
provisioner "file" {
|
||||
source = local.provisionneur
|
||||
destination = "/tmp/provision-host.sh"
|
||||
}
|
||||
|
||||
provisioner "remote-exec" {
|
||||
inline = [
|
||||
<<-EOT
|
||||
set -eu
|
||||
${local.sudo}env RACINE='${var.racine}' \
|
||||
REPO_URL='${var.depot_url}' \
|
||||
PROPRIETAIRE='${var.proprietaire}' \
|
||||
PUBLIC_IP='${var.adresse_publique}' \
|
||||
bash /tmp/provision-host.sh
|
||||
rm -f /tmp/provision-host.sh
|
||||
EOT
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# Piege : le jeton d'enregistrement expire en une heure. Un `apply` rejoue cette ressource des
|
||||
# que `runner_version` ou `runner_labels` change, et redemande donc un jeton frais.
|
||||
resource "null_resource" "runner_github" {
|
||||
depends_on = [null_resource.environnements]
|
||||
|
||||
triggers = {
|
||||
version = var.runner_version
|
||||
labels = var.runner_labels
|
||||
dossier = var.runner_dossier
|
||||
}
|
||||
|
||||
connection {
|
||||
type = "ssh"
|
||||
host = var.ssh_host
|
||||
port = var.ssh_port
|
||||
user = var.ssh_user
|
||||
private_key = file(pathexpand(var.ssh_private_key_path))
|
||||
timeout = "5m"
|
||||
}
|
||||
|
||||
provisioner "remote-exec" {
|
||||
inline = [
|
||||
<<-EOT
|
||||
set -eu
|
||||
${local.sudo}install -d -o ${var.proprietaire} -g ${var.proprietaire} ${var.runner_dossier}
|
||||
if [ ! -x ${var.runner_dossier}/config.sh ]; then
|
||||
curl -fsSL -o /tmp/${local.runner_archive} \
|
||||
https://github.com/actions/runner/releases/download/v${var.runner_version}/${local.runner_archive}
|
||||
${local.sudo}tar -xzf /tmp/${local.runner_archive} -C ${var.runner_dossier}
|
||||
${local.sudo}chown -R ${var.proprietaire}:${var.proprietaire} ${var.runner_dossier}
|
||||
rm -f /tmp/${local.runner_archive}
|
||||
fi
|
||||
if [ ! -f ${var.runner_dossier}/.runner ]; then
|
||||
${local.en_tant_que} sh -c 'cd ${var.runner_dossier} && ./config.sh --unattended --replace \
|
||||
--url ${var.runner_url} --token ${var.runner_token} \
|
||||
--labels ${var.runner_labels} --name ${var.runner_labels} --work _work'
|
||||
${local.sudo}${var.runner_dossier}/svc.sh install ${var.proprietaire}
|
||||
fi
|
||||
${local.sudo}${var.runner_dossier}/svc.sh start
|
||||
EOT
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user