Come posso inizializzare un database MySQL con schema in un contenitore Docker?


165

Sto cercando di creare un contenitore con un database MySQL e aggiungere uno schema a questi database.

Il mio Dockerfile attuale è:

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

Per creare il contenitore sto seguendo la documentazione fornita su Docker ed eseguendo questo comando:

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

Ma quando eseguo questo comando il contenitore non viene creato e nello stato Contenitore è possibile vedere che il CMD non è stato eseguito correttamente, infatti mysqlviene eseguito solo il comando.

Ad ogni modo, c'è un modo per inizializzare il database con lo schema o devo eseguire queste operazioni manualmente?


presumo che tu voglia creare una nuova immagine con un database seminato e pronto per partire?
Greg

Sì, è esattamente quello che voglio fare.
Marcus Gomes,


Spiegato anche qui: medium.com/@lvthillo/…
lvthillo

Risposte:


105

Mi dispiace per questa risposta lunghissima, ma hai un po 'di strada da fare per arrivare dove vuoi. Dirò che normalmente non metteresti la memoria per il database nello stesso contenitore del database stesso, monteresti un volume host in modo che i dati persistano sull'host docker o, forse, un contenitore potrebbe essere usato per contenere i dati (/ var / lib / mysql). Inoltre, sono nuovo di mysql, quindi potrebbe non essere super efficiente. Detto ciò...

Penso che qui potrebbero esserci alcuni problemi. Dockerfile viene utilizzato per creare un'immagine. Devi eseguire il passaggio di compilazione. Come minimo, dalla directory che contiene il Dockerfile dovresti fare qualcosa del tipo:

docker build .

Il Dockerfile descrive l'immagine da creare. Non so molto di mysql (sono un fan di Postgres), ma ho fatto una ricerca tra le interwebs per "come inizializzare un contenitore docker mysql". Prima ho creato una nuova directory su cui lavorare, l'ho chiamata mdir, quindi ho creato una directory di file in cui ho depositato un file epcis_schema.sql che crea un database e una singola tabella:

create database test;
use test;

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

Quindi ho creato uno script chiamato init_db nella directory dei file:

#!/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 maggior parte di questo script è stata sollevata da qui: https://gist.github.com/pda/9697520 )

Ecco lo script files / run_db che ho creato:

# 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

Infine, Dockerfile per legarli tutti:

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"

Quindi, ho inserito nella mia directory mdir (che ha il Dockerfile insieme alla directory dei file). Quindi eseguo il comando:

docker build --no-cache .

Dovresti vedere un output in questo modo:

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

Ora hai un'immagine '7f6d5215fe8d'. Potrei eseguire questa immagine:

docker run -d 7f6d5215fe8d

e l'immagine inizia, vedo una stringa di istanza:

4b377ac7397ff5880bc9218abe6d7eadd49505d50efb5063d6fab796ee157bd3

Potrei quindi 'fermarlo' e riavviarlo.

docker stop 4b377
docker start 4b377

Se guardi i registri, la prima riga conterrà:

docker logs 4b377

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

Quindi, alla fine dei registri:

Running with existing database in /var/lib/mysql

Questi sono i messaggi dallo script / tmp / run_db, il primo indica che il database è stato decompresso dalla versione salvata (iniziale), il secondo indica che il database era già lì, quindi è stata utilizzata la copia esistente.

Ecco una ls -lR della struttura di directory che descrivo sopra. Si noti che init_db e run_db sono script con il bit di esecuzione impostato:

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

3
Ehi Gary, grazie innanzitutto per l'aiuto. Ho seguito le tue istruzioni, ma quando eseguo la finestra mobile build --no-cache. , Ho un errore di autorizzazione per lo init_dbscript.
Marcus Gomes,

Ho già provato a risolverlo dando le autorizzazioni nel RUNcomando e il problema è apparentemente risolto. Ma poi quando eseguo docker runho lo stesso problema con lo run_dbscript.
Marcus Gomes,

1
init_db e run_db devono avere l'autorizzazione 0755 (sono script, devono avere il bit di esecuzione impostato. Esegui un chmod + x init_db run_db
Greg

Ho aggiornato la risposta con un elenco di directory che mostra le autorizzazioni su ciascuno dei file. Nota: chmod + x files / * _ db realizzerà le autorizzazioni necessarie.
Greg

2
@Greg Ho provato i passaggi precedenti ma sto ricevendo un errore ([ERRORE] Errore irreversibile: leggere la sezione "Sicurezza" del manuale per scoprire come eseguire mysqld come root!). Eventuali suggerimenti ?
Binish John,

121

Ho avuto lo stesso problema in cui volevo inizializzare lo schema della mia istanza di MySQL Docker, ma ho avuto difficoltà a farlo funzionare dopo aver fatto alcuni googling e seguendo gli esempi di altri. Ecco come l'ho risolto.

1) Scarica il tuo schema MySQL in un file.

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

2) Utilizzare il comando ADD per aggiungere il file dello schema alla /docker-entrypoint-initdb.ddirectory nel contenitore Docker. Il docker-entrypoint.shfile eseguirà tutti i file in questa directory che terminano con".sql" il database 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) Avvia l'istanza Docker MySQL.

docker-compose build
docker-compose up

