在 Dockerfile 建立 MySQL 并导入 dump

我试图为我的 LAMP 项目设置一个 Dockerfile,但是在启动 MySQL 时遇到了一些问题。我的 Dockerfile 文件中有以下几行:

VOLUME ["/etc/mysql", "/var/lib/mysql"]
ADD dump.sql /tmp/dump.sql
RUN /usr/bin/mysqld_safe & sleep 5s
RUN mysql -u root -e "CREATE DATABASE mydb"
RUN mysql -u root mydb < /tmp/dump.sql

但我一直得到这个错误:

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (111)

关于如何在 Dockerfile 构建期间设置数据库创建和转储导入,有什么想法吗?

172803 次浏览

Dockerfile中的每个 RUN指令在不同的层中执行(如 文件中所解释的)。

在你的 Dockerfile中,你有三个 RUN指令。问题是 MySQL 服务器只在第一个。在其他情况下,没有运行 MySQL,这就是为什么在使用 mysql客户机时会出现连接错误。

要解决这个问题,你有两个解决方案。

解决方案1: 使用一行 RUN

RUN /bin/bash -c "/usr/bin/mysqld_safe --skip-grant-tables &" && \
sleep 5 && \
mysql -u root -e "CREATE DATABASE mydb" && \
mysql -u root mydb < /tmp/dump.sql

解决方案2: 使用脚本

创建一个可执行脚本 init_db.sh:

#!/bin/bash
/usr/bin/mysqld_safe --skip-grant-tables &
sleep 5
mysql -u root -e "CREATE DATABASE mydb"
mysql -u root mydb < /tmp/dump.sql

把这些线添加到你的 Dockerfile:

ADD init_db.sh /tmp/init_db.sh
RUN /tmp/init_db.sh

官方 Mysql 码头图像的最新版本允许您在启动时导入数据

data:
build: docker/data/.
mysql:
image: mysql
ports:
- "3307:3306"
environment:
MYSQL_ROOT_PASSWORD: 1234
volumes:
- ./docker/data:/docker-entrypoint-initdb.d
volumes_from:
- data

这里,我将 data-dump. sql 放在 docker/data下,它是相对于 docker-compose 运行所在的文件夹的。我正在将这个 sql 文件挂载到容器上的这个目录 /docker-entrypoint-initdb.d中。

如果您对此感兴趣,可以查看 GitHub 中的 docker-entrypoint.sh。他们添加了这个块以允许导入数据

    echo
