Retour aux projets
20 oct. 2026 • Projet

Migration GCP → OVH : extranet Symfony

Migration d'un extranet Symfony et de son site vitrine de GCP vers un projet OVH Public Cloud dédié. Infra en Terraform, applicatif sous Docker Compose derrière Traefik, déploiement par GitHub Actions et bascule MySQL par réplication.

TerraformOVH Public CloudOpenStackDockerTraefikFrankenPHPMySQLRedisGitHub Actions

Le projet

L’extranet (Symfony) et son site vitrine tournaient sur GCP. Il fallait les passer sur OVH, dans une région française, sans casser la prod.

Tout le Terraform est écrit à la main, sans module tout fait, pour savoir exactement ce que chaque ressource crée.

Architecture

Un projet OVH dédié

Au départ, l’infra devait aller dans le projet Public Cloud existant de PharmaGDD. Elle a finalement été isolée dans son propre projet OVH : identifiants OpenStack et API séparés, facturation séparée, et une erreur sur ce projet ne peut pas toucher l’infra principale.

Ce choix a demandé un peu plus de travail au début : nouveaux identifiants, accès au registry et au S3 à refaire.

Réseau privé + bastion

La VM applicative est dans un réseau privé dédié (vRack/VLAN), séparé de celui de PharmaGDD. L’accès SSH passe uniquement par un bastion. Dans le security group, seuls le 80 et le 443 sont ouverts au public, et le 22 n’est ouvert que depuis le bastion.

Internet ──► Traefik (80/443) ──► FrankenPHP (extranet Symfony)
                               └─► conteneur SPA (site vitrine)
Admin ──► Bastion ──SSH──► VM app (réseau privé)

Terraform

Le Terraform est dans un repo à part. Le provider ovh gère le projet, le réseau et le DNS, OpenStack gère les instances et les security groups. Il faut respecter l’ordre réseau → sous-réseau → instance, et bien savoir ce qui dépend de l’API OVH et ce qui dépend d’OpenStack.

La VM est ensuite préparée (Docker, Compose, utilisateur, arborescence /opt/...) par un script lancé en SSH via le bastion.

Stack applicative

Tout tourne en Docker Compose sur la VM :

CI/CD

Le déploiement passe par GitHub Actions, avec un runner self-hosted partagé au niveau de l’organisation. Il n’y a aucun runner sur la VM de prod.

La bascule des données

La prod GCP écrit dans MySQL jusqu’au dernier jour, donc un simple dump/restore aurait imposé une longue coupure. La bascule passe par de la réplication :

  1. Copie initiale de la base (dump avec position GTID).
  2. La MySQL OVH devient réplique de la prod GCP. La connexion part d’OVH vers GCP, filtrée sur l’IP de sortie OVH et chiffrée en TLS. La base OVH reste en super_read_only pour qu’on ne puisse pas y écrire par erreur.
  3. Le jour de la bascule : prod en lecture seule, on attend que le lag tombe à zéro, on promeut la réplique, puis on bascule le DNS (TTL baissé quelques jours avant).

La prod n’est coupée que le temps que la réplique rattrape son retard, soit quelques minutes.