简体   繁体   English

如何在 Docker 容器中使用架构初始化 MySQL 数据库?

[英]How can I initialize a MySQL database with schema in a Docker container?

I am trying to create a container with a MySQL database and add a schema to these database.我正在尝试使用 MySQL 数据库创建一个容器并向这些数据库添加架构。

My current Dockerfile is:我目前的 Dockerfile 是:

FROM mysql
MAINTAINER  (me) <email>

# Copy the database schema to the /data directory
COPY files/epcis_schema.sql /data/epcis_schema.sql

# Change the working directory
WORKDIR data

CMD mysql -u $MYSQL_USER -p $MYSQL_PASSWORD $MYSQL_DATABASE < epcis_schema.sql

In order to create the container I am following the documentation provided on Docker and executing this command:为了创建容器,我遵循 Docker 上提供的文档并执行以下命令:

docker run --name ${CONTAINER_NAME} -e MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD} -e MYSQL_USER=${DB_USER} -e MYSQL_PASSWORD=${DB_USER_PASSWORD} -e MYSQL_DATABASE=${DB_NAME} -d mvpgomes/epcisdb

But when I execute this command the Container is not created and in the Container status it is possible to see that the CMD was not executed successfully, in fact only the mysql command is executed.但是当我执行这个命令时,Container并没有被创建,在Container状态下可以看到CMD没有执行成功,实际上只执行了mysql命令。

Anyway, is there a way to initialize the database with the schema or do I need to perform these operations manually?无论如何,有没有办法用模式初始化数据库,还是我需要手动执行这些操作?

I had this same issue where I wanted to initialize my MySQL Docker instance's schema, but I ran into difficulty getting this working after doing some Googling and following others' examples.我遇到了同样的问题,我想初始化我的 MySQL Docker 实例的架构,但是在做了一些谷歌搜索并遵循其他人的示例后,我遇到了困难。 Here's how I solved it.这是我解决它的方法。

1) Dump your MySQL schema to a file. 1) 将你的 MySQL 模式转储到一个文件中。

mysqldump -h <your_mysql_host> -u <user_name> -p --no-data <schema_name> > schema.sql

2) Use the ADD command to add your schema file to the /docker-entrypoint-initdb.d directory in the Docker container. 2) 使用 ADD 命令将您的架构文件添加到 Docker 容器中的/docker-entrypoint-initdb.d目录。 The docker-entrypoint.sh file will run any files in this directory ending with ".sql" against the MySQL database. docker-entrypoint.sh文件将针对 MySQL 数据库运行此目录中以".sql"结尾的任何文件。

Dockerfile: Dockerfile:

FROM mysql:5.7.15

MAINTAINER me

ENV MYSQL_DATABASE=<schema_name> \
    MYSQL_ROOT_PASSWORD=<password>

ADD schema.sql /docker-entrypoint-initdb.d

EXPOSE 3306

3) Start up the Docker MySQL instance. 3) 启动Docker MySQL 实例。

docker-compose build
docker-compose up

Thanks to Setting up MySQL and importing dump within Dockerfile for clueing me in on the docker-entrypoint.sh and the fact that it runs both SQL and shell scripts!感谢在 Dockerfile 中设置 MySQL 和导入转储,让我了解 docker-entrypoint.sh 以及它同时运行 SQL 和 shell 脚本的事实!

I am sorry for this super long answer, but, you have a little way to go to get where you want.对于这个超长的答案,我很抱歉,但是,您还有一段路可以到达您想要的地方。 I will say that normally you wouldn't put the storage for the database in the same container as the database itself, you would either mount a host volume so that the data persists on the docker host, or, perhaps a container could be used to hold the data (/var/lib/mysql).我会说,通常您不会将数据库的存储与数据库本身放在同一个容器中,您要么挂载一个主机卷,以便数据保留在 docker 主机上,或者,也许可以使用一个容器保存数据(/var/lib/mysql)。 Also, I am new to mysql, so, this might not be super efficient.另外,我是 mysql 的新手,所以,这可能不是非常有效。 That said...那说...

