Documente Academic
Documente Profesional
Documente Cultură
Título
Director/es
Departamento
Curso Académico
2012-2013
Mejores practicas de despliegue continuo para aplicaciones Symfony2, trabajo
fin de grado
de Fernando Arconada Orostegui, dirigido por Eloy Javier Mata Sotés (publicado por la
Universidad de La Rioja), se difunde bajo una Licencia
Creative Commons Reconocimiento-NoComercial-SinObraDerivada 3.0 Unported.
Permisos que vayan más allá de lo cubierto por esta licencia pueden solicitarse a los
titulares del copyright.
© El autor
© Universidad de La Rioja, Servicio de Publicaciones, 2013
publicaciones.unirioja.es
E-mail: publicaciones@unirioja.es
Mejores prácticas de despliegue continuo para aplicaciones
Symfony2
Fernando Arconada Orostegui
5 de junio de 2013
Índice general
Índice general i
1 Resumen 1
2 Abstract 1
3 Introducción 2
3.1. Antecedentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
3.2. Problema que se quiere solucionar . . . . . . . . . . . . . . . . . . . . 2
3.3. Elementos a conseguir . . . . . . . . . . . . . . . . . . . . . . . . . . 3
3.4. Flujos de trabajo habituales . . . . . . . . . . . . . . . . . . . . . . . 3
4 DevOps 6
4.1. Inculcar una cultura de DevOps . . . . . . . . . . . . . . . . . . . . . 6
4.2. Puntos a tener en cuenta para implantar con éxito una cultura de
DevOps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4.3. Cómo crear una cultura de DevOps . . . . . . . . . . . . . . . . . . . 9
i
7 Sistema de control de versiones 24
7.1. Modelo de Ramas para Git . . . . . . . . . . . . . . . . . . . . . . . 24
7.2. Release Candidates . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
7.3. Estado de commit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
10 Monitorización 35
11 Plan B 36
11.1. Los datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
11.2. Rollback con capifony . . . . . . . . . . . . . . . . . . . . . . . . . . 37
11.3. Página de mantenimiento con capifony . . . . . . . . . . . . . . . . . 37
12 Conclusiones 39
Bibliografía 40
ii
Índice de guras
iii
1 Resumen
Poner un proyecto de software en marcha comprende más cosas que desarrollar código.
El software es algo vivo, normalmente una vez que se pone online o se entrega al cliente
se sigue desarrollando y generando nuevas versiones. En la mayor parte de las empresas, la
puesta en producción de una nueva versión es un momento crítico por las incertidumbres
que genera. Dentro de las empresas de IT hay dos grupos marcados que creen tener obje-
tivos distintos, desarrollo (dev) y sistemas (ops). Cambiar la mentalidad de estos grupos,
automatizar todas las tareas posibles y establecer políticas de calidad y control claras son
fundamentales para que el proceso de trasladar valor a los clientes (implementar cambios)
sea un proceso frecuente, sencillo y seguro.
2 Abstract
Start a software project is more than develop code. Software is alive. You will deploy new
releases after run it online for rst time or deliver it to the customer. Most times every
software deployment it's a critical moment cause of uncertainty generated. IT rms use to
have two kind of teams, developers (devs) and operators (ops). Both think that they goals
are dierent but this is not true. Change their minds, automate every task and establish a
clear quality policy with checkpoints is something vital to increase the value perceived by
our customers (in the end, implement change). So this will become a frequent task, easy
and reliable.
1
3 Introducción
3.1. Antecedentes
Hasta la actualidad, son muchas las empresas que se han dedicado a crear software sin
una reexión seria sobre cómo poner y mantener ese software en producción. El software
está vivo y en constante evolución, no sólamente porque esté extendido el modelo de difun-
dir y parchear, sino porque el mercado exige evolucionar y aplicar cambios con celeridad.
En los modelos de desarrollo de software se ha ido pasando de metodologías en las que se
abordaba la totalidad de las funcionalidades del software en cascada a metodologías ágiles.
El desarrollo ágil de software son métodos de ingeniería del software basados en el desa-
rrollo iterativo e incremental, donde los requerimientos y soluciones evolucionan mediante
la colaboración de grupos auto organizados y multidisciplinarios. Existen muchos métodos
de desarrollo ágil; la mayoría minimiza riesgos desarrollando software en lapsos cortos. El
software desarrollado en una unidad de tiempo es llamado una iteración, la cual suele durar
de 1 a 4 semanas. Ha habido mucho debate respecto a cómo desarrollar software, pero sólo
recientemente se está planteando cómo debemos poner el software en manos de los usuarios,
tanto en la primera puesta en producción como en cada una de las iteraciones o parches
ofrecidos. Además, los usuarios son cada vez más exigentes y más globales, y por lo tanto
toleran peor los problemas de disponibilidad. El objetivo de este documento es ofrecer un
ejemplo de modelo de despliegue de aplicaciones en el que se reexione sobre las que pueden
ser las mejores prácticas para poner en producción de forma ágil las nuevas versiones de
las aplicaciones. Como el modelo de despliegue está muy ligado a la tecnología que utiliza
para desarrollar, en el presente trabajo n de grado nos vamos a centrar en aplicaciones
desarrolladas con el framework de desarrollo PHP Symfony2.
3.2. Problema que se quiere solucionar
El objetivo es encontrar una forma de trabajo en el desarrollo integral de software que
no sea el caos típico de la empresa ágil ni tan lento como la empresa burocrática. Hay
que encontrar un ujo integral que no implique cruzar los dedos cada vez que se hace
un despliegue ni que tenga que pasar una semana para que los usuarios puedan usar las
nuevas funcionalidades. Subir cambios a producción debe implicar una garantía de éxito.
La infraestructura debe estar al servicio del software, debe ser fácilmente reproducible y
gestionable. En el ciclo de vida del software hay 3 etapas claras: desarrollo, pruebas y
producción. Desarrollo y producción son inevitables. El entono de pruebas es altamente
recomendable. El objetivo de estos entornos es:
Desarrollo: entorno donde el equipo de desarrollo crea el software, normalmente es
su propio PC, que ellos suelen denominar local. Se suelen realizar muchos cambios
al día, del orden de decenas o incluso cientos. También es común ver entornos de
desarrollo compartidos entre miembros del equipo de desarrollo.
Producción: es el entorno donde se ejecutan las aplicaciones y pueden usarlas los
clientes nales. Normalmente este entorno suele ser, al menos, un servidor dedicado,
si no un cluster, y lo normal es que tenga un sistema operativo diferente al entorno de
desarrollo e incluso una arquitectura diferente. Debe permanecer estable. Suele estar
gestionado por el equipo de Sistemas.
2
Pruebas: Se congura prácticamente igual al de producción y sirve para validar cam-
bios e intentar reproducir los errores de producción.
3
controlar la complejidad, pero a cambio se ha sacricado la agilidad para hacer llegar los
cambios a los usuarios. Las modicaciones sencillas pueden tardar semanas en aplicarse e
implican tiempo de muchas personas. El Departamento de Infraestructuras o Sistemas es
el responsable de mantener los ratios de disponibilidad de los servicios y por lo tanto no
es proclive a realizar cambios. El Departamento de Desarrollo es el responsable de crear
las nuevas funcionalidades demandadas por los usuarios lo antes posible y por lo tanto su
trabajo es modicar los programas. La burocracia es el pegamento que hace que ambos
departamentos se pongan de acuerdo. Estas empresas suelen tener, incluso por escrito, los
formularios que debe cumplimentar una aplicación para que sea puesta en producción. Un
ejemplo de este ciclo puede ser:
En el entorno de desarrollo se despliega cada hora y se utiliza para que los cambios se
aprueben internamente.
5
4.2. Puntos a tener en cuenta para implantar con éxito una
cultura de DevOps
Difuminar la distinción entre programadores y administradores de sistemas. Si el pro-
gramador no tiene experiencia en sistemas se produce el típico en mi local funciona,
por ejemplo derivado de que en el servidor la fecha está en formato MM/DD/YYYY
porque está congurado en inglés, que es diferente de su PC Windows 7 en español
DD/MM/YYYY
El procedimiento de paso a producción debe ser plenamente seguro. Hacer los desplie-
gues en producción debe estar plenamente automatizado. Hacer despliegues a mano,
aunque estén todos los pasos por escrito en un manual de procedimiento es la forma
más fácil de cometer algún error.
El código no debe tener bugs. Es prácticamente imposible que el software no tenga fa-
llos, pero hay que incentivar que los programadores adopten técnicas de programación
defensiva y apliquen continuamente test unitarios y funcionales. De esta forma, no
sólo se evitan errores, sino que mejora la implicación entre los equipos de desarrollo y
sistemas, ya que si estos últimos encuentran que cada vez el software es más conable
tienen menos excusas para oponerse al cambio.
Hay que empezar por el producto mínimo viable. Citando al padre de C++ un sistema
grande y complejo que no ha evolucionado a partir de otro más pequeño no funciona y,
además, es imposible arreglarlo para que funcione. Por lo tanto el software debemos
concebirlo como pequeñas iteraciones frecuentes y trataremos de huir de las grandes
versiones con muchos cambios.
El diseño debe estar planicado para poder crecer en pequeños trozos. Si la programa-
ción se debe hacer en pequeños trozos el diseño debe ser pensado de forma ambiciosa.
Un elemento fundamental para lograr este objetivo es reducir el acoplamiento para
que determinadas piezas puedan ser fácilmente substituibles sin afectar a otras partes
del programa.
El sistema debe ser muy fácilmente auditable y depurable. Dado que se van a producir
cambios continuamente, hay que poder trazar lo que está sucediendo en cada instante.
En este punto el software libre juega un papel muy importante.
El sistema debe tener resiliencia. El sistema debe poder funcionar aunque se degraden
las condiciones del entorno.
Debe existir una política de contención de daños. Antes de pasar nada a producción
hay que intentar determinar qué es lo peor que podría pasar e intentar tener un plan
B por si se produce el desastre.
La organización debe aceptar que el software es algo vivo. Como tal, crece y evoluciona.
Cada día aparecen nuevas funcionalidades, y, por contra, alguna que otra desaparece o
deja de funcionar temporalmente. De igual forma los plazos se vuelven algo deslizante,
el software no se desarrolla, evoluciona y, como todas las evoluciones, su velocidad de
cambio y la dirección que tomen pueden ser muy variables en función del entorno.
Debe existir un sistema de documentación continua. Si al software se le añaden co-
sas todos los días, llega un momento en el que evoluciona hasta un punto en el cual
8
Sistemas tiene información sobre el entorno de ejecución. Actualmente Sistemas esta inun-
dado de información y agrega esta información como parte de su propio sistema de monitori-
zación. Sin embargo si esta información no uye hacia Desarrollo se pierde una oportunidad
de que éstos aprendan y mejoren.
Área 3
Desarrollo solo aporta nuevas funcionalidades sin tener en cuenta otros objetivos no
funcionales La idea de este área es integrar al equipo de Desarrollo dentro del equipo de
Sistemas. No se trata sólo de juntar los equipos sino también los objetivos y las actividades
de desarrollo dentro del área de sistemas. Desarrollo debe tener en cuenta no solamente
objetivos funcionales sino que tienen que considerar otros objetivos como la estabilidad y la
capacidad como parte del propio desarrollo.
Práctica: Poner la estabilidad y la capacidad como objetivos de Desarrollo.
Objetivos:
Alinear objetivos
Compartir incentivos
Área 4
Mientras se desplegaba el software en producción por primera vez se descubre que van a
ser necesarias nuevas máquinas para poder ejecutar el software. Hay que tratar de integrar al
equipo de Sistemas dentro del departamento de Desarrollo. Ambos equipos deben trabajar
juntos para conseguir la mejor solución posible. El equipo de Sistemas está sumamente
implicado en el desarrollo consultando y aportando ideas a la solución a desarrollar, no
apareciendo solamente cuando la funcionalidad ya está programada.
Práctica: Sistemas aporta feedback sobre el diseño de la aplicación en desarrollo de
manera temprana y frecuente.
Objetivos:
Desarrollo gana feedback sobre si la funcionalidad a desarrollar es factible.
Compartir conocimiento.
11
5 Infraestructura como código
Cometer un error es humano, propagar el error de forma automática a todos los servidores
es #devops - DevOps Borat
Muchas de las corrientes actuales tratan de automatizar todas las partes posibles del
ciclo de desarrollo del software. En este sentido están entre otros los test unitarios o los
sistemas de integración continua, sin embargo la parte de sistemas y servidores sigue siendo
un trabajo artesanal. La infraestructura incluye todas las partes de la solución que no son
desarrolladas como el software de la aplicación en sí, es decir, servidores web, sistemas
operativos, tareas programadas, etc. El concepto de infraestructura como código se reere
a intentar gestionar la infraestructura como si de un desarrollo software se tratase. Esto
se hace posible de manera sencilla gracias a la virtualización y herramientas como Puppet,
Chef o Cfengine.
5.1. Ventajas
Las principales ventajas son:
Los entornos dejan de estar instalados manualmente para hacerlo mediante un proceso
automático, de forma que se evitan errores y los sistemas son fácilmente reproducibles
de manera able.
Se reduce los tiempos dedicados a la administración de sistemas, puesto que las labores
de mantenimiento se hacen de forma automatizada y centralizada.
5.2. Herramientas
Gestionar una infraestructura como código se puede hacer con diversas herramientas. Un
sistema de control de versiones es indispensable, pero de eso no hablaremos ahora. Aunque
esta gestión de sistemas se puede hacer con scripts es recomendable emplear utilidades como
Puppet, Chef, Cfengine y otros.
Puppet
Puppet gestiona sistemas Linux/Unix y MS Windows de forma declarativa. El usuario
describe los recursos del sistema y sus estados utilizando un DSL (Domain Specic Lan-
guage) de Ruby en cheros de texto llamados manifests. Puppet descubre la información
del sistema con una utilidad llamada Facter y junto con los manifests crea un catálogo que
aplica a los sistemas de destino. El resultado de aplicar esta catálogo es reportado a un nodo
central.
Chef
Es una herramienta de gestión de conguraciones escrita en Ruby y Erlang. Chef describe
los recursos y estados de los sistemas en cheros llamados recetas. Los atributos de los
12
sistemas gestionados bajo Chef se reportan al servidor central que los indexa mediante Solr
y junto las recetas genera la conguración a aplicar.
Cfengine
Cfengine es una herramienta muy madura de gestión de conguraciones, se basa en la
Teoría Promesas de Mark Burgess. Esta herramienta facilita la automatización de sistemas
y el mantenimiento de sistemas de computadores de gran escala, incluyendo la gestión de
servidores, estaciones de trabajo, dispositivos de red y dispositivos móviles.
Elección de herramienta
Vamos a elegit Puppet por las siguientes razones.
Descartamos Cfengine porque posteriormente vamos a usar Vagrant para el entorno de
desarrollo y este sólo soporta Chef o Puppet, además el lenguaje de Cfengine es complicado
y cuestan bastante depurar las promesas (lenguaje de Cfengine).
El lenguaje DSL de Puppet resulta cómodo para los administradores de sistemas y el de
Chef para los programadores de Ruby. Ambos tienen una buena documentación, aunque
Puppet tiene más libros escritos.
La comunidad alrededor de Puppet y Chef es grande y crece cada día si bien es cierto
que al ser Puppet un producto más maduro tiene más comunidad y ésta es muy activa.
Otro elemento clave a la hora de elegir Puppet ha sido la inversion de 30 millones de
dolares en la herramienta por parte de VMware que es el lider en soluciones de virtualización
y pensamos que esto puede marcar una diferencia para hacer que Puppet llegue al corazón
de las empresas.
Por otro lado, el entorno servidor de Chef es algo más complicado de desplegar que el
entorno de Puppet.
De todas formas estamos totalmente seguros de que es fácil que cada uno encuentre sus
propias razones para hacer que se decante hacia una u otra herramienta sin que ello signique
una limitación de sus posibilidades a la hora de desplegar una infraestructura como código.
stage{bootstrap:}
Stage[bootstrap]->Stage[main]
node default{
class {'bootstrap': stage=> bootstrap}
class {'apache': }
class {'mysql': }
class { 'mysql::server':
config_hash => { 'root_password' => 'toor' }
}
mysql::db { `myapp':
user => `dbuser',
password => 'i6vbunhkj',
13
host => 'localhost',
grant => ['all'],
}
class { 'mysql::backup':
backupuser => 'backupuser',
backuppassword => 'binyuvgmngv',
backupdir => '/tmp/backups',
}
php::module { [ 'curl', 'gd', 'mcrypt', 'mysql' ]:
notify => Class['php::fpm::service'],
}
# Add a pool definition
php::fpm::pool { 'www':}
}
Este maniesto es muy sencillo y congurar un servidor de producción requeriría una
cuantas líneas más. Nuestro ejemplo lo que hace es instalar Apache, instalar MySQL y crear
una BD así como congurar una tarea de backup para la todas las BD, instalar PHP y los
módulos requeridos.
14
La versión concreta del S.O. elegido es Ubuntu 12.04 por ser la versión de soporte exten-
dido (LTS) y elegimos una arquitectura de 64bit para ejecutar la instancia en el servidor
más pequeño de Amazon y luego podemos escalar fácilmente a servidores más grandes. La
instancia de servidor más pequeña a considerar es la M1.Small puesto que las microinstan-
cias están más orientadas a desarrollo o ser ejecutadas como apoyo en ráfagas puntuales de
carga.
Instancia pequeña M1
Memoria de 1,7 GiB
1 unidad informática EC2 (1 núcleo virtual con 1 unidad informática EC2)
160 GB de almacenamiento de instancia
Plataforma de 32 o de 64 bit
Rendimiento de E/S: moderado
Instancia optimizada para EBS disponible: No
Nombre de API: m1.small
Las imagenes de Ubuntu Cloud para Amazon AWS se pueden encontrar en http://cloud-
images.ubuntu.com/locator/ec2/. Estas imágenes de Ubuntu tienen una instalación míni-
ma de software e incluyen cloud-init. Amazon AWS, desde su consola, permite especicar
conguraciones de cloud-init para inicializar el servidor. Con cloud-init personalizamos la
instancia del servidor en el momento del arranque sin tener que modicar el AMI en sí
empleamos la siguiente conguracion:
#cloud-config
package_update: true
package_upgrade: true
package_reboot_if_required: true
apt_preserve_sources_list: true
packages:
- git
- puppet
15
ssh_pwauth: False
ssh_authorized_keys:
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCjMjVJph1xs
06c2MOPYQufgdfdaS6rsJLQ71DPnkxZVGMaH
UOVSxbQ/7UBmMzASo61H7r1vJgr8rgdbtyebpc+04ig+G5QgHg8BlUl
BzKs4b+xaeka17z/807l4CP4fYV5W4TyxN
b7H/mI6zZQ/mNli75bAkvYSXWN2+7AZ8IGM+GTPo4Q
WCJKT9i//uxNcgCu++e7haGMjyXKEM+6hQLnNC8F5Z5
BInlhY8zDfxzHVghvzIwNX3IvgvHoqIvCYJmMDgfpdR2F91g09
HtQ/Pr4m5CVD0q9CO0eaOr24Z6e5p9q8tBenOcX3d/0hy+d6TNq5QoZEk/f mis-keys
disable_ec2_metadata: false
disable_root: false
locale: es_ES.UTF-8
timezone: Europe/Madrid
resize_rootfs: True
hostname: `server-01.myfirm.com'
output: {all: '| tee -a /var/log/cloud-init-output.log'}
runcmd:
- [ sh, -c ,"cat >/root/.ssh/id_rsa <<EOF
\n
-----BEGIN RSA PRIVATE KEY-----\n
MIIEpAIBAAKCrf5trddsdvdfIy8djSEGKDFf5SxPFGcykXXTuMSPCrfZdTtCN9vF\n
a2Igke43GJ5hvIIFGWuuQn1ncfxha8e+j9h+lD3yZAdgEI4AzI8Yceqb/ItcJBnR\n
Iilz2UeEDOaIbtTMXPVc5yeMVLYUFLzCHINPo8SKt2MRpr5AeIjjbAsu+0Bm0/sD\n
u1Uvu4SgaxLZE/JqmwNAhnS2D88TOYh5N0dwL1yRbNeN0CoRiYCBjBr1q4oCLzVI\n
+2cijaPM/mVTTfDM5QoBB+lBD+FZUl/lZdjU2u9FzUpVvSwffjBNg5cW12//4LkH\n
X08D3cm8T2FACXHyillC44pNALwSHEWqzaaYqQIDAQABAoIBAGU0CCGEINutQw3e\n
LDXfeTSFve+N9p08GF1AKnZvmCGTkA2zoobjEhaq+locrBPMktw3rkjcsQA37qFo\n
OZ9QukrxnEWQrahYrVp7IsZVizdn9kopmY6NuXJhkEkQlqHi1Q1agqYqLYQCnslO\n
lmlr3XbtFrC+fRfusSG8eUEuSp/PPr8aDsRVOnzzAp8woj/sXxVuIVcgoJVtyfwF\n
4MG8F6zyT54tSHx0E81XzduMgCqjxrsLNJnrtDQUq8yvHWYwYoEa4Utc8sN57Uo8\n
oIPwx439w/qMo0D6Zqf/xQ6EzuLWpsZz0PAp/+ZEsYPZMFNCs+71jBgGMFe4vJFI\n
NoBYu+gzoy0v6iM3Xi6S6NmnjcnHoJjCMD3+Ugai/2B7PbqUeZ45rHhCwyOnsA4R\n
6PtLn78yUQaNUJjqS80Bxa0CgYEAny+iqfyBlAmudrv4DLRWCloKwQiRufKLsFe6\n
3SxLGkrWFCqpasWq0UV/imnGZRm8hV6npJ1YomFReVM4/200oyIU4th6jaasFpl7\n
MWikiibnGjvgtsjqzBPyJUp6/9d1Ts90kGlt4sBzgO+aUgX60KHjKYYyXsTKmzeb\n
eehyC5ECgYAglD+xo6vU3SflOcM5CuCM7jfNumPGEj4wwb/U1Dq1k3akW7RfsWyw\n
GL+oCCaXgym9QqP5d3zpfiZ4wxHB90nRq3txhOU4tZwjho/A/kG5IMULVInAvKd0\n
9XcRdzHP3d2ChO1yJztFgH8//vJ5OZP+lkLcNkdd3sbG0IvL4qTwzg==\n
-----END RSA PRIVATE KEY-----\n
EOF"]
- [ sh, -c ,"echo ssh-rsa AAAAB3NzaC1yc2EAAAADAQABA
AABAQDQx/TTz0gjLx2
NIQYoMV/lLE8UZzKRddO4xI8Kt9l1O0I328VrYiCR7jcYnmG8
ggUZa65CfWdx/GFrx76P2H6UPfJkB2AQjgDMjxhx6pv8i1wkGd
EiKXPZR4QM5ohu1Mxc9VznJ4xUt
hQUvMIcg0+jxIq3YxGmvkB4iONsCy77QGbT+wO7VS+7hKBrEtk
16
T8mqbA0CGdLYPzxM5iHk3R3AvXJFs143QKh
GJgIGMGvWrigIvNUj7Z
yKNo8z+ZVNN8MzlCgEH6UEP4VlSX+Vl2NTa70XNSlW9LB9+ME2Dlx
bXb//guQdfTwPdybxPYUAJcfKKWULjik0AvBIcRar
Nppip root@kyoki-01 > /root/.ssh/id_rsa.pub"]
- chmod 600 /root/.ssh/id_rsa
- sed 's/^ //' -i /root/.ssh/id_rsa
- rm -Rf /etc/puppet.orig
- mv /etc/puppet /etc/puppet.orig
- ssh-keyscan -H bitbucket.org > /root/.ssh/known_hosts
- git clone git@bitbucket.org:myuser/puppet-lamp.git /etc/puppet
- puppet apply -v /etc/puppet/site.pp
apt_sources:
- source: deb http://apt.puppetlabs.com precise devel
keyid: 4BD6EC30
17
6 Entornos de producción, pruebas y desarrollo comparables
Como ya hemos comentado antes, en ciclo de vida del software hay 3 etapas claras:
desarrollo, pruebas y producción. Desarrollo y producción son inevitables. El entono de
pruebas es altamente recomendable.
class InstanceMgr:
def __init__(self):
yamlData = yaml.load(file('./settings.yaml'))
self.region = yamlData['aws']['region']
self.instance_type = yamlData['aws']['instance_type']
self.ami_id = yamlData['aws']['ami_id']
self.key_name = yamlData['aws']['key_name']
self.instance_tags = yamlData['aws']['instance_tags']
self.security_groups = yamlData['aws']['security_groups']
self.cloud_init_template_vars = yamlData['cloud-init']['template_vars']
self.cloud_init_template_url = yamlData['cloud-init']['template_url']
self.connection = boto.ec2.connect_to_region(self.region)
18
filename = self.cloud_init_template_url
template = urllib.urlopen(filename).read()
return Template(template).substitute(
self.cloud_init_template_vars
)
def launch(self):
reservation = self.connection.run_instances(
image_id = self.ami_id,
instance_type = self.instance_type,
key_name = self.key_name,
security_groups = self.security_groups,
user_data = self.get_script()
)
instance = reservation.instances[0]
self.connection.create_tags([instance.id], self.instance_tags)
self.instance = instance
return instance
def find_all_running(self):
foundInstances = []
reservations =
self.connection.get_all_instances(filters={'instance-state-name': 'running'})
for reservation in reservations:
for instance in reservation.instances:
foundInstances.append(instance)
return foundInstances
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=
19
'Lanza una instancia de un proyecto en AWS EC2')
group = parser.add_mutually_exclusive_group()
group.add_argument(
'--launch', help=
'lanza una instancia AWS EC2', action='store_true', default=False)
group.add_argument(
'--list-instances', help='listado de instancias activas',
action='store_true', default=False)
group.add_argument(
'--delete-project',
help='termina las instancias etiquetadas con un Project=projectid')
args = parser.parse_args()
if not args.launch and not args.delete_project and not args.list_instances:
parser.print_help()
instanceMgr = InstanceMgr()
if args.launch:
print instanceMgr.launch()
while instanceMgr.instance.state == 'pending':
instanceMgr.instance.update()
print 'waiting for 30s until instance in ready state'
time.sleep(30)
print instanceMgr.instance.public_dns_name
#print instanceMgr.get_script()
sys.exit(0)
if args.delete_project:
print 'Borrando imagenes del projecto=' + args.delete_project
instances = instanceMgr.find_instances_by_tag('Project', args.delete_project)
instanceMgr.terminate(instances)
for instance in instances:
print 'Terminada -> ' + instance.id + ' ' + instance.public_dns_name
sys.exit(0)
if args.list_instances:
instances = instanceMgr.find_all_running()
for instance in instances:
print instance.id + ' ' + instance.public_dns_name
for tag in instance.tags:
print "\t" + tag + '=' + instance.tags[tag]
sys.exit(0)
El script es muy sencillo pero nos puede simplicar la gestión de nuestros servidores
en Amazon AWS. Como los datos de producción son sensibles, este script crea el script de
cloud-init basándose en una plantilla y rellenándola con los datos de un chero settings.yaml
en el que se pueden poner las passwords, claves ssh, etc
20
La instancia de EC2 lee la conguración de cloud-init que es muy sencilla y que bási-
camente le indica al servidor cómo recuperar los maniestos de Puppet de Bitbucket
para proceder a autocongurarse.
Una vez que se aplican los maniestos de Puppet (puede tardar de 5 a 10 minutos) el
servidor de producción ya está listo para recibir la aplicación
25
Ramas principales
Las ramas principales son master y develop. La rama master en el repositorio principal
origin siempre contiene código que está listo para ponerse en producción. La rama develop
reeja el estado actual de desarrollo entregado. Es decir con funcionalidades terminadas
aunque todavía no aprobado para pasar a producción. El código de esta rama es el que
normalmente se ejecuta en los servidores de pruebas. Cuando el código de develop esta
listo para ser integrado en producción se hace un merge de develop a master.
26
Cada commit es una release potencial **, cada commit que un desarrolador hace sobre la
base de código se entiende que añade valor al negocio de alguna forma y mejora el sistema
en el que estamos trabajando. El trabajo de la integración continua es vericar cada release
candidate para ver si puede encajar o no producción. No hay que olvidar que una mejora
(feature) sólo está terminada cuando entrega valor al usuario, y esto sólo sucede cuando
está en producción.
27
8 Despliegue como proceso automático
Desplegar el código en producción o pruebas, y quizás también en desarrollo, es algo
que debe hacerse pulsando un botón (ejecutando un script). Hay que evitar los procesos
manuales, estos conllevan tiempo y son propensos a errores por mucho que esos procesos se
hayan repetido.
8.1. Herramientas de despliegue
Existen diferentes herramientas que pueden ayudarnos a hacer el despliegue de manera
automática:
Ant: es una herramienta de construcción para aplicaciones Java con diferentes tipos
de tareas que pueden incluir en el script, como por ejemplo hacer FTP o crear un zip.
Phing: es el equivalente a Ant pero orientado a PHP. Es una herramienta muy com-
pleta ideal para ejecutar validación de métricas, tests unitarios y depliegues de apli-
caciones PHP.
Capifony: es una herramienta especíca de despliegue de aplicaciones Symfony. Esta
herramienta tiene diversas utilidades orientadas al despliegue y es fácilmente extendi-
ble.
Fable: La libería de python Fabric es posiblemente una de las mejores soluciones
para la creación de scripts de despliegue con carácter general. Provee un conjunto de
utilidades relacionadas con el proceso de despliegue de aplicaciones por SSH y que son
la base para la creación de nuestros scripts.
Nuestra elección es emplear Capifony porque es una utilidad especíca para el entorno
en que nos centramos qué es Symfony2. Con Capifony podemos ejecutar comandos de Sym-
fony2, hacer rollbacks sencillos de las versiones y crear un único script de despliegue que se
adapte a los diferentes servidores de despliegue. Si decidiésemos invertir recursos para te-
ner algo más personalizado o consideramos desplegar además otro tipo de software, Python
Fabric sería la solución elegida.
8.2. Alternativas a un script
Una alternativa a hacer el despliegue mediante una herramienta especíca, o un script,
es sincronizar diferentes ramas del sistema de control de versiones en los servidores. Por
ejemplo, podemos sincronizar la rama master con el directorio del servidor web corres-
pondiente. También podemos hacer esto con la rama develop para el servidor de pruebas.
Con las aplicaciones PHP es posible porque no es necesario compilar los fuentes ni crear un
paquete como en otros lenguajes.
Una ventaja de este sistema es que podemos poner una tarea programada que sincronice
los fuentes en determinado horario y así establecer un calendario de despliegue separado
para producción y desarrollo, y si hay commits nuevos en las ramas de develop o master se
aplicarán en los servidores.
El inconveniente de este sistema es que buscamos una exibilidad mas allá de aplicar
nuestros cambios en un momento determinado, además muchas veces es necesario ejecutar
tareas adicionales a copiar los fuentes, como por ejemplo hacer modicaciones en la base de
datos.
28
8.3. Capifony
Capifony es una extensión de Capistrano (herramienta de deploy de Ruby) que incorpora
recetas especícas para Symfony. Hay otra extensión de Capistrano que vamos a incorporar
y es Capistrano-ext concretamente para poder hacer un script multistage, es decir, que el
mismo script nos sirva para producción (en Amazon EC2) y en pruebas (en una box de
Vagrant)
Script de deploy de capifony
deploy.rb
set :stages, %w(production staging)
set :default_stage, "staging"
set :stage_dir, "app/config"
require 'capistrano/ext/multistage'
set :branch, "develop"
29
top.upload "#{Dir.pwd}/app/config/parameters.yml.dist.#{stage}",
"#{deploy_to}/#{shared_dir}/app/config/parameters.yml"
end
end
stagging.rb
ssh_options[:port] = 2222
set :branch, "develop"
set :repository, "/Users/fernando/tuitlawyer"
set :update_vendors, false
set :clear_controllers, false
server 'sf.local', :app, :web, :primary => true
production.rb
ssh_options[:port] = 22
set :branch, "develop"
set :repository, "https://farconada@bitbucket.org/farconada/tuitlawyer.git"
set :update_vendors, false
set :clear_controllers, true
server 'ec2-107-20-125-86.compute-1.amazonaws.com', :app, :web, :primary => true
ssh_options[:keys] = "/home/fernando/Dropbox/ec2-keys/id-mis-keys"
30
9 Mantener la calidad del software
De nada sirve tener un sistema que permita actualizar rápidamente las versiones del
software si, a medida que crece, vamos perdiendo conanza en que haga lo que debe hacer
y sospechamos que está lleno de más errores.
Al mismo tiempo que fomentamos la agilidad para poner en producción los cambios, hay
que aumentar los procesos que revisan que nuestro software sigue siendo conable. Estos
procesos se deben ejecutar frecuentemente (por ejemplo tras cada commit en el sistema de
control de versiones) y, a ser posible, de manera automatizada.
Vamos a controlar dos aspectos fundamentales:
Las métricas y reglas de integración continua
Los tests de software automáticos
9.1. Qué es la integración continua
Una característica extraña pero común en muchos proyectos de software es que durante
largos periodos de tiempo en el proceso de desarrollo la aplicación no se encuentra en
un estado funcional. Normalmente durante el desarrollo la aplicación está rota. Esto es
especialmente cierto en proyectos que usan ramas que duran mucho tiempo o que dejan
los tests de aceptación para el nal. En cambio, hay otros proyectos que sólo durante unos
minutos la aplicación permanece rota con los últimos cambios. La diferencia entre un tipo
de proyecto y el otro es la integración continua. La integración continua requiere que cada
vez que alguien haga un commit se construya la aplicación entera y se que se ejecuten
una serie de tests automatizados. Es un cambio de paradigma. Sin integración continua el
software está roto hasta que alguien pruebe que funciona. Con la integración continua el
funcionamiento del software está comprobado en cada nuevo cambio. Para implementar la
integración continua hacen falta tres cosas:
Un sistema de control de versiones en el que se deposite todo lo relativo al proyecto.
Un sistema automatizado de build para la aplicación y ejecutar los tests.
La aceptación de los miembros del equipo, puesto que la integración continua es una
práctica y no una herramienta.
9.2. Métricas y reglas de integración contínua
En este aspecto vamos a emplear herramientas como phploc que permite obtener datos
de métricas de software como éstos:
phploc 1.7.4 by Sebastian Bergmann.
Directories: 14
Files: 54
Lines of Code (LOC): 5149
Cyclomatic Complexity / Lines of Code: 0.02
Comment Lines of Code (CLOC): 1464
Non-Comment Lines of Code (NCLOC): 3685
31
Namespaces: 15
Interfaces: 0
Traits: 0
Classes: 54
Abstract: 3 (5.56%)
Concrete: 51 (94.44%)
Average Class Length (NCLOC): 63
Methods: 252
Scope:
Non-Static: 252 (100.00%)
Static: 0 (0.00%)
Visibility:
Public: 220 (87.30%)
Non-Public: 32 (12.70%)
Average Method Length (NCLOC): 13
Cyclomatic Complexity / Number of Methods: 1.37
Anonymous Functions: 0
Functions: 0
Constants: 12
Global constants: 0
Class constants: 12
<?xml version="1.0"?>
<project name="BankAccount" basedir="." default="test">
<target name="test">
<phpunit haltonfailure="true" printsummary="true">
<batchtest>
<fileset dir=".">
<include name="*Test.php"/>
</fileset>
</batchtest>
</phpunit>
</target>
</Project>
34
10 Monitorización
Hay libros enteros dedicados a la monitorización y aquí no nos podemos extender en este
tema.
Simplemente comentar que, con independencia de la monitorización propia de los equipos
de Sistemas, hay que establecer otros sistemas más orientados al negocio y la funcionalidad
del software en sí para comprobar que todos los cambios que vamos haciendo tienen un
impacto positivo en los usuarios y que no se nos ha escapado nada a los tests automatizados
de software. Por esto es conveniente tener alertas de Google Analytics, vigilar que no se
estén produciendo errores HTTP 500, comprobar los tiempos de respuesta, etc.
35
11 Plan B
Todo despliegue debe tener un plan B, algo que hacer en caso de que algo salga mal.
Aun con un proceso automatizado de despliegues es posible que algo falle, por ejemplo
porque no hemos considerado los datos de producción y los datos que disponemos para
probar no son equiparables. La primera idea que viene a la cabeza como plan B es volver
a la versión anterior, esto es sencillo cuando lo único que se ha cambiado es el código
y todo lo tenemos en el sistema de control de versiones. Pero aun con esta idea de que
volver atrás un cambio que sólo afecte al código puede ser fácil, hay que tener alguna
otra alternativa como por ejemplo tener preparada una página que avise de que la web se
encuentra en mantenimiento y delimitar la ventana de trabajo que una vez superada debe
disparar el proceso de restauración de backup. Siempre hay que poder hacer rollback de los
cambios desplegados. Hacer debug de los problemas en un entorno de producción casi seguro
terminará en largas noches, errores, desafortunadas consecuencias y usuarios enfadados. En
los planes de rollback hay dos importantes obstáculos:
Si la release desplegada cambia los datos puede ser difícil volver atrás.
Si la release cambia más de un sistema entonces el proceso de rollback se complica.
Hay dos principios generales que hay que seguir cuando creamos un plan para hacer
rollback de una release desplegada:
Asegurarnos de que el entorno de producción, incluyendo las bases de datos y los
sistemas de cheros, tienen un backup antes de hacer el despliegue.
Practicar el plan de rollback, incluyendo la restauración del backup y la migración de
la base de datos.
Bajo determinadas circunstancias, y teniendo en cuenta que tenemos todo automatizado,
es posible que sea más sencillo volver a provisionar un entorno de producción nuevo. Hay
un par de buenas razones para hacer esto:
Si no tienes un proceso automatizado de rollback pero tienes un proceso automatizado
de despliegue y provisión de entornos, entonces es más sencillo puesto que es una
operación que tiene un tiempo jo y menos riesgos al ser automatizado.
Es el mismo proceso que has probado cientos de veces antes y hacer rollback es bastante
más infrecuente.
Así, para capifony es tan sencillo hacer rollback como mover los enlaces simbólicos a la
carpeta de la versión anterior. Además también tiene comandos que ejecutan acciones de
Doctrine migrations que se podría ejecutar junto al rollback
<VirtualHost *:80>
...
RewriteEngine On
37
# Show maintenance page if it exists
ErrorDocument 503 /system/maintenance.html
RewriteCond %{REQUEST_URI} !\.(css|gif|jpg|png)$
RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
RewriteRule ^.*$ - [redirect=503,last]
...
</VirtualHost>
38
12 Conclusiones
Para poder hacer despliegues de forma frecuente es necesario que los equipos de Desarrollo
y Sistemas comprendan que están trabajando juntos para lograr el mismo objetivo. Alredor
de la idea de que los equipos de Sistemas y Desarrollo trabajen de manera conjunta sin
enfrentamiento se gesta la losofía de DevOps, que es recomendable implantar en la empresa
para poder adaptarse a los cambios que requiere el mercado con agilidad.
El código a desplegar debe ser conable y eso se tiene que poder vericar de forma
automática.
La infraestructura debe ser tan conable como el propio código evitando dudas de sistemas
no comparables entre los entornos de desarrollo, pruebas y producción.
Hay que automatizar todo lo que sea posible, los tests de código, la vericación de calidad
el proceso de despliegue y la propia infraestructura.
Hay una serie de herramientas software de reciente aparición que permiten de una forma
sencilla automatizar procesos que hace unos años era imposible de automatizar especial-
mente en el área de sistemas y que permiten aplicar a la infraestructura los mismos modelos
de desarrollo que en el software (desarrollo, pruebas, producción, control de versiones etc)
Aún con todo, algo puede salir mal y por lo tanto siempre hay que tener un plan de
marcha atrás y monitorizar el cambio de manera continuada.
39
Bibliografía
[1] Phing. http://www.phing.info/.
[4] J. Humble and D. Farley, Continuous Delivery: Reliable Software Releases through
Build, Test, and Deployment Automation (Addison-Wesley Signature Series . Addison-
Feb. 2011.
continous-delivery-git-branching-model.html.
[12] 2013.01.11 tech talk on git and continuous delivery | big nerd ranch.
http://learn.bignerdranch.com/videos/2013-01-11-tech-talk-on-git-and-continuous-
delivery.
[16] G. Kim, K. Behr, and G. Spaord, The Phoenix Project: A Novel About IT, DevOps,
and Helping Your Business Win . IT Revolution Press, Jan. 2013.
https://puppetlabs.com/blog/vmware-invests-30-million-in-puppet-labs/.
or-chef.
[20] Software release life cycle, Mar. 2013. Page Version ID: 547341157.
40
[21] P. Swartout, Continuous delivery and DevOps: A Quickstart Guide . Packt Publishing,
Nov. 2012.
http://www.buildmeister.com/articles/automating_the_php_deployment_process_with_phing,_dbdeploy_a
codesnier.php.
[28] J. Loope, Managing Infrastructure with Puppet . O'Reilly Media, Inc., June 2011.
[30] P. Swartout, Continuous Delivery and DevOps: A Quickstart guide . Packt Publishing,
Nov. 2012.
vs-chef-battle-wages/.
[36] Development environment (software development process) - wikipedia, the free ency-
clopedia. http://en.wikipedia.org/wiki/Development_environment_(software_development_process).
[37] T. Copeland and A. Burns, Deploying Rails: Automate, Deploy, Scale, Maintain, and
Sleep at Night . Pragmatic Bookshelf, July 2012.
[38] J. Kutner,Deploying with JRuby: Deliver Scalable Web Apps using the JVM . Pragmatic
branching-model/.
41
[41] Behat BDD for PHP. http://behat.org/.
- programmers. http://programmers.stackexchange.com/questions/117945/dev-vs-
stage-environment-vs-prod-environment.
[44] The problem with separating data from puppet code | puppet labs.
https://puppetlabs.com/blog/the-problem-with-separating-data-from-puppet-code/.
[45] Metodología de desarrollo de software, Jan. 2013. Page Version ID: 61865375.
[46] dvdalvarez, DevOps. integre las operaciones para una entrega continua, Nov. 2012.
42