Déploiement PHP (ou autre) + SQL
#1
Salutations,

Variispace avançant plutôt bien, je commence à gratter pour le déployer en ligne. Le but étant d'avoir un système permettant de mettre à jour le jeu en ligne, et de gérer les éventuels foirages (quid si la BDD tombe en rade pendant/après le déploiement, quid si MySQL en prod n'arrive pas à digérer les scripts SQL de mon dev, etc)

Initialement, je pensais piocher dans les outils "tout fait", mais je me rend compte qu'ils ne sont qu'une coquille vide: à moi d'aller dire quels fichiers déployer, quoi mettre à jour dans la BDD, etc. Donc, j'ai préféré aller scripter une procédure de déploiement à ma sauce, sans passer par du Jenkins ou du Magallanes.

Mais la question qui me trotte en tête est la suivante: comment gérez-vous la mise à jour du serveur SQL?

Supposons qu'on ait un jeu en ligne, en PHP (ou autre langage osef) avec une BDD SQL (mysql postgre, etc osef). Supposons maintenant qu'on mette le jeu à jour, et qu'on ait des changements de BDD à passer en plus des changements de fichiers PHP (par exemple, on a rajouté le commerce dans le jeu, donc on a des pages PHP en plus, et des modifs SQL comme de nouvelles tables, et des tables modifiées).

Comment l'avez-vous géré?

Pour ma aprt, j'ai procédé ainsi:
- Je lance le script de déploiement du jeu
- Il vérifie que tout est commité (hg st)
- Il prépare les fichiers à mettre en ligne dans un dossier "tmp/release-Y-m-d-H-i-s" (il en copie certains, déplace d'autres, modifie des confs pour intégrer un n° de version, etc)
- Il envoie ça sur le serveur web (mon poste de dev crée une tarball gz de cette release, l'envoie en ligne, et le serveur la dé-tar-gz dans un dossier dédié)
- Le serveur rsync ce dossier de release avec le vrai dossier web du projet, en utilisant un fichier de conf spécial "Mise à jour en cours": ce fichier de conf throw une exception à chaque fois qu'on essaie d'accéder à la BDD, car elle n'est pas à jour (cette exception sera catchée par le reste du code, pour afficher une page "mise à jour en cours" au joueur et retourner le bon code HTTP pour les appels AJAX, qui pourront alors le récupérer et relancer leur requête qq secondes après, pour que ce soit transparent au joueur)
- Le serveur met ensuite la BDD à jour à partir des scripts SQL uploadés (dans la pratique, mes scripts SQL définissent les table/function/procedure/trigger de la BDD, donc le serveur charge tout dans une nouvelle BDD de test, et fait le diff entre cette BDD de test et la BDD du jeu, puis mets la BDD du jeu à jour)
- Si la mise à jour de BDD foire, on stoppe, je suis notifié, et les joueurs resteront sur l'écran "mise à jour en cours" (charge à moi de fixer l'upgrade de BDD pour poursuivre le déploiement)
- Si elle se passe bien, le serveur remplace la config "Mise à jour en cours" par la config normale du jeu, et tout reprend

Donc, j'ai une coupure de service pendant l'upgrade de BDD (mais je ne pense pas qu'elle soit gênante, si les pages web & appels AJAX se relancent tout seuls: ce sera une coupure transparente aux yeux du joueur, qui ne verra à la limite qu'un ralentissement des actions de jeu).

Ca me semble donc pas mal (testé avec un autre projet de backend, qui compile les logs pour en sortir des stats façon Urchin [mais Urchin n'est pas configurable sur un mutu donc j'en ai "réinventé" un bout]), mais j'aimerai savoir comment vous gérez les choses vous?


[edit]
En écrivant ça, je m'aperçoit que si le chargement des SQLs dans la BDD de test est foiré, alors le projet est bloqué pendant un certain temps... Donc, je change un peu:
- Préparation de la targz en local (hg st + copie des fichiers utiles + modifications des fichiers de conf si besoin)
- Upload dans un dossier "releases" du serveur web, et extraction de la tarball dans ce dossier
- Chargement des SQLs dans la BDD de test: en cas de foirage, on s'arrête là et donc le projet en prod n'est pas impacté
- Si succès, release du code sur le serveur web, avec une configuration "mise à jour en cours" qui bloque les accès à la BDD de prod
- Attente de la fin de toutes les actions des joueurs sur la BDD de prod (histoire de ne pas avoir de risque de concurrence)
- Comparaison de la BDD de prod et de la BDD de test précédemment chargée, et application du diff SQL sur la BDD de prod pour la mettre à jour
- Suppression du lock du jeu pour terminer la release complète

Ca me semble pas mal 2
Répondre
#2
Dans les frameworks industriels on utilise des migrations. On ne modifie jamais le schéma de la base de données directement, on le fait avec des scripts (qui implantent du code pour faire et pour défaire). Du coup, les changements sont explicites et versionnés.
Répondre
#3
Ouep, mais plusieurs points me gênent dans cette approche:
1) On doit faire soi-même le script de diff de migration, et le script de "défaisage" => on travaille donc par transition, et si jamais la BDD a dérivé de ce qui était prévu, il sera impossible de remonter le projet
2) Remonter le projet de 0 sera très chiant et long si les scripts de migration se sont accumulés
3) Impossible de retrouver pourquoi quelqu'un a rajouté telle colonne dans une table, sans devoir se palucher tous les scripts de migration pour essayer de comprendre
4) Si le script de migration a planté en plein milieu, quelle est la probabilité pour que le script de dé-migration fonctionne réellement, sachant qu'on est dans un état inconnu (vu que la migration a planté)?
5) On est quand même down pendant l'exécution de la migration SQL

