Docker mysql y mysqldump, para crear un entorno de desarrollo

Hace unos días, me plantee, tener un entorno de desarrollo local, para poder estar totalmente aislado de los cambios de mis compañeros y poder trabajar de forma más productiva. Obviamente las sesiones de integración con el entorno de preproducción no me las quita nadie.

Pero obtenemos una productividad mejor y obviamente, las integraciones con preproducción, las controlo y decido yo (hacia mi entorno local), no espero que algún iluminado, suba sus cambios y los pruebe.

REQUISITOS

Debemos saber, como manejarnos con una herramienta como docker, tengo una pequeña introducción aquí: https://www.apascualco.com/cloud/docker-instalacion-primeros-pasos

Por otro lado, requiere que tengáis instalado el cliente de mysql, no es necesario tener el servidor corriendo.

LANZANDO EL CONTENEDOR DOCKER RUN

Lo primero, lanzo un contenedor con la imagen, de la versión de mysql que necesito

docker run --name ${DOCKER_IMAGE_NAME} -p ${DOCKER_MYSQL_PORT}:3306 -e MYSQL_ROOT_PASSWORD=${DOCKER_MYSQL_PASSWORD} -d mysql:${DOCKER_MYSQL_VERSION}

Podéis llamarme el parametrizador, lo tengo todo con variables en mi script de generación y lanzamiento.

Considero importante el parámetro –name, que me permitirá enlazar, las imágenes, si lo necesitará. Por ejemplo, si luego lanzo una aplicación y necesito consumir desde ese nuevo contenedor, mysql, lo más fácil es crear un link, mediante el nombre –link ${DOCKER_IMAGE_NAME}.

El parámetro -p nos ayuda a “redirigir/exponer”, el puerto al anfitrión, por si necesitamos acceder.

Ahora toca a las variables de entorno -e MYSQL_ROOT_PASSWORD=${DOCKER_MYSQL_PASSWORD}, según la documentación de mysql en docker hub, estableciendo la variable de entorno MYSQL_ROOT_PASSWORD, podemos definir el password

COPIANDO EL ESQUEMA

Se paro la importación de los datos, en dos, el esquema y luego los datos, porque quiero todo el esquema, pero quizás no todos los datos, por si hay de sensibles o datos que no queremos.

mysqldump --user=${FROM_MYSQL_USER} --host=${FROM_MYSQL_HOST} --protocol=tcp --port=3306 --password=${FROM_MYSQL_PASSWORD} --default-character-set=utf8 --no-data "${FROM_MYSQL_SCHEMA}" > schema.sql

Creo que es auto explicativo este comando, lo único relevante es, definir el utf8, sino luego tendremos problemas, en mi caso utf8, en el vuestro, ya sabréis.

mysql --user=root --host=127.0.0.1 --protocol=tcp --port=${DOCKER_MYSQL_PORT} --password=${DOCKER_MYSQL_PASSWORD} -e "create database ${FROM_MYSQL_SCHEMA}"

Con este comando, creo la base de datos

mysql --user=root --host=127.0.0.1 --protocol=tcp --port=${DOCKER_MYSQL_PORT} --password=${DOCKER_MYSQL_PASSWORD} --default-character-set=utf8 ${FROM_MYSQL_SCHEMA} < schema.sql

Este otro, vuelca el esquema en mi nueva y mysql (Docker). Cuando veis FROM, de prefijo, es la base de datos de origen y cuando veis DOCKER es la de destino (Docker).

CREANDO USUARIOS Y OTROS

mysql --user=root --host=127.0.0.1 --protocol=tcp --port=3307 --password=pass -e "CREATE USER 'user'@'%' IDENTIFIED BY '${DOCKER_MYSQL_PASSWORD}'"
mysql --user=root --host=127.0.0.1 --protocol=tcp --port=3307 --password=pass -e "GRANT ALL PRIVILEGES ON * . * TO 'user'@'%'"

