【问题标题】:How to execute scripts after docker-compose up?docker-compose up 后如何执行脚本?
【发布时间】:2017-02-08 15:37:15
【问题描述】:

我正在尝试使用 docker(-compose) 使我的开发过程更容易/可维护。 我不想使用任何卷(如果可能的话)。 为什么我运行 'docker-compose up -d' 后 import.sh 没有被执行?

我有以下文件:

docker-compose.yml
  mysql
  ---- import.sh
  ---- db.sql
  ---- Dockerfile

docker-compose.yml 中有:

version: '2'

services:
  database:
    image: mysql
    build:
      context: ./mysql/
      dockerfile: Dockerfile
    container_name: mysqltest
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: 123456

/mysql/Dockerfile中有:

ADD import.sh /tmp/import.sh
ADD db.sql /tmp/db.sql
RUN /tmp/import.sh

/mysql/db.sql中有:

CREATE DATABASE test1;
CREATE DATABASE test2;
CREATE DATABASE test3;

【问题讨论】:

  • 镜像在构建时运行。 Docker Compose 会在运行之前为您构建镜像。所以你的脚本应该在运行docker-compose up -d 之前运行,而不是之后
  • 听起来您只是希望您的数据库转储在 mysql 守护程序启动之后运行。在这种情况下,请使用/docker-entrypoint-initdb.d,记录在MySQL Dockerhub Page 上并在此处解释:stackoverflow.com/questions/36781984/…(Postgres 和 MySQL 的功能相同)。
  • 是的,这就是我想要实现的目标,它对我有用,谢谢。但是如果我想在构建过程之后/当所有容器都准备好时运行其他脚本呢?
  • fzgregor 下面的答案解释了最好的方法。
  • 只是对@mkasberg 巧妙建议的一点补充,/docker-entrypoint-initdb.d 解决方案中的脚本将仅在容器的新启动时执行(即,如果您使用命名卷来持久化已包含数据库文件的数据,脚本将被忽略)。您可能会找到关于此here 的好帖子

标签: mysql docker docker-compose


【解决方案1】:

您可以在 Dockerfile 中使用 ENTRYPOINTCMD 在容器启动时执行命令。它们之间的区别在于ENTRYPOINT 在容器启动的任何时候都会执行,而CMD 可能会被命令行选项替换。假设你要执行的命令是X

docker run my-image Y

如果 ENTRYPOINT X 在 Dockerfile 中,将执行 X,如果 CMD X 在 Dockerfile 中,则执行 Y

但是,有两个警告:

  1. 每次启动容器时都会执行该命令。
  2. 命令终止后,容器将关闭。

因此,一个典型的解决方案是拥有一个docker-entrypoint 脚本。它检查它是否在启动其环境的新容器中运行,然后执行容器的实际程序。 查看official mysql Dockerfile and entrypoint 了解一下。

一个示例入口点脚本可能如下所示:

$ cat docker_entrypoint.sh                                                                                                                                          
if [ ! -f .initialized ]; then                                                                                                                                                                                    
    echo "Initializing container"                                                                                                                                                                                 
    # run initializing commands                                                                                                                                                                                   
    touch .initialized                                                                                                                                                                                            
fi                                                                                                                                                                                                                

exec "$@"

首先,它检查是否有一个名为.initialized 的文件。如果没有,则运行一些命令来初始化容器环境。之后touch .initialized.initialized 创建为一个空文件。因此,后续容器启动不会再次执行初始化命令。 其次,它启动了实际的服务。使用exec 执行此操作会将shell 进程替换为服务进程。因此,docker 将保持容器运行,直到服务终止。 "$@" 将包含“容器/图像命令”。正如我在上面已经指出的,这是在 Dockerfile 中使用CMD X 设置的,并在命令中被覆盖。通过使用exec "$@",您将能够在容器中启动不同的程序进行检查,例如bash,并默认启动服务,在 Dockerfile 的 CMD 语句中指定。

【讨论】:

  • 有人可以编辑吗? XY 是脚本吗?在这两个警告中,CMDENTRYPOINT 的区别是什么?
  • 据我了解,Y 是对 docker 映像的引用,而 X 是对诸如 apachectl 之类的命令的引用
【解决方案2】:

如果你只是想在第一次初始化你的数据库,你可以使用这个简单的方法。

    volumes:
      - [the scripts dir]:/docker-entrypoint-initdb.d

初始化一个新实例 首次启动容器时,将使用提供的配置变量创建并初始化具有指定名称的新数据库。此外,它将执行 /docker-entrypoint-initdb.d 中的扩展名为 .sh、.sql 和 .sql.gz 的文件。文件将按字母顺序执行。您可以通过将 SQL 转储安装到该目录并提供带有贡献数据的自定义图像来轻松填充您的 mysql 服务。 SQL 文件将默认导入到 MYSQL_DATABASE 变量指定的数据库中。

文档在这里:https://docs.docker.com/samples/library/mysql/

【讨论】:

    猜你喜欢
    • 2021-01-29
    • 2018-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多