Grazie alla configurazione di MySQL e all'importazione del dump all'interno di Dockerfile per avermi informato su docker-entrypoint.sh e sul fatto che esegue sia script SQL che shell!


2
Questa è sicuramente la risposta migliore. Copiare DDL e script di inizializzazione nella directory /docker-entrypoint-initdb.d è ciò che i documenti dockerhub mysql dicono di fare con queste cose.
Chacewells,

2
Cosa succede quando qualcosa cambia schema.sql? Voglio che il mio db venga aggiornato di conseguenza. Inoltre cosa succede quando creo questo contenitore la seconda volta? Db verrà distrutto e creato di nuovo?
Goga Koreli,

1
@Goga Koreli Docker esegue questo comando init solo se non è presente alcuna voce di dati in / var / lib / mysql
medTech

38

Un altro modo basato su una fusione di risposte server qui prima:

Docker-compose file:

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

dove /home/user .. è una cartella condivisa sull'host

E nella /home/user/db/mysql/initcartella .. basta rilasciare un file sql, con qualsiasi nome, ad esempio init.sqlcontenente:

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 ...
[ ... ]

Secondo la documentazione ufficiale di mysql , è possibile inserire più di un file sql in docker-entrypoint-initdb.d, vengono eseguiti in ordine alfabetico


28

L'altro modo semplice, utilizzare docker-compose con le seguenti righe:

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

Inserire lo schema del database in ./database/install_db.sql. Ogni volta che si crea il contenitore, verrà eseguito install_db.sql.


26

Ho provato la risposta di Greg senza successo, devo aver fatto qualcosa di sbagliato dal momento che il mio database non aveva dati dopo tutti i passaggi: stavo usando l'ultima immagine di MariaDB, per ogni evenienza.

Quindi ho deciso di leggere il punto di accesso per l' immagine MariaDB ufficiale e l'ho usato per generare un semplice file di composizione docker :

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"

Ora sono in grado di conservare i miei dati e generare un database con il mio schema!


1
Ciao, sto provando anche a fare lo stesso, ma lo script non viene mai eseguito. C'è qualche altro parametro che deve essere fornito? Ho appena aggiunto questo volume per mariadb - ./database/schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro. Grazie
bilak

Nota: lo script verrà eseguito una sola volta, durante l'inizializzazione del contenitore. Se in seguito aggiungi un nuovo script, questo non verrà eseguito.
ALex_hha,

23

Dopo il 4 agosto 2015, se stai usando l'immagine mysql Docker ufficiale, puoi semplicemente AGGIUNGERE / COPIARE un file nella directory /docker-entrypoint-initdb.d/ e verrà eseguito con il contenitore inizializzato. Vedi github: https://github.com/docker-library/mysql/commit/14f165596ea8808dfeb2131f092aabe61c967225 se si desidera implementarlo su altre immagini del contenitore


1
Questa è la risposta corretta per le versioni correnti dell'immagine MSQL Docker ufficiale.
NaN,

11

La soluzione più semplice è usare tutum / mysql

Passo 1

docker pull tutum/mysql:5.5

Passo 2

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

Fase 3

Supera CONTAINER_ID e quindi esegui il comando docker logsper visualizzare le informazioni sulla password generata.

docker logs #<CONTAINER_ID>

Hai ottenuto questo per eseguire correttamente? Ho avuto a che fare con tutum / mysql per settimane senza successo.
Iammesol,

2
Sì. Io uso tutum/mysql:5.5ed è successo. docker run -d -p 3306:3306 -v /tmp:/tmp -e MYSQL_PASS="admin" -e STARTUP_SQL="/tmp/mysqldump.mysql" tutum/mysql:5.5. Puoi sempre eseguire il comando docker logs CONTAINER_IDper visualizzare i messaggi di errore se hai riscontrato problemi.
mainframer

non riesco a capire da dove /tmp/to_be_imported.mysqlprovenga il percorso . è un percorso sul sistema operativo host? dove è un COPYo ADDper mettere le cose sul filesystem del contenitore?
Randy L

@ the0ther non è necessario COPY/ ADDperché la directory host / tmp è montata su / tmp del contenitore. Guarda da vicino il comando c'è la parte -v /tmp:/tmp. Personalmente non monterei un volume semplicemente per rendere il file disponibile nel contenitore ma immagino che sia una scelta personale.
Willa,

1
Per essere onesti, non dovresti usare immagini non ufficiali, a meno che tu non voglia che ciò accada di nuovo.
Dragas,

3

Per quelli che non vogliono creare uno script entrypoint come me, in realtà puoi avviare mysqld al momento della compilazione e quindi eseguire i comandi mysql nel tuo Dockerfile in questo modo:

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 chiave qui è inviare mysqld_safe in background con il singolo &segno.


1

Di seguito è riportato il Dockerfile che ho usato con successo per installare xampp, creare un MariaDB con schema e pre-popolato con le informazioni utilizzate sul server locale (usrs, ordini di foto, ecc.)

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

0

Dopo aver lottato un po 'con quello, dai un'occhiata al Dockerfile usando i volumi con nome (db-data). È importante dichiarare un plus nella parte finale, dove ho detto che il volume è[external]

Tutto ha funzionato alla grande in questo modo!

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.