在Dockerfile中设置MySQL并导入转储

时间:2014-09-18 18:37:28

标签: mysql docker

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

6 个答案:

答案 0 :(得分:151)

官方mysql docker image的最新版本允许您在启动时导入数据。这是我的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

这里,我在docker/data下面有我的data-dump.sql,它与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"]

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

答案 1 :(得分:107)

RUN中的每条Dockerfile指令都在不同的层中执行(如documentation of 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

答案 2 :(得分:33)

我所做的是将我的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时,转储将在db。中恢复。

答案 3 :(得分:9)

我使用了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

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 ...;
...
...
...

所以发生了什么,我用过&#34; RUN sed -i&#39; s / MYSQL_DATABASE /&#39; $ MYSQL_DATABASE&#39; / g&#39; /etc/mysql/data.sql"命令将MYSQL_DATABASE占位符替换为我在.env文件中设置的数据库名称。

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

现在您已准备好构建并运行容器

答案 4 :(得分:5)

这是使用v3中的docker-compose.yml的工作版本。关键是volumes指令:

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中的文件,请发表评论,我将更新此答案。

答案 5 :(得分:1)

编辑:我在这里误解了这个问题。我的以下回答说明了如何在容器创建时运行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/