Configurazione di MySQL e importazione di dump in Dockerfile


127

Sto cercando di impostare un Dockerfile per il mio progetto LAMP, ma ho alcuni problemi all'avvio di MySQL. Ho le seguenti righe sul mio Dockerfile:

VOLUME ["/etc/mysql", "/var/lib/mysql"]
ADD dump.sql /tmp/dump.sql
RUN /usr/bin/mysqld_safe & sleep 5s
RUN mysql -u root -e "CREATE DATABASE mydb"
RUN mysql -u root mydb < /tmp/dump.sql

Ma continuo a ricevere questo errore:

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (111)

Qualche idea su come impostare la creazione del database e l'importazione del dump durante una build Dockerfile?


Ciò è dovuto al fatto che ogni RUNcomando viene eseguito in un contenitore diverso. E 'ben spiegata qui: stackoverflow.com/questions/17891669/...
Kuhess

Questo spiega solo che i comandi RUN hanno contesti diversi. Ma dipendo da un demone, non dal contesto.
Vinnylinux

1
Sì, ma questo spiega perché non puoi connetterti a MySQL. È perché funziona solo nella prima RUNriga.
Kuhess

Per eseguire le istruzioni SQL, è necessario avviare MySQL e utilizzare il client MySQL nello stesso contenitore: uno RUNcon diversi passaggi. È possibile trovare un esempio con un impianto multi-step di un programma potrai: stackoverflow.com/questions/25899912/install-nvm-in-docker/...
Kuhess

Puoi anche dare un'occhiata al servizio con docker-compose: docs.docker.com/compose/wordpress/#build-the-project con questo, mysql può essere allegato alla tua app
aurny2420289

Risposte:


121

Ogni RUNistruzione in a Dockerfileviene eseguita in un livello diverso (come spiegato nella documentazione diRUN ).

Nel tuo Dockerfile, hai tre RUNistruzioni. Il problema è che il server MySQL viene avviato solo nel primo. Negli altri, nessun MySQL è in esecuzione, ecco perché ricevi il tuo errore di connessione con il mysqlclient.

Per risolvere questo problema hai 2 soluzioni.

Soluzione 1: usa una riga RUN

RUN /bin/bash -c "/usr/bin/mysqld_safe --skip-grant-tables &" && \
  sleep 5 && \
  mysql -u root -e "CREATE DATABASE mydb" && \
  mysql -u root mydb < /tmp/dump.sql

Soluzione 2: usa uno script

Crea uno script eseguibile init_db.sh:

#!/bin/bash
/usr/bin/mysqld_safe --skip-grant-tables &
sleep 5
mysql -u root -e "CREATE DATABASE mydb"
mysql -u root mydb < /tmp/dump.sql

Aggiungi queste righe a Dockerfile:

ADD init_db.sh /tmp/init_db.sh
RUN /tmp/init_db.sh

Hai idea di come posso mantenere queste informazioni? I database e le tabelle che sto creando sulla build Dockerfile non sono disponibili quando eseguo cose sui contenitori. :(
vinnylinux

1
Dipende da cosa intendi per persistere. Se si desidera che i dati siano persistenti in diverse docker runesecuzioni, è necessario montare i volumi. Se vuoi solo avere un contenitore con il tuo dump, ma non vuoi persistere ulteriori modifiche, puoi sbarazzarti delle VOLUMEistruzioni nel tuo file Dockerfile.
Kuhess

16
Ottengo ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)quando provo la soluzione 1. Seguendo i registri mysqld_safe Starting mysqld daemon with databases from /var/lib/mysqlemysqld_safe mysqld from pid file /var/run/mysqld/mysqld.pid ended
Vituel

1
Trovo che sia molto meglio avere un controllo dello script all'avvio per vedere se mysql ha creato un database. In caso affermativo, lasciarlo in pace, altrimenti eseguire mysql_init_dbe caricare nella struttura del database. Ciò consente la flessibilità di reimpostare automaticamente il database durante il test, ma se si desidera che persista o provi diversi set di dati, è sufficiente montare un volume su / var / lib / mysql utilizzando docker run -v ....
tu-Reinstate Monica-dor duh

1
@trevorgrayson - Neanche questo funziona. Ora dà l'errore ERRORE 2003 (HY000): Impossibile connettersi al server MySQL su '127.0.0.1' (111)
Deep

166

L'ultima versione dell'immagine ufficiale mysql docker consente di importare i dati all'avvio. Ecco il mio docker-compose.yml

data:
  build: docker/data/.
mysql:
  image: mysql
  ports:
    - "3307:3306"
  environment:
    MYSQL_ROOT_PASSWORD: 1234
  volumes:
    - ./docker/data:/docker-entrypoint-initdb.d
  volumes_from:
    - data

Qui, ho il mio data-dump.sql sotto il docker/dataquale è relativo alla cartella da cui è in esecuzione docker-compose. Sto montando quel file sql in questa directory /docker-entrypoint-initdb.dsul contenitore.

