miércoles, 20 de agosto de 2014

Capistrano y Monit

Últimamente me ha pasado un par de veces que al hacer una subida a producción, Capistrano y Monit no se llevan muy bien.

El problema es que en el deploy se reinician algunos servicios, como Sidekiq, y si coincide con el chequeo de Monit, se lanza otro reinicio, con el resultado de tener 2 Sidekiq arrancados en producción.

Tambien puede pasar que quieras parar algún servicio manualmente, por ejemplo Unicorn desde una tarea de Capistrano y Monit lo levante automáticamente.

Afortunadamente, la solución es simple, consiste en añadir unas tareas en Capistrano y dar permisos al usuario de la aplicación para ejecutar Monit.

Para ejecutar los comandos de Monit, se necesitan permisos de sudo, pero por seguridad, no queremos dar acceso sudo sin más. Tampoco interesa dar acceso a toda la funcionalidad de Monit, ya que se podría parar cualquier servicio monitorizado con Monit externo a la aplicación.

Así que solo daremos permiso para ver el estado de la monitorización (monit summary) y parar o iniciar la monitorización (monit monitor y monit unmonitor)

La forma de conseguirlo es tan simple como añadir un nuevo fichero /etc/sudoers.d/monit con esos permisos
my_user ALL = NOPASSWD: /usr/bin/monit summary, /usr/bin/monit unmonitor *, /usr/bin/monit monitor *
No le pedimos la contraseña al usuario para ejecutar estos comandos, ya que el usuario no tiene contraseña asignada (solo le permitimos acceder por medio de clave pública).

Y ese mismo fichero creado desde ansible

- name: Allow execute monit commands to users
  action: 'lineinfile dest=/etc/sudoers.d/monit state=present create=yes regexp="{{item}}" line="{{item}} ALL = NOPASSWD: /usr/bin/monit summary, /usr/bin/monit unmonitor *, /usr/bin/monit monitor *" validate="visudo -cf %s"'
  with_items:
    - my_user
Una vez que tenemos permisos, creamos un módulo de capistrano con las diferentes tareas a ejecutar en lib/capistrano/tasks


namespace :monit do
  desc 'Monit summary'
  task :summary do
    on roles :app do
      puts capture :sudo, :monit, :summary
    end
  end

  desc 'Monit unmonitor'
  task :unmonitor do
    on roles :app do
      puts capture :sudo, :monit, :unmonitor, :sidekiq
    end
  end

  desc 'Monit monitor'
  task :monitor do
    on roles :app do
      puts capture :sudo, :monit, :monitor, :sidekiq
    end
  end
end

Y invocamos esas tareas al empezar y al acabar el deploy

after 'deploy:starting',  'monit:unmonitor'
after 'deploy:finished',  'monit:monitor'
Además, la tarea summary permite al usuario monitorizar el estado del servidor desde línea de comandos
$ cap production monit summary
...
System 'teowaki.com'                Running
Process 'sidekiq'                   Running
Process 'sshd'                      Running
Filesystem 'rootfs'                 Accessible
...
Por último, comentar que la gema capistrano-sidekiq incluye algunas tareas similares, pero no me cuadraba su uso en mi caso, ya que me obliga a cambiar el nombre del servicio monitorizado.