Deploy automatizado com Puppet: do zero a produção em 5 minutos

Recebi a oportunidade de experimentar o beta teste do serviço de cloud Flutue, no qual um colega tem trabalhado. Os inscritos no beta podem testar gratuitamente durante 30 dias uma VM Linux com 1 vCPU, 512MB RAM e 15GB de espaço em disco. Resolvi então me cadastrar e migrar esse site para essa nova VM. Decidi usar o Puppet para fazer a configuração desde o zero e esse texto é um relato de como fiz. Isso não é um tutorial explicando como fazer, é apenas um relato como eu fiz para subir um servidor na internet capaz de responder por um site em apenas alguns minutos.

Sobre o serviço Flutue não há do que reclamar. O cadastro é muito rápido e não requer nenhuma informação que você não queria compartilhar. O painel de controle é simples e direto, com dois cliques você cria uma nova VM. Existem apenas duas opções de sistema operacional, CentOS 5.10 ou Ubuntu Server 12.04, escolhi CentOS e em 5 minutos estava recebendo um email com IP e senha de root para conexão na VM. Já aproveitei para registrar o IP do servidor no DNS do meu domínio.

A primeira coisa que fiz no servidor foi habilitar os repositórios EPEL e instalar o Puppet:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
[root@ultrav ~]# wget http://dl.fedoraproject.org/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm
--2014-04-18 21:37:40--  http://dl.fedoraproject.org/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm
Resolving dl.fedoraproject.org... 209.132.181.23, 209.132.181.26, 209.132.181.27, ...
Connecting to dl.fedoraproject.org|209.132.181.23|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 12232 (12K) [application/x-rpm]
Saving to: `epel-release-5-4.noarch.rpm'

100%[=============================================================================================================>] 12.232      70,9K/s   in 0,2s

2014-04-18 21:37:41 (70,9 KB/s) - `epel-release-5-4.noarch.rpm' saved [12232/12232]

[root@ultrav ~]# rpm -ivh epel-release-5-4.noarch.rpm 
warning: epel-release-5-4.noarch.rpm: Header V3 DSA signature: NOKEY, key ID 217521f6
Preparing...                ########################################### [100%]
   1:epel-release           ########################################### [100%]

[root@ultrav ~]# yum install puppet
Loaded plugins: fastestmirror, security
Loading mirror speeds from cached hostfile
 * base: mirror.globo.com
 * epel: mirror.globo.com
 * extras: mirror.globo.com
 * rpmforge: repoforge.xpg.com.br
 * updates: mirror.globo.com
Setting up Install Process
Resolving Dependencies
--> Running transaction check
---> Package puppet.noarch 0:2.7.25-1.el5 set to be updated
--> Processing Dependency: facter < 1:2.0 for package: puppet
--> Processing Dependency: ruby(abi) >= 1.8 for package: puppet
--> Processing Dependency: ruby >= 1.8.5 for package: puppet
--> Processing Dependency: facter >= 1.5 for package: puppet
--> Processing Dependency: ruby-shadow for package: puppet
--> Processing Dependency: ruby-augeas for package: puppet
--> Processing Dependency: libselinux-ruby for package: puppet
--> Processing Dependency: /usr/bin/ruby for package: puppet
--> Running transaction check
---> Package facter.x86_64 0:1.6.18-3.el5 set to be updated
---> Package libselinux-ruby.x86_64 0:1.33.4-5.7.el5 set to be updated
---> Package ruby.x86_64 0:1.8.5-31.el5_9 set to be updated
---> Package ruby-augeas.x86_64 0:0.4.1-2.el5.rf set to be updated
--> Processing Dependency: augeas-libs >= 0.8.0 for package: ruby-augeas
---> Package ruby-libs.x86_64 0:1.8.5-31.el5_9 set to be updated
---> Package ruby-shadow.x86_64 0:1.4.1-7.el5 set to be updated
--> Running transaction check
---> Package augeas-libs.x86_64 0:1.1.0-1.el5 set to be updated
--> Finished Dependency Resolution

Dependencies Resolved

=======================================================================================================================================================
 Package                                 Arch                           Version                                 Repository                        Size
=======================================================================================================================================================
Installing:
 puppet                                  noarch                         2.7.25-1.el5                            epel                             3.0 M
