Automatización de WordPress con CI/CD y GitOps
La gestión tradicional de sitios WordPress, basada en actualizaciones manuales mediante FTP, parches aplicados directamente en producción y la temida edición en vivo de archivos PHP, es un lastre operativo que choca frontalmente con las prácticas modernas de DevOps. Para un SysAdmin, mantener decenas o cientos de sitios WordPress con este enfoque no solo es ineficiente, sino una fuente constante de vulnerabilidades de seguridad y desviaciones de configuración.
La solución radica en aplicar los principios de CI/CD (Integración Continua y Despliegue Continuo) y GitOps al ecosistema de WordPress. Esto transforma la gestión del CMS en un proceso declarativo, auditable y reproducible, donde Git actúa como la única fuente de verdad y los pipelines automatizados se encargan del resto. A continuación, desglosamos cómo implementar este flujo de trabajo de forma práctica y robusta.
¿Por qué WordPress necesita CI/CD y GitOps?
WordPress no es una aplicación monolítica cualquiera. Su naturaleza basada en plugins, temas y una base de datos dinámica presenta desafíos únicos. Aplicar GitOps aquí significa que el estado deseado de tu sitio (versión de WordPress, plugins activos, configuración de wp-config.php, reglas de nginx) está definido en un repositorio de Git. Cualquier cambio en ese repositorio dispara un pipeline de CI/CD que reconcilia el estado real del servidor con el estado deseado.
Los beneficios son inmediatos:
- Auditabilidad total: Cada cambio queda registrado en el historial de commits. Sabes quién, cuándo y por qué se modificó algo.
- Rollbacks instantáneos: Si un plugin rompe el sitio, revertir el commit correspondiente es más rápido que restaurar un backup completo.
- Entornos idénticos: Desarrollo, staging y producción se despliegan desde el mismo código, eliminando el clásico "en mi máquina funciona".
- Seguridad por diseño: Las credenciales se inyectan como secretos en el pipeline, no se hardcodean en archivos del repositorio.
Arquitectura base del pipeline CI/CD para WordPress
Antes de escribir código YAML, debemos definir los componentes. La arquitectura se apoya en tres pilares:
- Repositorio Git: Almacena el código del tema, plugins (o sus versiones bloqueadas), la configuración de infraestructura (Docker Compose, Kubernetes manifests) y el archivo de estado de WordPress.
- Servidor de CI/CD: Herramientas como GitLab CI, GitHub Actions o Jenkins. Escucha los eventos de Git y ejecuta los pipelines.
- Entorno de ejecución: Puede ser un servidor bare-metal, una VM o, idealmente, un clúster Kubernetes. La elección define la complejidad del despliegue.
Estructura de repositorio recomendada
Un repositorio bien organizado es la base del éxito. Propongo la siguiente estructura:
/
├── .gitlab-ci.yml # Configuración del pipeline
├── docker-compose.yml # Para entornos locales o single-server
├── kubernetes/ # Manifiestos para K8s
│ ├── deployment.yaml
│ ├── service.yaml
│ └── configmap.yaml
├── wordpress/
│ ├── wp-content/
│ │ ├── themes/
│ │ │ └── tu-tema-personalizado/
│ │ └── plugins/
│ │ └── plugin-personalizado/
│ ├── wp-config.php # Template con variables de entorno
│ └── .htaccess # (si usas Apache)
├── scripts/
│ ├── deploy.sh
│ └── backup-db.sh
└── README.md
[INFO] No incluyas el core de WordPress ni la carpeta
wp-content/uploadsen el repositorio. El core se descarga durante el pipeline, y los uploads se gestionan con un volumen persistente o un almacenamiento externo (S3, NFS).
Implementación del pipeline CI/CD
Vamos a construir un pipeline con GitLab CI, pero el concepto es trasladable a cualquier otra herramienta. El pipeline tendrá tres stages principales: test, build y deploy.
Stage de Test: Validación de código
No desplegues nada que no haya pasado pruebas. En WordPress, las pruebas pueden ser limitadas, pero podemos validar la sintaxis PHP y las vulnerabilidades conocidas.
stages:
- test
- build
- deploy
test-php:
stage: test
image: php:8.1-cli
script:
- apt-get update && apt-get install -y unzip git
# Verificar sintaxis de todos los archivos PHP
- find . -name "*.php" -exec php -l {} \;
# Ejecutar linter (PHP CodeSniffer con estándares de WordPress)
- curl -OL https://squizlabs.github.io/PHP_CodeSniffer/phpcs.phar
- php phpcs.phar --standard=WordPress ./wordpress/wp-content/themes/tu-tema/
only:
- main
- develop
Stage de Build: Preparación del artefacto
Aquí ensamblamos el sitio. Descargamos el core de WordPress, instalamos dependencias de Composer (si usas Bedrock) y generamos un artefacto listo para desplegar.
build-wordpress:
stage: build
image: alpine:latest
script:
- apk add --no-cache curl unzip
# Descargar versión específica de WordPress
- curl -O https://wordpress.org/wordpress-6.4.2.zip
- unzip -q wordpress-6.4.2.zip
- rm wordpress-6.4.2.zip
# Copiar temas y plugins personalizados
- cp -r wordpress/wp-content wordpress-6.4.2/wp-content
# Generar wp-config.php desde plantilla
- envsubst < wordpress/wp-config.php > wordpress-6.4.2/wp-config.php
# Empaquetar el artefacto
- tar -czf wordpress-build.tar.gz -C wordpress-6.4.2 .
artifacts:
paths:
- wordpress-build.tar.gz
expire_in: 1 week
Stage de Deploy: Aplicar GitOps
El stage de deploy es donde se materializa GitOps. Aquí no hacemos un simple rsync. En su lugar, actualizamos el estado deseado en el repositorio de configuración (o aplicamos directamente los manifests de Kubernetes).
Opción A: Despliegue en servidor único con Docker Compose.
deploy-production:
stage: deploy
image: docker:latest
services:
- docker:dind
script:
- docker context create remote --docker "host=ssh://user@server-produccion"
- docker context use remote
- docker compose down
- docker compose up -d
environment:
name: production
only:
- main
Opción B: Despliegue en Kubernetes (GitOps puro).
Esta es la opción más alineada con GitOps. En lugar de desplegar directamente, el pipeline actualiza el repositorio Git que contiene los manifests de Kubernetes. ArgoCD o Flux se encargan de sincronizar el clúster.
update-gitops-repo:
stage: deploy
image: alpine/git
script:
- git clone https://gitlab.com/tu-org/gitops-wordpress.git
- cd gitops-wordpress
- sed -i "s|image: wordpress:.*|image: wordpress:${CI_PIPELINE_ID}|" kubernetes/deployment.yaml
- git config user.email "ci@example.com"
- git config user.name "CI Pipeline"
- git commit -am "Actualizar imagen de WordPress a build ${CI_PIPELINE_ID}"
- git push origin main
only:
- main
Gestión de la base de datos: El talón de Aquiles
El mayor desafío de GitOps con WordPress es la base de datos. El código es inmutable, pero los datos (posts, configuraciones de plugins, usuarios) cambian constantemente. No podemos versionar la base de datos completa en Git.
Estrategias para manejar la base de datos
- Migraciones con scripts SQL: Utiliza herramientas como
wp db exportywp db importde WP-CLI. Los cambios estructurales se guardan como scripts SQL en el repositorio. - Plugin de control de versiones de base de datos: Plugins como "VersionPress" intentan versionar los cambios de la base de datos, pero su fiabilidad es limitada en producción.
- Separación total: Acepta que la base de datos es estado vivo. En cada despliegue, ejecutas un script que aplica migraciones pendientes (
wp core update-db) y limpias cachés de objetos. La base de datos nunca se sobrescribe desde el pipeline.
[WARNING] Nunca sobrescribas la base de datos de producción con una copia de staging en un pipeline automatizado. Podrías borrar pedidos, usuarios o contenido reciente. Usa siempre migraciones incrementales.
Automatización de backups con GitOps
Un pipeline CI/CD también puede orquestar backups. Por ejemplo, un job programado (cron en el pipeline) que ejecute:
backup-database:
stage: test
image: wordpress:cli
script:
- wp db export /tmp/backup-$(date +%Y%m%d).sql --allow-root
- aws s3 cp /tmp/backup-*.sql s3://tu-bucket/backups/
only:
- schedules
variables:
SCHEDULE: "0 2 * * *" # Todos los días a las 2 AM
Este enfoque asegura que los backups se ejecuten con las mismas credenciales y control de versiones que el resto del pipeline.
Seguridad y secretos en el pipeline
Los pipelines CI/CD exponen secretos si no se manejan con cuidado. Sigue estas reglas:
- Nunca pongas
DB_PASSWORD,AUTH_KEYo claves de API en el repositorio. - Usa variables de entorno protegidas en tu servidor de CI (GitLab CI Variables, GitHub Secrets).
- Inyecta los secretos en el contenedor en tiempo de ejecución, no en la imagen.
Ejemplo de wp-config.php template:
define('DB_NAME', getenv('WORDPRESS_DB_NAME'));
define('DB_USER', getenv('WORDPRESS_DB_USER'));
define('DB_PASSWORD', getenv('WORDPRESS_DB_PASSWORD'));
define('DB_HOST', getenv('WORDPRESS_DB_HOST'));
define('AUTH_KEY', getenv('WORDPRESS_AUTH_KEY'));
define('SECURE_AUTH_KEY', getenv('WORDPRESS_SECURE_AUTH_KEY'));
// ... resto de salts
Monitorización post-despliegue
GitOps no termina cuando el pipeline se ejecuta con éxito. Debes monitorizar que el sitio funciona correctamente después del despliegue. Añade un stage de verificación:
health-check:
stage: deploy
image: curlimages/curl:latest
script:
- curl -f -s -o /dev/null -w "%{http_code}" https://tusitio.com/wp-admin/admin-ajax.php
- curl -f -s -o /dev/null -w "%{http_code}" https://tusitio.com/wp-json/wp/v2/posts
after_script:
- echo "Health check completado"
Si el health check falla, el pipeline debe marcar el despliegue como fallido y, idealmente, activar un rollback automático.
Caso práctico: Flujo completo de GitOps
Imagina que un desarrollador quiere actualizar un plugin personalizado. El flujo sería:
- Desarrollador modifica el código del plugin en su rama
feature/mejora-plugin. - Push a GitLab. Esto dispara el pipeline en la rama
feature. - Stage test: Se ejecutan linters y pruebas de sintaxis.
- Stage build: Se genera un artefacto con el nuevo código del plugin.
- Stage deploy (staging): El pipeline despliega automáticamente en el entorno de staging.
- QA verifica el cambio en staging.
- Merge a
main. Esto dispara el pipeline de producción. - Pipeline de producción genera el artefacto final y actualiza el repositorio GitOps.
- ArgoCD/Flux detecta el cambio en el repositorio GitOps y sincroniza el clúster Kubernetes.
- El sitio se actualiza sin downtime (gracias a rolling updates en K8s).
Herramientas complementarias
- WP-CLI: Indispensable para automatizar tareas de WordPress dentro del pipeline (actualizar core, plugins, limpiar caché).
- Composer + Bedrock: Si usas Roots Bedrock, tu
composer.jsondefine todas las dependencias de WordPress, plugins y temas. El pipeline solo ejecutacomposer install. - Terraform/Pulumi: Para gestionar la infraestructura (servidores, bases de datos RDS, buckets S3) como código, complementando GitOps.
- Ansible: Útil para configurar el servidor base antes del primer despliegue (instalar PHP, Nginx, etc.).
[TIP] Empieza con un sitio WordPress no crítico para validar el pipeline. El plugin "WP Crontrol" te ayudará a depurar tareas programadas que puedan fallar tras el cambio a un entorno orquestado.
Conclusión
Automatizar WordPress con CI/CD y GitOps no es un lujo, es una necesidad para cualquier organización que gestione sitios a escala. Elimina el error humano, acelera las entregas y proporciona una capa de seguridad y auditoría que los métodos tradicionales jamás podrán ofrecer. La curva de aprendizaje es real, especialmente al gestionar el estado de la base de datos, pero los beneficios en fiabilidad y velocidad de iteración compensan con creces la inversión inicial. Como SysAdmin, adoptar este modelo te permitirá pasar de apagar incendios a diseñar sistemas que apenas requieren intervención manual.
