En cualquier proyecto web es deseable que el despliegue a producción se haga de forma automatizada: nos libera de realizar una tarea repetitiva, propensa a errores y que suele requerir bastante tiempo. Aún así, existe la percepción de que configurar y mantener un sistema de despliegue automático es demasiado costoso y muchos equipos de desarrollo no se aventuran a ello. Vamos a ver como en realidad no es algo tan complejo si usamos una herramienta como Capistrano.

Aunque Capistrano se creó originariamente para desplegar aplicaciones Ruby on Rails, es muy configurable y actualmente soporta frameworks de otros lenguajes de programación. Incluso dispone de un módulo de Symfony que nos va a facilitar la tarea de integrarlo en nuestro proyecto.

Cómo funciona Capistrano

Antes de empezar a usar Capistrano es importante entender como funciona. Cada vez que hacemos un deploy, Capistrano se conecta por SSH al servidor y ejecuta en orden una serie de tareas. Estas tareas pueden ir desde hacer un pull del repositorio hasta vaciar la caché de Symfony.

En el servidor, Capistrano crea una jerarquía de directorios para gestionar el código fuente de la aplicación y los ficheros relacionados con el despliegue. La ruta raíz de esta estructura se define en variable de configuración :deploy_to.

  • releases: En cada deploy se crea un nuevo directorio dentro de esta ruta con el código fuente actual de la aplicación.
  • shared: El contenido de este directorio es enlazado simbólicamente en cada nueva release. Se utiliza para datos que tengan que persistir de un despliegue a otro, como ficheros de configuración o logs.
  • current: Es un enlace simbólico que apunta a la última release. En caso de que el deploy falle en algún paso, seguirá apuntando a la anterior release.
  • repo: Contiene una copia del repositorio de control de versiones.
  • revisions.log: Fichero donde se escribe el histórico de los despliegues.

Requisitos previos

Debemos cumplir una serie de requisitos para poder utilizar Capistrano:

  • Disponer en nuestra máquina local Ruby versión 2.0 o superior (En caso de que la versión del repositorio de paquetes del sistema sea menor, podemos instalarlo usando un gestor de versiones de Ruby como RVM o rbenv).
  • El proyecto debe usar un sistema de control de versiones (están soportados Git, Mercurial y Subversion).
  • El sistema de control de versiones que usemos debe estar instalado también en el servidor.
  • El servidor debe permitir la conexión por SSH usando autenticación con clave pública/privada.
  • Tener configurado el reenvío del agente SSH al servidor remoto (Es necesario para que el servidor pueda conectarse al repositorio privado de código).

Si el tema de la autenticación basada en claves de SSH es algo nuevo para ti en GitHub tienes un par de tutoriales sobre como crear claves SSH y configurar el reenvío de agente SSH.

Instalar Capistrano

En el directorio raíz de nuestro proyecto Symfony creamos un fichero Gemfile. Este fichero sirve para indicar las gemas (paquetes de Ruby) que queremos que se instalen.

source "https://rubygems.org"

gem 'capistrano', '~> 3.4'
gem 'capistrano-symfony', '~> 1.0.0.rc1'

Para instalar en el sistema lo que hay especificado en el Gemfile usamos Bundler, un programa para gestionar las dependencias de las gemas.

$ gem install bundler
$ bundle install

Gemfile es el equivalente en Ruby al fichero composer.json de PHP. Además Bundler crea automáticamente el fichero Gemfile.lock, análogo a composer.lock, donde se registran las versiones exactas de las gemas que se han instalado.

Inicializamos la configuración de Capistrano.

$ bundle exec cap install

Esto crea la siguiente estructura en el directorio raíz de nuestro proyecto.

├── Capfile
├── config
│   ├── deploy
│   │   ├── production.rb
│   │   └── staging.rb
│   └── deploy.rb
└── lib
    └── capistrano
            └── tasks
  • Capfile define la lista de módulos de Capistrano que se usarán en el proyecto.
  • config/deploy.rb contiene la configuración global de despliegue para este proyecto.
  • config/deploy/production.rb y config/deploy/staging.rb contienen configuración específica para esos entornos. Podemos definir todos los entornos que deseemos.
  • En el directorio lib/capistrano/tasks se puede crear ficheros .rake con tareas personalizadas.

En el fichero Capfile, añadimos la siguiente línea al final de los require para cargar el módulo de Symfony.

require 'capistrano/symfony'

Ya tenemos listo Capistrano para funcionar con Symfony, a falta de configurarlo para nuestro proyecto.

Configurar Capistrano