Du coup, c'est pour ça que j'ai préféré l'approche: je crée un fichier par table/trigger/function/procedure qui crée cet élément SQL, je le charge dans une BDD vide (celle de "test"), puis je compare la BDD de test et la BDD de prod, j'en tire un diff SQL et je le lance sur cette BDD de prod, s'il foire, je recommence mon diff et mon éxécution jusqu'à ce que ça passe (ou jusqu'à ce que la 1ere ligne du diff plante ou que le diff soit considéré comme 'tournant en rond', auquel cas l'intervention manuelle sera probablement requise)

Mais bon, l'un dans l'autre, en utilisant des scripts de migration/démigration ou en faisant le diff automatiquement entre la BDD de prod et une BDD de test, j'ai le même "problème" (en fait, pas critique du tout, mais pour le principe) de "downtime": entre le moment où la migration SQL est lancée et le moment où elle est finie avec succès, le jeu est down. Je ne sais pas s'il existe des approches pour l'éviter sans perdre de données?!
Répondre
#4
normalement dans l'approche script de migration, avec de bons outils, tout se fait tout seul :

il sait créé le script de diff entre la version X et la version Y (par accumulation ou que sais je des script intermédiaires)

bon après c est pas moi qui m en occupe de notre coté donc je peux pas rentrer dans le détail, mais je sais que la philosophie est le script
[WIP]projet Rivages
[WIP]projet Arthur (comme si ça suffisait pas d'un...)
Répondre
#5
L'un dans l'autre, ça revient au même, mais qu'en est-il de l'exécution de ces scripts? Parce que leur origine, bon, je pourrai sauver & commiter le diff généré (j'en vois pas l'intérêt du tout franchement, je trouve qu'il a juste sa place dans les logs et c'est tout) mais partant de ces scripts de migrations, comment ces outils gèrent-il les downtime et l'application de la migration sur le SQL?

Parce que le patch du SQL et le patch du serveur web ne peuvent pas être faites "pile poil en même temps et en 0 secondes", donc y'aura forcément une période où soit le SQL sera "trop" à jour (le code web est en retard de version) soit l'inverse, le SQL n'est pas encore à jour alors que le code web l'est... Et comme la migration SQL n'est pas instantanée (surtout si elle a chié), y'a forcément un "trou" pendant lequel le jeu est bloqué?

Mantis a l'air de procéder ainsi (mise en "offline" pendant la durée de la mise à jour).
Wordpress, je ne sais pas trop...
Vous avez d'autres exemples/pistes/réponses en tête sur ce point-là?

@Ter Rowan Si ce n'est pas toi qui te charge de ça, est-ce que celui/celle en charge de ces déploiement a une procédure que tu peux communiquer ou saurai répondre à la question si tu lui demandes?

Parce que bon, nous de notre côté au boulot, c'est "on déploie le code web d'un côté, on exécute le script de diff [forgé à la mano] de l'autre, et on croise les doigts pour que rien ne pète; et au cas par cas, soit on lance le SQL d'abord puis le web, soit l'inverse [suivant ce qui est le plus cassant]". Je trouve ça un peu... bof :/ Ca marche, certes, mais bof...


[edit]
Tiens, en revanche, cette histoire de diff de rollback etc me fait tilter que j'ai déjà une tâche de rollback en cas de foirage du déploiement: je reviens en arrière dans Hg sur le dernier commit déployé (un tag l'indique) et je relance le déploiement: le SQL s'alignera tout seul sur la structure qu'il avait à ce moment-là... 2
Répondre
#6
Le plus simple c'est de prévoir ce downtime et arrêter le site pour maintenance.

