Wie kann ich eine MySQL-Datenbank mit einem Schema in einem Docker-Container initialisieren?

165

Ich versuche, einen Container mit einer MySQL-Datenbank zu erstellen und dieser Datenbank ein Schema hinzuzufügen.

Meine aktuelle Docker-Datei lautet:

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

Um den Container zu erstellen, folge ich der Dokumentation in Docker und führe diesen Befehl aus:

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

Aber wenn ich diesen Befehl ausführe, wird der Container nicht erstellt und im Container-Status kann man sehen, dass die CMD nicht erfolgreich ausgeführt wurde, sondern nur der mysqlBefehl ausgeführt wird.

Gibt es eine Möglichkeit, die Datenbank mit dem Schema zu initialisieren, oder muss ich diese Vorgänge manuell ausführen?

Marcus Gomes
quelle
Ich gehe davon aus, dass Sie ein neues Bild mit einer Datenbank erstellen möchten, die gesetzt und einsatzbereit ist.
Greg
Ja, genau das möchte ich tun.
Marcus Gomes
Erklärt auch hier: medium.com/@lvthillo/…
lvthillo

Antworten:

105

Es tut mir leid für diese super lange Antwort, aber Sie haben noch einen kleinen Weg vor sich, um dorthin zu gelangen, wo Sie wollen. Ich werde sagen, dass Sie normalerweise den Speicher für die Datenbank nicht im selben Container wie die Datenbank selbst ablegen würden, sondern entweder ein Host-Volume bereitstellen würden, damit die Daten auf dem Docker-Host erhalten bleiben, oder dass möglicherweise ein Container verwendet werden könnte Halten Sie die Daten (/ var / lib / mysql). Außerdem bin ich neu in MySQL, daher ist dies möglicherweise nicht sehr effizient. Das gesagt...

Ich denke, hier kann es einige Probleme geben. Die Docker-Datei wird verwendet, um ein Bild zu erstellen. Sie müssen den Erstellungsschritt ausführen. In dem Verzeichnis, das die Docker-Datei enthält, würden Sie mindestens Folgendes tun:

docker build .

Die Docker-Datei beschreibt das zu erstellende Bild. Ich weiß nicht viel über MySQL (ich bin ein Postgres-Fan), aber ich habe in den Interwebs nach "Wie initialisiere ich einen MySQL-Docker-Container?" Gesucht. Zuerst habe ich ein neues Verzeichnis erstellt, in dem ich arbeiten kann, ich habe es mdir genannt, dann habe ich ein Dateiverzeichnis erstellt, in dem ich eine epcis_schema.sql-Datei abgelegt habe, die eine Datenbank und eine einzelne Tabelle erstellt:

create database test;
use test;

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

Dann habe ich ein Skript namens init_db im Dateiverzeichnis erstellt:

#!/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

