Cómo crear un servicio MySQL con Docker. Parte 3.

Hemos visto en entradas anteriores cómo podíamos levantar un contenedor MySQL, añadiendo volúmenes para persistir los datos y cómo crear una base de datos en el momento de creación del contenedor. Sin embargo, a la hora de desplegar una aplicación, lo ideal es levantar todos los servicios a la vez mediante docker-compose, tal y como lo hacíamos con nuestra aplicación y la base de datos en AWS.

Vamos ahora a realizar lo mismo, pero utilizando nuestra base de datos MySQL«dockerizada«. Podemos hacerlo de dos formas, o bien utilizando la imagen que habíamos creado anteriormente, o bien parametrizar todos esos datos en el docker-compose.yml.

Veamos la primera opción:

version: '3'

services:
  mysql:
    image: mysql-db/basic:latest
    expose:
      - 3306

  app:
    image: secdevoops/spring-boot-docker:0.0.1-SNAPSHOT
    expose:
      - 8080
    ports:
      - "8080:8080"
    depends_on:
      - mysql

En este caso, como vemos, estamos usando ambas imágenes que habíamos creado para generar nuestro fichero docker-compose.yml. Debemos recordar que en nuestra aplicación debemos poner las propiedades de conexión a nuestra base de datos de forma adecuada en el application.properties y generar la imagen de nuevo si es necesario. En este caso, quedaría así:

spring.datasource.url=jdbc:mysql://mysql:3306/myapp
spring.datasource.username=root
spring.datasource.password=password

Ya simplemente tenemos que levantar nuestros servicios con el comando:

$ docker-compose up --build

La otra opción de que disponemos es poner todas las propiedades de nuestra base de datos MySQL en el docker-compose.yml usando como imagen base la imagen oficial de MySQL en lugar de la nuestra e indicar todos los parámetros en el fichero de configuración.

version: '3'

services:
  mysql:
    image: mysql:latest
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=myapp
    volumes:
        - mysql_volume:/var/lib/mysql
        - mysql_entrypoint:/docker-entrypoint-initdb.d
    expose:
      - 3306

  app:
    image: secdevoops/spring-boot-docker:0.0.1-SNAPSHOT
    expose:
      - 8080
    ports:
      - "8080:8080"
    depends_on:
      - "mysql"

volumes:
      mysql_volume:
      mysql_entrypoint:

En este caso, hemos creado dos volúmenes para el contenedor MySQL. El primero será para la persistencia de datos y el segundo para poder copiar el script que usaremos para crear la base de datos.

Vamos a crear lo primero los contenedores y los volúmenes mediante el siguiente comando con la opción –no-start para que se creen, pero no se levanten:

$ docker-compose up --no-start

Ahora copiaremos nuestro script al volumen docker_mysql_entrypoint. Debemos copiarlo como usuario con permisos de root.

$ sudo cp init_script.sql /var/lib/docker/volumes/docker_mysql_entrypoint/_data/

Al levantar nuestros servicios con docker-compose por primera vez, vamos a tener un problema, y es que la base de datos aún no ha sido creada y, por tanto, nuestra aplicación no se puede conectar. Si lo paramos y lo volvemos a ejecutar, no debería darnos problemas, ya que ahora la base de datos sí estará creada.

Este problema surge porque nuestra aplicación no está esperando a que el contenedor de MySQL termine de levantarse. Incluso, aunque se haya creado, podría darse el caso de que tarde más que la aplicación en levantarse y sigamos teniendo el mismo problema. ¿Cómo podemos solucionar esto? Lo ideal es que el contenedor de nuestra aplicación espere a que el servicio de MySQL esté levantado por completo.

Una opción es modificar el fichero de propiedades de la aplicación para indicarle a Spring que pruebe hasta que la base de datos esté disponible.

spring.datasource.testOnBorrow = true
spring.datasource.testWhileIdle = true
spring.datasource.timeBetweenEvictionRunsMillis = 60000
spring.datasource.minEvictableIdleTimeMillis = 30000
spring.datasource.validationQuery = SELECT 1
spring.datasource.max-active = 15
spring.datasource.max-idle = 10
spring.datasource.max-wait = 8000

Ahora ya podremos levantar nuestra aplicación junto con la base de datos ejecutando:

$ docker-compose up

El proyecto entero está disponible en GitHub https://github.com/secdevoops/spring-boot-docker

Categorías