Quand au nombre de migrations, j'ai travaillé sur beaucoup d'app Rails avec des centaines de migrations et ça n'a jamais posé problème, à moins que quelqu'un ne modifie la BDD de production a la mano entre temps, chose improbable.

Tu les génères via une ligne de commande, genre :

rails generate migration AddInfoToUsers name level:int

Ça te génère un fichier du type db/migrate/YYYYMMDDHHMMSS_add_info_to_users.rb


class AddInfoToUsers < ActiveRecord::Migration
 def change
   add_column :users, :name, :string
   add_column :users, :level, :integer
 end
end

La plupart des migrations sont automatiquement réversibles (même de bien plus compliquées). Si tu migres les données, c'est bien sûr à toi de le faire.

Les outils de déploiement automatiques (Mina, Capistrano) déploient via le SCM (généralement Git) et ont une fonction de rollback qui remet les anciennes sources et relance les scripts de rollback.
Répondre
#7
Ouep, je crois que je vais rester sur le down temporaire avec une bonne petite 503.
Répondre
#8
Notre seule procédure (ou presque) est de respecter scrupuleusement les bonnes pratiques du marché de notre framework (ce qui au vu des différents sujets qu'on voit sur stack overflow et compagnie est loin d'être le cas par les professionnels, quelque soit le framework d'ailleurs, médiocrité quand tu nous tiens...)

Bref pour nous :
environnement .net / azure (mais valable aussi avec amazon ou autre)/ base de données quelconque 

on utilise entity framework => on déclare le modèle dans entity framework (pas de create table dans la bdd) et on déclare les changements dans entity framework.
C'est lui qui se charge de générer les scripts down et up. Evidemment le framework permet de créer des exceptions (au sens différent du process "standard", pas au sens erreur) pour les cas particuliers, mais dans ce cas on le fait aussi dans entity framework quitte à ce que ce soit plus verbeux qu'un simple alter table ou quoique ce soit

pour le "down time" tout dépend.

Soit on est en load balancing, et là il n'y a aucune interruption de service back (évidemment faut avoir codé le système dans ce sens)
Soit on est en mono serveur et évidemment il y a une interruption de service. C'est alors au front de prendre la main pour faire patienter l'utilisateur et de reprendre la connexion quand elle est up (soit en interrogeant le serveur, soit en attendant un push du serveur)

j'espère que c'est clair 34
[WIP]projet Rivages
[WIP]projet Arthur (comme si ça suffisait pas d'un...)
Répondre
#9
Ouep, je retombe sur ce que j'en comprenais. Nouvelle question dès lors:

savez-vous comment le load balancing gère les choses point de vue BDD? Parce qu'un load balancer applicatif, c'est assez facile à faire mais quand la structure de BDD change... je me demande comment le bouzin se démerde... 'fin, là, c'est de la pure curiosité inutile, au sens où "c'est MySQL cluster qui gère ça comme un grand" (ou assimilé suivant le LB) mais je me demande comment on arrive à LB une BDD dont on change la structure...

Parce que si a N serveurs, qu'on change la structure sur l'un (qui n'est plus appelé par le LB) puis que le LB bascule sur ce serveur à nouvelle structure, alors y'a pas de données dedans...

'fin dans mon cas, je vais effectivement rester sur le 2nd cas, mono serveur: le front affichera le petit logo de chargement pendant le down, et cela sera transparent pour l'utilisateur (juste une impression de ralentissement... d'ailleurs, je l'ai implémenté hier soir, plutôt simple et efficace 2 )
Répondre


Sujets apparemment similaires...
Sujet Auteur Réponses Affichages Dernier message
  Déploiement automatisé Zamentur 2 1 687 05-03-2010, 09:39 AM
Dernier message: Sephi-Chan



Utilisateur(s) parcourant ce sujet : 1 visiteur(s)