- miguel19436
Primeros pasos Rundeck en Docker
Updated: Jul 20, 2020
Publicado por Luis Toledo, Programador Senior de Variacode Software
Siguiendo la serie de posts presentados por Reiner Acuña acerca de Rundeck: Primeros pasos con Rundeck y Conociendo más a fondo Rundeck, en el siguiente post se presentará como utilizar Rundeck en un ambiente basado en containers. Se profundizará desde cómo crear una instalación básica, hasta extenderla para crear instalaciones más completas.
Imagen de Rundeck en Docker
Rundeck posee una imagen oficial de docker que permite comenzar a utilizar el producto con un conjunto de configuraciones por defecto.
Existen distintas imágenes para Rundeck Open Source y Enterprise.
Rundeck Open Source: https://hub.docker.com/r/rundeck/rundeck
Rundeck Enterprise: https://hub.docker.com/r/rundeckpro/enterprise
También es posible acceder a ejemplos útiles en el siguiente repositorio:
Ejemplos: https://github.com/rundeck/docker-zoo
Es posible acceder a distintas ediciones de ambas imágenes, las cuales se diferencian por los tags en el nombre de la imagen (por ejemplo rundeck/rundeck:3.2.8-20200608). Siempre se recomienda usar la última versión disponible. También existe una versión de pruebas que tiene las últimas funcionalidades en desarrollo (SNAPSHOT).
Ejemplo básico de Rundeck
A continuación se presenta un ejemplo básico para iniciar Rundeck en docker. En este post se utilizará docker-compose por su capacidad para orquestar entornos de containers.
Recomendaciones para utilizar Rundeck en docker:
Usar una base de datos externa para contar con data persistente (no se recomienda trabajar con la base embebida salvo en casos de testing). La base de datos puede ser una base de datos existente o se puede montar con docker.
Almacenar los logs de ejecuciones en algún volumen compartido (como veremos más adelante esto también se puede realizar a través de otro servicio docker)
docker-compose.yaml
version: '3'
services:
rundeck:
image: rundeck/rundeck:SNAPSHOT
container_name: rundeck-example
ports:
- '4444:4440'
environment:
RUNDECK_GRAILS_URL: 'http://localhost:4444'
RUNDECK_DATABASE_DRIVER: com.mysql.jdbc.Driver
RUNDECK_DATABASE_USERNAME: rundeck
RUNDECK_DATABASE_PASSWORD: '${DB_PASSWORD}'
RUNDECK_DATABASE_URL: 'jdbc:mysql://mysql/rundeck?autoReconnect=true&useSSL=false'
Donde:
ports: define el puerto donde se expondrá rundeck, por defecto Rundeck inicia en el puerto 4440. Se puede utilizar cualquier puerto para exponer el servicio con el host, pero se debe setear el puerto en RUNDECK_GRAILS_URL.
RUNDECK_GRAILS_URL: URL por la cual se puede acceder al servicio de rundeck. Para poder acceder a rundeck desde el host, se debe incluir el puerto con que se exponer el container (eg: http://localhost:4444)
RUNDECK_DATABASE_XXX: define los parámetros de conexión a la base de datos.
Para construir el container se deben ejecutar los siguientes comandos:
$ docker-compose build
$ docker-compose up
#(revisar si el container está corriendo)
$ docker-compose ps
# (ver logs de rundeck)
docker-compose logs
Para ingresar a Rundeck debe utilizar el valor definido en RUNDECK_GRAILS_URL en el browser.
Extender imagen base
¿Por qué extender la imagen base de Rundeck?
Instalar software adicional
Copiar plugins/addons al container
agregar/modificar archivos de configuración
Crear certificados e importarlos en cacerts/truststore de java o Rundeck.
Cualquier otro archivo que se necesite copiar a la imagen
Como concepto general de docker, la imagen que se cree debe ser lo suficientemente “atómica” de tal forma de que no se necesite instalar nada extra una vez que el container sea iniciado. Es por esto que todos los archivos de configuración, software requeridos, etc, deben ser incorporados cuando la imagen se construye, y las configuraciones customizadas deben ser expuestas a través de variables de entorno.
¿Cómo extender la imagen?
Crear un archivo Dockerfile que extienda de la imagen base de Rundeck
Usar el Dockerfile en el docker-compose.yaml del proyecto
> Estructura de carpetas del ejemplo:
├── example1
│ ├── Dockerfile
│ └── docker-compose.yaml
> Dockerfile:
FROM rundeck/rundeck:SNAPSHOT
USER root
# upgrade os
RUN apt-get -y update && \
apt-get -y install \
software-properties-common
# install python
RUN apt-get -y install python3-pip && \
pip3 install --upgrade pip
RUN password rundeck:rundeck
USER rundeck
En el ejemplo primero el Dockerfile extiende la imagen oficial de Rundeck (FROM rundeck/rundeck:SNAPSHOT), luego cambia a usuario root para realizar una serie de instalaciones de software, y finalmente vuelve al usuario Rundeck.
version: '3'
services:
rundeck:
build:
context: .
container_name: rundeck-single
ports:
- '4444:4440'
environment:
RUNDECK_GRAILS_URL: 'http://localhost:4444'
RUNDECK_DATABASE_DRIVER: com.mysql.jdbc.Driver
RUNDECK_DATABASE_USERNAME: rundeck
RUNDECK_DATABASE_PASSWORD: '${DB_PASSWORD}'
RUNDECK_DATABASE_URL: 'jdbc:mysql://mysql/rundeck?autoReconnect=true&useSSL=false'
En docker-compose ahora haremos referencia al Dockerfile, utilizado los atributos “build/context”. Al utilizar un punto en dicho valor, le decimos a docker que busque el Dockerfile en la misma carpeta. Si se trabaja con subfolders se debe indicar el nombre en dicha propiedad.
Sistema de templates de archivos de configuración
Rundeck utiliza un sistema de templates para construir los archivos de configuración basados en variables de entorno. A través de estos templates se generan archivos como rundeck-config.properties, framework.properties, log4j2.properties, etc, los cuales controlan los principales aspectos de configuración de Rundeck.
Los templates se generan usando el software REMCO.
Como se mencionó, existen casos en los cuales se necesita agregar configuraciones extras a los archivos principales de configuración de rundeck (rundeck-config.properties, framework.properties), o que se necesite crear algún otro archivo dinámico dependiente de variables de entorno del container. Por ejemplo, puede que sea necesario agregar configuraciones de algún plugin de Rundeck que no viene instalado por defecto o que se necesite modificar la contraseña por defecto del usuario admin en realm.properties.
Algunos ejemplos de templates existentes:
Docker Zoo: https://github.com/rundeck/docker-zoo/tree/master/config
Vault Plugin: https://github.com/rundeck-plugins/vault-storage/tree/master/docker
Cómo agregar un template
A continuación presentaré un ejemplo de cómo configurar un custom template.
Estructura de carpetas:
├── Dockerfile
├── README.md
├── docker-compose.yaml
└── remco
├── resources.d
│ └── extra-rundeck-config.properties.toml
└── templates
└── extra-rundeck-config.properties
Lo primero para crear un custom tempate es definir la estructura de carpetas como se ve en el ejemplo: se debe crear una carpeta denominada remco, con dos carpetas dentro llamadas resource.d y templates.
Dentro de la carpeta resource.d se debe crear los archivos .toml que definen la ruta fuente y destino donde se copiaran los archivos de configuración. Un archivo .toml debe ser como el siguiente:
[[template]]
src = "${REMCO_TEMPLATE_DIR}/extra-rundeck-config.properties"
dst = "${REMCO_TMP_DIR}/rundeck-config/extra-rundeck-config.properties"
mode = "0644"
Fuente (src) apunta a los archivos que se definirán en remco/tempates de la carpeta de nuestro proyecto.
Destinos (dst) apunta a las carpetas del container, las cuales pueden ser:
${REMCO_TMP_DIR}/rundeck-config/nombrearchivotemplate.properties => si se define al path ${REMCO_TMP_DIR}/rundeck-config/ el archivo de configuración se fusionará con /home/rundeck/service/config/rundeck-config.properties de rundeck
${REMCO_TMP_DIR}/framework/nombrearchivotemplate.properties => si se define al path ${REMCO_TMP_DIR}/framework/ el archivo de configuración se fusionará con /home/rundeck/etc/framework.properties.
Cualquier path , por ejemplo => /home/rundeck/etc/nombre.aclpolicy
Luego, el template definido en la fuente del archivo .toml puede contener reemplazo de variables como se ve en el siguiente ejemplo. Además, puede aceptar condicionales simples:
# remco/template/extra-rundeck-config.properties
rundeck.feature.pagedjoblist.enabled={{ getv("/rundeck/feature/pagedjoblist/enabled", "false") }}
{% if exists("/rundeck/security/ldap/bindpassword") -%}
rundeck.security.ldap.bindPassword={{ getv("/rundeck/security/ldap/bindpassword") }}
{% endif %}
Finalmente, las variables definidas en el template anterior se pueden especificar en docker-compose.yaml. Para esto se debe transformar el path en una formato de variable de entorno, por ejemplo:
/rundeck/feature/pagedjoblist/enabled => RUNDECK_FEATURE_PAGEDJOBLIST_ENABLED
/rundeck/security/ldap/bindpassword => RUNDECK_JAAS_LDAP_BINDPASSWORD
version: '3'
services:
rundeck:
build:
context: .
container_name: rundeck-single
ports:
- '4444:4440'
environment:
RUNDECK_GRAILS_URL: 'http://localhost:4444'
RUNDECK_DATABASE_DRIVER: com.mysql.jdbc.Driver
RUNDECK_DATABASE_USERNAME: rundeck
RUNDECK_DATABASE_PASSWORD: '${DB_PASSWORD}'
RUNDECK_DATABASE_URL: 'jdbc:mysql://mysql/rundeck?autoReconnect=true&useSSL=false'
RUNDECK_FEATURE_PAGEDJOBLIST_ENABLED: “true”
RUNDECK_JAAS_LDAP_BINDPASSWORD: “password123”
Pasar configuraciones de java a la instancia de Rundeck
A veces es necesario definir configuraciones de JAVA extras al container que levanta Rundeck (por ejemplo para habilitar el uso de ssl o configurar un módulo de login extra). Para esto se puede usar el atributo “command” de docker compose.
version: '3'
services:
rundeck:
image: rundeck/rundeck:SNAPSHOT
container_name: rundeck-single
command: '-Dloginmodule.conf.name=jaas-loginmodule-reloaded.conf -Dloginmodule.name=rundeck'
ports:
- '4444:4440'
environment:
RUNDECK_GRAILS_URL: 'http://localhost:4444'
RUNDECK_DATABASE_DRIVER: com.mysql.jdbc.Driver
RUNDECK_DATABASE_USERNAME: rundeck
RUNDECK_DATABASE_PASSWORD: '${DB_PASSWORD}'
RUNDECK_DATABASE_URL: 'jdbc:mysql://mysql/rundeck?autoReconnect=true&useSSL=false'
Ejemplo de Rundeck completo
A continuación se mostrará un ejemplo completo de Rundeck interactuando con otros servicios en docker, como una base de datos y servicio de storage. La estructura de carpeta es la siguiente:
├── Dockerfile
├── .env
├── data
│ └── realm.properties
├── docker-compose.yaml
├── lib
│ ├── generate-ssl.sh
│ └── keytool_input
├── plugins
│ └── README.md
└── remco
├── resources.d
│ ├── custom-framework.properties.toml
│ ├── jaas-loginmodule-hotreload.conf.toml
│ └── plugin-rundeck-config.properties.toml
└── templates
├── custom-framework.properties
├── jaas-loginmodule-hotreload.conf
└── plugin-rundeck-config.properties
Donde:
Dockerfile: imagen de Rundeck extendida
.env: archivos con variables para pasar a docker-compose
data/realm.properties: archivo de configuración para agregar usuarios/grupos
carpeta lib: genera self-certificate para iniciar Rundeck con ssl
carpeta plugins: sirve para cargar plugins externos
carpeta remco: para extender archivos de configuración
Dockerfile:
ARG IMAGE
FROM ${IMAGE}
USER root
# install python
RUN apt-get -y update && \
apt-get -y install python-pip && \
pip install --upgrade pip
# install docker on container
RUN apt-get -y install docker.io
USER rundeck
ADD --chown=rundeck:root https://github.com/rundeck-plugins/docker/releases/download/1.4.1/docker-container-1.4.1.zip libext/
COPY --chown=rundeck:root remco /etc/remco
COPY --chown=rundeck:root plugins/* ./libext/
COPY --chown=rundeck:root lib docker-lib
RUN chmod +x docker-lib/generate-ssl.sh
RUN ./docker-lib/generate-ssl.sh
docker-compose.yaml
version: '3'
services:
rundeck:
build:
context: .
args:
IMAGE: '${RUNDECK_IMAGE:-rundeck/rundeck:SNAPSHOT}'
container_name: rundeck-demo
command: "-Dserver.https.port=4443 -Drundeck.ssl.config=/home/rundeck/server/config/ssl.properties"
ports:
- 4447:4443
environment:
RUNDECK_GRAILS_URL: 'https://localhost:4447'
#DATABASE CONNECTIO
RUNDECK_DATABASE_DRIVER: com.mysql.jdbc.Driver
RUNDECK_DATABASE_USERNAME: rundeck
RUNDECK_DATABASE_PASSWORD: '${DB_PASSWORD}'
RUNDECK_DATABASE_URL: 'jdbc:mysql://mysql/rundeck?autoReconnect=true&useSSL=false'
#LOG STORAGE
RUNDECK_PLUGIN_EXECUTIONFILESTORAGE_NAME: org.rundeck.amazon-s3
RUNDECK_PLUGIN_EXECUTIONFILESTORAGE_S3_ENDPOINT: http://minio:9000/
RUNDECK_PLUGIN_EXECUTIONFILESTORAGE_S3_BUCKET: rundeck
RUNDECK_PLUGIN_EXECUTIONFILESTORAGE_S3_REGION: us-east-2
RUNDECK_PLUGIN_EXECUTIONFILESTORAGE_S3_PATHSTYLE: "true"
AWS_ACCESS_KEY_ID: ${STORAGE_ACCESS_KEY_ID}
AWS_SECRET_KEY: ${STORAGE_SECRET_KEY}
volumes:
- ./data/realm.properties:/home/rundeck/server/config/realm.properties
mysql:
image: mysql:5.7
container_name: rundeck-mysql
ports:
- 33060:3306
environment:
- MYSQL_ROOT_PASSWORD=${DB_PASSWORD}
- MYSQL_DATABASE=rundeck
- MYSQL_USER=rundeck
- MYSQL_PASSWORD=${DB_PASSWORD}
volumes:
- ./data/database:/var/lib/mysql
minio:
image: minio/minio:latest
container_name: rundeck-minio
ports:
- "9000:9000"
entrypoint: sh
command: -c 'mkdir -p /export/rundeck && mkdir -p /export/plugins && /usr/bin/minio server /export --compat'
environment:
MINIO_ACCESS_KEY: ${STORAGE_ACCESS_KEY_ID}
MINIO_SECRET_KEY: ${STORAGE_SECRET_KEY}
volumes:
- ./data/storage:/export
.env
RUNDECK_IMAGE=rundeck/rudeck:SNAPSHOT
DB_PASSWORD=admin.
Ver ejemplo completo en https://github.com/variacode/rundeck-docker-examples