Création d'un conteneur docker mysql avec un schéma de base de données préparé

17

Je veux créer une image docker au-dessus de celle de mysql qui contient déjà le schéma nécessaire pour mon application.

J'ai essayé d'ajouter des lignes au Dockerfile qui importera mon schéma en tant que fichier sql. Je l'ai fait en tant que tel (mon 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"

À ma connaissance, cela n'a pas fonctionné car l'image de docker mysql ne contient pas de client mysql (les meilleures pratiques indiquent "n'ajoutez pas les choses simplement parce qu'elles seront agréables à avoir") (ai-je tort à ce sujet?)

quelle pourrait être une bonne façon de procéder? J'ai pensé à plusieurs choses, mais elles semblent toutes être des solutions de contournement compliquées.

  1. installez le client mysql, faites ce que j'ai à faire avec, puis supprimez / purgez-le.
  2. copiez le binaire client mysql dans l'image, faites ce que j'ai à faire, puis supprimez-le.
  3. Créez le schéma dans un autre serveur sql et copiez directement le fichier db (cela semble très compliqué et me semble être un pool de problèmes contaminé)

Aucune suggestion? Si tout va bien d'une manière qui sera facile à entretenir plus tard et peut-être également conforme aux meilleures pratiques?

Tom Klino
la source

Réponses:

14

Vous devez placer votre script init dans un répertoire monté comme /docker-entrypoint-initdb.d- voir la section "Initialisation d'une nouvelle instance" dans la documentation de l'image MySQL Docker .

Greg Dubicki
la source
2
Cela fonctionne pour apporter un nouveau conteneur et le charger avec mon schéma. C'est une bonne façon de le contourner, mais que se passe-t-il si je recherche un moyen de créer ma propre image docker qui a déjà le schéma préinstallé?
Tom Klino
En fait, peu importe :-) Je pensais que /docker-entrypoint-initdb.dc'était dans l'hôte mais c'est en fait dans le conteneur. J'ai changé la ADDcommande pour copier dans ce répertoire et j'ai supprimé la RUNcommande. Docker a construit l'image avec succès et je l'ai testée et cela fonctionne.
Tom Klino
14

J'ai dû le faire à des fins de test.

Voici comment je l'ai fait en tirant parti des images MySQL / MariaDB réelles sur dockerhub et de la construction en plusieurs étapes:

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

Exemple de travail complet ici: https://github.com/lindycoder/prepopulated-mysql-container-example

Martin Roy
la source
2
meilleure réponse que j'ai trouvée sur Internet, la mienne était pour les postgres, donc c'était un peu plus difficile, mais finalement ça a fonctionné. Et ça marche parfaitement!
snowe2010
Les versions plus anciennes de mysql (5.7.9) n'ont pas /usr/local/bin/docker-entrypoint.sh en lien symbolique avec /entrypoint.sh, au lieu de cela il suffit d'avoir le entrypoint.sh dans /. Changer /usr/local/bin/docker-entrypoint.sh en /entrypoint.sh fonctionne et devrait probablement fonctionner aussi pour les versions "modernes".
Marvin
2

Crédits à @Martin Roy

Modifications mineures apportées au fonctionnement de mysql ...

Contenu 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

Content setup.sql

CREATE DATABASE myexample;

USE myexample;

CREATE TABLE mytable (myfield VARCHAR(20));

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

Exemple de travail complet ici: https://github.com/iamdvr/prepopulated-mysql-container-example

Venkateswara Rao
la source
-1

Un logiciel de gestion comme Ansible peut vous aider à automatiser une importation mysql facilement sans avoir à installer et réinstaller un client. Ansible a de grandes fonctionnalités intégrées pour gérer les images et les conteneurs Docker et les bases de données mysql.

Patrick
la source
C'est intéressant - j'ai utilisé Ansible mais je ne l'ai pas utilisé pour les images Docker. Pouvez-vous étendre votre réponse avec quelques exemples, Patrick?
Greg Dubicki
Ansible a une excellente page de documentation, vous pouvez trouver le module Ansible sur cette url: docs.ansible.com/ansible/docker_module.html Sur chaque page du chapitre module de ce guide, vous trouverez quelques exemples.
Patrick