Con los comandos anteriores, creo un usuario nuevo llamado user y le doy todos los privilegios. Hay que tener en cuenta en asignarle un host, correcto, en este caso tiro la casa por la ventana y le doy todos %.

EXPORTANDO E IMPORTANDO LOS DATOS

Ahora le tocan a los datos, esta parte, como podéis deducir, tiene mucha carga, pero totalmente asumible.

mysqldump --user=${FROM_MYSQL_USER} --host=${FROM_MYSQL_HOST} --quick --max_allowed_packet=2024M  --protocol=tcp --port=3306 --password=${FROM_MYSQL_PASSWORD} --default-character-set=utf8 --no-create-db --no-create-info ${FROM_MYSQL_SCHEMA}${IGNORE} >> data.sql

Las partes a destacar, serían la parte de ${IGNORE}, en una parte del script, le paso una lista de tablas, que quiero que ignore y luego monto esta variables, de la siguiente manera:

IGNORE=""
IFS=',' read -ra ADDR <<< "$MYSQL_IGNORE_TABLES"
for i in "${ADDR[@]}"; do
    IGNORE+=' --ignore-table '$FROM_MYSQL_SCHEMA.$i
done

El enfoque puede ser al revés, en vez de tablas que ignoras, sólo pasarle las tablas que requieres, en mi caso es mas fácil escluir.

mysql --user=root --host=127.0.0.1 --protocol=tcp --port=${DOCKER_MYSQL_PORT} --password=${DOCKER_MYSQL_PASSWORD} --default-character-set=utf8 ${FROM_MYSQL_SCHEMA} < data.sql

Igual que hicimos con el esquema. ahora toca volcar los datos en nuestro contenedor. Si bien la primera parte ha tardado, esta dependerá de de la CPU de nuestro contenedor.

TABLAS ESTRA

Llegados a este punto, ya tenemos una copia, totalmente funcional de nuestra entorno de PRO/PRE.

Pero que pasa si sólo queremos parte de una tabla en nuestro entorno local ?

mysqldump --user=${FROM_MYSQL_USER} --host=${FROM_MYSQL_HOST} --protocol=tcp --port=3306 --password=${FROM_MYSQL_PASSWORD} --default-character-set=utf8 ${FROM_MYSQL_SCHEMA} USER --where='email like "%paco%"' > member.sql

El comando anterior, hace un dump, de una tabla pasada “USER”, aplicándole el –where

mysql --user=root --host=127.0.0.1 --protocol=tcp --port=${DOCKER_MYSQL_PORT} --password=${DOCKER_MYSQL_PASSWORD} --default-character-set=utf8 ${FROM_MYSQL_SCHEMA} < member.sql

Y para terminar, limpiamos los archivos generados

rm -f schema.sql
rm -f data.sql
rm -f member.sql

Es una primera versión de mi fabuloso script, pero espero que os guste. Aún requiere modificaciones y que sea adaptable para varios esquemas, multiple images, etc.. Pero es un buen punto de partida

#!/bin/bash

startProcess=`date +%s`
export PATH=$PATH:/usr/local/opt/mysql@5.7/bin

while getopts u:p:P:s:t:H:U:W:S: option; do
case "${option}" in
u) DBUSER=${OPTARG};;
p) DBPASSWORD=${OPTARG};;
P) DBPORT=${OPTARG};;
s) DBSCHEMA=${OPTARG};;
t) IGNORETABLES=${OPTARG};;
H) FROMDBHOST=${OPTARG};;
U) FROMDBUSER=${OPTARG};;
W) FROMDBPASSWORD=${OPTARG};;
S) FROMSBSCHEMA=${OPTARG};;
esac
done

declare -r DOCKER_IMAGE_NAME="develop-mysql"
declare -r DOCKER_MYSQL_VERSION="5.7"
declare -r DOCKER_MYSQL_PASSWORD=${DBPASSWORD:-pass}
declare -r DOCKER_MYSQL_PORT=${DBPORT:-3307}
declare -r MYSQL_IGNORE_TABLES=${IGNORETABLES=Tabla1,Tabla2,Tabla3}