Installing for dependencies:
 augeas-libs                             x86_64                         1.1.0-1.el5                             epel                             355 k
 facter                                  x86_64                         1.6.18-3.el5                            epel                              61 k
 libselinux-ruby                         x86_64                         1.33.4-5.7.el5                          base                              61 k
 ruby                                    x86_64                         1.8.5-31.el5_9                          base                             279 k
 ruby-augeas                             x86_64                         0.4.1-2.el5.rf                          rpmforge                          26 k
 ruby-libs                               x86_64                         1.8.5-31.el5_9                          base                             1.6 M
 ruby-shadow                             x86_64                         1.4.1-7.el5                             epel                             9.6 k

Transaction Summary
=======================================================================================================================================================
Install       8 Package(s)
Upgrade       0 Package(s)

Total download size: 5.5 M
Is this ok [y/N]: y
Downloading Packages:
(1/8): ruby-shadow-1.4.1-7.el5.x86_64.rpm                                                                                       | 9.6 kB     00:00     
(2/8): ruby-augeas-0.4.1-2.el5.rf.x86_64.rpm                                                                                    |  26 kB     00:00     
(3/8): facter-1.6.18-3.el5.x86_64.rpm                                                                                           |  61 kB     00:00     
(4/8): libselinux-ruby-1.33.4-5.7.el5.x86_64.rpm                                                                                |  61 kB     00:00     
(5/8): ruby-1.8.5-31.el5_9.x86_64.rpm                                                                                           | 279 kB     00:00     
(6/8): augeas-libs-1.1.0-1.el5.x86_64.rpm                                                                                       | 355 kB     00:00     
(7/8): ruby-libs-1.8.5-31.el5_9.x86_64.rpm                                                                                      | 1.6 MB     00:01     
(8/8): puppet-2.7.25-1.el5.noarch.rpm                                                                                           | 3.0 MB     00:03     
-------------------------------------------------------------------------------------------------------------------------------------------------------
Total                                                                                                                  882 kB/s | 5.5 MB     00:06     
warning: rpmts_HdrFromFdno: Header V3 DSA signature: NOKEY, key ID 217521f6
epel/gpgkey                                                                                                                     | 1.7 kB     00:00     
Importing GPG key 0x217521F6 "Fedora EPEL <epel@fedoraproject.org>" from /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL
Is this ok [y/N]: y
Running rpm_check_debug
Running Transaction Test
Finished Transaction Test
Transaction Test Succeeded
Running Transaction
  Installing     : ruby-libs                                                                                                                       1/8 
  Installing     : ruby                                                                                                                            2/8 
  Installing     : ruby-shadow                                                                                                                     3/8 
  Installing     : augeas-libs                                                                                                                     4/8 
  Installing     : ruby-augeas                                                                                                                     5/8 
  Installing     : libselinux-ruby                                                                                                                 6/8 
  Installing     : facter                                                                                                                          7/8 
  Installing     : puppet                                                                                                                          8/8

Installed:
  puppet.noarch 0:2.7.25-1.el5

Dependency Installed:
  augeas-libs.x86_64 0:1.1.0-1.el5      facter.x86_64 0:1.6.18-3.el5        libselinux-ruby.x86_64 0:1.33.4-5.7.el5   ruby.x86_64 0:1.8.5-31.el5_9  
  ruby-augeas.x86_64 0:0.4.1-2.el5.rf   ruby-libs.x86_64 0:1.8.5-31.el5_9   ruby-shadow.x86_64 0:1.4.1-7.el5

Complete!

Para facilitar e agilizar as configurações do Puppet prefiro instalar uns módulos prontos feitos pela comunidade. Abaixo a instalação de módulos para gerencia Apache, SSH e sudo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
[root@ultrav ~]# puppet module install puppetlabs-stdlib
dnsdomainname: Unknown host
Preparing to install into /etc/puppet/modules ...
Downloading from http://forge.puppetlabs.com ...
Installing -- do not interrupt ...
/etc/puppet/modules
└── puppetlabs-stdlib (v4.1.0)

[root@ultrav ~]# puppet module install puppetlabs-apache
dnsdomainname: Unknown host
Preparing to install into /etc/puppet/modules ...
Downloading from http://forge.puppetlabs.com ...
Installing -- do not interrupt ...
/etc/puppet/modules
└─┬ puppetlabs-apache (v1.0.1)
  └── puppetlabs-concat (v1.1.0-rc1)

