Erstellen eines Docker-MySQL-Containers mit einem vorbereiteten Datenbankschema

17

Ich möchte ein Docker-Image über dem MySQL-Image erstellen, das bereits das für meine App erforderliche Schema enthält.

Ich habe versucht, der Docker-Datei Zeilen hinzuzufügen, die mein Schema als SQL-Datei importieren. Ich habe es so gemacht (meine Dockerfile):

FROM mysql

ENV MYSQL_ROOT_PASSWORD="bagabu"
ENV MYSQL_DATABASE="imhere"

ADD imhere.sql /tmp/imhere.sql

RUN "mysql -u root --password="bagabu" imhere < /tmp/imhere.sql"

Meines Erachtens hat das nicht funktioniert, weil das MySQL-Docker-Image keinen MySQL-Client enthält (Best Practices lauten: "Fügen Sie keine Dinge hinzu, nur weil sie nett sind") (irre ich mich dabei?)

Was könnte ein guter Weg sein, dies zu tun? Ich habe ein paar Dinge im Sinn gehabt, aber sie scheinen alle chaotisch zu sein.

  1. Installieren Sie den MySQL-Client, tun Sie, was ich damit zu tun habe, und entfernen / bereinigen Sie ihn dann.
  2. Kopieren Sie die MySQL-Client-Binärdatei in das Image, tun Sie, was ich tun muss, und entfernen Sie sie dann.
  3. Erstellen Sie das Schema in einem anderen SQL-Server und kopieren Sie die Datenbankdatei direkt selbst (dies scheint sehr chaotisch zu sein und klingt für mich wie ein verseuchter Pool von Problemen).

Irgendwelche Vorschläge? Hoffentlich auf eine Weise, die später einfach zu warten ist und möglicherweise auch den Best Practices entspricht?

Tom Klino
quelle

Antworten:

14

Sie sollten Ihr Init-Skript in einem Verzeichnis ablegen, das wie /docker-entrypoint-initdb.dfolgt eingebunden ist: Siehe Abschnitt "Initialisieren einer neuen Instanz" in den MySQL Docker-Image-Dokumenten .

Greg Dubicki
quelle
2
Das funktioniert, wenn Sie einen neuen Container aufrufen und ihn mit meinem Schema laden. Was ist ein guter Weg, aber was ist, wenn ich nach einer Möglichkeit suche , mein eigenes Docker-Image zu erstellen , auf dem das Schema bereits vorinstalliert ist?
Tom Klino
Eigentlich egal :-) Ich dachte das /docker-entrypoint-initdb.dwar im Host, aber es ist tatsächlich im Container. Ich habe den ADDBefehl zum Kopieren in dieses Verzeichnis geändert und den RUNBefehl entfernt. Docker hat das Image erfolgreich erstellt und ich habe es getestet und es funktioniert.
Tom Klino
14

Ich musste dies zu Testzwecken tun.

Hier ist, wie ich es gemacht habe, indem ich die tatsächlichen MySQL / MariaDB-Images auf dockerhub und den mehrstufigen Build verwendet habe:

FROM mariadb:latest as builder

# That file does the DB initialization but also runs mysql daemon, by removing the last line it will only init
RUN ["sed", "-i", "s/exec \"$@\"/echo \"not running $@\"/", "/usr/local/bin/docker-entrypoint.sh"]

# needed for intialization
ENV MYSQL_ROOT_PASSWORD=root

COPY setup.sql /docker-entrypoint-initdb.d/

# Need to change the datadir to something else that /var/lib/mysql because the parent docker file defines it as a volume.
# https://docs.docker.com/engine/reference/builder/#volume :
#       Changing the volume from within the Dockerfile: If any build steps change the data within the volume after
#       it has been declared, those changes will be discarded.
RUN ["/usr/local/bin/docker-entrypoint.sh", "mysqld", "--datadir", "/initialized-db", "--aria-log-dir-path", "/initialized-db"]

FROM mariadb:latest

COPY --from=builder /initialized-db /var/lib/mysql

Vollständiges Beispiel hier: https://github.com/lindycoder/prepopulated-mysql-container-example

Martin Roy
quelle
2
Die beste Antwort, die ich im ganzen Internet gefunden habe, meine war für Postgres, also war es etwas schwieriger, aber endlich hat es funktioniert. Und es funktioniert perfekt!
snowe2010
In älteren Versionen von mysql (5.7.9) ist /usr/local/bin/docker-entrypoint.sh nicht mit /entrypoint.sh verknüpft, sondern nur mit entrypoint.sh in /. Das Ändern von /usr/local/bin/docker-entrypoint.sh in /entrypoint.sh funktioniert und sollte vermutlich auch für die "modernen" Releases funktionieren.
Marvin
2

Dank an @Martin Roy

Kleinere Änderungen an der Arbeit für MySQL vorgenommen ...

Content Dockerfile

FROM mysql:latest as builder

# That file does the DB initialization but also runs mysql daemon, by removing the last line it will only init
RUN ["sed", "-i", "s/exec \"$@\"/echo \"not running $@\"/", "/usr/local/bin/docker-entrypoint.sh"]

# needed for intialization
ENV MYSQL_ROOT_PASSWORD=root

COPY setup.sql /docker-entrypoint-initdb.d/

# Need to change the datadir to something else that /var/lib/mysql because the parent docker file defines it as a volume.
# https://docs.docker.com/engine/reference/builder/#volume :
#       Changing the volume from within the Dockerfile: If any build steps change the data within the volume after
#       it has been declared, those changes will be discarded.
RUN ["/usr/local/bin/docker-entrypoint.sh", "mysqld", "--datadir", "/initialized-db"]

FROM mysql:latest

COPY --from=builder /initialized-db /var/lib/mysql

Inhalt setup.sql

CREATE DATABASE myexample;

USE myexample;

CREATE TABLE mytable (myfield VARCHAR(20));

INSERT INTO mytable VALUES ('Hello'), ('Dolly');

Vollständiges Funktionsbeispiel hier: https://github.com/iamdvr/prepopulated-mysql-container-example

Venkateswara Rao
quelle
-1

Verwaltungssoftware wie Ansible kann Ihnen helfen, einen MySQL-Import einfach zu automatisieren, ohne einen Client installieren und neu installieren zu müssen. Ansible verfügt über hervorragende integrierte Funktionen zum Verwalten von Docker-Bildern und -Containern sowie von MySQL-Datenbanken.

Patrick
quelle
Das ist interessant - ich habe Ansible verwendet, aber nicht für Docker-Images. Können Sie Ihre Antwort mit einigen Beispielen erweitern, Patrick?
Greg Dubicki
Ansible hat eine großartige Dokumentseite. Das Ansible-Modul finden Sie unter folgender URL: docs.ansible.com/ansible/docker_module.html Auf jeder Seite im Modulkapitel dieses Handbuchs finden Sie einige Beispiele.
Patrick