web-dev-qa-db-fra.com

Comment initialiser une base de données MySQL avec un schéma dans un conteneur Docker?

J'essaie de créer un conteneur avec une base de données MySQL et d'ajouter un schéma à ces bases de données.

Mon Dockerfile actuel est:

FROM mysql
MAINTAINER  (me) <email>

# Copy the database schema to the /data directory
COPY files/epcis_schema.sql /data/epcis_schema.sql

# Change the working directory
WORKDIR data

CMD mysql -u $MYSQL_USER -p $MYSQL_PASSWORD $MYSQL_DATABASE < epcis_schema.sql

Afin de créer le conteneur, je suis la documentation fournie sur Docker et j'exécute cette commande:

docker run --name ${CONTAINER_NAME} -e MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD} -e MYSQL_USER=${DB_USER} -e MYSQL_PASSWORD=${DB_USER_PASSWORD} -e MYSQL_DATABASE=${DB_NAME} -d mvpgomes/epcisdb

Mais lorsque j'exécute cette commande, le conteneur n'est pas créé et, dans l'état du conteneur, il est possible de voir que le CMD n'a pas été exécuté avec succès. En fait, seule la commande mysql est exécutée.

Quoi qu'il en soit, existe-t-il un moyen d'initialiser la base de données avec le schéma ou dois-je effectuer ces opérations manuellement?

131
Marcus Gomes

Je suis désolé pour cette très longue réponse, mais vous avez un petit chemin à parcourir pour arriver où vous voulez. Je dirai que, normalement, vous ne placeriez pas le stockage de la base de données dans le même conteneur que la base de données elle-même, vous monteriez un volume d'hôte de manière à ce que les données persistent sur l'hôte docker, ou peut-être qu'un conteneur pourrait être utilisé pour contenir les données (/ var/lib/mysql). De plus, je suis nouveau sur mysql, donc, cela n’est peut-être pas très efficace. Cela dit...

Je pense qu'il peut y avoir quelques problèmes ici. Le fichier Docker est utilisé pour créer une image. Vous devez exécuter l'étape de construction. Au minimum, à partir du répertoire contenant le fichier Dockerfile, vous feriez quelque chose comme:

docker build .

Le fichier de docker décrit l'image à créer. Je ne connais pas grand chose à propos de mysql (je suis un fanboy postgres), mais, j’ai fait une recherche dans les interwebs pour savoir comment initialiser un conteneur mysql docker. J'ai d'abord créé un nouveau répertoire dans lequel travailler, je l'ai appelé mdir, puis j'ai créé un répertoire de fichiers dans lequel j'ai déposé un fichier epcis_schema.sql qui crée une base de données et une seule table:

create database test;
use test;

CREATE TABLE testtab
(
id INTEGER AUTO_INCREMENT,
name TEXT,
PRIMARY KEY (id)
) COMMENT='this is my test table';

Ensuite, j'ai créé un script appelé init_db dans le répertoire files:

#!/bin/bash

# Initialize MySQL database.
# ADD this file into the container via Dockerfile.
# Assuming you specify a VOLUME ["/var/lib/mysql"] or `-v /var/lib/mysql` on the `docker run` command…
# Once built, do e.g. `docker run your_image /path/to/docker-mysql-initialize.sh`
# Again, make sure MySQL is persisting data outside the container for this to have any effect.

set -e
set -x

mysql_install_db

# Start the MySQL daemon in the background.
/usr/sbin/mysqld &
mysql_pid=$!

until mysqladmin ping >/dev/null 2>&1; do
  echo -n "."; sleep 0.2
done

# Permit root login without password from outside container.
mysql -e "GRANT ALL ON *.* TO root@'%' IDENTIFIED BY '' WITH GRANT OPTION"

# create the default database from the ADDed file.
mysql < /tmp/epcis_schema.sql

# Tell the MySQL daemon to shutdown.
mysqladmin shutdown