[root@ultrav ~]# puppet module install example42-openssh
dnsdomainname: Unknown host
Preparing to install into /etc/puppet/modules ...
Downloading from http://forge.puppetlabs.com ...
Installing -- do not interrupt ...
/etc/puppet/modules
└─┬ example42-openssh (v2.0.9)
  └── example42-puppi (v2.1.9)

[root@ultrav ~]# puppet module install example42-sudo
dnsdomainname: Unknown host
Preparing to install into /etc/puppet/modules ...
Downloading from http://forge.puppetlabs.com ...
Installing -- do not interrupt ...
/etc/puppet/modules
└── example42-sudo (v2.0.12)

Com o Puppet e seus módulos instalados criei o arquivo /etc/puppet/default.pp descrevendo tudo que ele precisa fazer para deixar o servidor como eu quero. Meu site são apenas arquivos estáticos então os requisitos para hospeda-lo são bem simples. Em resumo fiz uma configuração que:

  • Crie um arquivo /tmp/puppet.txt
  • Suba serviço de SSH
  • Crie usuário vinicius com permissão para dar sudo
  • Suba o Apache configurado com virtual host para meu domínio

A sintaxe do Puppet é bem direta e clara, é possível entender a configuração até mesmo antes de estudar a documentação. O arquivo final ficou assim:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[root@ultrav ~]# cat /etc/puppet/default.pp 
include 'stdlib'
include 'openssh'
include 'sudo'
include 'apache'


file { '/tmp/puppet.txt':
  ensure => present,
  content => "Managed by Puppet!\n",
}

user { 'vinicius':
  ensure     => present,
  gid        => 'wheel',
  shell      => '/bin/bash',
  home       => '/home/vinicius',
  managehome => true,
}

sudo::directive { 'vinicius':
    content => "vinicius ALL=NOPASSWD:ALL \n",
}

apache::vhost { 'www.ultrav.com.br':
    port => '80',
    docroot => '/var/www/ultrav.com.br',
    docroot_owner => 'vinicius',
    docroot_group => 'apache',
}

O começo é um include dos módulos que instalei. A primeira regra cria um arquivo de texto com conteúdo específico. As duas seguintes servem para criar um usuário no sistema operacional e configurar acesso ao sudo sem senha para ele. A última configura um virtual host no Apache respondendo pelo meu domínio.

Essas 30 linhas são suficientes para tudo e ao executar o Puppet faz o que for necessário para atingir essa configuração. Com as 5 linhas da configuração de virtual host o Puppet vai baixar, instalar, configurar e subir o serviço do Apache.

Molezinha hein? O que resta para mim é acompanhar o log de execução enquanto o Puppet trabalha. Para aplicar as configurações basta um:

1
[root@ultrav puppet]# puppet apply --verbose default.pp

Depois de cuspir bastante texto na tela devido ao --verbose, o Puppet finaliza com:

1
notice: Finished catalog run in 3.95 seconds

Diz ele que em menos de 4 segundos finalizou o trabalho. Melhor que isso, só se for verdade, então vamos conferir!

Arquivo de texto em /tmp criado com o conteúdo esperado:

1
2
[root@ultrav puppet]# cat /tmp/puppet.txt 
Managed by Puppet!

Usuário criado e acesso ao sudo configurado:

1
2
3
4
5
[root@ultrav puppet]# grep vinicius /etc/passwd
vinicius:x:500:10::/home/vinicius:/bin/bash

[root@ultrav puppet]# grep vinicius /etc/sudoers
vinicius ALL=NOPASSWD:ALL

Agora só falta o Apache com a configuração de virtual host:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@ultrav puppet]$ /etc/init.d/httpd status
httpd (pid  1988) is running...

[root@ultrav puppet]# ps -ef | grep httpd
root      1988     1  0 21:42 ?        00:00:00 /usr/sbin/httpd
apache    1989  1988  0 21:42 ?        00:00:00 /usr/sbin/httpd
apache    1990  1988  0 21:42 ?        00:00:00 /usr/sbin/httpd
apache    1991  1988  0 21:42 ?        00:00:00 /usr/sbin/httpd
apache    1992  1988  0 21:42 ?        00:00:00 /usr/sbin/httpd
apache    1997  1988  0 21:42 ?        00:00:00 /usr/sbin/httpd
apache    1998  1988  0 21:42 ?        00:00:00 /usr/sbin/httpd
apache    1999  1988  0 21:42 ?        00:00:00 /usr/sbin/httpd
apache    2000  1988  0 21:42 ?        00:00:00 /usr/sbin/httpd
root      2051  1380  0 21:43 pts/0    00:00:00 grep httpd

