Este blog comenzó sus días alojado en un servidor con OpenBSD y usando relayd como reverse proxy. Intenté varias cosas para desplegar, como Capistrano o Mina. En líneas generales funcionaban bien pero siempre acababa entrando al servidor para arreglar cosas que no terminaban de funcionar. La culpa era mía por no entender 100% cómo funcionaba el sistema (plugins para todo). Cada vez aprendía un poco más y sin embargo este proceso hacía que no tuviese ganas de desplegar más cambios y un día dejé de desarrollar más funcionalidades.
Profesionalmente he usado Docker desde 2015. Para desarrollo viene muy bien pero para un producto tan pequeño como este blog no me apetecía montar todo en producción. Hasta que llegóMRSK Kamal.
Al final he conseguido tener un proceso de despliegue fácil y rápido. Para lograrlo he ido aprendiendo tanto de la documentación oficial como de unos cuantos artículos distribuidos por internet. Los iré enlazando a continuación.
Lo primero que hice fue ver el vídeo introductorio de DHH. En 5 minutos ya tenía desplegado el blog en un servidor nuevo. En otro post explicaré cómo migré la base de datos.
En el vídeo se sigue un ejemplo de nivel medio, más avanzado de lo que necesito para este blog. Éste post me ayudó a configurarlo todo en el mismo servidor. Básicamente hay que poner la misma IP tanto en el servidor como en los accessories.
El Dockerfile lo saqué del generador que vendrá en la versión 7.1. Este blog todavía está en la versión 7.0.4 a día de hoy.
Profesionalmente he usado Docker desde 2015. Para desarrollo viene muy bien pero para un producto tan pequeño como este blog no me apetecía montar todo en producción. Hasta que llegó
Al final he conseguido tener un proceso de despliegue fácil y rápido. Para lograrlo he ido aprendiendo tanto de la documentación oficial como de unos cuantos artículos distribuidos por internet. Los iré enlazando a continuación.
Lo primero que hice fue ver el vídeo introductorio de DHH. En 5 minutos ya tenía desplegado el blog en un servidor nuevo. En otro post explicaré cómo migré la base de datos.
En el vídeo se sigue un ejemplo de nivel medio, más avanzado de lo que necesito para este blog. Éste post me ayudó a configurarlo todo en el mismo servidor. Básicamente hay que poner la misma IP tanto en el servidor como en los accessories.
El Dockerfile lo saqué del generador que vendrá en la versión 7.1. Este blog todavía está en la versión 7.0.4 a día de hoy.
# config/deploy.yml service: blog image: usuario/blog servers: web: hosts: - ip-del-host registry: username: usuario password: - KAMAL_REGISTRY_PASSWORD env: clear: RAILS_SERVE_STATIC_FILES: true DB_HOST: ip-del-host secret: - RAILS_MASTER_KEY - POSTGRES_USER - POSTGRES_DB - POSTGRES_PASSWORD accessories: db: image: postgres host: ip-del-host port: 5432 env: secret: - POSTGRES_USER - POSTGRES_DB - POSTGRES_PASSWORD directories: - data:/var/lib/postgresql/data
Todas las variables de entorno definidas en secret se leen desde un fichero .env en la raíz del proyecto.
Kamal necesita que la app principal tenga un endpoint para hacer healthcheck. Es decir, necesita comprobar que la aplicación está funcionando antes de dar por finalizado el despliegue. En Rails 7.1 ya viene una ruta configurada para este propósito. En mi caso he tenido que añadir manualmente en config/routes.rb.
get "/up", to: proc { [200, {}, ["success"]] }
El siguiente paso es configurar el reverse proxy para usar TLS y permitir el acceso a la web mediante https. Por defecto Kamal usa traefik. Otra herramienta más para aprender. Pasé horas leyendo la documentación y entendí cómo funcionaba pero no conseguía hacerlo funcionar con Kamal. Por suerte encontré esta conversación en GitHub en la que se explica claramente cómo configurarlo.
Antes de desplegar has de crear el fichero de configuración en cada server (no en los accessories). Para comprobar si todo ha ido bien, una vez desplegado puedes consultar el contenido del fichero. No debería estar vacío.
Es muy importante darle el permiso correcto, sino no va a funcionar.
mkdir -p /letsencrypt && touch /letsencrypt/acme.json && chmod 600 /letsencrypt/acme.json
# config/deploy.yml service: blog image: usuario/blog servers: web: hosts: - ip-del-host labels: traefik.http.routers.blog-web.rule: Host(`tu-dominio.com`) traefik.http.routers.blog-web.tls: true traefik.http.routers.blog-web.tls.certresolver: letsencrypt traefik: options: publish: - "443:443" volume: - "/letsencrypt/acme.json:/letsencrypt/acme.json" args: entryPoints.web.address: ":80" entryPoints.websecure.address: ":443" entryPoints.web.http.redirections.entryPoint.to: websecure entryPoints.web.http.redirections.entryPoint.scheme: https entryPoints.web.http.redirections.entrypoint.permanent: true certificatesResolvers.letsencrypt.acme.email: "tu@email.com" certificatesResolvers.letsencrypt.acme.storage: "/letsencrypt/acme.json" certificatesResolvers.letsencrypt.acme.httpchallenge: true certificatesResolvers.letsencrypt.acme.httpchallenge.entrypoint: web registry: username: usuario password: - KAMAL_REGISTRY_PASSWORD env: clear: RAILS_SERVE_STATIC_FILES: true DB_HOST: ip-del-host secret: - RAILS_MASTER_KEY - POSTGRES_USER - POSTGRES_DB - POSTGRES_PASSWORD accessories: db: image: postgres host: ip-del-host port: 5432 env: secret: - POSTGRES_USER - POSTGRES_DB - POSTGRES_PASSWORD directories: - data:/var/lib/postgresql/data
No estoy 100% seguro pero creo que las siguientes opciones las has de configurar una vez ya tengas el certificado la primera vez. Yo lo hice así pero no sé si es necesario.
Lo que hacen estas opciones es forzar a que todas las peticiones vayan por https.
entryPoints.web.http.redirections.entryPoint.to: websecure entryPoints.web.http.redirections.entryPoint.scheme: https entryPoints.web.http.redirections.entrypoint.permanent: true
Con esto la aplicación de Rails con Postgresql debería funcionar correctamente y la base de datos debería permanecer tras cada despliegue. Si se borra cada vez, consulta que el path especificado en directores sea correcto.
* Después de actualizar las reglas de Traefik no hace falta hacer deploy completo, solo:
$ bin/kamal traefik reboot
En otro artículo explicaré cómo he añadido Redis y Sidekiq. Es muy fácil pero hay un par de cosillas que me gustaría dejar por escrito para no olvida.
Actualización (12 sept 2023): MRSK ahora se llama Kamal. He cambiado algunas líneas del deploy.yml que copié tal cual de la documentación.