Tecnología8 阅读

Kamal2: Guía de inicio para el despliegue en VPS

Ahora, los frameworks full-stack que uso principalmente son Next.js 16 y Rails 8. Usando Rails, conocí la herramienta de despliegue recomendada oficialmente, Kamal. Normalmente la uso para desplegar proyectos en servidores de RN y Alibaba Cloud. Es muy cómoda y sencilla de usar, ahora me gustaría presentarles el concepto de Kamal2 y cómo empezar a usarlo.

Este artículo no empezará con contenidos demasiado complejos. Prefiero dejar claro lo más esencial de Kamal2: qué es realmente, qué nos ayuda a hacer, cómo empezar con lo más básico, y cuáles son las operaciones más comunes. Al final, daré un caso de uso con Next.js para ayudarte a aplicar los conceptos anteriores a un proyecto concreto.

¿Qué es Kamal2?

Si se pudiera resumir en una frase, Kamal2 es una herramienta que **completa el despliegue de aplicaciones a través de SSH y Docker**. No proporciona capacidades de plataforma completa como Heroku, ni es un sistema de orquestación pesado como Kubernetes; más bien organiza la tarea de "desplegar un conjunto de contenedores Docker" en un conjunto de comandos y configuraciones repetibles.

La idea central de Kamal es bastante directa:

Esta es una de las razones por las que me gusta Kamal. No introduce demasiadas abstracciones adicionales; sabes más o menos lo que está haciendo, por lo que es más fácil solucionar problemas cuando surgen.

¿Para qué escenarios es adecuado Kamal2?

Creo que Kamal es especialmente adecuado para la siguiente situación:

En otras palabras, Kamal no te ayuda a "reemplazar Docker", sino a hacer el despliegue con Docker más cómodo.

Primero, entiende algunos conceptos básicos

Antes de comenzar, te sugiero que recuerdes los conceptos más importantes de Kamal.

config/deploy.yml

Este es el archivo de configuración principal de Kamal, la configuración de despliegue se lee de aquí. Puedes entenderlo como el "manual de instrucciones de este despliegue": el nombre del servicio, el nombre de la imagen, la lista de servidores, el registro de imágenes, las variables de entorno, builder, proxy, etc., todo se escribe aquí.

.kamal/secrets

Esta es la ubicación predeterminada del archivo de secrets, Kamal leerá las variables sensibles de aquí. Por ejemplo, la contraseña del registro de imágenes, o RAILS_MASTER_KEY de Rails, generalmente no se codifican directamente en deploy.yml, sino que se inyectan a través de .kamal/secrets.

kamal setup

Este es el comando más importante para el primer despliegue. La documentación dice claramente que se conecta al servidor, instala Docker (si no está), inicia sesión en el registro de imágenes, construye la imagen, la sube, la descarga, inicia kamal-proxy, inicia el nuevo contenedor y cambia el tráfico después de que GET /up devuelva 200 OK.

kamal deploy

Este es el comando más utilizado para versiones posteriores. Una vez que el primer setup ha funcionado, los despliegues posteriores se realizan habitualmente con kamal deploy.

Cómo instalar Kamal2

Si ya tienes un entorno Ruby local, la forma más directa de instalarlo es:

bash
gem install kamal

Esta es la forma estándar de instalación indicada en la documentación oficial. Si no tienes Ruby, también puedes ejecutar Kamal dockerizado, pero la documentación menciona explícitamente que esta forma tiene algunas limitaciones, por lo que para principiantes recomiendo usar la instalación con gem.

Una vez instalado, puedes ver la versión:

bash
kamal version

Inicializar un proyecto

Entra en el directorio de tu proyecto y ejecuta:

bash
kamal init

Este comando inicializará los archivos básicos necesarios para Kamal, los más importantes son config/deploy.yml y .kamal/secrets.

Si tu proyecto ya tiene un Dockerfile en la raíz, entonces ya tienes una condición previa clave. El proceso de despliegue de Kamal por defecto construye la imagen a partir del Dockerfile estándar en el directorio raíz del proyecto.

Configuración mínima viable

Recomiendo empezar con un config/deploy.yml muy pequeño. El ejemplo mínimo que da la documentación oficial es algo así:

yaml
service: myapp
image: your-registry-user/myapp

servers:
  - 203.0.113.10

registry:
  username: your-registry-user
  password:
    - KAMAL_REGISTRY_PASSWORD

builder:
  arch: amd64

env:
  secret:
    - AUTH_SECRET

En esta configuración, lo más importante que debes entender primero son los siguientes elementos:

En esta etapa, no busques una configuración completa; es más importante asegurarte de que el flujo básico funcione.

Configurar los secrets

A continuación, prepara .kamal/secrets. Por ejemplo:

bash
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
AUTH_SECRET=your-auth-secret

Si es un proyecto Rails, en el ejemplo de la documentación se lee RAILS_MASTER_KEY desde config/master.key. Esta es también una de las razones por las que Rails y Kamal se integran tan naturalmente: los proyectos nuevos de Rails ya son bastante fáciles de conectar con este método de despliegue.

¿Qué ocurre en el primer despliegue?

Cuando la configuración y los secrets están listos, puedes ejecutar:

bash
kamal setup

Este comando hace muchas cosas, pero puedes entenderlo como un "despliegue inicial completo". Según la documentación oficial, al menos realiza estas acciones:

  1. Se conecta al servidor a través de SSH.

  2. Si al servidor le falta Docker, lo instala automáticamente.

  3. Inicia sesión en el registro de imágenes local y remoto.

  4. Construye la imagen usando el Dockerfile en la raíz del proyecto.

  5. Sube la imagen al registro.

  6. Hace que el servidor descargue la imagen.

  7. Asegura que kamal-proxy esté funcionando en los puertos 80/443.

  8. Inicia el nuevo contenedor.

  9. Espera a que GET /up devuelva 200 OK.

  10. Cambia el tráfico al nuevo contenedor.

  11. Detiene el contenedor antiguo y limpia imágenes y contenedores detenidos innecesarios.

