Déployer un nouveau code en direct

29

Quelle est la meilleure pratique pour déployer un nouveau code sur un site en ligne (e-commerce)?

Pour l'instant, j'ai arrêté apache pendant +/- 10 secondes lors du changement de nom du répertoire public_html_newen public_htmlancien vers public_html_old. Cela crée un court temps d'arrêt, avant de redémarrer Apache.

La même question se pose si vous utilisez Git pour tirer le nouveau référentiel vers le répertoire en direct. Puis-je retirer le dépôt lorsque le site est actif? Et si je dois également copier une base de données?

Pendant la compression tar (à des fins de sauvegarde) du site en direct, j'ai remarqué que des changements étaient survenus dans le répertoire multimédia. Cela m'a indiqué que les fichiers continuent de changer périodiquement. Et si ces modifications peuvent interférer si Apache n'est pas arrêté pendant le déploiement.

nicoX
la source

Réponses:

13

L'utilisation d'un équilibreur de charge est une bonne idée. Si le site est suffisamment important pour s'inquiéter de quelques secondes de temps d'arrêt, il est suffisamment important pour se soucier de la tolérance aux pannes.

Cela mis à part, s'il s'agit d'un système UNIX, vous pouvez mettre Apache en attente pendant le changement de nom (ou la mise à jour du lien symbolique, etc.):

killall -STOP httpd  # Pause all httpd processes
mv public_html public_html_orig
mv public_html_new public_html
killall -CONT httpd  # Resume all httpd processes

Cela empêchera Apache d'accepter de nouvelles demandes pendant le changement de nom. Si vous préférez les liens symboliques ou une autre approche, la même idée peut être utilisée:

killall -STOP httpd  # Pause all httpd processes
rm /var/www/html
ln -s /var/www/version/03 /var/www/html
killall -CONT httpd  # Resume all httpd processes

Notez que toutes les connexions ou tous les paquets en attente seront mis en file d'attente dans le système d'exploitation. Pour un site extrêmement occupé, envisagez de régler ListenBacklog si approprié pour votre type de travailleur httpd et vérifiez les paramètres de votre système d'exploitation liés au backlog d'écoute TCP.

Vous pouvez également modifier DocumentRoot dans httpd.conf et effectuer un redémarrage gracieux ( apachectl graceful). L'inconvénient ici est le risque accru d'erreurs, car vous devez également mettre à jour toute Directoryconfiguration.

GargantuChet
la source
La session de pause aura-t-elle toujours le site en marche?
nicoX du
4
Il cesse de donner du temps CPU à Apache. Si vous avez essayé d'accéder au site dans un navigateur alors qu'Apache est en pause, le navigateur attendra de se connecter jusqu'à ce qu'Apache soit repris (ou le navigateur expire, si Apache est suspendu plus longtemps que le délai d'expiration). Si quelqu'un est en train de télécharger un fichier, Apache cessera d'envoyer des données pendant qu'il est en pause, encore une fois car il ne reçoit pas de temps CPU. Encore une fois, cela ne causera des problèmes que si Apache est arrêté pendant si longtemps que le transfert expire.
GargantuChet du
5
Autrement dit, le site ne répondra pas pendant la pause d'Apache, mais les opérations en attente se termineront à sa reprise. Les utilisateurs n'obtiendront pas de "connexion refusée" et les téléchargements ne s'arrêteront pas, mais les opérations ne se poursuivront qu'à la reprise d'Apache. Cela garantira que les transactions existantes peuvent se terminer, mais les nouvelles demandes ne seront traitées qu'après la mise en place de votre nouveau contenu.
GargantuChet
1
Veuillez noter que dans tout site Web à fort trafic, cela pourrait très facilement tuer votre service Apache. 200 rq / s jetteront très facilement votre pool de connexions dès que vous «déverrouillerez» votre processus Apache après le déplacement (si le déplacement prend un certain temps)
CloudWeavers
1
Sur un site à fort trafic, il y aura beaucoup de demandes en vol à terminer lors de la reprise d'Apache. Cela échelonnera le traitement des nouvelles demandes. C'est également un bon argument pour vous assurer que vos paramètres Apache (nombre maximum de threads / serveurs / clients) sont raisonnables, et régler le backlog TCP en conséquence. Bien que je ne sache pas ce que vous entendez par «tuer» le service. Apache est très ajustable.
GargantuChet
32

Le plus rapide et le plus simple consiste à utiliser un répertoire de version tel que

/var/www/version/01
/var/www/version/02

et utilisez un lien symbolique actuel comme racine html:

/var/www/html -> /var/www/version/02

Cette technique s'intègre parfaitement dans un système de contrôle de révision (svn, git, mercurial, ...) car vous pouvez extraire des branches et des balises, changer le lien symbolique et recharger Apache. Le temps d'arrêt est minime en utilisant cette technique et il permet une restauration très facile .

Il s'intègre également bien avec les systèmes de déploiement plus complexes tels que les packages RPM ou l'infrastructure de gestion des changements de configuration (chef, marionnette, etc.).

CloudWeavers
la source
4
Les solutions les plus simples sont toujours les meilleures ... :-) Bien sûr, n'oubliez pas de mentionner que certains FollowSymlinks et de tels drapeaux apache dans les configurations peuvent être nécessaires.
Peterh dit de réintégrer Monica
Faites particulièrement attention à ce que @PeterHorvath a dit. Apache peut devenir très grincheux lorsque vous travaillez avec DocumentRoots avec lien symbolique. Assurez-vous de tester soigneusement!
mhutter
@mhutter Merci :-) Ce qui est vraiment problématique, c'est que l'activation de FollowSymlinks sur apache peut provoquer des problèmes de sécurité ...
Peter dit de rétablir Monica
La mise à jour d'un lien symbolique n'est pas une opération atomique. Même en utilisant quelque chose comme ln -snfpour écraser le lien symbolique d'origine, l'opération sous-jacente est un unlinket symlink. Il est possible que les utilisateurs obtiennent un 404 lors de la mise à jour. Ce n'est pas mieux que de renommer simplement le répertoire d'origine et de renommer un nouveau en place (en supposant que vous ne traversez pas les systèmes de fichiers). Voir la réponse ci-dessus avec une coche à côté, qui répond à cette préoccupation.
GargantuChet
14

Renommer les répertoires sans arrêter Apache devrait également fonctionner. Cela raccourcira considérablement la fenêtre. mv public_html public_html_old && mv public_html_new public_htmldevrait se terminer en une fraction de seconde.

Quelques inconvénients sont que cette approche donnera une réponse 404à toute demande qui parvient toujours à se produire pendant la fenêtre. Et si vous exécutez la commande ci-dessus sans avoir de public_html_newrépertoire, elle échouera et vous laissera un site donnant 404à chaque demande.

Le faire atomiquement avec des répertoires n'est pas pris en charge. Mais vous pouvez le faire avec des liens symboliques. Au lieu d'avoir un répertoire nommé public_html, ayez un répertoire nommé public_html.version-numberet un lien symbolique appelé public_htmlpointant vers ce répertoire. Vous pouvez maintenant créer un répertoire appelé public_html.new-version-numberet un nouveau lien symbolique appelé public_html.new.

Ensuite, vous pouvez renommer public_html.newto public_htmlpour basculer atomiquement. Notez que mvc'est "trop ​​intelligent" pour effectuer ce changement de nom, mais cela pourrait être fait à l'aide os.renamede python ou de toute autre chose qui appellera l' renameappel système sans essayer d'être intelligent.

Que faire de la base de données dépend de la base de données que vous utilisez et de la raison pour laquelle vous l'utilisez. Vous devez fournir beaucoup plus de détails sur la base de données avant que nous puissions vous donner une bonne réponse à cette partie de votre question.

kasperd
la source
1
Sur mon système Debian, mva une -Toption qui l'empêche de suivre le lien symbolique. Cela vous permettra de renommer atomiquement public_html.newsur public_html, si les deux sont des liens souples.
GargantuChet
11

Les liens symboliques et mv sont vos amis, cependant, si vous devez vraiment éviter que les utilisateurs finaux obtiennent une page d'erreur lors du déploiement d'une nouvelle version, vous devez avoir un proxy inverse ou un équilibreur de charge devant au moins 2 serveurs backend (apache dans ton cas).

Pendant le déploiement, il vous suffit d'arrêter un backend à la fois, de déployer le nouveau code, de le redémarrer, puis d'itérer sur les backends restants.

Les utilisateurs finaux seront toujours dirigés vers de bons backends par le proxy.

Giovanni Toraldo
la source
4
J'étais en train de travailler sur cette réponse quand je vous ai déjà vu la poster. Balancer + 2 serveurs rend le processus invisible et plus facile à récupérer après une mauvaise mise à niveau ...
Bart Silverstrim
9

Si vous appliquez régulièrement des changements sur un système de production, je m'occuperais d'un cycle de vie structuré. Une bonne pratique est Capistrano http://capistranorb.com/ . Il s'agit d'une solution open source pour déployer des logiciels sur un ou plusieurs serveurs sur plusieurs plates-formes et configurations.