# Wait for the MySQL daemon to exit.
wait $mysql_pid

# create a tar file with the database as it currently exists
tar czvf default_mysql.tar.gz /var/lib/mysql

# the tarfile contains the initialized state of the database.
# when the container is started, if the database is empty (/var/lib/mysql)
# then it is unpacked from default_mysql.tar.gz from
# the ENTRYPOINT /tmp/run_db script

(la majeure partie de ce script a été levée à partir d'ici: https://Gist.github.com/pda/969752 )

Voici le script files/run_db que j'ai créé:

# start db

set -e
set -x

# first, if the /var/lib/mysql directory is empty, unpack it from our predefined db
[ "$(ls -A /var/lib/mysql)" ] && echo "Running with existing database in /var/lib/mysql" || ( echo 'Populate initial db'; tar xpzvf default_mysql.tar.gz )

/usr/sbin/mysqld

Enfin, le fichier Docker pour tous les lier:

FROM mysql
MAINTAINER  (me) <email>

# Copy the database schema to the /data directory
ADD files/run_db files/init_db files/epcis_schema.sql /tmp/

# init_db will create the default
# database from epcis_schema.sql, then
# stop mysqld, and finally copy the /var/lib/mysql directory
# to default_mysql_db.tar.gz
RUN /tmp/init_db

# run_db starts mysqld, but first it checks
# to see if the /var/lib/mysql directory is empty, if
# it is it is seeded with default_mysql_db.tar.gz before
# the mysql is fired up

ENTRYPOINT "/tmp/run_db"

Je me suis donc rendu dans mon répertoire mdir (qui contient le fichier Docker avec le répertoire files). Je lance alors la commande:

docker build --no-cache .

Vous devriez voir la sortie comme ceci:

Sending build context to Docker daemon 7.168 kB
Sending build context to Docker daemon 
Step 0 : FROM mysql
 ---> 461d07d927e6
Step 1 : MAINTAINER (me) <email>
 ---> Running in 963e8de55299
 ---> 2fd67c825c34
Removing intermediate container 963e8de55299
Step 2 : ADD files/run_db files/init_db files/epcis_schema.sql /tmp/
 ---> 81871189374b
Removing intermediate container 3221afd8695a
Step 3 : RUN /tmp/init_db
 ---> Running in 8dbdf74b2a79
+ mysql_install_db
2015-03-19 16:40:39 12 [Note] InnoDB: Using atomics to ref count buffer pool pages
...
/var/lib/mysql/ib_logfile0
 ---> 885ec2f1a7d5
Removing intermediate container 8dbdf74b2a79
Step 4 : ENTRYPOINT "/tmp/run_db"
 ---> Running in 717ed52ba665
 ---> 7f6d5215fe8d
Removing intermediate container 717ed52ba665
Successfully built 7f6d5215fe8d

Vous avez maintenant une image '7f6d5215fe8d'. Je pourrais lancer cette image:

docker run -d 7f6d5215fe8d

et l'image commence, je vois une chaîne d'instance:

4b377ac7397ff5880bc9218abe6d7eadd49505d50efb5063d6fab796ee157bd3

Je pourrais alors "l'arrêter" et le redémarrer.

docker stop 4b377
docker start 4b377

Si vous regardez les journaux, la première ligne contiendra:

docker logs 4b377

Populate initial db
var/lib/mysql/
...

Puis, à la fin des logs:

Running with existing database in /var/lib/mysql

Ce sont les messages du script/tmp/run_db, le premier indique que la base de données a été décompressée de la version enregistrée (initiale), le second indique que la base de données était déjà présente, la copie existante a donc été utilisée.

Voici un ls -lR de la structure de répertoire que je décris ci-dessus. Notez que init_db et run_db sont des scripts avec le bit d'exécution défini:

gregs-air:~ gfausak$ ls -Rl mdir
total 8
-rw-r--r--  1 gfausak  wheel  534 Mar 19 11:13 Dockerfile
drwxr-xr-x  5 gfausak  staff  170 Mar 19 11:24 files

mdir/files:
total 24
-rw-r--r--  1 gfausak  staff   126 Mar 19 11:14 epcis_schema.sql
-rwxr-xr-x  1 gfausak  staff  1226 Mar 19 11:16 init_db
-rwxr-xr-x  1 gfausak  staff   284 Mar 19 11:23 run_db
86
Greg

Je rencontrais le même problème pour lequel je voulais initialiser le schéma de mon instance MySQL Docker, mais j’ai eu du mal à le faire fonctionner après avoir fait quelques recherches sur Google et suivi les exemples d’autres. Voici comment je l'ai résolu.

1) Videz votre schéma MySQL dans un fichier.