I think there may be a few issues here.我认为这里可能存在一些问题。 The Dockerfile is used to create an image. Dockerfile 用于创建映像。 You need to execute the build step.您需要执行构建步骤。 At a minimum, from the directory that contains the Dockerfile you would do something like :至少,从包含 Dockerfile 的目录中,您可以执行以下操作:

docker build .

The Dockerfile describes the image to create. Dockerfile 描述了要创建的镜像。 I don't know much about mysql (I am a postgres fanboy), but, I did a search around the interwebs for 'how do i initialize a mysql docker container'.我对 mysql 不太了解(我是 postgres 粉丝),但是,我在互联网上搜索了“如何初始化 mysql docker 容器”。 First I created a new directory to work in, I called it mdir, then I created a files directory which I deposited a epcis_schema.sql file which creates a database and a single table:首先我创建了一个新目录来工作,我称之为 mdir,然后我创建了一个文件目录,我存放了一个 epcis_schema.sql 文件,它创建了一个数据库和一个表:

create database test;
use test;

CREATE TABLE testtab
(
id INTEGER AUTO_INCREMENT,
name TEXT,
PRIMARY KEY (id)
) COMMENT='this is my test table';

Then I created a script called init_db in the files directory:然后我在文件目录中创建了一个名为 init_db 的脚本:

#!/bin/bash

# Initialize MySQL database.
# ADD this file into the container via Dockerfile.
# Assuming you specify a VOLUME ["/var/lib/mysql"] or `-v /var/lib/mysql` on the `docker run` command…
# Once built, do e.g. `docker run your_image /path/to/docker-mysql-initialize.sh`
# Again, make sure MySQL is persisting data outside the container for this to have any effect.

set -e
set -x

mysql_install_db

# Start the MySQL daemon in the background.
/usr/sbin/mysqld &
mysql_pid=$!

until mysqladmin ping >/dev/null 2>&1; do
  echo -n "."; sleep 0.2
done

# Permit root login without password from outside container.
mysql -e "GRANT ALL ON *.* TO root@'%' IDENTIFIED BY '' WITH GRANT OPTION"

# create the default database from the ADDed file.
mysql < /tmp/epcis_schema.sql

# Tell the MySQL daemon to shutdown.
mysqladmin shutdown

# Wait for the MySQL daemon to exit.
wait $mysql_pid

# create a tar file with the database as it currently exists
tar czvf default_mysql.tar.gz /var/lib/mysql

# the tarfile contains the initialized state of the database.
# when the container is started, if the database is empty (/var/lib/mysql)
# then it is unpacked from default_mysql.tar.gz from
# the ENTRYPOINT /tmp/run_db script

