miércoles, 27 de abril de 2022

Usando Docker y Jenkins

Vamos a instalar un jenkins dentro de un contenedor docker para ellos vamos a utilizar la imagen oficial de jenkins jenkins/jenkins.

Podemos hacerlo de dos formas:
  • Comandos:
           Ejecutamos un contendor a partir de una imagen jenkins

                        docker run -p 8081:8080 -p 50000:50000 jenkins/jenkins

Abrimos un navegador web y accedemos a http://localhost:8081 para entrar en la consola de administración de Jenkins.
La contraseña que se solicita la podemos obtener en la salida de la  ejecución del comando anterior o ejecutando el siguiente comando:
                
                        docker ps | grep jenkins/jenkins

                        3183b39448bd   jenkins/jenkins:lts   "/sbin/tini -- /usr/…"   16 hours ago   Up 16 hours                           50000/tcp, 0.0.0.0:8081->8080/tcp, :::8081->8080/tcp   jenkins1

Con el identificador del contenedor (la primera cadena de caracteres) lanzamos el siguiente comando y obtendremos la contraseña que nos solicitan al acceder a localhost:8081 :

docker exec -it 3183b39448bd cat /var/jenkins_home/secrets/initialAdminP

Si queremos que los cambios que realicemos en la configuración de Jenkins persistan incluso tras la destrucción del contenedor, debemos arrancar el contenedor con un volumen:

docker run -p 8081:8080 -p 50000:50000 -v jenkins_home:/var/jenkins_home jenkins/jenkins

  • Crear una imagen Docker con Jenkins a medida: para no tener que repetir las configuraciones manuales en cada nueva instalación podemos construir una imagen Docker con Jenkins a medida con todo lo que necesitemos. Lo podemos hacer con el DockerFile, añadiendo las instrucciones que necesitemos para crear la imagen o con Docker Compose (docker-compose.yml) con el que podemos ejecutar una serie de servicios como diferentes contenedores donde tienen que interactuar entre sí.
Usar Compose es básicamente un proceso de tres pasos.
    1. Defina el entorno de su aplicación con un Dockerfile para que pueda reproducirse en cualquier lugar.
    2. Defina los servicios que conforman su aplicación en docker-compose.yml para que puedan ejecutarse juntos en un entorno aislado.
    3. Por último, ejecute docker-compose up y Compose se iniciará y ejecutará toda la aplicación.
Estructura del DockerFile (vamos a utilizar lo mínimo)
FROM jenkins/jenkins:lts

LABEL MAINTAINER = PruebasDocker

Un ejemplo de utilización de Compose:

version: '3.8' -->

services:
  pruebas-jenkins-master:
    container_name: jenkins1
    build: .
    image: pruebas/jenkins:1.0.0
    ports:
      - "8081:8080"
    networks:
      - pruebas-ci-network  
    volumes:
      - pruebas-jenkins-master:/var/jenkins_home
      - /usr/bin/docker:/usr/bin/docker
      - /var/run/docker.sock:/var/run/docker.sock
    restart: always  

  pruebas-sonarqube:
    container_name: sonarqube
    image: sonarqube:community
    ports:
      - "9002:9000"
    restart: always          

volumes:
  pruebas-jenkins-master:
    name: pruebas-jenkins-master

networks:
  pruebas-ci-network:
    name: pruebas-ci-network
    driver: bridge
    ipam:
      driver: default
      config:
      - subnet: 172.16.239.0/24   

Veamos que significa algunos parámetro del docker-compose:

Puedes encontrar todos los parámetros que podemos definir en la documentación oficial.

version: Los archivos docker-compose.yml son versionados, lo que significa que es muy importante indicar la versión de las instrucciones que queremos darle. A medida de que Docker evoluciona, habrá nuevas versiones, pero de todos modos, siempre hay compatibilidad hacia atrás.

services: contiene una configuración que se aplica a cada contenedor iniciado para ese servicio.

image: imagen desde la que iniciar el contenedor. Puede ser un repositorio/etiqueta o una identificación de imagen parcial.

ports publicamos los puertos al host y podemos especificar el mapeo (HOST:CONTENEDOR).

networks: Son las redes a las que se unirán los contenedores, referenciando las entradas debajo de las redes de nivel superior.

volumes:  Montamos rutas o volúmenes, especificamos una ruta en el host (HOST:CONTENEDOR), Igual podemos especificar modo de acceso (HOST:CONTENEDOR:rw)

container-name: especifica un nombre de contenedor personalizado, en lugar de un nombre predeterminado generado.

restart: always: Indicamos la política de reinicio del contenedor si por cualquier condición se para.