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

Eu quero criar uma imagem docker em cima do mysql que já contém o esquema necessário para o meu aplicativo.

Tentei adicionar linhas ao Dockerfile que importará meu esquema como um arquivo sql. Eu fiz isso como tal (meu Dockerfile):

FROM mysqlENV MYSQL_ROOT_PASSWORD="bagabu"ENV MYSQL_DATABASE="imhere"ADD imhere.sql /tmp/imhere.sqlRUN "mysql -u root --password="bagabu" imhere < /tmp/imhere.sql"

No meu entendimento, isso não funcionou porque a imagem do mysql docker não contém um cliente mysql (as melhores práticas afirmam "não adicione coisas só porque elas serão boas de ter") (estou errado sobre isso?)

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

  1. instale o cliente mysql, faça o que tenho a ver 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 sql server e copie o arquivo db diretamente (isso parece muito confuso e soa para mim como um pool contaminado de problemas)

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

Eu tive que fazer isso para fins de testes.

Veja como fiz aproveitando as imagens reais do MySQL / MariaDB no dockerhub e a compilação em 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 initRUN ["sed", "-i", "s/exec \"$@\"/echo \"not running $@\"/", "/usr/local/bin/docker-entrypoint.sh"]# needed for intializationENV MYSQL_ROOT_PASSWORD=rootCOPY 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:latestCOPY --from=builder /initialized-db /var/lib/mysql

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

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

Créditos para @ Martin Roy

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

Conteúdo 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 initRUN ["sed", "-i", "s/exec \"$@\"/echo \"not running $@\"/", "/usr/local/bin/docker-entrypoint.sh"]# needed for intializationENV MYSQL_ROOT_PASSWORD=rootCOPY 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:latestCOPY --from=builder /initialized-db /var/lib/mysql

Configuração de conteúdo.banco

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

Isso funciona e segue a interface com o script de ponto de entrada mariadb. Arquivos com configurações, tabelas, dados e usuários são copiados para pastas. Quando o contêiner inicia, o script do ponto de entrada encontra os arquivos e cria um novo banco de dados.

FROM mariadb:10.5.5ENV MYSQL_ROOT_PASSWORD=blablablablablablaCOPY settings/my.cnf /etc/mysql/conf.d# comment out !includedir /etc/mysql/conf.d/ to stop recursionRUN sed -i 's/!includedir \/etc\/mysql\/conf\.d\//#!includedir \/etc\/mysql\/conf\.d\//' /etc/mysql/conf.d/my.cnfCOPY db_scripts/db_setup.sql /docker-entrypoint-initdb.d/COPY db_scripts/db_data.sql.template /docker-entrypoint-initdb.d/db_template.sqlCOPY db_scripts/db_users.sql /docker-entrypoint-initdb.d/# Note the port 3306 can be exposed

A resposta de @Venkateswara Rao e @ Martin Roy funciona muito bem se você não se importa se as alterações no banco de dados dockerizado ainda são colocadas em um Volume. No meu caso, eu queria uma imagem do Docker pré-povoada com dados, mas em um projeto em que temos migrações frequentes de banco de dados. Assim, eu queria ocasionalmente fazer um contêiner de banco de dados, executar migrações e, de alguma forma, empurrar essas alterações de volta para que o próximo usuário a usar a imagem de banco de dados já tivesse migrações aplicadas. Como os arquivos de banco de dados vivem em um Volume, eles não são rolados em uma imagem com docker commmit my-migrated-db-container my-new-db-image.

Minha solução foi usar o oficial MySQL (5.6 no meu. caso) Dockerfile (e arquivo entrypoint) para recriar seu trabalho depois de remover o VOLUME /var/lib/mysql linha. A partir da imagem resultante, usei os arquivos de Venkateswara para fazer uma imagem de banco de dados pré-carregada, onde até mesmo todos os dados de banco de dados futuros são armazenados no próprio contêiner (não em um Volume).

Nota: O arquivo Dockerfile vinculado é antigo refere-se a keyservers GPG obsoletos (ie keys.openpgp.org). Você pode substituir esses nomes de servidor por, digamos, keyserver.ubuntu.com.

Aqui está o meu arquivo docker funcionando absolutamente bem./ sql-scripts / conterá seu arquivo sql personalizado (contendo seu banco de dados preparado) que é executado assim que o contêiner for executado. Você pode querer olhar para montagem de volume embora.

FROM mysql:5.6COPY ./sql-scripts/ /docker-entrypoint-initdb.d/

Software de gerenciamento como Ansible pode ajudá-lo a automatizar uma importação mysql fácil, sem a necessidade de instalar e reinstalar um cliente.O Ansible possui ótimos recursos integrados para gerenciar imagens e contêineres do docker e bancos de dados mysql.

Veja também: Como posso inicializar um banco de dados MySQL com esquema em um contêiner Docker?