Slide 1

Slide 1 text

Déploiement d'une application Rails sans interruption de service Apéro Ruby Nord - Avril 2016 1 / 38

Slide 2

Slide 2 text

Bob Maerten http://levups.com 2 / 38

Slide 3

Slide 3 text

Pourquoi le ZDD ? (Zero Downtime Deployment) 3 / 38

Slide 4

Slide 4 text

Parce que c'est pratique quand il y a des users ! 4 / 38

Slide 5

Slide 5 text

Parce que les devs n'aiment pas deploy aux aurores ! 5 / 38

Slide 6

Slide 6 text

Parce qu'il n'y a que les petites natures qui ne deploy pas plusieurs fois par jour ! 6 / 38

Slide 7

Slide 7 text

Le ZDD dans l'esprit commun 7 / 38

Slide 8

Slide 8 text

Blue/Green 8 / 38

Slide 9

Slide 9 text

9 / 38

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

Mais pour des apps à taille "humaine" ? 12 / 38

Slide 13

Slide 13 text

Unicorn ! 13 / 38

Slide 14

Slide 14 text

Unicorn Avantages protection du code non-threadsafe ;-) multi-process = multi-core ; isolation des crashes de workers 14 / 38

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

The killer feature! 16 / 38

Slide 17

Slide 17 text

Rolling restart $ k i l l - U S R 2 < u n i c o r n _ p i d > 17 / 38

Slide 18

Slide 18 text

Unicorn rolling restart en détail envoi du signal USR2 au master process ; 18 / 38

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

Quid d'un déploiement avec migration ? 25 / 38

Slide 26

Slide 26 text

Cas simples Creation de tables l'ancien code ne connait pas le modèle associé 26 / 38

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

Renommage de colonne ajouter une nouvelle colonne 31 / 38

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

Démo ? Questions ? 36 / 38

Slide 37

Slide 37 text

Images campagne "préjugés" de Cofidis http://techblog.betgenius.com/content/images/2014/Nov/Simple-Blue- Green-2.jpg http://levups.com https://github.com/images/error/angry_unicorn.png 37 / 38

Slide 38

Slide 38 text

Google-est-mon-ami-graphie https://www.numergy.com/developpeurs-blog/bluegreen-deployment-le- deploiement-continu-facile/ http://blog.octo.com/zero-downtime-deployment/ http://blog.appsignal.com/blog/2016/03/17/ruby-magic-mastering- concurrency.html https://unicorn.bogomips.org/SIGNALS.html https://blog.codeship.com/rails-migrations-zero-downtime/ http://jakeyesbeck.com/2016/02/07/how-to-remove-a-column-with-zero- downtime-in-ruby-on-rails/ https://www.rainforestqa.com/blog/2014-06-27-zero-downtime-database- migrations/ 38 / 38