Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

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. Déploiement d'une application Rails
    sans interruption de service
    Apéro Ruby Nord - Avril 2016
    1 / 38

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  7. Le ZDD dans l'esprit commun
    7 / 38

    View full-size slide

  8. Blue/Green
    8 / 38

    View full-size slide

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

    View full-size slide

  10. 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

    View full-size slide

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

    View full-size slide

  12. Unicorn !
    13 / 38

    View full-size slide

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

    View full-size slide

  14. 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

    View full-size slide

  15. The killer feature!
    16 / 38

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  18. 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

    View full-size slide

  19. 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

    View full-size slide

  20. 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

    View full-size slide

  21. 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

    View full-size slide

  22. 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

    View full-size slide

  23. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  26. 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

    View full-size slide

  27. 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

    View full-size slide

  28. 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

    View full-size slide

  29. 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

    View full-size slide

  30. Renommage de colonne
    ajouter une nouvelle colonne
    31 / 38

    View full-size slide

  31. 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

    View full-size slide

  32. 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

    View full-size slide

  33. 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

    View full-size slide

  34. 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

    View full-size slide

  35. Démo ?
    Questions ?
    36 / 38

    View full-size slide

  36. 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

    View full-size slide

  37. 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

    View full-size slide