DEV Community

Luis_Zapata_Yamo
Luis_Zapata_Yamo

Posted on • Edited on

Implementación de una Aplicación SpringBoot Utilizando Docker y Jenkins (Docker-outside-of-Docker - DooD)

Inicialmente tenemos que instalar docker en nuestra maquina host, en este caso estoy en windows, Docker Desktop.

Importante entrar a docker desktop y habilitar en settings

epose daemon

Para fines prácticos se ha realizado pasos que se podrían mejorar usando nodos en Jenkins.

Usaremos el concepto de construcción de contenedores a partir de DockerFiles y usando Docker compose.

Lo que haremos es un flujo para que cuando realicemos un push a nuestro repositorio remoto Jenkins pueda iniciar un pipeline que permita la creación de un contenedor de una aplicación.

Creación de contenedor Jenkins y Base de datos

DockerFile.jenkinslocal

Este primer DockerFile es para el contenedor Jenkins, llamado DockerFile.jenkinslocal.

# Utiliza la imagen oficial de Jenkins
FROM jenkins/jenkins:lts

# Cambia al usuario root para instalar paquetes
USER root

# Instala wget, dpkg y dependencias necesarias
RUN apt-get update && apt-get install -y wget dpkg apt-transport-https ca-certificates curl gnupg2 software-properties-common

# Instala Java
RUN apt-get install -y java-common


# Descarga e instala Amazon Corretto 17
ADD https://corretto.aws/downloads/latest/amazon-corretto-17-x64-linux-jdk.deb /tmp/

RUN dpkg -i /tmp/amazon-corretto-17-x64-linux-jdk.deb

# Limpia el cache de apt y elimina el paquete de instalación de Corretto
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/amazon-corretto-17-x64-linux-jdk.deb

# Descarga e instala Maven
ADD https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz /opt/

RUN tar -xzf /opt/apache-maven-3.9.6-bin.tar.gz -C /opt/

ENV PATH="/opt/apache-maven-3.9.6/bin:${PATH}"

# Instala Docker CLI
RUN curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -

RUN add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"

RUN apt-get update && apt-get install -y docker-ce-cli


# Agrega el usuario de Jenkins al grupo docker
RUN groupadd docker

RUN usermod -aG docker jenkins

# Cambia al usuario de Jenkins
USER jenkins
Enter fullscreen mode Exit fullscreen mode

Se necesita tener instalado en el contenedor de jenkins:

  • Dependencias necesarias
  • Java, en este caso usando Amazon Coretto 17
  • Maven
  • El daemon de docker

Creación del docker-compose.yml

Este docker file sera usado dentro del docker-compose.yml y dentro también crearemos el contenedor de la base de datos con parámetros establecidos para crear una bd inicial llamada crud.

version: '3.8'

services:
  jenkinslocal:
    container_name: jenkinslocal
    build:
      context: .
      dockerfile: Dockerfile.jenkinslocal
    ports:
      - "8080:8080"
      - "500:5000"
    environment:
      JAVA_OPTS: "-Djenkins.install.runSetupWizard=false"
      DOCKER_HOST: "tcp://host.docker.internal:2375"
    depends_on:
      - postgres

    volumes:
      - jenkins_home:/var/jenkins_home
      - /var/run/docker.sock:/var/run/docker.sock

  postgres:
    container_name: db-crud
    image: postgres
    restart: always
    ports:
      - "5432:5432"
    environment:
      POSTGRES_DB: crud
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres

volumes:
  jenkins_home:
Enter fullscreen mode Exit fullscreen mode

El primer servicio es para el contenedor de jenkins:

  • Se crea a partir del DockerFile.jenkinslocal
  • se habilitan los puertos
  • Se agrega el host del docker
  • Y como volumen se incluye la ruta del socket de docker

El segundo servicio es para el contenedor de docker es para la base de datos, en postgres.

  • Se crea a partir de la imagen de postgres
  • Se habilitan los puertos
  • Se crean variables de entorno para configuraciones iniciales de la base de datos

Levantar Contenedores

Para poder levantar el docker compose se usa:

  • docker compose up -d

Si hacemos cambios en el internos en los servicios tenemos que hacer:

  • docker compose down
  • docker compose up -d (--detach/segundo plano)

Compose up

Configurar Aplicación

La aplicación, en este caso una api usa el puerto 8081, adicional tendro del pom.xml se define el nombre del artefacto que se crea, llamado mi-app.jar .

Es importante saber que jenkins dentro de un contenedor necesita la ip del host local

Para SpringBoot el cambio de puerto se puede hacer en el archivo application.properties :

#Ejemplo
spring.application.name=crud
spring.datasource.url=jdbc:postgresql://ip_local:5432/crud
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
server.port=8081
Enter fullscreen mode Exit fullscreen mode

Para el pom en este caso se uso el finalName:

<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                    <finalName>mi-app</finalName>
                </configuration>
            </plugin>
        </plugins>
    </build>
Enter fullscreen mode Exit fullscreen mode

