Criando um contêiner docker mysql com um esquema de banco de dados preparado

17

Quero criar uma imagem do docker em cima do mysql que já contenha o esquema necessário para o meu aplicativo.

Tentei adicionar linhas ao Dockerfile que importariam meu esquema como um arquivo sql. Fiz isso como tal (meu 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"

No meu entender, isso não funcionou porque a imagem do docker mysql não contém um cliente mysql (o estado das práticas recomendadas "não adicione coisas apenas porque elas serão boas em ter") (estou errado sobre isso?)

qual pode ser uma boa maneira de fazer isso? Eu tinha algumas coisas em mente, mas todas elas parecem soluções alternativas complicadas.

  1. instale o cliente mysql, faça o que eu tenho que fazer com ele e remova / limpe-o.
  2. copie o binário do cliente mysql para a imagem, faça o que tenho que fazer e remova-o.
  3. Crie o esquema em outro servidor sql e copie o arquivo db diretamente (isso parece muito confuso e me parece um conjunto de problemas contaminado)

Alguma sugestão? Esperançosamente, de uma maneira que seja fácil de manter mais tarde e que talvez esteja em conformidade com as melhores práticas também?

Tom Klino
fonte

Respostas:

14

Você deve colocar seu script init em um diretório montado como /docker-entrypoint-initdb.d- consulte a seção "Inicializando uma instância nova" nos documentos de imagem do MySQL Docker .

Greg Dubicki
fonte
2
Isso funciona para abrir um contêiner novo e carregá-lo com meu esquema. Qual é uma boa maneira de contornar isso, mas e se eu estiver procurando uma maneira de criar minha própria imagem de janela de encaixe que já tenha o esquema pré-instalado?
Tom Klino
Na verdade, deixa pra lá :-) Eu pensei que /docker-entrypoint-initdb.destava no host, mas na verdade está no contêiner. Alterei o ADDcomando para copiar para esse diretório e removi o RUNcomando. O Docker construiu a imagem com sucesso e eu a testei e funciona.
Tom Klino
14

Eu tive que fazer isso para fins de testes.

Aqui está como eu fiz, aproveitando as imagens reais do MySQL / MariaDB no dockerhub e na compilação de vários estágios:

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

Exemplo de trabalho completo aqui: https://github.com/lindycoder/prepopulated-mysql-container-example

Martin Roy
fonte
2
melhor resposta que encontrei em toda a internet, a minha era para o postgres, por isso foi um pouco mais difícil, mas finalmente consegui funcionar. E funciona perfeitamente!
snowe2010
As versões mais antigas do mysql (5.7.9) não têm /usr/local/bin/docker-entrypoint.sh vinculado a /entrypoint.sh, apenas o entrypoint.sh em /. Alterar /usr/local/bin/docker-entrypoint.sh para /entrypoint.sh funciona e provavelmente deve funcionar também para os lançamentos "modernos".
Marvin
2

Créditos a @Martin Roy

Fez pequenas alterações para trabalhar com o mysql ...

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

Conteúdo setup.sql

CREATE DATABASE myexample;

USE myexample;

CREATE TABLE mytable (myfield VARCHAR(20));

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

Exemplo de trabalho completo aqui: https://github.com/iamdvr/prepopulated-mysql-container-example

Venkateswara Rao
fonte
-1

Um software de gerenciamento como o Ansible pode ajudá-lo a automatizar uma importação mysql com facilidade, sem a necessidade de instalar e reinstalar um cliente. O Ansible possui ótimos recursos internos para gerenciar imagens e recipientes de janela de encaixe e bancos de dados mysql.

Patrick
fonte
Isso é interessante - usei o Ansible, mas não o usei para imagens do Docker. Você pode estender sua resposta com alguns exemplos, Patrick?
Greg Dubicki
O Ansible possui uma excelente página de documentos, você pode encontrar o módulo Ansible neste URL: docs.ansible.com/ansible/docker_module.html Em cada página do capítulo do módulo deste guia, há alguns exemplos.
Patrick