(most of this script was lifted from here: https://gist.github.com/pda/9697520 ) (这个脚本的大部分是从这里解除的: https : //gist.github.com/pda/9697520

Here is the files/run_db script I created:这是我创建的 files/run_db 脚本:

# start db

set -e
set -x

# first, if the /var/lib/mysql directory is empty, unpack it from our predefined db
[ "$(ls -A /var/lib/mysql)" ] && echo "Running with existing database in /var/lib/mysql" || ( echo 'Populate initial db'; tar xpzvf default_mysql.tar.gz )

/usr/sbin/mysqld

Finally, the Dockerfile to bind them all:最后,Dockerfile 将它们全部绑定:

FROM mysql
MAINTAINER  (me) <email>

# Copy the database schema to the /data directory
ADD files/run_db files/init_db files/epcis_schema.sql /tmp/

# init_db will create the default
# database from epcis_schema.sql, then
# stop mysqld, and finally copy the /var/lib/mysql directory
# to default_mysql_db.tar.gz
RUN /tmp/init_db

# run_db starts mysqld, but first it checks
# to see if the /var/lib/mysql directory is empty, if
# it is it is seeded with default_mysql_db.tar.gz before
# the mysql is fired up

ENTRYPOINT "/tmp/run_db"

So, I cd'ed to my mdir directory (which has the Dockerfile along with the files directory).所以,我 cd 到我的 mdir 目录(其中包含 Dockerfile 和文件目录)。 I then run the command:然后我运行命令:

docker build --no-cache .

You should see output like this:你应该看到这样的输出:

Sending build context to Docker daemon 7.168 kB
Sending build context to Docker daemon 
Step 0 : FROM mysql
 ---> 461d07d927e6
Step 1 : MAINTAINER (me) <email>
 ---> Running in 963e8de55299
 ---> 2fd67c825c34
Removing intermediate container 963e8de55299
Step 2 : ADD files/run_db files/init_db files/epcis_schema.sql /tmp/
 ---> 81871189374b
Removing intermediate container 3221afd8695a
Step 3 : RUN /tmp/init_db
 ---> Running in 8dbdf74b2a79
+ mysql_install_db
2015-03-19 16:40:39 12 [Note] InnoDB: Using atomics to ref count buffer pool pages
...
/var/lib/mysql/ib_logfile0
 ---> 885ec2f1a7d5
Removing intermediate container 8dbdf74b2a79
Step 4 : ENTRYPOINT "/tmp/run_db"
 ---> Running in 717ed52ba665
 ---> 7f6d5215fe8d
Removing intermediate container 717ed52ba665
Successfully built 7f6d5215fe8d

You now have an image '7f6d5215fe8d'.您现在有一个图像“7f6d5215fe8d”。 I could run this image:我可以运行这个图像:

docker run -d 7f6d5215fe8d

and the image starts, I see an instance string:图像开始,我看到一个实例字符串:

4b377ac7397ff5880bc9218abe6d7eadd49505d50efb5063d6fab796ee157bd3

I could then 'stop' it, and restart it.然后我可以“停止”它,然后重新启动它。

docker stop 4b377
docker start 4b377

If you look at the logs, the first line will contain:如果您查看日志,第一行将包含:

docker logs 4b377

Populate initial db
var/lib/mysql/
...

Then, at the end of the logs:然后,在日志的末尾:

Running with existing database in /var/lib/mysql

These are the messages from the /tmp/run_db script, the first one indicates that the database was unpacked from the saved (initial) version, the second one indicates that the database was already there, so the existing copy was used.这些是来自 /tmp/run_db 脚本的消息,第一个表明数据库是从保存的(初始)版本解压出来的,第二个表明数据库已经存在,因此使用了现有的副本。

Here is a ls -lR of the directory structure I describe above.这是我上面描述的目录结构的 ls -lR。 Note that the init_db and run_db are scripts with the execute bit set:请注意,init_db 和 run_db 是设置了执行位的脚本:

gregs-air:~ gfausak$ ls -Rl mdir
total 8
-rw-r--r--  1 gfausak  wheel  534 Mar 19 11:13 Dockerfile
drwxr-xr-x  5 gfausak  staff  170 Mar 19 11:24 files

mdir/files:
total 24
-rw-r--r--  1 gfausak  staff   126 Mar 19 11:14 epcis_schema.sql
-rwxr-xr-x  1 gfausak  staff  1226 Mar 19 11:16 init_db
-rwxr-xr-x  1 gfausak  staff   284 Mar 19 11:23 run_db

Another way based on a merge of serveral responses here before :另一种基于之前合并多个响应的方法:

docker-compose file : docker-compose 文件:

version: "3"
services:
    db:
      container_name: db
      image: mysql
      ports:
       - "3306:3306"  
      environment:
         - MYSQL_ROOT_PASSWORD=mysql
         - MYSQL_DATABASE=db

      volumes:
         - /home/user/db/mysql/data:/var/lib/mysql
         - /home/user/db/mysql/init:/docker-entrypoint-initdb.d/:ro

where /home/user .. is a shared folder on the host其中/home/user .. 是主机上的共享文件夹

And in the /home/user/db/mysql/init folder .. just drop one sql file, with any name, for example init.sql containing :/home/user/db/mysql/init文件夹中.. 只需删除一个 sql 文件,任何名称,例如init.sql包含:

CREATE DATABASE mydb;
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'%' IDENTIFIED BY 'mysql';
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'localhost' IDENTIFIED BY 'mysql';
USE mydb
CREATE TABLE CONTACTS (
    [ ... ]
);
INSERT INTO CONTACTS VALUES ...
[ ... ]

According to the official mysql documentation , you can put more than one sql file in the docker-entrypoint-initdb.d , they are executed in the alphabetical order根据mysql官方文档,可以在docker-entrypoint-initdb.d放置多个sql文件,按字母顺序执行

The other simple way, use docker-compose with the following lines:另一种简单的方法是使用 docker-compose 和以下几行:

mysql:
  from: mysql:5.7
  volumes:
    - ./database:/tmp/database
  command: mysqld --init-file="/tmp/database/install_db.sql"

Put your database schema into the ./database/install_db.sql.将您的数据库架构放入 ./database/install_db.sql。 Every time when you build up your container, the install_db.sql will be executed.每次构建容器时,都会执行 install_db.sql。

I've tried Greg's answer with zero success, I must have done something wrong since my database had no data after all the steps: I was using MariaDB's latest image, just in case.我已经尝试了 Greg 的答案,但成功率为零,我一定是做错了什么,因为我的数据库在所有步骤之后都没有数据:我使用的是 MariaDB 的最新图像,以防万一。

Then I decided to read the entrypoint for the official MariaDB image , and used that to generate a simple docker-compose file:然后我决定读取官方MariaDB 镜像的入口点,并使用它来生成一个简单的docker-compose文件:

database:
  image: mariadb
  ports:
     - 3306:3306
  expose:
     - 3306
  volumes:
     - ./docker/mariadb/data:/var/lib/mysql:rw
     - ./database/schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro
  environment:
     MYSQL_ALLOW_EMPTY_PASSWORD: "yes"

Now I'm able to persist my data AND generate a database with my own schema!现在我可以保留我的数据并使用我自己的模式生成一个数据库!

After Aug. 4, 2015, if you are using the official mysql Docker image, you can just ADD/COPY a file into the /docker-entrypoint-initdb.d/ directory and it will run with the container is initialized. 2015 年 8 月 4 日之后,如果您使用官方的 mysql Docker 镜像,您只需 ADD/COPY 一个文件到 /docker-entrypoint-initdb.d/ 目录中,它就会在容器初始化的情况下运行。 See github: https://github.com/docker-library/mysql/commit/14f165596ea8808dfeb2131f092aabe61c967225 if you want to implement it on other container images如果想在其他容器镜像上实现,请参见github: https : //github.com/docker-library/mysql/commit/14f165596ea8808dfeb2131f092aabe61c967225

The easiest solution is to use tutum/mysql最简单的解决方法是使用tutum/mysql

Step1第1步

docker pull tutum/mysql:5.5

Step2第2步

docker run -d -p 3306:3306 -v /tmp:/tmp  -e STARTUP_SQL="/tmp/to_be_imported.mysql" tutum/mysql:5.5

Step3 Step3

Get above CONTAINER_ID and then execute command docker logs to see the generated password information.获取上面的 CONTAINER_ID 然后执行命令docker logs查看生成的密码信息。

docker logs #<CONTAINER_ID>

For the ones not wanting to create an entrypoint script like me, you actually can start mysqld at build-time and then execute the mysql commands in your Dockerfile like so:对于那些不想像我一样创建入口点脚本的人,您实际上可以在构建时启动 mysqld,然后在您的 Dockerfile 中执行 mysql 命令,如下所示:

RUN mysqld_safe & until mysqladmin ping; do sleep 1; done && \
    mysql -uroot -e "CREATE DATABASE somedb;" && \
    mysql -uroot -e "CREATE USER 'someuser'@'localhost' IDENTIFIED BY 'somepassword';" && \
    mysql -uroot -e "GRANT ALL PRIVILEGES ON somedb.* TO 'someuser'@'localhost';"

The key here is to send mysqld_safe to background with the single & sign.这里的关键是使用单个&符号将 mysqld_safe 发送到后台。

After to struggle a little bit with that, take a look the Dockerfile using named volumes (db-data).在为此苦苦挣扎之后,使用命名卷(db-data)查看 Dockerfile。 It's important declare a plus at final part, where I mentioned that volume is [external]在最后一部分声明一个加号很重要,我提到音量是[external]

All worked great this way!这样一切都很好!

version: "3"

services:

  database:
    image: mysql:5.7
    container_name: mysql
    ports:
      - "3306:3306"
    volumes:
      - db-data:/docker-entrypoint-initdb.d
    environment:
      - MYSQL_DATABASE=sample
      - MYSQL_ROOT_PASSWORD=root

volumes:
  db-data:
    external: true

Below is the Dockerfile I used successfully to install xampp, create a MariaDB with scheme and pre populated with the info used on local server(usrs,pics orders,etc..)下面是我用来成功安装 xampp 的 Dockerfile,使用方案创建一个 MariaDB,并预先填充了本地服务器上使用的信息(usrs、pics 订单等)

FROM ubuntu:14.04

COPY Ecommerce.sql /root

RUN apt-get update \
 && apt-get install wget -yq \
 && apt-get install nano \
 && wget https://www.apachefriends.org/xampp-files/7.1.11/xampp-linux-x64-7.1.11-0-installer.run \
 && mv xampp-linux-x64-7.1.11-0-installer.run /opt/ \
 && cd /opt/ \
 && chmod +x xampp-linux-x64-7.1.11-0-installer.run \
 && printf 'y\n\y\n\r\n\y\n\r\n' | ./xampp-linux-x64-7.1.11-0-installer.run \
 && cd /opt/lampp/bin \
 && /opt/lampp/lampp start \
 && sleep 5s \

 && ./mysql -uroot -e "CREATE DATABASE Ecommerce" \
 && ./mysql -uroot -D Ecommerce < /root/Ecommerce.sql \
 && cd / \
 && /opt/lampp/lampp reload \
 && mkdir opt/lampp/htdocs/Ecommerce

COPY /Ecommerce /opt/lampp/htdocs/Ecommerce

EXPOSE 80

Since I struggled with this problem recently, I'm adding a docker-compose file that really helped me:由于我最近遇到了这个问题,因此我添加了一个对我有帮助的 docker-compose 文件:

version: '3.5'

services:
  db:
    image: mysql:5.7
    container_name: db-container
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
      - "./scripts/schema.sql:/docker-entrypoint-initdb.d/1.sql"
      - "./scripts/data.sql:/docker-entrypoint-initdb.d/2.sql"
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: test
      MYSQL_USER: test-user
      MYSQL_PASSWORD: password
    ports:
      - '3306:3306'
    healthcheck:
      test: "/usr/bin/mysql --user=root --password=password --execute \"SHOW DATABASES;\""
      interval: 2s
      timeout: 20s
      retries: 10

You just need to create a scripts folder in the same location as the docker-compose.yml file above.您只需要在与上面docker-compose.yml文件相同的位置创建一个scripts文件夹。

The scripts folder will have 2 files: scripts文件夹将包含 2 个文件:

  • schema.sql: DDL scripts (create table...etc) schema.sql:DDL 脚本(创建表...等)
  • data.sql: Insert statements that you want to be executed right after schema creation. data.sql:插入要在模式创建后立即执行的语句。

After this, you can run the command below to erase any previous database info (for a fresh start):在此之后,您可以运行以下命令来清除任何以前的数据库信息(重新开始):

docker-compose rm -v -f db && docker-compose up

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM