226 lines
6.2 KiB
Markdown
226 lines
6.2 KiB
Markdown
# 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.ralph # Pipeline del cliente Ralph
|
||
```
|
||
|
||
## Arquitectura
|
||
|
||
- **Jenkins master**: corre en Docker en el servidor Minio (`186.67.82.140`).
|
||
- **Agentes (SCOs)**: cada terminal SCO conecta al master vía JNLP (puerto 50000). El proceso del agente corre como `root`.
|
||
- **Storage**: Minio almacena el software de cada cliente en buckets separados (ej: bucket `ralph`).
|
||
|
||
### Labels de agentes
|
||
|
||
Formato: `sco <cliente> <tienda>`
|
||
|
||
| Cliente | Tienda | Agentes |
|
||
|---|---|---|
|
||
| ralph | yabucoa | sco02–sco07 |
|
||
| ralph | san-lorenzo | sco03–sco06 |
|
||
| ralph | rio-grande | sco01–sco06 |
|
||
|
||
## Levantar el servidor
|
||
|
||
```sh
|
||
docker compose up -d --build
|
||
```
|
||
|
||
Jenkins queda disponible en `http://<server-ip>:8080` (admin / H0l4mund0!).
|
||
|
||
## Conectar un agente SCO
|
||
|
||
1. Descargar el agente desde Jenkins:
|
||
```sh
|
||
curl -sO http://<server-ip>:8080/jnlpJars/agent.jar
|
||
mv agent.jar /opt/jenkins-agent/agent.jar
|
||
```
|
||
|
||
2. Obtener el secret del nodo: en Jenkins → *Manage Jenkins → Nodes → (nombre del nodo)*.
|
||
|
||
3. Crear el servicio systemd en el SCO:
|
||
```ini
|
||
# /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 http://<server-ip>:8080/ \
|
||
-secret <SECRET> \
|
||
-name "<nombre-del-nodo>" \
|
||
-workDir "/opt/jenkins-agent"
|
||
Restart=always
|
||
RestartSec=10
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
```
|
||
|
||
4. Habilitar y arrancar:
|
||
```sh
|
||
systemctl daemon-reload
|
||
systemctl enable --now jenkins-agent
|
||
```
|
||
|
||
## Ejecutar un deploy
|
||
|
||
1. En Jenkins, abrir el job `deploy-ralph`.
|
||
2. Click en **Build with Parameters**.
|
||
3. Seleccionar la **tienda** destino en el dropdown (yabucoa / san-lorenzo / rio-grande).
|
||
4. El pipeline despliega `install.sh ralph` en paralelo en todos los SCOs online de esa tienda.
|
||
|
||
## Qué hace `install.sh`
|
||
|
||
Recibe el nombre del cliente como argumento (`$1`):
|
||
|
||
1. Genera config de rclone apuntando al Minio local.
|
||
2. Sincroniza el bucket `$CUSTOMER` desde Minio hacia `/opt/sco/` en el SCO (excluyendo datos persistentes del backend).
|
||
3. Ajusta permisos en `/opt/sco/`.
|
||
4. Instala servicios systemd desde `/opt/sco/resources/services/`.
|
||
5. Configura autostart del usuario `sco`.
|
||
6. Instala crontabs de `root` y `sco`.
|
||
7. Instala paquetes Python offline.
|
||
8. Carga imágenes Docker.
|
||
9. Inicializa carpetas y archivos de base de datos del cpi-server.
|
||
10. Genera `engine.properties` para SymmetricDS (solo en primera instalación).
|
||
|
||
## Operaciones de mantenimiento
|
||
|
||
### Agregar un nuevo cliente
|
||
|
||
El deploy es idéntico para todos los clientes: el `install.sh` recibe el nombre del cliente como `$1`.
|
||
Solo cambia el nombre del job, el Jenkinsfile, y los nodos registrados.
|
||
|
||
**1. Registrar los nodos en `data/jenkins/jenkins.yaml`**
|
||
|
||
Bajo la clave `nodes`, añadir un bloque por cada SCO del cliente:
|
||
|
||
```yaml
|
||
- permanent:
|
||
name: "nuevocliente-tienda1-sco01"
|
||
labelString: "sco nuevocliente tienda1"
|
||
remoteFS: "/opt/jenkins-agent"
|
||
numExecutors: 1
|
||
retentionStrategy: "always"
|
||
launcher:
|
||
inbound: {}
|
||
```
|
||
|
||
Repetir para cada combinación tienda/SCO. Convención de nombres:
|
||
- Nombre del nodo: `<cliente>-<tienda>-<sco>` (ej: `ralph-yabucoa-sco02`)
|
||
- Label: `sco <cliente> <tienda>` (ej: `sco ralph yabucoa`)
|
||
|
||
**2. Crear el Jenkinsfile en `data/jenkins/pipelines/Jenkinsfile.<cliente>`**
|
||
|
||
Copiar `Jenkinsfile.ralph` y ajustar dos cosas:
|
||
|
||
```groovy
|
||
// En parameters: listar las tiendas del nuevo cliente
|
||
choices: ['tienda1', 'tienda2', 'tienda3'],
|
||
|
||
// En el stage Deploy: cambiar el nombre del cliente (dos lugares)
|
||
def labelExpr = "nuevocliente && ${params.TIENDA}"
|
||
sh "bash install.sh 'nuevocliente'"
|
||
```
|
||
|
||
**3. Agregar el job en `data/jenkins/jenkins.yaml`**
|
||
|
||
Al final de la sección `jobs`:
|
||
|
||
```yaml
|
||
- script: |
|
||
pipelineJob('deploy-nuevocliente') {
|
||
description('Deploy de install.sh a los SCOs de NuevoCliente.')
|
||
definition {
|
||
cps {
|
||
script(new File('/opt/jenkins/Jenkinsfile.nuevocliente').text)
|
||
sandbox(true)
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**4. Montar el Jenkinsfile en `docker-compose.yml`**
|
||
|
||
```yaml
|
||
volumes:
|
||
- ./data/jenkins/pipelines/Jenkinsfile.nuevocliente:/opt/jenkins/Jenkinsfile.nuevocliente:ro
|
||
```
|
||
|
||
**5. Recrear el contenedor**
|
||
|
||
```sh
|
||
docker compose up -d --build
|
||
```
|
||
|
||
En el servidor remoto:
|
||
|
||
```sh
|
||
# Copiar los archivos modificados al servidor primero, luego:
|
||
docker compose up -d --build
|
||
```
|
||
|
||
---
|
||
|
||
### Agregar una tienda a un cliente existente
|
||
|
||
**1. Añadir los nodos de la nueva tienda en `jenkins.yaml`** (un bloque por SCO, igual que arriba).
|
||
|
||
**2. Agregar la tienda al dropdown del Jenkinsfile del cliente:**
|
||
|
||
```groovy
|
||
choices: ['yabucoa', 'san-lorenzo', 'rio-grande', 'nueva-tienda'],
|
||
```
|
||
|
||
**3. Aplicar en el servidor:**
|
||
|
||
```sh
|
||
docker compose restart jenkins
|
||
```
|
||
|
||
No hace falta rebuild completo si solo cambia `jenkins.yaml` o el Jenkinsfile — el contenedor los monta como volúmenes y JCasC los recarga.
|
||
|
||
> Si agregaste nodos nuevos pero no reiniciaste Jenkins, también podés recargar desde la UI: *Manage Jenkins → Configuration as Code → Reload existing configuration*.
|
||
|
||
---
|
||
|
||
### Agregar un SCO a una tienda existente
|
||
|
||
Solo tocar `jenkins.yaml`: añadir el nodo nuevo bajo `nodes`.
|
||
|
||
```yaml
|
||
- permanent:
|
||
name: "ralph-yabucoa-sco08"
|
||
labelString: "sco ralph yabucoa"
|
||
remoteFS: "/opt/jenkins-agent"
|
||
numExecutors: 1
|
||
retentionStrategy: "always"
|
||
launcher:
|
||
inbound: {}
|
||
```
|
||
|
||
Luego recargar la configuración:
|
||
|
||
```sh
|
||
docker compose restart jenkins
|
||
# o desde la UI: Manage Jenkins → Configuration as Code → Reload existing configuration
|
||
```
|
||
|
||
Una vez que Jenkins lo reconoce, conectar el agente en el SCO físico (ver sección "Conectar un agente SCO").
|