Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

Déploiement d'une application Rails sans interr...

Déploiement d'une application Rails sans interruption de service

Parce que la pleine disponibilité d'une application est cruciale pour le bon ressenti de ses utilisateurs, et que pouvoir déployer sans se soucier de ce manque de disponibilité est un confort essentiel au bien-être des développeurs.

Présentation faite dans le cadre des apéros RubyNord.
http://ruby-nord.org/

Le code source de cette présentation est disponible sur https://gitlab.com/bobmaerten/presentation-zdd

Bob Maerten

April 19, 2016
Tweet

More Decks by Bob Maerten

Other Decks in Technology

Transcript

  1. Parce qu'il n'y a que les petites natures qui ne

    deploy pas plusieurs fois par jour ! 6 / 38
  2. Blue/Green Avantages test avant bascule ; usage en pseudo A/B

    ; rollback "facile" ; architectures multi-éléments 10 / 38
  3. Blue/Green Avantages test avant bascule ; usage en pseudo A/B

    ; rollback "facile" ; architectures multi-éléments Inconvénients doubles ressources ; gestion des sessions lors de la bascule ; delta DB pendant la bascule. 11 / 38
  4. Unicorn Avantages protection du code non-threadsafe ;-) multi-process = multi-core

    ; isolation des crashes de workers Inconvénients optimisé pour les "fast-clients" (frontal web obligatoire) consommation mémoire 15 / 38
  5. Rolling restart $ k i l l - U S

    R 2 < u n i c o r n _ p i d > 17 / 38
  6. Unicorn rolling restart en détail envoi du signal USR2 au

    master process ; unicorn duplique son master ; u n i c o r n m a s t e r ( o l d ) \ _ u n i c o r n w o r k e r [ 0 ] \ _ u n i c o r n w o r k e r [ 1 ] \ _ u n i c o r n w o r k e r [ 2 ] \ _ u n i c o r n m a s t e r \ _ u n i c o r n w o r k e r [ 0 ] \ _ u n i c o r n w o r k e r [ 1 ] \ _ u n i c o r n w o r k e r [ 2 ] 19 / 38
  7. Unicorn rolling restart en détail envoi du signal USR2 au

    master process ; unicorn duplique son master ; u n i c o r n m a s t e r ( o l d ) \ _ u n i c o r n w o r k e r [ 0 ] \ _ u n i c o r n w o r k e r [ 1 ] \ _ u n i c o r n w o r k e r [ 2 ] \ _ u n i c o r n m a s t e r \ _ u n i c o r n w o r k e r [ 0 ] \ _ u n i c o r n w o r k e r [ 1 ] \ _ u n i c o r n w o r k e r [ 2 ] envoi du signal T T O U à l'ancien master : ses workers se terminent après leur requête en cours ; 20 / 38
  8. Unicorn rolling restart en détail envoi du signal USR2 au

    master process ; unicorn duplique son master ; u n i c o r n m a s t e r ( o l d ) \ _ u n i c o r n w o r k e r [ 0 ] \ _ u n i c o r n w o r k e r [ 1 ] \ _ u n i c o r n w o r k e r [ 2 ] \ _ u n i c o r n m a s t e r \ _ u n i c o r n w o r k e r [ 0 ] \ _ u n i c o r n w o r k e r [ 1 ] \ _ u n i c o r n w o r k e r [ 2 ] envoi du signal T T O U à l'ancien master : ses workers se terminent après leur requête en cours ; Plus de workers sur l'ancien master : envoi du signal Q U I T ; 21 / 38
  9. Unicorn rolling restart en détail envoi du signal USR2 au

    master process ; unicorn duplique son master ; u n i c o r n m a s t e r ( o l d ) \ _ u n i c o r n w o r k e r [ 0 ] \ _ u n i c o r n w o r k e r [ 1 ] \ _ u n i c o r n w o r k e r [ 2 ] \ _ u n i c o r n m a s t e r \ _ u n i c o r n w o r k e r [ 0 ] \ _ u n i c o r n w o r k e r [ 1 ] \ _ u n i c o r n w o r k e r [ 2 ] envoi du signal T T O U à l'ancien master : ses workers se terminent après leur requête en cours ; Plus de workers sur l'ancien master : envoi du signal Q U I T ; sinon, envoi de H U P à l'ancien master et Q U I T au nouveau pour retourner à l'état initial. 22 / 38
  10. config/unicorn.rb b e f o r e _ f o

    r k d o | s e r v e r , w o r k e r | d e f i n e d ? ( A c t i v e R e c o r d : : B a s e ) a n d A c t i v e R e c o r d : : B a s e . c o n n e c t i o n . d i s c o n n e c t ! o l d _ p i d = " # { s e r v e r . c o n f i g [ : p i d ] } . o l d b i n " i f o l d _ p i d ! = s e r v e r . p i d b e g i n s i g = ( w o r k e r . n r + 1 ) > = s e r v e r . w o r k e r _ p r o c e s s e s ? : Q U I T : : T T O U P r o c e s s . k i l l ( s i g , F i l e . r e a d ( o l d _ p i d ) . t o _ i ) r e s c u e E r r n o : : E N O E N T , E r r n o : : E S R C H e n d e n d e n d https://github.com/defunkt/unicorn/blob/master/examples/unicorn.conf.rb 23 / 38
  11. config/deploy .rb n a m e s p a c

    e : d e p l o y d o t a s k : r e s t a r t d o i n v o k e ' u n i c o r n : r e s t a r t ' e n d e n d lib/capistrano/tasks/unicorn.cap n a m e s p a c e : u n i c o r n d o t a s k : e n v i r o n m e n t d o s e t : u n i c o r n _ p i d , " # { s h a r e d _ p a t h } / t m p / p i d s / u n i c o r n . p i d " e n d t a s k : r e s t a r t = > : e n v i r o n m e n t d o o n r o l e s ( : a p p ) d o i f t e s t ( " [ - f # { f e t c h ( : u n i c o r n _ p i d ) } ] " ) e x e c u t e : k i l l , " - s U S R 2 $ ( < # { f e t c h ( : u n i c o r n _ p i d ) } ) " e l s e s t a r t _ u n i c o r n e n d e n d e n d e n d 24 / 38
  12. Cas simples Creation de tables l'ancien code ne connait pas

    le modèle associé Ajout de colonne l'ancien code ne connait pas la colonne sauf si containte/validation SQL sur la colonne 27 / 38
  13. Cas nécessitant un peu d'at tention Suppression de colonne a

    priori OK depuis Rails 4.0 si l'ancien code n'utilise plus l'attribut 28 / 38
  14. Cas nécessitant un peu d'at tention Suppression de colonne a

    priori OK depuis Rails 4.0 si l'ancien code n'utilise plus l'attribut sinon migrer en 2 étapes : préciser à ActiveRecord d'ignorer la colonne c l a s s U s e r d e f s e l f . c o l u m n s s u p e r . r e j e c t { | c o l u m n | c o l u m n . n a m e = = " n o t e s " } e n d e n d 29 / 38
  15. Cas nécessitant un peu d'at tention Suppression de colonne a

    priori OK depuis Rails 4.0 si l'ancien code n'utilise plus l'attribut sinon migrer en 2 étapes : préciser à ActiveRecord d'ignorer la colonne c l a s s U s e r d e f s e l f . c o l u m n s s u p e r . r e j e c t { | c o l u m n | c o l u m n . n a m e = = " n o t e s " } e n d e n d déployer une migration qui supprime la colonne 30 / 38
  16. Renommage de colonne ajouter une nouvelle colonne s'assurer de l'écriture

    des données sur les 2 colonnes d e f f i r s t _ n a m e s u p e r | | a t t r i b u t e s [ " f n a m e " ] e n d 32 / 38
  17. Renommage de colonne ajouter une nouvelle colonne s'assurer de l'écriture

    des données sur les 2 colonnes d e f f i r s t _ n a m e s u p e r | | a t t r i b u t e s [ " f n a m e " ] e n d migrer les données, mettre à jour les éventuelles requêtes SQL 33 / 38
  18. Renommage de colonne ajouter une nouvelle colonne s'assurer de l'écriture

    des données sur les 2 colonnes d e f f i r s t _ n a m e s u p e r | | a t t r i b u t e s [ " f n a m e " ] e n d migrer les données, mettre à jour les éventuelles requêtes SQL supprimer l'ancienne colonne comme au point précédent 34 / 38
  19. Renommage de colonne ajouter une nouvelle colonne s'assurer de l'écriture

    des données sur les 2 colonnes d e f f i r s t _ n a m e s u p e r | | a t t r i b u t e s [ " f n a m e " ] e n d migrer les données, mettre à jour les éventuelles requêtes SQL supprimer l'ancienne colonne comme au point précédent Dans tous les cas ! testez vos migrations en local sur une version à jour de votre db de production 35 / 38