for f in /docker-entrypoint-initdb.d/*; do
case "$f" in
*.sh)  echo "$0: running $f"; . "$f" ;;
*.sql) echo "$0: running $f"; "${mysql[@]}" < "$f" && echo ;;
*)     echo "$0: ignoring $f" ;;
esac
echo
done

另外,如果您希望在 mysql 容器停止和删除之后仍然保持数据,那么您需要一个单独的数据容器,如 docker-compose 中所示。Yml.数据容器 Dockerfile 的内容非常简单。

FROM n3ziniuka5/ubuntu-oracle-jdk:14.04-JDK8


VOLUME /var/lib/mysql


CMD ["true"]

对于持久性,数据容器甚至不必处于开始状态。

我所做的就是将 sql 转储下载到一个“ db-dump”文件夹中,然后挂载它:

mysql:
image: mysql:5.6
environment:
MYSQL_ROOT_PASSWORD: pass
ports:
- 3306:3306
volumes:
- ./db-dump:/docker-entrypoint-initdb.d

当我第一次运行 docker-compose up时,转储在数据库中还原。

我使用了 docker-entrypoint-initdb. d 方法(感谢@Kuhess) 但是在我的例子中,我想根据我定义的一些参数创建数据库。Env 文件,所以我做了这些

1) 首先,我在 docker root 项目目录中定义. env 文件

MYSQL_DATABASE=my_db_name
MYSQL_USER=user_test
MYSQL_PASSWORD=test
MYSQL_ROOT_PASSWORD=test
MYSQL_PORT=3306

然后我定义我的码头作品。Yml 文件。因此,我使用 args 指令定义环境变量,并从。Env 文件

version: '2'
services:
### MySQL Container
mysql:
build:
context: ./mysql
args:
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
ports:
- "${MYSQL_PORT}:3306"

3) 然后定义一个 mysql 文件夹,其中包含一个 Dockerfile

FROM mysql:5.7
RUN chown -R mysql:root /var/lib/mysql/


ARG MYSQL_DATABASE
ARG MYSQL_USER
ARG MYSQL_PASSWORD
ARG MYSQL_ROOT_PASSWORD


ENV MYSQL_DATABASE=$MYSQL_DATABASE
ENV MYSQL_USER=$MYSQL_USER
ENV MYSQL_PASSWORD=$MYSQL_PASSWORD
ENV MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD


ADD data.sql /etc/mysql/data.sql
RUN sed -i 's/MYSQL_DATABASE/'$MYSQL_DATABASE'/g' /etc/mysql/data.sql
RUN cp /etc/mysql/data.sql /docker-entrypoint-initdb.d


EXPOSE 3306

4) 现在我使用 mysqldump 转储数据库,并将 data.sql 放到 mysql 文件夹中

mysqldump -h <server name> -u<user> -p <db name> > data.sql

这个文件只是一个普通的 sql 转储文件,但是我在开头添加了两行,这样文件看起来就像这样

--
-- Create a database using `MYSQL_DATABASE` placeholder
--
CREATE DATABASE IF NOT EXISTS `MYSQL_DATABASE`;
USE `MYSQL_DATABASE`;


-- Rest of queries
DROP TABLE IF EXISTS `x`;
CREATE TABLE `x` (..)
LOCK TABLES `x` WRITE;
INSERT INTO `x` VALUES ...;
...
...
...

因此,我使用“ RUN sed-i’s/MYSQL _ DATABASE/’$MYSQL _ DATABASE’/g’/etc/MYSQL/data.sql”命令将 MYSQL_DATABASE占位符替换为我所设置的 DB 的名称。Env 文件。

|- docker-compose.yml
|- .env
|- mysql
|- Dockerfile
|- data.sql

现在您已经准备好构建和运行容器了

下面是一个使用 docker-compose.ymlv3的工作版本,关键是 数量指令:

mysql:
image: mysql:5.6
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_USER: theusername
MYSQL_PASSWORD: thepw
MYSQL_DATABASE: mydb
volumes:
- ./data:/docker-entrypoint-initdb.d

在我的 docker-compose.yml目录中,我有一个包含 .sql转储文件的 data目录。这很好,因为您可以为每个表提供一个 .sql转储文件。

我只要运行 docker-compose up就可以了。数据在停止之间自动保持。如果你想删除数据和“吸入”新的 .sql文件运行 docker-compose down然后 docker-compose up

如果有人知道如何得到的 mysql码头重新处理文件在 /docker-entrypoint-initdb.d没有删除卷,请留下评论,我会更新这个答案。

编辑: 我误解了这里的问题。我接下来的回答解释了如何在 容器创建时间容器创建时间上运行 sql 命令,但是不能按照 OP 的要求在 图像创建时间图像创建时间上运行。

我不太喜欢 Kuhess 接受的答案,因为 sleep 5在我看来有点骇人听闻,因为它假设 mysql db 守护进程已经在这个时间框架内正确加载。这只是假设,不能保证。另外,如果您使用提供的 mysql docker 映像,映像本身已经负责启动服务器; 我不会干扰定制的 /usr/bin/mysqld_safe

我按照这里的其他答案,将 bash 和 sql 脚本复制到 docker 容器中的文件夹 /docker-entrypoint-initdb.d/中,因为这显然是 mysql 映像提供程序的预期方式。一旦 db 守护进程准备就绪,就会执行该文件夹中的所有内容,因此您应该能够依赖它。

作为对其他答案的补充——因为没有其他答案明确提到这一点: 除了 sql 脚本之外,您还可以将 bash 脚本复制到该文件夹中可能会给你更多的控制。

例如,这就是我所需要的,因为我也需要导入一个转储,但是仅仅导入转储是不够的,因为它没有提供它应该导入到哪个数据库中。因此,在我的例子中,我有一个名为 db_custom_init.sh的脚本,其中包含以下内容:

mysql -u root -p$MYSQL_ROOT_PASSWORD -e 'create database my_database_to_import_into'
mysql -u root -p$MYSQL_ROOT_PASSWORD my_database_to_import_into < /home/db_dump.sql


这个 Dockerfile 复制了那个脚本:

FROM mysql/mysql-server:5.5.62
ENV MYSQL_ROOT_PASSWORD=XXXXX
COPY ./db_dump.sql /home/db_dump.sql
COPY ./db_custom_init.sh /docker-entrypoint-initdb.d/


我也遇到过同样的问题,但是通过分离 MySQL 的启动命令,我设法让它工作起来:

sudo docker build -t MyDB_img -f Dockerfile.dev
sudo docker run --name SomeDB -e MYSQL_ROOT_PASSWORD="WhatEver" -p 3306:3306 -v $(pwd):/app -d MyDB_img

然后 睡20秒在运行 MySQL 脚本之前,它工作。

sudo docker exec -it SomeDB sh -c yourscript.sh

我只能假设 MySQL 服务器在接受传入的连接和脚本之前需要几秒钟的启动时间。

基于 库赫斯回复,但没有硬睡眠:

RUN /bin/bash -c "/usr/bin/mysqld_safe --skip-grant-tables &" && \
while ! mysqladmin ping --silent; do sleep 1; echo "wait 1 second"; done && \
mysql -u root -e "CREATE DATABASE mydb" && \
mysql -u root mydb < /tmp/dump.sql

将执行添加到/docker-entrypoint-initdb. d 的任何文件或脚本 在集装箱的开始

确保不添加或运行任何可以使用 Mysql 服务从 Dockerfile。他们将失败并停止图像 因为 mysql 服务尚未启动时,这个文件或 添加.sh 文件的最佳方法是将它们添加到 /docker-entrypoint-initdb. d 目录

工作范例

FROM mysql
ADD mysqlcode.sh /docker-entrypoint-initdb.d/mysqlcode.sh
ADD db.sql /home/db.sql
RUN chmod -R 775 /docker-entrypoint-initdb.d
ENV MYSQL_ROOT_PASSWORD mypassword

Sh 将在 mysql 服务处于活动状态时执行一些命令

Mysqlcode.sh

#!/bin/bash
mysql -u root -pmypassword --execute "CREATE DATABASE IF NOT EXISTS mydatabase;"
mysql -u root -pmypassword mydatabase < /home/db.sql