Cómo desplegar Ghost (CMS/Blog) en Kubernetes
Ghost en Kubernetes (v6.x) por SREDevOps.Org
Despliega la principal plataforma de publicación de código abierto, Ghost, en Kubernetes con la máxima seguridad y eficiencia utilizando una imagen de contenedor endurecida y multi-arquitectura.
Mantenido por SREDevOps.org: SRE, DevOps, Linux, Hacking Ético, IA, ML, Código Abierto, Cloud Native, Platform Engineering en Inglés, Español y Portugués (Brasil).
Aspectos Destacados: Seguridad y Eficiencia
Este repositorio implementa Ghost CMS v6.xx.x de @TryGhost (Oficial) en Kubernetes con una imagen personalizada, que ofrece mejoras significativas para el uso en producción y características de seguridad en Kubernetes.
Seguridad Mejorada
- Ejecución Sin Root: Tanto los componentes de Ghost como los de MySQL se ejecutan exclusivamente como un usuario sin privilegios (non-root) (UID/GID 65532) en Kubernetes, previniendo posibles ataques de escalada de privilegios.
- Tiempo de Ejecución Distroless: Utilizamos Google Container Tools Distroless Debian 13 - NodeJS 22 como el entorno de tiempo de ejecución final. Las imágenes Distroless contienen solo las dependencias de la aplicación y el lenguaje requeridas, excluyendo shells y gestores de paquetes, lo que las hace sustancialmente más seguras y reduce la superficie de ataque.
- Reducción de Vulnerabilidades: Al reemplazar
gosucon un flujo de ejecución de contenedor nativo y adoptar Distroless, eliminamos varias vulnerabilidades críticas reportadas en la imagen original de Ghost:- Resultado: Solo este cambio redujo 6 vulnerabilidades críticas y 34 vulnerabilidades altas reportadas por Docker Scout en la imagen oficial.
Ejemplo de Reportes de Seguridad:
| Imagen Oficial de Ghost | Imagen de Ghost en Kubernetes |
|---|---|
Escaneo de ejemplo para la Imagen Oficial de Ghost: ![]() |
Ejemplo de nuestra Imagen de Ghost en Kubernetes en Docker Hub: ![]() |
Rendimiento y Arquitectura
- Artefactos de Build Personalizados: Mantenemos dos Dockerfiles distintos para producción y desarrollo:
- Imagen de Producción: La imagen principal construida utilizando nuestro proceso de construcción endurecido y multi-etapa. Ver el Dockerfile.
- Imagen de Desarrollo: Una variante adaptada para pruebas, que incluye soporte para SQLite. Ver el Dockerfile-dev.
- Soporte Multi-Arquitectura: Las imágenes están construidas para las arquitecturas amd64 y arm64.
- Build Multi-Etapa: Utilizamos la imagen oficial de Node 22 Jod LTS para la construcción, lo que reduce significativamente el tamaño final de la imagen y mejora la seguridad al eliminar componentes de construcción innecesarios.
- Ghost v6 y NodeJS 22 LTS Actualizados: Utilizando las últimas versiones estables para seguridad y rendimiento.
- Punto de Entrada Robusto (entrypoint.js): Un script de punto de entrada Node.js personalizado, ejecutado por el usuario sin privilegios, maneja las operaciones de tiempo de ejecución necesarias, como la actualización de temas predeterminados, antes de iniciar la aplicación Ghost. El script se puede revisar aquí: entrypoint.js.
- Contenedor Init Dedicado: El despliegue incluye un initContainer para manejar la creación de directorios, la propiedad correcta (UID/GID 65532) y la configuración de permisos antes del lanzamiento del contenedor principal de Ghost, asegurando una operación fluida dentro del contenedor Distroless.
Resumen de la Arquitectura de Despliegue
Este proyecto proporciona archivos manifest completos de Kubernetes (deploy/) para ejecutar una instancia de Ghost lista para producción, respaldada por una base de datos MySQL.
| Recurso | Componentes | Detalles |
|---|---|---|
| Namespace | ghost-on-kubernetes | Proporciona aislamiento lógico para todos los componentes. (Archivo: 00-namespace.yaml) |
| StatefulSet | ghost-on-kubernetes-mysql | Gestiona la base de datos MySQL 8, asegurando red estable y almacenamiento persistente. (Archivo: 05-mysql.yaml) |
| Deployment | ghost-on-kubernetes | Gestiona los pods de la aplicación Ghost v6. (Archivo: 06-ghost-deployment.yaml) |
| Services | ghost-on-kubernetes-service, ghost-on-kubernetes-mysql-service | Expone Ghost (2368) y MySQL (3306) internamente dentro del clúster. (Archivo: 03-service.yaml) |
| PersistentVolumeClaims (PVC) | k8s-ghost-content, ghost-on-kubernetes-mysql-pvc | Solicita almacenamiento persistente para el contenido de Ghost (temas, imágenes) y los datos de MySQL. (Archivo: 02-pvc.yaml) |
| Secrets | ghost-config-prod, ghost-on-kubernetes-mysql-env, tls-secret | Almacena de forma segura la configuración de Ghost, las credenciales de la base de datos y los certificados TLS (opcional). (Archivos: 01-mysql-config.yaml, 04-ghost-config.yaml, 01-tls.yaml) |
| Ingress | ghost-on-kubernetes-ingress | Expone la aplicación Ghost al mundo exterior a través de HTTP/HTTPS (requiere un TLD). (Archivo: 07-ingress.yaml) |
Nota: Puedes alojar múltiples instancias de Ghost reemplazando la especificación de Namespace en cada archivo manifest.
Instrucciones de Instalación (Producción)
Sigue estos pasos para desplegar Ghost en tu clúster de Kubernetes.
Prerrequisitos
- Un clúster de Kubernetes en funcionamiento (
kubectlconfigurado). - Un StorageClass provisionado (requerido para los PVCs).
0. Clonar (o hacer fork) del Repositorio
## Clonar el repositorio
git clone https://github.com/sredevopsorg/ghost-on-kubernetes.git --depth 1 --branch main --single-branch --no-tags
## Cambiar de directorio
cd ghost-on-kubernetes
1. Revisar y Configurar
Revisa los archivos de configuración de ejemplo y modifica los manifests en la carpeta deploy/ para adaptarlos a tu entorno (ej. clase de almacenamiento, nombre de dominio, valores de secretos).
- Configuraciones: Revisa los archivos de configuración de ejemplo en el directorio examples/:
config.production.sample.yaml: Configuración recomendada usando MySQL 8. Requiere un dominio de nivel superior (TLD) válido para el campourly la configuración de Ingress.config.development.sample.yaml: Utiliza SQLite para entornos de prueba.
- Documentación Oficial de Ghost: Consulta la documentación oficial de Ghost para opciones de configuración detalladas.
2. Secuencia de Despliegue
Es crucial aplicar los manifests en el orden correcto para asegurar la resolución de dependencias (especialmente los componentes de la base de datos).
- Crear el Namespace:
kubectl apply -f deploy/00-namespace.yaml
Exponer Ghost con Ingress (Opcional/Recomendado):
# Enruta el tráfico externo al Service de Ghost
kubectl apply -f deploy/07-ingress.yaml
Desplegar la Aplicación Ghost (Deployment):
# Espera a que MySQL esté listo antes de comenzar
kubectl apply -f deploy/06-ghost-deployment.yaml
Desplegar la Base de Datos MySQL (StatefulSet):
# Espera a que el PVC de MySQL esté enlazado
kubectl apply -f deploy/05-mysql.yaml
Crear Almacenamiento Persistente y Services:
kubectl apply -f deploy/02-pvc.yaml
kubectl apply -f deploy/03-service.yaml
Crear Secrets (Credenciales y Configuración):
# IMPORTANTE: Personaliza estos secretos antes de aplicarlos
kubectl apply -f deploy/01-mysql-config.yaml
kubectl apply -f deploy/04-ghost-config.yaml
kubectl apply -f deploy/01-tls.yaml
¡Tu Blog Ghost está Desplegado!
¡Felicidades! Has desplegado una instancia de Ghost v6 altamente segura y escalable en Kubernetes.
Acceso Sin Nombre de Dominio (Pruebas)
Para previsualizar el sitio web sin configurar Ingress o un TLD, puedes usar el port forwarding:
- Configura temporalmente las URL
urlyadminen tu Secretconfig.production.jsonpara usarhttp://localhost:2368/. - Reinicia el/los pod(s) de Ghost después de actualizar el Secret.
- Ejecuta el comando de port-forwarding:
kubectl port-forward -n ghost-on-kubernetes services ghost-on-kubernetes-service 2368:2368
Contribuciones
¡Damos la bienvenida a las contribuciones de la comunidad! Por favor, revisa el archivo CONTRIBUTING.md para obtener más información sobre cómo contribuir a este proyecto.
Licencia y Créditos
- Este proyecto está licenciado bajo la Licencia MIT. Por favor, revisa el archivo LICENSE para obtener más información.
- Ghost CMS está licenciado bajo la Licencia MIT.
- La imagen de node y la imagen Distroless están licenciadas por sus respectivos propietarios.
Historial de Estrellas
Enlaces
Related content
El nuevo Traefik Proxy v3.5 te permite migrar desde ingress-nginx sin modificar tus actuales recursos e incluye soporte Post-Quantum-Secure TLS
Cómo migrar desde Ingress NGINX sin editar tus actuales manifiestos? Traefik 3.5 presenta un Ingress Provider compatible con ingress-nginx, permitiendo migrar sin reescribir tus manifiestos existentes.
Read the full post →
Knative se gradúa en la CNCF: serverless en Kubernetes va en serio
La CNCF ha declarado oficialmente a Knative como listo para producción. Prometen menos dolores de cabeza con YAML, más fooco en "event driven" y, quizás, ahorres algunos centavos en el billing de tu señor feudal en la nube favorito.
Read the full post →
- Register with Email