(Der größte Teil dieses Skripts wurde von hier entfernt: https://gist.github.com/pda/9697520 )

Hier ist das Skript files / run_db, das ich erstellt habe:

# 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

Schließlich die Docker-Datei, um sie alle zu binden:

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"

Also habe ich in mein mdir-Verzeichnis (das die Docker-Datei zusammen mit dem Dateiverzeichnis enthält) cd'ed. Ich führe dann den Befehl aus:

docker build --no-cache .

Sie sollten die Ausgabe wie folgt sehen:

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

Sie haben jetzt ein Bild '7f6d5215fe8d'. Ich könnte dieses Bild ausführen:

docker run -d 7f6d5215fe8d

und das Bild startet, ich sehe eine Instanzzeichenfolge:

4b377ac7397ff5880bc9218abe6d7eadd49505d50efb5063d6fab796ee157bd3

Ich könnte es dann "stoppen" und neu starten.

docker stop 4b377
docker start 4b377

Wenn Sie sich die Protokolle ansehen, enthält die erste Zeile:

docker logs 4b377

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

Dann am Ende der Protokolle:

Running with existing database in /var/lib/mysql

Dies sind die Nachrichten aus dem Skript / tmp / run_db. Die erste zeigt an, dass die Datenbank aus der gespeicherten (anfänglichen) Version entpackt wurde, die zweite zeigt an, dass die Datenbank bereits vorhanden war, sodass die vorhandene Kopie verwendet wurde.

Hier ist ein ls -lR der oben beschriebenen Verzeichnisstruktur. Beachten Sie, dass init_db und run_db Skripte mit gesetztem Ausführungsbit sind:

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
Greg
quelle
3
Hey Gary, zuerst danke für deine Hilfe. Ich habe Ihre Anweisungen befolgt, aber wenn ich Docker Build --no-Cache ausführe. Ich habe einen Berechtigungsfehler für das init_dbSkript.
Marcus Gomes
Ich versuche bereits, das zu beheben, indem ich Berechtigungen im RUNBefehl erteile, und das Problem ist anscheinend gelöst. Aber dann, wenn ich ausführe, habe docker runich das gleiche Problem mit dem run_dbSkript.
Marcus Gomes
1
init_db und run_db müssen die Berechtigung 0755 haben (es handelt sich um Skripte, für die das Ausführungsbit gesetzt sein muss. Führen Sie ein chmod + x init_db run_db aus
Greg
Ich habe die Antwort mit einer Verzeichnisliste aktualisiert, in der die Berechtigungen für jede der Dateien aufgeführt sind. Hinweis: chmod + x files / * _ db erfüllt die erforderlichen Berechtigungen.
Greg
2
@ Greg Ich habe die obigen Schritte versucht, erhalte jedoch eine Fehlermeldung ([FEHLER] Schwerwiegender Fehler: Bitte lesen Sie den Abschnitt "Sicherheit" des Handbuchs, um herauszufinden, wie Sie mysqld als root ausführen können!). Irgendwelche Vorschläge ?
Binish John
121

Ich hatte das gleiche Problem, bei dem ich das Schema meiner MySQL Docker-Instanz initialisieren wollte, aber ich hatte Schwierigkeiten, dies zum Laufen zu bringen, nachdem ich ein bisschen gegoogelt und den Beispielen anderer gefolgt war. So habe ich es gelöst.

1) Speichern Sie Ihr MySQL-Schema in einer Datei.

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

2) Verwenden Sie den Befehl ADD, um Ihre Schemadatei zum /docker-entrypoint-initdb.dVerzeichnis im Docker-Container hinzuzufügen . Die docker-entrypoint.shDatei führt alle Dateien in diesem Verzeichnis aus, die mit ".sql"der MySQL-Datenbank enden .

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) Starten Sie die Docker MySQL-Instanz.

docker-compose build
docker-compose up

Dank des Einrichtens von MySQL und des Importierens eines Dumps in Dockerfile, um mich auf die Datei docker-entrypoint.sh aufmerksam zu machen, und der Tatsache, dass sowohl SQL- als auch Shell-Skripte ausgeführt werden!

Brett Cooper
quelle
2
Dies ist definitiv die bessere Antwort. Das Kopieren von DDLs und Initialisierungsskripten in das Verzeichnis /docker-entrypoint-initdb.d ist das, was die Dockerhub-MySQL-Dokumente zu solchen Dingen sagen.
Chacewells
2
Was passiert, wenn sich etwas ändert schema.sql? Ich möchte, dass meine Datenbank entsprechend aktualisiert wird. Was passiert auch, wenn ich diesen Container zum zweiten Mal baue? Wird db zerstört und neu erstellt?
Goga Koreli
1
@ Goga Koreli Docker führt diesen Init-Befehl nur aus, wenn keine Dateneingabe in / var / lib / mysql
medTech
38

Ein anderer Weg, der auf einer Zusammenführung mehrerer Antworten basiert:

Docker-Compose-Datei:

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

Dabei ist /home/user.. ein freigegebener Ordner auf dem Host

Und im /home/user/db/mysql/initOrdner ... legen Sie einfach eine SQL-Datei mit einem beliebigen Namen ab, die beispielsweise Folgendes init.sqlenthält:

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

Laut der offiziellen MySQL-Dokumentation können Sie mehr als eine SQL-Datei in die docker-entrypoint-initdb.d, sie werden in alphabetischer Reihenfolge ausgeführt

phico
quelle
28

Verwenden Sie Docker-Compose auf andere einfache Weise mit den folgenden Zeilen:

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

Fügen Sie Ihr Datenbankschema in die Datei ./database/install_db.sql ein. Jedes Mal, wenn Sie Ihren Container aufbauen, wird die Datei install_db.sql ausgeführt.

Balázs Zámbó
quelle
26

Ich habe Gregs Antwort mit null Erfolg versucht. Ich muss etwas falsch gemacht haben, da meine Datenbank nach allen Schritten keine Daten enthielt: Ich habe das neueste Bild von MariaDB verwendet, nur für den Fall.