El fichero deploy.rb tendrá un contenido similar a lo siguiente:

set :application, 'capistrano-symfony-example'
set :deploy_to, '/var/www/my_app_name'

set :repo_url, 'https://github.com/symfony/symfony-demo.git'
set :scm, :git
set :branch, 'master'

set :linked_files, ["app/config/parameters.yml"]
set :linked_dirs, ["var/logs", "web/uploads"]

set :keep_releases, 5

set :symfony_directory_structure, 3
set :sensio_distribution_version, 5

set :permission_method, :acl
set :file_permissions_users, ["www-data"]
set :file_permissions_paths, ["var", "web/uploads"]

Variables de despliegue

  • :application: Nombre de la aplicación.
  • :deploy_to: Directorio al que se desplegará la aplicación en el servidor. Por defecto es /var/www/<nombre-de-aplicación>.
  • :repo_url: URL del repositorio de código de nuestro proyecto.
  • :scm: Tipo de sistema de control de versiones usado. Por defecto es :git.
  • :branch: Rama del repositorio a desplegar en el servidor. Por defecto es master.
  • :linked_files: Los ficheros serán enlazados simbólicamente en el directorio de la release durante el despliegue. Útil para crear ficheros de configuración persistentes.
  • :linked_dirs: Exactamente igual a :linked_files pero para directorios.
  • :keep_releases: Número de releases que se mantendrán en el servidor para poder efectuar un rollback a cualquiera de ellas.

Estas son solo algunas de las variables que podemos utilizar, consulta el resto en la documentación de Capistrano.

Variables de Symfony

  • :symfony_directory_structure: Hay que establecer un 2 o un 3 dependiendo de la versión de Symfony que use nuestro proyecto.
  • :sensio_distribution_version: Solo es necesario establecerlo en proyectos de Symfony 2 que usen una versión de SensioDistributionBundle menor a la 5.

Aunque con establecer estas variables en principio es suficiente, para proyectos de Symfony con estructuras poco convencionales disponemos de variables para un mayor control.

Variables de Permisos

Un escenario común suele ser que el usuario que corre el servidor web y el usuario con el que se reliza el deploy sean distintos, y ambos necesitan tener acceso de lectura/escritura a ciertos directorios de Symfony. En este caso hay que establecer las siguientes variables.

  • :permission_method: Método para cambiar los permisos. Puede ser :chmod, :acl o :chgrp.
  • :file_permissions_users: Usuario que ejecuta el servidor web. Suele ser www-data en distribuciones basadas en Debian.
  • :file_permissions_paths: Directorios del proyecto que requieren cambiar los permisos.

Configuración del servidor

En los ficheros que hay en config/deploy se establece la configuración específica para cada entorno. La mínima configuración que hay que meter es el servidor al que desplegar y con qué usuario.

server 'miserver.com', user: 'miuser', roles: %w{web}

Para proyectos complejos que necesitan distintos tipos de servidores (servidor de base de datos, servidor web…), Capistrano introduce el concepto de roles para etiquetar cada servidor y controlar las tareas que se ejecutan en él. En este post no vamos a adentrarnos en su uso.

Preparar el servidor

Dado que el directorio current apunta a la release activa, debemos establecer en la configuración de nuestro servidor web que la raíz pública del site estará en /var/www/my_app_name/current/web.

Si nuestro servidor web es Apache hay que editar la directiva DocumentRoot del Virtual Host. En caso de usar Nginx, la directiva se llama root.

Hay una cosa que Capistrano no puede hacer automáticamente, y es crear el fichero parameters.yml que necesita Symfony con la configuración del entorno producción. Por ello, antes de hacer deploy por primera vez necesitamos crearlo en la ruta /var/www/my_app_name/shared/app/config del servidor y rellenarlo con los parámetros que necesite nuestra aplicación (comúnmente los parámetros de conexión a Base de Datos).

Despliegue

Una vez todo configurado, podemos realizar el despliegue a producción con el comando:

$ bundle exec cap production deploy

Para desplegar en un entorno distinto solo tenemos que cambiar production por otro que tengamos definido.

A parte de deploy Capistrano dispone de otros comandos que pueden resultarnos útiles. Podemos ver el listado completo ejecutando:

$ bundle exec cap -T

Usar la consola de Symfony

A través de Capistrano se pueden enviar comandos a la consola de Symfony del servidor con el formato bundle exec entorno cap symfony:console[comando,parámetros,rol]. Por ejemplo para crear el esquema de la Base de Datos en producción lanzamos:

$ bundle exec cap production symfony:console[doctrine:schema:create]