Se sei interessato a vedere come funziona, dai un'occhiata al loro docker-entrypoint.shsu GitHub. Hanno aggiunto questo blocco per consentire l'importazione dei dati

    echo
    for f in /docker-entrypoint-initdb.d/*; do
        case "$f" in
            *.sh)  echo "$0: running $f"; . "$f" ;;
            *.sql) echo "$0: running $f"; "${mysql[@]}" < "$f" && echo ;;
            *)     echo "$0: ignoring $f" ;;
        esac
        echo
    done

Una nota aggiuntiva, se vuoi che i dati siano persistenti anche dopo che il contenitore mysql è stato arrestato e rimosso, devi avere un contenitore di dati separato come vedi nel docker-compose.yml. I contenuti del contenitore dati Dockerfile sono molto semplici.

FROM n3ziniuka5/ubuntu-oracle-jdk:14.04-JDK8

VOLUME /var/lib/mysql

CMD ["true"]

Il contenitore di dati non deve nemmeno essere nello stato iniziale per la persistenza.


1
Questa è la risposta migliore IMHO. Permette di NON creare un'immagine da soli. Grazie per questo suggerimento.
Metal3d

5
Una piccola modifica per i volumi: - ./docker/data:/docker-entrypoint-initdb.d—rimosso la .directory del contenitore davanti.
David Sinclair

7
Sebbene questa sia la procedura corretta, non affronta molto bene il caso d'uso. Uno dei vantaggi di Docker è che puoi avviare un ambiente molto rapidamente. Se devi aspettare 3-4 minuti mentre Docker importa un database MySQL durante l'avvio, perdi questo vantaggio. L'obiettivo è avere un contenitore che contenga già i dati nel database, in modo da poterlo utilizzare il più rapidamente possibile.
Garreth McDaid

3
questa risposta funziona ancora con le ultime versioni? non sembra funzionare più
Daniel

2
Notare che l'esempio di docker-compose qui è v2 non v3. "volumi_from:" non è supportato in v3.
Ernest

37

Quello che ho fatto è stato scaricare il mio dump sql in una cartella "db-dump" e montarlo:

mysql:
 image: mysql:5.6
 environment:
   MYSQL_ROOT_PASSWORD: pass
 ports:
   - 3306:3306
 volumes:
   - ./db-dump:/docker-entrypoint-initdb.d

Quando eseguo docker-compose upper la prima volta, il dump viene ripristinato nel db.


3
+1, con un'aggiunta: il collegamento allo script in esecuzione per una migliore comprensione di ciò che sta effettivamente accadendo: github.com/docker-library/mariadb/blob/…
Tom Imrei

6
l'ultimo mysqlsembra non caricare il file sql scaricato, e anche usando 5.6 ho problemi con i motori di archiviazione InnoDb.
Zinking

1
lo stesso qui, ha tali istruzioni e ho persino visto durante la registrazione che carica i file di inizializzazione, ma db è vuoto!
holms

11

Ho usato l'approccio docker-entrypoint-initdb.d (Grazie a @Kuhess) Ma nel mio caso voglio creare il mio DB in base ad alcuni parametri che ho definito nel file .env quindi ho fatto questi

1) Per prima cosa definisco il file .env qualcosa di simile nella mia directory del progetto di root docker

MYSQL_DATABASE=my_db_name
MYSQL_USER=user_test
MYSQL_PASSWORD=test
MYSQL_ROOT_PASSWORD=test
MYSQL_PORT=3306

2) Quindi definisco il mio file docker-compose.yml. Quindi ho usato la direttiva args per definire le mie variabili di ambiente e le ho impostate dal file .env

version: '2'
services:
### MySQL Container
    mysql:
        build:
            context: ./mysql
            args:
                - MYSQL_DATABASE=${MYSQL_DATABASE}
                - MYSQL_USER=${MYSQL_USER}
                - MYSQL_PASSWORD=${MYSQL_PASSWORD}
                - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
        ports:
            - "${MYSQL_PORT}:3306"

3) Quindi definisco una cartella mysql che include un Dockerfile. Quindi il Dockerfile è questo

FROM mysql:5.7
RUN chown -R mysql:root /var/lib/mysql/

ARG MYSQL_DATABASE
ARG MYSQL_USER
ARG MYSQL_PASSWORD
ARG MYSQL_ROOT_PASSWORD

ENV MYSQL_DATABASE=$MYSQL_DATABASE
ENV MYSQL_USER=$MYSQL_USER
ENV MYSQL_PASSWORD=$MYSQL_PASSWORD
ENV MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD

ADD data.sql /etc/mysql/data.sql
RUN sed -i 's/MYSQL_DATABASE/'$MYSQL_DATABASE'/g' /etc/mysql/data.sql
RUN cp /etc/mysql/data.sql /docker-entrypoint-initdb.d

EXPOSE 3306

4) Ora uso mysqldump per scaricare il mio db e inserire data.sql nella cartella mysql

mysqldump -h <server name> -u<user> -p <db name> > data.sql

Il file è solo un normale file di dump sql ma aggiungo 2 righe all'inizio in modo che il file assomigli a questo

--
-- Create a database using `MYSQL_DATABASE` placeholder
--
CREATE DATABASE IF NOT EXISTS `MYSQL_DATABASE`;
USE `MYSQL_DATABASE`;

-- Rest of queries
DROP TABLE IF EXISTS `x`;
CREATE TABLE `x` (..)
LOCK TABLES `x` WRITE;
INSERT INTO `x` VALUES ...;
...
...
...

Quindi quello che sta succedendo è che ho usato il comando "RUN sed -i 's / MYSQL_DATABASE /' $ MYSQL_DATABASE '/ g' /etc/mysql/data.sql" per sostituire il MYSQL_DATABASEsegnaposto con il nome del mio DB in cui l'ho impostato file .env.

|- docker-compose.yml
|- .env
|- mysql
     |- Dockerfile
     |- data.sql

Ora sei pronto per creare ed eseguire il tuo container


Mi piace l'approccio dell'utilizzo di un .envfile. Tuttavia, in base a ciò , la .envfunzionalità file funziona solo quando si utilizza il docker-compose upcomando e non funziona con docker stack deploy. Pertanto, nel caso in cui desideri utilizzare il .envfile in produzione, potresti voler controllare i segreti della finestra mobile che sono stati introdotti con docker 17.06. Quindi puoi usare il tuo file .env insieme ai segreti sia nelle fasi di sviluppo docker compose upche in quella di produzionedocker stack deploy
ira

Un buon approccio ma suggerirei di utilizzare RUN sed -i '1s/^/CREATE DATABASE IF NOT EXISTS $ MYSQL_DATABASE ;\nUSE $ MYSQL_DATABASE ;\n/' data.sqlinvece del sedcomando che hai suggerito. In questo modo puoi usare qualsiasi file di dump che hai - è utile se stai lavorando con grandi quantità di dati :)
Tomasz Kapłoński

9

Ecco una versione funzionante utilizzando v3dei docker-compose.yml. La chiave è la direttiva sui volumi :

mysql:
  image: mysql:5.6
  ports:
    - "3306:3306"
  environment:
    MYSQL_ROOT_PASSWORD: root
    MYSQL_USER: theusername
    MYSQL_PASSWORD: thepw
    MYSQL_DATABASE: mydb
  volumes:
    - ./data:/docker-entrypoint-initdb.d

Nella directory che ho mia docker-compose.ymlho una directory datache contiene i .sqlfile di dump. Questo è utile perché puoi avere un .sqlfile di dump per tabella.

Corro semplicemente docker-compose upe sono a posto. I dati persistono automaticamente tra le fermate. Se si desidera cancellare i dati e "risucchiare" nuovi .sqlfile eseguiti docker-compose downpoi docker-compose up.

Se qualcuno sa come ottenere la mysqlfinestra mobile per rielaborare i file /docker-entrypoint-initdb.dsenza rimuovere il volume, lascia un commento e aggiornerò questa risposta.


2
questa risposta mi ha aiutato. la nota su docker-compose downera molto importante in quanto non vedevo modifiche nonostante il riavvio di docker-compose. MYSQL_DATABASE è una variabile obbligatoria in questo caso
nxmohamad

0

Non mi piace molto la risposta accettata da sleep 5Kuhess in quanto mi sembra un po 'hacker poiché presume che il demone mysql db sia stato caricato correttamente entro questo lasso di tempo. È un presupposto, nessuna garanzia. Inoltre, se si utilizza un'immagine docker mysql fornita, l'immagine stessa si occupa già di avviare il server; Non interferirei con questo con un'usanza /usr/bin/mysqld_safe.

Ho seguito le altre risposte qui intorno e ho copiato gli script bash e sql nella cartella /docker-entrypoint-initdb.d/all'interno del contenitore docker poiché questo è chiaramente il modo previsto dal provider di immagini mysql. Tutto in questa cartella viene eseguito una volta che il demone db è pronto, quindi dovresti essere in grado di fare affidamento su di esso.

In aggiunta alle altre, poiché nessun'altra risposta lo menziona esplicitamente: oltre agli script sql puoi anche copiare gli script bash in quella cartella che potrebbe darti un maggiore controllo.

Questo è ciò di cui avevo bisogno, ad esempio, poiché avevo anche bisogno di importare un dump, ma il dump da solo non era sufficiente in quanto non forniva in quale database importare. Quindi nel mio caso ho uno script denominato db_custom_init.shcon questo contenuto:

mysql -u root -p$MYSQL_ROOT_PASSWORD -e 'create database my_database_to_import_into'
mysql -u root -p$MYSQL_ROOT_PASSWORD my_database_to_import_into < /home/db_dump.sql

e questo Dockerfile che copia quello script:

FROM mysql/mysql-server:5.5.62
ENV MYSQL_ROOT_PASSWORD=XXXXX
COPY ./db_dump.sql /home/db_dump.sql
COPY ./db_custom_init.sh /docker-entrypoint-initdb.d/

modifica: nota che questo importerebbe solo il dump sql al momento della creazione del contenitore, non al momento della creazione dell'immagine!

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.