我试图为我的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构建期间设置数据库创建和转储导入的任何想法吗?
答案 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个解决方案。
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
创建可执行脚本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/