declare -r FROM_MYSQL_HOST=${FROMDBHOST=mysql-pre-host}
declare -r FROM_MYSQL_USER=${FROMDBUSER=preuser}
declare -r FROM_MYSQL_PASSWORD=${FROMDBPASSWORD=passwordpre}
declare -r FROM_MYSQL_SCHEMA=${FROMSBSCHEMA=blog}

startDocker=`date +%s`
declare -r EXISTING_CONTAINER_WITH_NAME=$(docker ps -a --filter "name=^/${DOCKER_IMAGE_NAME}$" -q)
if [ ! -z "$EXISTING_CONTAINER_WITH_NAME" ]
then
echo [$(date +%d/%m/%YT%H:%M:%S)] Image with name ${DOCKER_IMAGE_NAME} and id ${EXISTING_CONTAINER_WITH_NAME} exist in local hub
echo [$(date +%d/%m/%YT%H:%M:%S)] - Stopping container
docker stop ${EXISTING_CONTAINER_WITH_NAME}
echo [$(date +%d/%m/%YT%H:%M:%S)] - Removing container
docker rm ${EXISTING_CONTAINER_WITH_NAME}
fi

declare -r EXISTING_CONTAINER_PORT=$(docker ps -a --filter "name=^/${DOCKER_IMAGE_NAME}$" --filter expose=${DOCKER_MYSQL_PORT} -q)
if [ ! -z "$EXISTING_CONTAINER_PORT" ]
then
echo [$(date +%d/%m/%YT%H:%M:%S)] Image with name ${DOCKER_IMAGE_NAME}, port ${DOCKER_MYSQL_PORT} and id ${EXISTING_CONTAINER_PORT} exist in local hub
echo [$(date +%d/%m/%YT%H:%M:%S)] - Stopping container
docker stop ${EXISTING_CONTAINER_PORT}
echo [$(date +%d/%m/%YT%H:%M:%S)] - Removing container
docker rm ${EXISTING_CONTAINER_PORT}
fi

echo [$(date +%d/%m/%YT%H:%M:%S)] Run docker images with name ${DOCKER_IMAGE_NAME} exposed port ${DOCKER_MYSQL_PORT}
docker run --name ${DOCKER_IMAGE_NAME} -p ${DOCKER_MYSQL_PORT}:3306 -e MYSQL_ROOT_PASSWORD=${DOCKER_MYSQL_PASSWORD} -d mysql:${DOCKER_MYSQL_VERSION}
endDocker=`date +%s`
echo [$(date +%d/%m/%YT%H:%M:%S)] Time to create container $((endDocker-startDocker))s

IGNORE=""
IFS=',' read -ra ADDR <<< "$MYSQL_IGNORE_TABLES"
for i in "${ADDR[@]}"; do
IGNORE+=' --ignore-table '$FROM_MYSQL_SCHEMA.$i
done

startSchema=`date +%s`
echo [$(date +%d/%m/%YT%H:%M:%S)] Dump schema from host ${FROM_MYSQL_HOST} schema ${FROM_MYSQL_SCHEMA}
mysqldump --user=${FROM_MYSQL_USER} --host=${FROM_MYSQL_HOST} --protocol=tcp --port=3306 --password=${FROM_MYSQL_PASSWORD} --default-character-set=utf8 --no-data "${FROM_MYSQL_SCHEMA}" > schema.sql
endSchema=`date +%s`
echo [$(date +%d/%m/%YT%H:%M:%S)] Time to export schema $((endSchema-startSchema))s

echo Add user
mysql --user=root --host=127.0.0.1 --protocol=tcp --port=3307 --password=pass -e "CREATE USER 'user'@'%' IDENTIFIED BY '${DOCKER_MYSQL_PASSWORD}'"
mysql --user=root --host=127.0.0.1 --protocol=tcp --port=3307 --password=pass -e "GRANT ALL PRIVILEGES ON * . * TO 'user'@'%'"

