Jenkins SCO — Deploy Server
Jenkins centralizado para el despliegue de software en terminales SCO (Self-Checkout) en producción.
Estructura del repositorio
.
├── docker-compose.yml
└── data/
└── jenkins/
├── Dockerfile # Imagen Jenkins con plugins
├── jenkins.yaml # Configuración JCasC (nodos, seguridad, jobs)
├── deploy/
│ └── install.sh # Script desplegado en cada SCO
└── pipelines/
└── Jenkinsfile.sco # Pipeline único de deploy (NODO + CLIENTE)
Arquitectura
- Jenkins master: corre en Docker en un servidor (
172.19.13.204). No expone puertos al host; solo es alcanzable dentro de la red interna Dockerproxy. - Nginx Proxy Manager (NPM): reverse proxy interno que resuelve el hostname
jenkins.laoficina1782.comy hace forward haciajenkins-server:8080. Corre en el mismo servidor, redproxy. - Cloudflare Tunnel (
cloudflared): es el único punto de entrada desde internet. El contenedorcloudflaredabre una conexión saliente hacia el edge de Cloudflare (autenticada conTUNNEL_TOKEN), por lo que no hace falta abrir puertos entrantes en el firewall/router del servidor. El tunnel está configurado del lado de Cloudflare para enrutar el hostname público haciahttp://npm:80dentro de la redproxy. - Agentes (SCOs): cada terminal SCO conecta al master vía WebSocket (no JNLP), outbound hacia
wss://jenkins.laoficina1782.com/. El proceso del agente corre comoroot. - Storage: Minio almacena el software de cada cliente en buckets separados. El nombre del bucket es el mismo valor que se selecciona en el parámetro
CLIENTEdel deploy (ej: bucketmbs-ralphs).
Flujo de tráfico
Internet
│
▼
Cloudflare Edge (DNS + proxy)
│ túnel saliente autenticado (TUNNEL_TOKEN)
▼
cloudflared (contenedor, red "proxy", sin puertos publicados)
│ http://npm:80
▼
NPM (nginx-proxy-manager) — vhost jenkins.laoficina1782.com
│ http://jenkins-server:8080
▼
jenkins-server (sin puertos publicados al host)
Jenkins no expone puertos al host: NPM y cloudflared se comunican con él por nombre de contenedor dentro de la red Docker proxy. Como no hay puertos entrantes abiertos en el servidor, toda la superficie pública depende de Cloudflare (WAF, DNS, TLS terminado en el edge).
⚠️ NPM publica además
80,443y81directamente al host (verdocker-compose.yml). Si el firewall del servidor permite esas conexiones, Jenkins/NPM también serían alcanzables sin pasar por Cloudflare. Para que el tunnel sea realmente el único punto de entrada, esos puertos deberían quedar bloqueados a nivel de firewall/red salvo acceso local.
Variables de entorno
El tunnel necesita el token generado en el dashboard de Cloudflare (Zero Trust → Networks → Tunnels):
cp .env.example .env
# editar .env y setear CLOUDFLARE_TUNNEL_TOKEN=<token>
Levantar el servidor
docker compose up -d --build
Jenkins queda disponible en https://jenkins.laoficina1782.com una vez configurados el proxy y el tunnel.
Nginx Proxy Manager
Panel de administración: http://172.19.13.204:81 (o localmente en el servidor).
Configuración del proxy host para Jenkins:
| Campo | Valor |
|---|---|
| Domain Names | jenkins.laoficina1782.com |
| Scheme | http |
| Forward Hostname | jenkins-server |
| Forward Port | 8080 |
| Websockets Support | ✅ activado |
Cloudflare Tunnel
- En el dashboard de Cloudflare (Zero Trust → Networks → Tunnels), crear un tunnel y copiar su token.
- Configurar la ruta pública (Public Hostname) del tunnel:
jenkins.laoficina1782.com→http://npm:80. - Setear el token en
.envcomoCLOUDFLARE_TUNNEL_TOKEN(ver arriba). - Levantar el stack: el contenedor
cloudflaredse conecta solo, sin necesidad de abrir puertos en el servidor.
Conectar un agente SCO
-
Descargar el agente desde Jenkins:
curl -sO http://<server-ip>:8080/jnlpJars/agent.jar mv agent.jar /opt/jenkins-agent/agent.jar -
Obtener el secret del nodo: en Jenkins → Manage Jenkins → Nodes → (nombre del nodo).
-
Crear el servicio systemd en el SCO:
# /etc/systemd/system/jenkins-agent.service [Unit] Description=Jenkins Agent After=network.target [Service] User=root ExecStart=/usr/bin/java -jar /opt/jenkins-agent/agent.jar \ -url https://jenkins.laoficina1782.com/ \ -webSocket \ -secret <SECRET> \ -name "<nombre-del-nodo>" \ -workDir "/opt/jenkins-agent" Restart=always RestartSec=10 [Install] WantedBy=multi-user.target -
Habilitar y arrancar:
systemctl daemon-reload systemctl enable --now jenkins-agent
Ejecutar un deploy
Hay un único job, deploy-sco, que despliega a un nodo puntual (no a una tienda entera).
- En Jenkins, abrir el job
deploy-sco. - Click en Build with Parameters.
- Completar NODO con el nombre exacto del agente a deployar (ej.
ralph-yabucoa-sco05). - Seleccionar CLIENTE en el dropdown — es el nombre del bucket de Minio que se sincroniza en ese nodo.
Ambos parámetros son obligatorios: si NODO queda vacío o CLIENTE queda en SELECCIONAR_CLIENTE (el placeholder inicial), el build falla explícitamente en vez de deployar por accidente. Para desplegar a varios nodos (ej. toda una tienda) hay que correr el job una vez por nodo.
Nota: el primer build de este job (o de cualquier job parametrizado nuevo) corre antes de que Jenkins conozca los parámetros declarados en el Jenkinsfile — es una limitación de cómo Jenkins descubre los parámetros la primera vez. El pipeline lo detecta (
params.CLIENTE == null) y termina comoNOT_BUILTsin deployar nada; alcanza con volver a correr el job con Build with Parameters normalmente.
También se puede disparar desde consola con el Jenkins CLI o curl, ver Ejecutar un job desde consola.
Ejecutar un job desde consola
curl -O https://jenkins.laoficina1782.com/jnlpJars/jenkins-cli.jar
java -jar jenkins-cli.jar -s https://jenkins.laoficina1782.com/ \
-auth TU_USUARIO:TU_API_TOKEN \
build deploy-sco -p NODO=ralph-yabucoa-sco05 -p CLIENTE=mbs-ralphs -s -v
-sespera a que termine el build;-vmuestra el log en consola.- El API Token se genera en el usuario de Jenkins → Configure → API Token.
- Alternativa sin el CLI:
curl -X POST https://jenkins.laoficina1782.com/job/deploy-sco/buildWithParameters --user TU_USUARIO:TU_API_TOKEN --data-urlencode "NODO=ralph-yabucoa-sco05" --data-urlencode "CLIENTE=mbs-ralphs". - Si se dispara por CLI/
curlomitiendo-p CLIENTE=..., Jenkins no manda un valor vacío: rellena el parámetro con su default, que esSELECCIONAR_CLIENTE(el placeholder es a propósito el primer valor de la lista, para que unCLIENTEfaltante falle en vez de deployar silenciosamente al primer cliente real de la lista).
Qué hace install.sh
Recibe el nombre del cliente como argumento ($1), que es el mismo valor que se selecciona en el parámetro CLIENTE del deploy:
- Da de alta (o reutiliza) un alias
mcapuntando a Minio a través del hostname públicohttps://minio-api.laoficina1782.com. - Mirrorea el bucket
$CUSTOMERdesde Minio hacia/opt/sco/en el SCO (excluyendo datos persistentes del backend), con--remove --overwritepara dejar el destino idéntico al bucket.
Los pasos de instalación local (permisos, servicios systemd, autostart, crontabs, paquetes Python, imágenes Docker, inicialización de bases de datos del cpi-server, engine.properties de SymmetricDS) ya no están en este script — quedaron fuera del alcance actual de install.sh, que hoy solo se ocupa de traer el software del cliente a /opt/sco/.
Agregar un nodo o un cliente nuevo
Desde que el deploy pasó a un job único (deploy-sco, con NODO + CLIENTE como parámetros en vez de un Jenkinsfile/label por cliente), dar de alta algo nuevo es mucho más simple y ya no requiere tocar docker-compose.yml ni crear Jenkinsfiles:
- Agregar un nodo (a un cliente existente o nuevo): agregar una entrada
permanenten.jenkins.nodesdedata/jenkins/jenkins.yamlcon el nombre del agente (no hace faltalabelString, el deploy targetea por nombre exacto de nodo). Después conectar el agente físico siguiendo Conectar un agente SCO. - Agregar un cliente: agregar el nombre del bucket a la lista
choicesdel parámetroCLIENTEendata/jenkins/pipelines/Jenkinsfile.sco. - En ambos casos, aplicar el cambio con
docker compose up -d --build(el contenedor de Jenkins re-leejenkins.yamlvía JCasC).
⚠️
data/jenkins/scripts/create-node.shycreate-client.shquedaron obsoletos: automatizan el esquema viejo (un Jenkinsfile y un labelsco <cliente> <tienda>por cliente), que ya no existe. No usarlos hasta reescribirlos para el esquema dedeploy-sco.