Deploy aplicatii web cu Capistrano

Postat la Sat 31 October 2015 in tutoriale

Am prezentat anterior efectuarea deploy-ului la aplicatiile web folosind git. Este o solutie simpla ce se aplica la proiectele mici si one-man job. Dar in cazul proiectelor mai mari/complexe situatia e diferita:

  • exista un risc mai mare ca un bug sa scape;
  • e nevoie de un sistem de deploy pe mai multe stagii de dezvoltare (devel, testare, productie);
  • e nevoie de un sistem de deploy pe mai multe servere simultan;
  • e nevoie de un sistem care sa permita un rollback rapid si usor al codului la o versiune stabila anterioara.

O aplicatie ce rezolva cu success astfel de probleme este Capistrano, scris in Ruby si folosit intens de aceasta comunitate.

Instalarea este usoara daca avem instalata pe sistem un versiune de Ruby >= 1.9.3 sau daca folosim RVM:

gem install capistrano

Scriptul de de deploy poate fi instalat oriunde de exemplu in folderul cap-deploy. in care initializam configuratia de deploy cu comanda:

cap install

sau in cazul multii stage:

cap install STAGES=devel,test,productie

ce va produce urmatoarea structura:

.
├── Capfile
├── config
│   ├── deploy
│   │   ├── devel.rb
│   │   ├── productie.rb
│   │   └── test.rb
│   └── deploy.rb
└── lib
    └── capistrano
        └── tasks

Setarile generale legate de proiect se regasesc in fisierul config/deploy.rb

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
config valid only for current version of Capistrano
lock '3.4.0'

#nume aplicatie
set :application, 'proiect'

# locatia repo git ptr poiect
set :repo_url, 'git@github.com:user/proiect_repo.git'

# locatia unde se face deploy pe server
set :deploy_to, '/var/www/#{fetch(:application)}'

# tipul repo, default git
set :scm, :git

# fisierele comune ce nu se regasesc in repo din motive de securitate si se face link
set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/secrets.yml')

# foldere comune ce nu se regasesc in repo (upload, logs, cache etc)
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')

# Numar de deploy-uri ce se pastreaza pe server, default sunt 5
# set :keep_releases, 5

La nivel de stagiu se definesc serverele, de exemplu in fisierul config/deploy/productie.rb

1
2
3
4
5
6
7
8
9
# Definire la nivel de server

server 'fe-1.domeniu.ro', user: 'deploy', roles: %w{app}
server 'fe-2.domeniu.ro', user: 'deploy', roles: %w{app web}

# Definire servere dupa rol

role :app, %w{deploy@fe-1.domeniu.ro deploy@fe-2.domeniu.ro},
role :web, %w{deploy@fe-2.domeniu.ro},

Trebuie sa ne asiguram ca:

  • cheia noastra publica se regaseste pe fiecare server de deploy
  • serverul are o cheie valida cu care se poate conecta la serverul de git unde este gazduit poiectul

Ca masura suplimentara de protectie se recomanda folosirea metodei de forward a cheii private (utilizate de user-ul ce face deploy), dupa cum este explicat aici.

Deploy-ul propriu zis se face usor cu comanda cap in folderul de pe calculatorul master (ce controleaza operatia de deploy)

1
2
3
4
5
6
7
8
# deploy pe serverele de dezvoltare
cap devel deploy

# deploy pe serverele de testare
cap test deploy

# deploy pe serverele de productie
cap productie deploy

Comanda va crea urmatoarea structura de foldere pe servere:

├── current -> /var/www/proiect/releases/20151018104909
├── releases
│   └── 20151018104909
├── repo
├── revisions.log
└── shared
    ├── config
    └── tmp
        ├── pids
        ├── cache
        └── vendors

unde gasim:

  • releases - versiunile de cod puse pe server in foldere cu data si ora efectuarii deploy-ului
  • repo - copia locala a repo-ului
  • shared - foldere si fisiere comune tuturor deploy-urilor
  • current - o legatura simbolica la versiunea curenta a codului. De accea directorul radacina a aplicatiei este pecificat acesta
  • revision.log - un log al operatiilor efectuate

Spor la deploy.