[root@ultrav puppet]# ls -l /var/www/
total 52
drwxr-xr-x  2 root      root   4096 Abr  3 19:55 cgi-bin
drwxr-xr-x  3 root      root   4096 Abr 15 11:24 error
drwxr-xr-x  2 root      root   4096 Abr  3 19:55 html
drwxr-xr-x  3 root      root   4096 Abr 15 11:25 icons
drwxr-xr-x 14 root      root   4096 Abr 15 11:25 manual
drwxr-xr-x  2 vinicius  apache 4096 Abr 18 21:42 ultrav.com.br
drwxr-xr-x  2 webalizer root   4096 Abr 15 11:01 usage

Serviço no ar e diretório criado, vamos conferir o virtual host que foi configurado em /etc/httpd/conf.d/25-www.ultrav.com.br.conf:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# ************************************
# Vhost template in module puppetlabs-apache
# Managed by Puppet
# ************************************

<VirtualHost *:80>
    ServerName www.ultrav.com.br

    ## Vhost docroot
    DocumentRoot "/var/www/ultrav.com.br"

    ## Directories, there should at least be a declaration for /var/www/ultrav.com.br

    <Directory "/var/www/ultrav.com.br">
        Options Indexes FollowSymLinks MultiViews
        AllowOverride None
        Order allow,deny
        Allow from all
    </Directory>

    ## Load additional static includes


    ## Logging
    ErrorLog "/var/log/httpd/www.ultrav.com.br_error.log"
    ServerSignature Off
    CustomLog "/var/log/httpd/www.ultrav.com.br_access.log" combined
</VirtualHost>

Nada mal, o Puppet fez tudo que tinha que fazer e em poucos segundos. Para finalizar o trabalho apenas configurei a senha do usuário e subi os arquivos do site via SCP. Uma linha a mais na regra de usuário e a senha seria criada também pelo Puppet.

Descontando o tempo de criação da VM não levei 5 minutos para fazer o trabalho. Posso seguramente dizer que o processo inteiro de criar um servidor Linux para hospedar um site simples usando Puppet e bons serviços de cloud como Flutue não leva 15 minutos.

É tudo tão rápido que fiz o processo três vezes. A primeira VM que criei foi feita manualmente seguindo os passos do meu tutorial. Depois reproduzi as configurações através do Puppet, destrui o ambiente só para ver o Puppet consertar tudo com um puppet apply. Já convencido que o danado é poderoso resolvi fazer o teste final descrito nesse texto. Deletei a VM, criei uma nova e tudo que fui fiz foi instalar o Puppet, alguns módulos e aplicar o arquivo de configuração.

Os requisitos eram simples e a configuração ainda pode ser refinada mas se você esta lendo esse site, significa que o servidor ficou pronto e funcionou. Do zero a produção em menos de 5 minutos.

O Puppet faz muito mais do que isso. Aqui apenas utilizei ele em modo standalone mas o real poder dele pode ser visto funcionando em modo servidor. Elegemos um servidor que será o Puppet master, responsável por guardar todas as regras de configuração, e os demais servidores consultam o master de hora em hora para checar se suas configurações estão corretas. Se você precisa de 10 servidores Apache e 5 MySQL para seu ambiente, basta instalar o Puppet nos servidores e dizer 'Aplique a regra Apache nesses 10 e aplique a regra MySQL nesses 5'. Enquanto você faz alguma outra coisa o Puppet trabalha e entrega os servidores conforme sua configuração. Ele não só configura como mantém as configurações. De hora em hora os servidores checarão o Puppet master e se algo estiver diferente das regras, será reconfigurado. Alguém deletou o usuário? Será recriado. Modificaram o Virtual Host manualmente? Será sobrescrito pela especificação da regra. Isso gera um novo jeito de trabalhar, ao invés de modificar os servidores diretamente, os administradores passam a centralizar as configurações no Puppet e ele distribui conforme necessário.

Comentários