mysqldump -h <your_mysql_Host> -u <user_name> -p --no-data <schema_name> > schema.sql

2) Utilisez la commande ADD pour ajouter votre fichier de schéma au répertoire /docker-entrypoint-initdb.d du conteneur Docker. Le fichier docker-entrypoint.sh exécutera tous les fichiers de ce répertoire se terminant par ".sql" sur la base de données MySQL.

Dockerfile:

FROM mysql:5.7.15

MAINTAINER me

ENV MYSQL_DATABASE=<schema_name> \
    MYSQL_ROOT_PASSWORD=<password>

ADD schema.sql /docker-entrypoint-initdb.d

EXPOSE 3306

3) Démarrez l’instance Docker MySQL.

docker-compose build
docker-compose up

Merci à Configuration de MySQL et importation de dump dans Dockerfile pour m'avoir informé du docker-entrypoint.sh et du fait qu’il exécute des scripts SQL et Shell!

96
Brett Cooper

Une autre manière basée sur une fusion de plusieurs réponses ici auparavant:

docker-composer le fichier:

version: "3"
services:
    db:
      container_name: db
      image: mysql
      ports:
       - "3306:3306"  
      environment:
         - MYSQL_ROOT_PASSWORD=mysql
         - MYSQL_DATABASE=db

      volumes:
         - /home/user/db/mysql/data:/var/lib/mysql
         - /home/user/db/mysql/init:/docker-entrypoint-initdb.d/:ro

/home/user .. est un dossier partagé sur l'hôte

Et dans le dossier /home/user/db/mysql/init .. déposez simplement un fichier SQL, avec n'importe quel nom, par exemple init.sql contenant:

CREATE DATABASE mydb;
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'%' IDENTIFIED BY 'mysql';
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'localhost' IDENTIFIED BY 'mysql';
USE mydb
CREATE TABLE CONTACTS (
    [ ... ]
);
INSERT INTO CONTACTS VALUES ...
[ ... ]

Selon le documentation officielle de MySQL , vous pouvez mettre plusieurs fichiers SQL dans le docker-entrypoint-initdb.d, ils sont exécutés dans l'ordre alphabétique.

31
phico

J'ai essayé la réponse de Greg avec un succès nul, j'ai dû faire quelque chose de mal car ma base de données ne contenait aucune donnée après toutes les étapes: j'utilisais la dernière image de MariaDB, juste au cas où.

Ensuite, j'ai décidé de lire le point d’entrée du fichier officiel image MariaDB et de l’utiliser pour générer un fichier simple docker-compose :

database:
  image: mariadb
  ports:
     - 3306:3306
  expose:
     - 3306
  volumes:
     - ./docker/mariadb/data:/var/lib/mysql:rw
     - ./database/schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro
  environment:
     MYSQL_ALLOW_EMPTY_PASSWORD: "yes"

Je peux maintenant conserver mes données ET générer une base de données avec mon propre schéma!

24
mrArias

L'autre façon simple, utilisez docker-compose avec les lignes suivantes:

mysql:
  from: mysql:5.7
  volumes:
    - ./database:/tmp/database
  command: mysqld --init-file="/tmp/database/install_db.sql"