Dann habe ich beschlossen, den Einstiegspunkt für das offizielle MariaDB-Image zu lesen und daraus eine einfache Docker-Compose- Datei zu generieren :

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"

Jetzt kann ich meine Daten beibehalten UND eine Datenbank mit meinem eigenen Schema erstellen!

mrArias
quelle
1
Hallo, ich versuche auch das gleiche zu tun, aber das Skript wird nie ausgeführt. Gibt es einen anderen Parameter, der angegeben werden muss? Ich habe gerade diesen Band für mariadb - ./database/schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro hinzugefügt. Danke
bilak
Hinweis: Das Skript wird während der Containerinitialisierung nur einmal ausgeführt. Wenn Sie später ein neues Skript hinzufügen, wird es nicht ausgeführt.
ALex_hha
23

Wenn Sie nach dem 4. August 2015 das offizielle MySQL-Docker-Image verwenden, können Sie einfach eine Datei in das Verzeichnis /docker-entrypoint-initdb.d/ HINZUFÜGEN / kopieren und sie wird ausgeführt, wenn der Container initialisiert wird. Siehe github: https://github.com/docker-library/mysql/commit/14f165596ea8808dfeb2131f092aabe61c967225, wenn Sie es auf anderen Container-Images implementieren möchten

JDWatkins
quelle
1
Dies ist die richtige Antwort für aktuelle Versionen des offiziellen Docker MSQL-Images.
NaN
11

Die einfachste Lösung ist die Verwendung von tutum / mysql

Schritt 1

docker pull tutum/mysql:5.5

Schritt 2

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

Schritt 3

Gehen Sie zu CONTAINER_ID und führen Sie den Befehl aus docker logs, um die generierten Kennwortinformationen anzuzeigen .

docker logs #<CONTAINER_ID>
Mainframer
quelle
Haben Sie dies erfolgreich ausgeführt? Ich habe wochenlang ohne Erfolg mit Tutum / MySQL gespielt.
Iammesol
2
Ja. Ich benutze tutum/mysql:5.5und es war erfolgreich. docker run -d -p 3306:3306 -v /tmp:/tmp -e MYSQL_PASS="admin" -e STARTUP_SQL="/tmp/mysqldump.mysql" tutum/mysql:5.5. Sie können jederzeit einen Befehl ausführen docker logs CONTAINER_ID, um die Fehlermeldungen anzuzeigen, wenn Probleme aufgetreten sind.
Mainframer
Ich kann nicht herausfinden, woher der Weg /tmp/to_be_imported.mysqlkommt. Ist das ein Pfad auf dem Host-Betriebssystem? Wo ist ein COPYoder ADD, um Dinge in das Dateisystem des Containers zu stellen?
Randy L
@ the0ther Sie brauchen COPY/ nicht, ADDweil das Host-Verzeichnis / tmp in / tmp des Containers eingehängt ist. Schauen Sie sich den Befehl genau an, da ist das Teil -v /tmp:/tmp. Persönlich würde ich ein Volume nicht einfach bereitstellen, um die Datei für den Container verfügbar zu machen, aber ich denke, es ist eine persönliche Entscheidung.
Willa
1
Um fair zu sein, sollten Sie nicht nicht-offizielle Bilder verwenden, es sei denn , Sie wollen dies noch einmal passieren.
Dragas
3

Für diejenigen, die kein Einstiegspunktskript wie mich erstellen möchten, können Sie mysqld tatsächlich zur Erstellungszeit starten und dann die mysql-Befehle in Ihrer Docker-Datei wie folgt ausführen:

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';"

Der Schlüssel hier ist, mysqld_safe mit dem Einzelzeichen in den Hintergrund zu senden &.

roothahn
quelle
1

Unten finden Sie die Docker-Datei, mit der ich xampp erfolgreich installiert, eine MariaDB mit Schema erstellt und mit den auf dem lokalen Server verwendeten Informationen (Benutzer, Bildbestellungen usw.) vorab ausgefüllt habe.

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
Paddy Popeye
quelle
0

Nachdem Sie sich ein wenig damit abgefunden haben, schauen Sie sich die Docker-Datei mit benannten Volumes (DB-Daten) an. Es ist wichtig, im letzten Teil, in dem ich erwähnt habe, dass es sich um eine Lautstärke handelt, ein Plus zu erklären[external]

Alle haben auf diese Weise großartig funktioniert!

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
allysson vieira
quelle