Hay un detalle muy importante aquí: **la verificación de salud por defecto es GET /up**. Por lo tanto, es mejor que tu aplicación tenga una interfaz de verificación de salud ligera como esta; de lo contrario, el contenedor nuevo podría estar funcionando pero Kamal no cambiará el tráfico.

Los despliegues posteriores son mucho más simples

Una vez que el primer setup ha tenido éxito, las actualizaciones posteriores generalmente solo requieren ejecutar:

bash
kamal deploy

La documentación ya lo establece claramente como el comando de despliegue posterior. Puedes entenderlo como "entrada de lanzamiento normal": reconstruye la imagen, la sube, la descarga, inicia un nuevo contenedor, verifica la salud, cambia el tráfico y detiene el contenedor antiguo.

Por lo tanto, desde la experiencia de uso, lo más cómodo de Kamal es: el primer despliegue requiere un poco más de preparación, pero luego se vuelve muy estable.

Operaciones comunes

Para empezar, creo que estos comandos son los más útiles:

Inicializar

bash
kamal init

Genera los archivos básicos de despliegue.

Primer despliegue

bash
kamal setup

Pone en marcha el servidor, Docker, la imagen, el proxy y la aplicación por primera vez.

Lanzamientos posteriores

bash
kamal deploy

El comando más utilizado en el día a día.

Despliegue multi-entorno

Si luego empiezas a diferenciar staging y production, Kamal admite especificar el destino con -d, por ejemplo:

bash
kamal deploy -d staging

La documentación oficial explica que en este caso Kamal combina config/deploy.staging.yml con la configuración base.

Esta capacidad es muy práctica, pero si estás empezando, puedes saber que existe, sin necesidad de usarla de inmediato.

Por qué se complementa bien con Rails

Los proyectos nuevos de Rails 8 ya suelen incluir su propio Dockerfile, y el flujo de despliegue de Kamal se basa precisamente en el Dockerfile. Además, el ecosistema de Rails acepta naturalmente la cadena de herramientas de gemas de Ruby, por lo que conocer Kamal desde Rails es casi algo natural.

Para mí personalmente, fue precisamente porque vi este método en un proyecto de Rails que empecé a considerarlo seriamente como una solución de despliegue viable a largo plazo.

Un caso de uso básico con Next.js

Finalmente, un ejemplo más cercano a mi día a día: si quiero desplegar un proyecto Next.js con Kamal, normalmente lo convierto en una aplicación Docker estándar y luego se la entrego a Kamal para su publicación.

Primer paso: hacer que Next.js genere un standalone

La documentación de Next.js indica que al habilitar output: 'standalone', el resultado de la compilación genera .next/standalone, que contiene los archivos mínimos necesarios para ejecutar el despliegue y un server.js. Esto es muy adecuado para el despliegue con Docker, ya que no requiere copiar todo el entorno de desarrollo completo.

En next.config.js se puede escribir así:

js
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'standalone',
}

module.exports = nextConfig

Cabe señalar que la documentación de Next.js menciona que el modo output: 'standalone' es más adecuado para usar directamente el server.js generado, en lugar de seguir usando next start.

Segundo paso: preparar el Dockerfile

Un Dockerfile simple para Next.js podría verse así:

Dockerfile
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM node:22-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/static ./.next/static
EXPOSE 3000
CMD ["node", "server.js"]

El punto aquí no son los trucos de Docker en sí, sino la idea: **primero convertir Next.js en un contenedor estándar y ejecutable, y luego dejar que Kamal se encargue del despliegue.**

Tercer paso: escribir la configuración de Kamal

Por ejemplo:

yaml
service: my-next-app
image: your-registry-user/my-next-app

servers:
  - 203.0.113.10

registry:
  username: your-registry-user
  password:
    - KAMAL_REGISTRY_PASSWORD

builder:
  arch: amd64

env:
  clear:
    PORT: 3000
    NODE_ENV: production

La lógica de esta configuración es muy simple:

Cuarto paso: añadir una interfaz de verificación de salud

Dado que Kamal por defecto verifica GET /up, en Next.js añadiré una ruta muy simple, por ejemplo, en App Router:

ts
export async function GET() {
  return Response.json({ ok: true })
}

Colócalo en, por ejemplo, app/up/route.ts, así /up devolverá una respuesta simple de éxito. Esta interfaz debe ser lo más ligera posible; su único propósito es decirle a Kamal: el contenedor ya puede recibir tráfico.

Quinto paso: desplegar

Finalmente, volvemos al flujo estándar de Kamal:

bash
kamal setup

Actualizaciones posteriores:

bash
kamal deploy

Si este flujo se ejecuta de manera estable en un proyecto Next.js, descubrirás que a Kamal no le importa si usas Rails o no; lo que realmente le importa es **que puedas proporcionar una imagen Docker estándar y un servicio web que pueda verificar su estado de salud.**

Hasta aquí por ahora

Si eres como yo, que conociste Kamal a través de Rails 8 y luego fuiste migrando este método a proyectos de Next.js 16, entonces la posición de Kamal2 es muy fácil de entender: no es una plataforma, sino una herramienta que ordena el despliegue autogestionado con Docker.

En la fase inicial, basta con dominar esto:

Cuando todo esto funcione bien, será más natural explorar temas como múltiples entornos, accessories, hooks y configuraciones de proxy complejas.

Compartir

Compartir

Comparte este artículo.