设置MySQL并在Dockerfile中导入转储


127

我正在尝试为我的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构建期间设置数据库创建和转储导入的任何想法?


这是由于每个RUN命令在不同的容器中执行的事实。在这里有很好的解释:stackoverflow.com/questions/17891669/…–
Kuhess

这仅说明RUN命令具有不同的上下文。但是我依赖于守护程序,而不是上下文。
vinnylinux

1
是的,但这说明了为什么无法连接到MySQL。这是因为它仅在您的第一RUN行中运行。
Kuhess 2014年

要执行SQL语句,需要启动MySQL,并在同一个容器中使用MySQL客户端:一个RUN包含几个步骤。您可以在此处找到软件分步安装的示例:stackoverflow.com/questions/25899912/install-nvm-in-docker/…–
Kuhess

您还可以使用docker -compose来查看服务:docs.docker.com/compose/wordpress/#build-the-project,mysql可以附加到您的应用程序上
aurny2420289

Answers:


122

中的每条RUN指令都在Dockerfile不同的层中执行(如的文档中所述RUN)。

在中Dockerfile,您有三个RUN说明。问题是MySQL服务器仅在第一个启动。在其他版本中,没有MySQL正在运行,这就是为什么mysql客户端出现连接错误的原因。

要解决此问题,您有2个解决方案。

解决方案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

您是否知道我可以如何保留这些信息?当我在容器上运行内容时,我在Dockerfile构建上创建的数据库和表不可用。:(
vinnylinux

1
这取决于您坚持的意思。如果要使数据在多个docker run执行中保持不变,则需要装入卷。如果您只想在转储中包含一个容器,但又不想保留进一步的修改,则可以摆脱中的VOLUME说明Dockerfile
Kuhess

16
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)在尝试解决方案1时遇到问题。遵循日志mysqld_safe Starting mysqld daemon with databases from /var/lib/mysqlmysqld_safe mysqld from pid file /var/run/mysqld/mysqld.pid ended
Vituel

1
我发现最好在启动时检查脚本,以查看mysql是否已创建数据库。如果有的话,那就别管它了,否则运行mysql_init_db并加载到数据库结构中。这样可以灵活地在测试时自动重置数据库,但是如果您希望数据库持久化或测试不同的数据集,则可以使用来在/ var / lib / mysql上挂载一个卷docker run -v ...
tu-Restate Monica-dor duh,2016年

1
@trevorgrayson-这也不起作用。现在,它给出错误ERROR 2003(HY000):无法连接到“ 127.0.0.1”(111)上的MySQL服务器– 2013
深夜

166

最新版本的官方mysql docker映像允许您在启动时导入数据。这是我的docker-compose.yml

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容器上的此目录中。

如果您有兴趣了解其工作原理,请docker-entrypoint.sh在GitHub中查看它们。他们添加了此块以允许导入数据

    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"]

数据容器甚至不必处于启动状态即可保持持久性。


1
恕我直言,这是更好的答案。它不允许自己创建图像。感谢您的提示。
Metal3d

5
卷的一个小更改:- - ./docker/data:/docker-entrypoint-initdb.d删除了.容器目录前面的。
大卫·辛克莱

7
尽管这是正确的过程,但并不能很好地解决用例。Docker的优点之一是您可以非常快速地启动环境。如果在启动期间Docker导入MySQL DB时需要等待3-4分钟,则会失去这一优势。目的是要有一个已经包含数据库中数据的容器,以便您可以尽快使用它。
Garreth McDaid

3
这个答案仍然适用于最新版本吗?似乎不再工作了
丹尼尔(Daniel)

2
请注意,此处的docker-compose示例是v2而不是v3。v3不支持“ volumes_from:”。
欧内斯特(Ernest)

37

我所做的是将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第一次运行时,转储将还原到数据库中。


3
+1,一个加法:链接到脚本中运行为了更好地理解什么是真正发生的事情:github.com/docker-library/mariadb/blob/...
汤姆Imrei

6
最新mysql似乎无法加载转储的sql文件,即使使用5.6,InnoDb存储引擎也有问题。
zinking

1
同样在这里,它有这样的指令,我什至在日志中看到正在加载init文件,但是db为空!
霍尔姆斯'17

11

我使用了docker-entrypoint-initdb.d方法(感谢@Kuhess),但就我而言,我想基于在.env文件中定义的一些参数来创建数据库,所以我做了这些

1)首先,我在Docker根项目目录中定义类似以下的.env文件

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

2)然后定义我的docker-compose.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)然后,我定义一个包含Dockerfile的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转储文件,但我在开头添加了2行,因此文件看起来像这样

--
-- 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占位符替换为我在其中设置的数据库的名称。 .env文件。

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

现在您可以构建并运行容器了


我喜欢使用.env文件的方法。但是,据此.env文件功能仅在使用docker-compose up命令时有效,而不能与一起使用docker stack deploy。因此,如果您想.env在生产环境中使用该文件,则可能需要查看引入的Docker机密docker 17.06。然后,您可以将.env文件与开发docker compose up和生产docker stack deploy阶段的秘密一起使用
ira

好的方法,但是我建议使用RUN sed -i '1s/^/CREATE DATABASE IF NOT EXISTS $ MYSQL_DATABASE ;\nUSE $ MYSQL_DATABASE ;\n/' data.sql而不是sed您建议的命令。这样,您可以使用拥有的任何转储文件-如果您要处理大量数据,这将非常有用:)
TomaszKapłoński17

9

下面是使用一个工作版本v3docker-compose.yml。关键是volume指令:

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我拥有的data目录中,我有一个包含.sql转储文件的目录。很好,因为.sql每个表都可以有一个转储文件。

我只是跑步docker-compose up,我很好。数据会在停靠之间自动保留。如果你想删除的数据,并“吸入”新的.sql文件上运行docker-compose down,然后docker-compose up

如果有人知道如何mysql/docker-entrypoint-initdb.d不删除卷的情况下使Docker重新处理文件,请发表评论,我将更新此答案。


2
这个答案帮助了我。该注释docker-compose down非常重要,因为尽管重新启动docker-compose,我仍然没有看到任何变化。在这种情况下,MYSQL_DATABASE是必需变量
nxmohamad
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.