Placez votre schéma de base de données dans ./database/install_db.sql. Chaque fois que vous construisez votre conteneur, le fichier install_db.sql est exécuté.

20
Balázs Zámbó

Après le 4 août 2015, si vous utilisez l'image officielle de Docker mysql, vous pouvez simplement ajouter/copier un fichier dans le répertoire /docker-entrypoint-initdb.d/ et il sera exécuté avec le conteneur initialisé. Voir github: https://github.com/docker-library/mysql/commit/14f165596ea8808dfeb2131f092aabe61c967225 si vous souhaitez l'implémenter sur d'autres images de conteneur

18
JDWatkins

La solution la plus simple consiste à utiliser tutum/mysql

Étape 1

docker pull tutum/mysql:5.5

Étape 2

docker run -d -p 3306:3306 -v /tmp:/tmp  -e STARTUP_SQL="/tmp/to_be_imported.mysql" tutum/mysql:5.5

Étape 3

Passez au-dessus de CONTAINER_ID, puis exécutez la commande docker logs pour afficher les informations de mot de passe générées.

docker logs #<CONTAINER_ID>
11
mainframer

Pour ceux qui ne veulent pas créer un script de point d’entrée comme moi, vous pouvez réellement démarrer mysqld au moment de la compilation, puis exécuter les commandes mysql dans votre fichier Docker comme suit:

RUN mysqld_safe & until mysqladmin ping; do sleep 1; done && \
    mysql -uroot -e "CREATE DATABASE somedb;" && \
    mysql -uroot -e "CREATE USER 'someuser'@'localhost' IDENTIFIED BY 'somepassword';" && \
    mysql -uroot -e "GRANT ALL PRIVILEGES ON somedb.* TO 'someuser'@'localhost';"

La clé ici est d’envoyer mysqld_safe en tâche de fond avec le signe unique &.

3
roothahn

Ci-dessous, le fichier Docker que j'ai utilisé avec succès pour installer xampp, créer un MariaDB avec un schéma et pré-renseigné avec les informations utilisées sur le serveur local (usrs, commandes de photos, etc.).

FROM ubuntu:14.04

COPY Ecommerce.sql /root

RUN apt-get update \
 && apt-get install wget -yq \
 && apt-get install nano \
 && wget https://www.apachefriends.org/xampp-files/7.1.11/xampp-linux-x64-7.1.11-0-installer.run \
 && mv xampp-linux-x64-7.1.11-0-installer.run /opt/ \
 && cd /opt/ \
 && chmod +x xampp-linux-x64-7.1.11-0-installer.run \
 && printf 'y\n\y\n\r\n\y\n\r\n' | ./xampp-linux-x64-7.1.11-0-installer.run \
 && cd /opt/lampp/bin \
 && /opt/lampp/lampp start \
 && sleep 5s \

 && ./mysql -uroot -e "CREATE DATABASE Ecommerce" \
 && ./mysql -uroot -D Ecommerce < /root/Ecommerce.sql \
 && cd / \
 && /opt/lampp/lampp reload \
 && mkdir opt/lampp/htdocs/Ecommerce

COPY /Ecommerce /opt/lampp/htdocs/Ecommerce

EXPOSE 80
1
Paddy Popeye

Après avoir un peu lutté avec cela, jetez un coup d’œil au fichier Docker en utilisant des volumes nommés (db-data). Il est important de déclarer un plus dans la dernière partie, où j'ai mentionné que le volume est [external]

Tout a bien fonctionné de cette façon!

version: "3"

services:

  database:
    image: mysql:5.7
    container_name: mysql
    ports:
      - "3306:3306"
    volumes:
      - db-data:/docker-entrypoint-initdb.d
    environment:
      - MYSQL_DATABASE=sample
      - MYSQL_ROOT_PASSWORD=root

volumes:
  db-data:
    external: true
0
allysson vieira