startImportSchema=`date +%s`
echo [$(date +%d/%m/%YT%H:%M:%S)] Create database in docker ${FROM_MYSQL_SCHEMA}
mysql --user=root --host=127.0.0.1 --protocol=tcp --port=${DOCKER_MYSQL_PORT} --password=${DOCKER_MYSQL_PASSWORD} -e "create database ${FROM_MYSQL_SCHEMA}"

echo [$(date +%d/%m/%YT%H:%M:%S)] Import schema into docker
mysql --user=root --host=127.0.0.1 --protocol=tcp --port=${DOCKER_MYSQL_PORT} --password=${DOCKER_MYSQL_PASSWORD} --default-character-set=utf8 ${FROM_MYSQL_SCHEMA} < schema.sql
endImportSchema=`date +%s`
echo [$(date +%d/%m/%YT%H:%M:%S)] Time to import schema $((endImportSchema-startImportSchema))s

startData=`date +%s`
echo [$(date +%d/%m/%YT%H:%M:%S)] Dump data from host ${FROM_MYSQL_HOST} schema ${FROM_MYSQL_SCHEMA}
mysqldump --user=${FROM_MYSQL_USER} --host=${FROM_MYSQL_HOST} --quick --max_allowed_packet=2024M --protocol=tcp --port=3306 --password=${FROM_MYSQL_PASSWORD} --default-character-set=utf8 --no-create-db --no-create-info ${FROM_MYSQL_SCHEMA}${IGNORE} >> data.sql
endData=`date +%s`
echo [$(date +%d/%m/%YT%H:%M:%S)] Time to export data $(((endData-startData)/60))m

startImportData=`date +%s`
echo [$(date +%d/%m/%YT%H:%M:%S)] Import data into docker
mysql --user=root --host=127.0.0.1 --protocol=tcp --port=${DOCKER_MYSQL_PORT} --password=${DOCKER_MYSQL_PASSWORD} --default-character-set=utf8 ${FROM_MYSQL_SCHEMA} < data.sql
endImportData=`date +%s`
echo [$(date +%d/%m/%YT%H:%M:%S)] Time to import data $(((endImportData-startImportData)/60))m

startMember=`date +%s`
echo [$(date +%d/%m/%YT%H:%M:%S)] Dump members
mysqldump --user=${FROM_MYSQL_USER} --host=${FROM_MYSQL_HOST} --protocol=tcp --port=3306 --password=${FROM_MYSQL_PASSWORD} --default-character-set=utf8 ${FROM_MYSQL_SCHEMA} Member --where='email like "%paco%"' > member.sql

echo [$(date +%d/%m/%YT%H:%M:%S)] Import members into docker
mysql --user=root --host=127.0.0.1 --protocol=tcp --port=${DOCKER_MYSQL_PORT} --password=${DOCKER_MYSQL_PASSWORD} --default-character-set=utf8 ${FROM_MYSQL_SCHEMA} < member.sql
endMember=`date +%s`
echo [$(date +%d/%m/%YT%H:%M:%S)] Time to import member $((endMember-startMember))s

echo [$(date +%d/%m/%YT%H:%M:%S)] Remove sql used files
rm -f schema.sql
rm -f data.sql
rm -f member.sql
endProcess=`date +%s`

echo [$(date +%d/%m/%YT%H:%M:%S)] Total time $(((endProcess-startProcess)/60))m

echo DOCKER MYSQL CONNECTION
echo [HOST]: 127.0.0.1 / localhost
echo [PORT] ${DOCKER_MYSQL_PORT}
echo [PASSWORD] ${DOCKER_MYSQL_PASSWORD}
echo [DB] ${FROM_MYSQL_SCHEMA}

Deja una respuesta

A %d blogueros les gusta esto: