Je ne suis pas sûr que ma question soit pertinente car je peux essayer de mélanger des outils (Capistrano et Docker) qui ne devraient pas être mélangés.
J'ai récemment docké une application qui est déployée avec Capistrano. Docker compose est utilisé à la fois pour les environnements de développement et de transfert.
Voici à quoi ressemble mon projet (les fichiers d'application ne sont pas affichés):
Capfile
docker-compose.yml
docker-compose.staging.yml
config/
deploy.rb
deploy
staging.rb
Les fichiers Docker Compose créent tous les conteneurs nécessaires (Nginx, PHP, MongoDB, Elasticsearch, etc.) pour exécuter l'application dans un environnement de développement ou de transfert (d'où certains paramètres spécifiques définis dans docker-compose.staging.yml
).
L'application est déployée dans l'environnement de transfert avec cette commande:
cap staging deploy
L'architecture des dossiers sur le serveur est celle de Capistrano:
current
releases
20160912150720
20160912151003
20160912153905
shared
La commande suivante a été exécutée dans le répertoire current
du serveur de transfert pour instancier tous les conteneurs nécessaires à l'exécution de l'application:
docker-compose -f docker-compose.yml -f docker-compose.staging.yml up -d
Jusqu'ici tout va bien. Les choses se compliquent au prochain déploiement: le lien symbolique current
pointera vers un nouveau répertoire du répertoire releases
:
deploy.rb
Définit des commandes qui doivent être exécutées à l'intérieur des conteneurs (comme docker-compose exec php composer install
Pour PHP), Docker indique que les conteneurs n'existent pas encore (car les existants ont été créés dans le dossier de version précédent ).docker-compose up -d
Est exécutée dans le processus de déploiement de Capistrano, je reçois des erreurs en raison de conflits de port (les conteneurs précédents existent toujours).Avez-vous une idée sur la façon de résoudre ce problème? Dois-je m'éloigner de Capistrano et faire quelque chose de différent?
L'idée serait de conserver le déploiement (quasi) zéro temps d'arrêt que Capistrano offre avec la flexibilité des conteneurs Docker (fournissant plusieurs versions PHP pour diverses applications sur le même serveur par exemple).
Pour autant que je sache, vous utilisez capistrano sur l'hôte, pour redéployer toute la pile d'applications, c'est-à-dire les conteneurs. Vous utilisez donc capistrano pour orchestrer la construction, la création de conteneurs et donc le déploiement.
Pendant que vous le faites, vous utilisez essentiellement le déploiement de cap
Vous le faites pour obtenir un déploiement "presque" sans interruption de service.
Si vous vous souciez vraiment des temps d'arrêt et de la formalisation de votre processus de déploiement, vous devez le faire correctement en utilisant une implémentation de pipeline appropriée pour
Je ne pense pas que capistrano puisse/doive être l'un des outils que vous pouvez utiliser pendant cette stratégie. Capistrano est destiné au déploiement d'une application directement sur un serveur en utilisant ssh et git comme transport. L'utilisation de cap pour créer des images entières sur le serveur cible, puis les démarrer en tant que conteneurs, est vraiment exagérée, à mon humble avis.
Soit utilisez un serveur CI/CD comme jenkins/bamboo/gocd pour créer une image de version pour votre application. En supposant que seule l'application est personnalisée en termes de "version", disons que vous avez db et app en tant que conteneurs/services, l'application inclura votre code source et changera régulièrement pendant les versions.
C'est donc un processus CD/CI pour créer une nouvelle image d'application (version) hors site sur votre serveur CI. Tirez le code source de votre application et empaquetez-le dans votre image en utilisant COPY
puis n'importe quelle instruction RUN
pour compiler vos ressources (npm/gulp/grunt que ce soit). Tout cela ne se produit pas sur le serveur de production, mais sur l'agent CI/CD.
Ensuite, vous poussez cette image de libération, appelons cette image yourregistry.com/yourapp
dans votre registre privé comme nouvelle "version" pour le déploiement.
Pour déployer sur votre serveur de production ou de transfert AVEC des temps d'arrêt, vous devez simplement faire un docker-composer stop && docker-composer up
- cela va automatiquement extraire l'image la plus récente puis la démarrer dans votre pile - votre application est mise à niveau
Le serveur doit bien sûr pouvoir extraire de votre référentiel privé.
Pour obtenir un déploiement sans interruption, vous devez utiliser le concept de déploiement bleu-vert . Ainsi, vous ajoutez un proxy à votre configuration et n'exposez plus le port public de l'application, mais utilisez plutôt ce port public proxy. Votre système en direct actuel peut fonctionner sur un port aléatoire 21231, le proxy transfère de 443 à 21231.
Nous utilisons des ports aléatoires pour éviter le conflit lors du déploiement du "deuxième" système, couvrant l'un des problèmes que vous avez mentionnés.
Lors du redéploiement, vous ne démarrerez qu'un "nouveau" conteneur basé sur la nouvelle image d'application en plus (à l'ancien), il obtient un nouveau port aléatoire 12312 - si vous le souhaitez, exécutez vos tests d'intégration contre 12312 directement (ne pas utiliser le proxy). Si vous avez terminé et que vous êtes satisfait, reconfigurez le proxy pour maintenant le transférer vers 12312 - puis supprimez l'ancien conteneur (21231).
Si vous souhaitez automatiser la reconfiguration du proxy, qui en détail est hors de portée pour cette question, vous pouvez utiliser la découverte de service et un registraire qui rend les ports aléatoires sont beaucoup plus pratiques et facilitent la reconfiguration de votre proxy, que ce soit nginx/haproxy pendant leur exécution. Les outils seraient, par exemple.
consul watch
+ consul-template
ou tiller sur le proxy pour mettre à jour le proxy-configJe ne pense pas que Capistrano soit le bon outil pour le travail. Cela a été récemment discuté dans un PR pour SSHKit, qui sous-tend Capistrano.
https://github.com/capistrano/sshkit/pull/368
@EugenMayer explique mieux une manière "normale" d'utiliser Docker.