Pour Magento, il existe même un plugin: https://github.com/augustash/capistrano-ash/wiki/Magento-Example

Pour un serveur unique et des transitions presque transparentes, je recommande d'utiliser des liens symboliques.

Skiaddict
la source
4

La façon dont je le fais est de valider mes modifications depuis mon environnement de développement local vers un référentiel Git en ligne tel que Github. Mon environnement de production s'exécute à partir d'un référentiel distant, donc tout ce que je dois faire est ssh sur le serveur et exécuter git pullpour apporter les dernières modifications. Pas besoin d'arrêter votre serveur web.

Si votre projet contient des fichiers dont les paramètres et / ou le contenu diffèrent de votre version locale (tels que les fichiers de configuration et les téléchargements multimédias), vous pouvez utiliser des variables d'environnement et / ou ajouter ces fichiers / répertoires à un .gitignorefichier pour empêcher la synchronisation avec le référentiel.

Harry
la source
3

Ma première idée est:

# deploy into public_html_new, and then:
rsync -vaH --delete public_html_new/ public_html/

Une bonne solution consistait à utiliser rsync. Il n'a changé que les fichiers vraiment modifiés. Attention, les barres obliques à la fin des chemins sont ici importantes.

Normalement, apache n'a pas besoin d'un redémarrage, ce n'est pas le monde java. Il vérifie la modification de chaque fichier php sur demande et relit (et re-tokenise) automatiquement la modification.

Git pull était similaire et efficace, bien qu'il soit un peu plus difficile à écrire. Bien sûr, il a permis un large éventail de différentes possibilités de détection de fusion / changement.

Cette solution ne fonctionnera de manière transparente que s'il n'y a pas de changements vraiment majeurs - s'il y a de grands changements dans le déploiement, un peu de danger ne peut pas être fermé, car il y a un intervalle de temps non négligeable, lorsque le code sera partiellement modifié et surtout pas.

S'il y a de gros changements, ma suggestion était votre solution initiale (deux renommer).


Voici une solution un peu hardcore, mais 100% atomique:

(1) faire un montage alternatif de certains de votre système de fichiers, où votre magento a lieu:

mount /dev/sdXY /mnt/tmp

(2) faites un --bindmontage de votre public_html_new sur public_html:

mount --bind /path/to/public_html_new /path/to/public_html

À partir de ce moment, l'apache verra votre nouveau déploiement. Tout changement de 404 est impossible.

(3) faire la synhcronistation avec rsync, mais sur le point de montage alternatif):

rsync -vaH --delete /mnt/tmp/path/to/public_html_new/ /mnt/tmp/path/to/public_html/

(4) Retirez le support de fixation

umount /path/to/public_html
peterh dit réintégrer Monica
la source
La commande supprimera-t-elle public_html et y déploiera-t-elle public_html_new?
nicoX
@nicoX Non, il copiera uniquement les modifications.
peterh dit réintégrer Monica
@nicoX Il passe par les deux structures de répertoires, et s'il trouve une différence (nouveau fichier, fichier modifié, fichier supprimé), il modifie le deuxième répertoire pour correspondre au premier, selon les besoins. Le résultat si vous avez supprimé public_html puis déplacé public_html_new à sa place, mais sans possibilité de problème temporaire 404.
peterh dit réintégrer Monica
1
Non, ce n'est pas une bonne idée. Selon les modifications, vous pouvez avoir une courte période de temps où le code public_htmlest dans un état incohérent et vous ne voulez pas prendre cette chance.
Sven
@SvW Vous avez raison, mon idée n'est valable que s'il n'y a que des changements mineurs. J'ai étendu ma réponse en conséquence.
peterh dit réintégrer Monica
1

Le déplacement / remplacement du http_publicdossier peut être réalisé avec des commandes simples mvou ln -sou l'équivalent pendant que votre serveur http continue de fonctionner. Vous pouvez effectuer des scripts pour réduire considérablement les temps d'arrêt, mais vérifiez attentivement les codes retour de vos commandes dans le script si vous automatisez le processus.

Cela dit, si vous ne souhaitez obtenir aucun temps d'arrêt, votre application doit également la prendre en charge. La plupart des applications utilisent une base de données pour la persistance. Le fait de voir la version N de votre application jouer avec la version N + 1 (ou l'inverse) de votre modèle de données peut casser les choses si cela n'est pas prévu par l'équipe de développement.

Par expérience, le maintien d'une telle cohérence par le biais de mises à niveau n'est pas acquis pour la plupart des applications. Un arrêt correct, malgré le temps d'arrêt, est un bon moyen d'éviter les problèmes de cohérence.

Uriel
la source