Creación del DockerFile para la aplicación

Requisitos para la app:

  • Instalar y configurar Java
  • Jar que se genera en el pipeline
# Dockerfile para el contenedor app-crud
FROM debian:bullseye-slim

# Instala wget y dpkg
RUN apt-get update && apt-get install -y wget && apt-get install -y dpkg
RUN apt-get update && apt-get install -y java-common


# Descarga e instala Amazon Corretto 17
ADD https://corretto.aws/downloads/latest/amazon-corretto-17-x64-linux-jdk.deb /tmp/

RUN dpkg -i /tmp/amazon-corretto-17-x64-linux-jdk.deb

# Limpia el cache de apt y elimina el paquete de instalación de Corretto
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/amazon-corretto-17-x64-linux-jdk.deb

# Configura las variables de entorno JAVA_HOME y PATH
ENV JAVA_HOME /usr/lib/jvm/java-17-amazon-corretto

ENV PATH $JAVA_HOME/bin:$PATH

# Define el directorio de trabajo
WORKDIR /app

# # Copia el JAR generado a la imagen
COPY target/mi-app.jar /app/mi-app.jar

# # Comando para ejecutar la aplicación
CMD ["java", "-jar", "/app/mi-app.jar"]
Enter fullscreen mode Exit fullscreen mode

Crear el JenkinsFile

Se necesita el flujo para poder hacer el despliegue.

pipeline {
    agent any
    environment {
        DOCKER_HOST = 'tcp://host.docker.internal:2375'
        CONTAINER_NAME = 'mi-app-container'
        IMAGE_NAME = 'mi-app:latest'
    }

    stages {
        stage('Build') {
            steps {
                sh 'mvn clean package'
            }

        }

        stage('Build Docker Image') {
            steps {
                script {
                    sh 'docker build -t ${IMAGE_NAME} -f Dockerfile.app-crud .'
                }
            }
        }

        stage('Deploy Docker Container') {
            steps {
                script {
                    // Stop and remove the old container if it exists
                    sh '''
                    if [ "$(docker ps -aq -f name=${CONTAINER_NAME})" ]; then
                        if [ "$(docker ps -aq -f status=running -f name=${CONTAINER_NAME})" ]; then
                            docker stop ${CONTAINER_NAME}
                        fi
                        docker rm ${CONTAINER_NAME}
                    fi
                    '''
                    
                    // Run the new container
                    sh '''
                    docker run -d --name ${CONTAINER_NAME} -p 8081:8081 ${IMAGE_NAME}
                    '''
                }

            }

        }

    }

}
Enter fullscreen mode Exit fullscreen mode

Este pipeline:

  1. Compila la aplicación y crea el JAR (mi-app.jar).
  2. Construye una imagen Docker.
  3. Despliega el contenedor, deteniendo y eliminando el existente si es necesario.

Configuración de Jenkins

Cuando se crea un contenedor jenkins hay casos que te piden una clave, esta sale en el log de ejecución del contenedor. Y luego sigues los pasos hasta ver la pagina principal

Jenkins Config

Plugins

Instala los siguientes plugins en Jenkins:

Configuración del Job

Crea un nuevo Job en Jenkins con estas configuraciones:

  • Trigger: GitHub hook trigger for GITScm polling
  • Pipeline: Pipeline script from SCM
  • SCM: Git con URL SSH
  • En Repository URL le colocamos la URL pero con el protocolo SSH
  • En credential lo dejamos vacío por ahora.

Pipeline

Abriremos una terminal del contenedor de Jenkins para crear una llave ssh:

  • docker exec -it -u jenkins id_contenedor bash

Luego dentro de la terminal

# Comandos de ejemplo
cd ~
ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/var/jenkins_home/.ssh/id_rsa):
# Output...

eval $(ssh-agent -s)
ssh-add .ssh/id_rsa
# Reconoceremos a github para la conexion por ssh
ssh -T git@github.com

# Mostramos la llave privada
cat .ssh/id_rsa
# Mostramos la llave publica
cat .ssh/id_rsa.pub

Enter fullscreen mode Exit fullscreen mode

Para agregar la llave privada a las credenciales de Jenkins hacemos los iguiente:

  • Abrimos la interfaz de jenkins y vamos a la configuración del job creado y agregamos una

Add credential

Les saldrá una ventana asi

Credential

  • En Kind le colocamos SSH Username with private key
  • El ID debe ser único a la otras credenciales que ya tienes
  • En Private Key le das click en Enter directly para agregar la llave privada directamente y le damos en Add.
  • Luego si es que la llave tiene clave la agregamos en el campo Passphrase
  • Al final de dan en agregar para guardar la credencial.

La llave publica la agregaremos al repositorio remoto en Settings>Deploys Keys>Add deploy key.

Add deploy key

Vamos al Job creado y la credencial ya podríamos escogerla sin inconvenientes.

Cuando se ejecute el pipeline se creara un contenedor y ya estaria el deploy

Contenedor pipeline

Top comments (0)