Tworzenie kontenera mysql dokera z przygotowanym schematem bazy danych

17

Chcę utworzyć obraz dokera na szczycie mysql, który już zawiera schemat niezbędny dla mojej aplikacji.

Próbowałem dodać wiersze do pliku Docker, który zaimportuje mój schemat jako plik sql. Zrobiłem to jako takie (mój plik Docker):

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"

W moim rozumieniu, to nie zadziałało, ponieważ obraz dokowanego mysql nie zawiera klienta mysql (najlepsze praktyki stwierdzają, że „nie dodawaj rzeczy tylko dlatego, że będą miło mieć”) (czy się mylę?)

co może być dobrym sposobem na to? Miałem na myśli kilka rzeczy, ale wszystkie wydają się być niechlujnymi obejściami.

  1. zainstaluj klienta mysql, zrób to, co mam z nim zrobić, a następnie usuń / wyczyść go.
  2. skopiuj plik binarny klienta mysql do obrazu, zrób to, co muszę, a następnie usuń go.
  3. Utwórz schemat na innym serwerze sql i skopiuj bezpośrednio plik db (wydaje się to bardzo niechlujne i brzmi jak skażona pula problemów)

Jakieś sugestie? Mam nadzieję, że w sposób, który będzie później łatwy do utrzymania i być może zgodny z najlepszymi praktykami?

Tom Klino
źródło

Odpowiedzi:

14

Powinieneś umieścić swój skrypt init w katalogu zamontowanym jako /docker-entrypoint-initdb.d- patrz sekcja „Inicjowanie świeżej instancji” w dokumentacji obrazów MySQL Docker .

Greg Dubicki
źródło
2
Działa to przy podnoszeniu świeżego pojemnika i ładowaniu go moim schematem. Co jest dobrym sposobem na obejście tego, ale co, jeśli szukam sposobu na utworzenie własnego obrazu dokera, który ma już wstępnie zainstalowany schemat?
Tom Klino,
Właściwie nieważne :-) Myślałem, że /docker-entrypoint-initdb.dbył u gospodarza, ale tak naprawdę jest w kontenerze. Zmieniłem ADDpolecenie, aby skopiować do tego katalogu i usunąłem RUNpolecenie. Docker zbudował obraz z powodzeniem, przetestowałem go i działa.
Tom Klino,
14

Musiałem to zrobić w celach testowych.

Oto jak to zrobiłem, wykorzystując rzeczywiste obrazy MySQL / MariaDB w dockerhub i kompilacji wieloetapowej:

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

Pełny przykład działania tutaj: https://github.com/lindycoder/prepopulated-mysql-container-example

Martin Roy
źródło
2
najlepsza odpowiedź, jaką znalazłem w całym Internecie, mój był dla postgresu, więc było trochę trudniej, ale w końcu działało. I działa idealnie!
snowe2010
Starsze wersje mysql (5.7.9) nie mają /usr/local/bin/docker-entrypoint.sh połączonych z /entrypoint.sh, zamiast tego mają entrypoint.sh w /. Zmiana /usr/local/bin/docker-entrypoint.sh na /entrypoint.sh działa i prawdopodobnie powinna również działać w wydaniach „nowoczesnych”.
Marvin
2

Kredyty dla @Martin Roy

Wprowadzono drobne zmiany w pracy dla mysql ...

Plik Docker treści

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

Treść setup.sql

CREATE DATABASE myexample;

USE myexample;

CREATE TABLE mytable (myfield VARCHAR(20));

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

Pełny przykład działania tutaj: https://github.com/iamdvr/prepopulated-mysql-container-example

Venkateswara Rao
źródło
-1

Oprogramowanie do zarządzania, takie jak Ansible, może pomóc w łatwej automatyzacji importu mysql bez konieczności instalowania i ponownej instalacji klienta. Ansible ma świetne wbudowane funkcje do zarządzania obrazami dokerów i kontenerów i baz danych mysql.

Patrick
źródło
To ciekawe - użyłem Ansible, ale nie użyłem go do obrazów Docker. Czy potrafisz udzielić odpowiedzi na kilka przykładów, Patrick?
Greg Dubicki,
Ansible ma świetną stronę z dokumentami, moduł Ansible można znaleźć pod tym adresem: docs.ansible.com/ansible/docker_module.html Na każdej stronie w rozdziale modułu tego przewodnika znajduje się kilka przykładów.
Patrick,