【问题标题】:How to clean up temporary files after exec-ing inside entrypoint script?在入口点脚本中执行后如何清理临时文件?
【发布时间】:2019-01-18 23:57:56
【问题描述】:

我正在尝试编写自己的 mariadb docker 映像。我想在容器启动后(exec mysqld 之后)执行一些 sql 语句。但是我发现mysqld --init-file 选项对我的情况很有用。所以我的入口点脚本如下所示。

Dockerfile

FROM alpine:edge

RUN set -ex \
    && apk add mariadb mariadb-client \
    && mkdir -p /run/mysqld \
    && chown -R mysql:mysql /run/mysqld \
    && ln -snf /usr/lib/mariadb /usr/lib/mysql \
    && mysql_install_db --user=mysql --skip-name-resolve --auth-root-authentication-method=socket --auth-root-socket-user=root --force --rpm --skip-test-db

   COPY entrypoint.sh /
   ENTRYPOINT ["/entrypoint.sh"]
   EXPOSE 3306

   CMD ["mysqld"]

entrypoint.sh

#!/bin/sh

set -ex
{
    echo  "CREATE USER IF NOT EXISTS '${MYSQL_USER}'@'%' IDENTIFIED BY '${MYSQL_PASSWORD}';"
    echo  "CREATE DATABASE IF NOT EXISTS ${MYSQL_DATABASE};"
    echo  "GRANT ALL ON ${MYSQL_DATABASE}.* TO '${MYSQL_USER}'@'%';"
} > /tmp/mysqld-init.sql


exec $@ --init-file="/tmp/mysqld-init.sql"

如您所见,临时初始化文件包含一些敏感信息。我想在执行exec $@ --init-file="/tmp/mysqld-init.sql"后清理它。

现在我想到了两个想法。一种是为临时 sql 命令创建命名管道 (FIFO) 文件或使用 trap 命令。

想法1

但这里的问题是一个不必要的子后台进程在容器上继续运行,因为我使用了进程控制运算符&。但是我是徒劳的,我该如何退出该过程。

if [ ! -p "/tmp/mysqld.init" ]; then
    mkfifo /tmp/mysqld.init
fi

{
    echo  "CREATE USER IF NOT EXISTS '${MYSQL_USER}'@'%' IDENTIFIED BY '${MYSQL_PASSWORD}';"
    echo  "CREATE DATABASE IF NOT EXISTS ${MYSQL_DATABASE};"
    echo  "GRANT ALL ON ${MYSQL_DATABASE}.* TO '${MYSQL_USER}'@'%';"
} > /tmp/mysqld.init &

exec $@ --init-file="/tmp/mysqld.init"

想法2

exec 命令被执行时,使用trap 命令并清理临时文件。但我不知道如何捕捉 exec 信号。

trap cleanup "the exec signal"

cleanup()
{
  echo "Caught Signal ... cleaning up."
  rm -rf /tmp/mysqld-init.sql
  echo "Done cleanup ... quitting."
  exit 1
}
  set -ex
{
    echo  "CREATE USER IF NOT EXISTS '${MYSQL_USER}'@'%' IDENTIFIED BY '${MYSQL_PASSWORD}';"
    echo  "CREATE DATABASE IF NOT EXISTS ${MYSQL_DATABASE};"
    echo  "GRANT ALL ON ${MYSQL_DATABASE}.* TO '${MYSQL_USER}'@'%';"
} > /tmp/mysqld-init.sql

exec $@ --init-file="/tmp/mysqld.init"

【问题讨论】:

  • 您可以删除初始化文件,但环境变量会发生什么?你要取消它们吗?
  • 我认为可以使用 file_env github.com/docker-library/mariadb/blob/… 取消设置。但是现在我要离开它。但是我怎样才能删除临时文件。
  • 环境变量将在docker inspectps 输出中可见。容器中/tmp 中的文件可能比这隐藏了一点更多,并且会在容器退出时自动清理。

标签: mysql docker named-pipes entry-point bash-trap


【解决方案1】:

使用tini 解决此信号和僵尸进程问题。

FROM alpine:edge

RUN set -ex \
    && apk add --no-cache mariadb mariadb-client tini \
    && mkdir -p /run/mysqld \
    && chown -R mysql:mysql /run/mysqld \
    && ln -snf /usr/lib/mariadb /usr/lib/mysql \
    && mysql_install_db --user=mysql --skip-name-resolve --auth-root-authentication-method=socket --auth-root-socket-user=root --force --rpm --skip-test-db

COPY entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]
EXPOSE 3306

CMD ["mysqld"]

入口点.sh

if [ ! -p "/tmp/mysqld.init" ]; then
    mkfifo /tmp/mysqld.init
fi

{
    echo  "CREATE USER IF NOT EXISTS '${MYSQL_USER}'@'%' IDENTIFIED BY '${MYSQL_PASSWORD}';"
    echo  "CREATE DATABASE IF NOT EXISTS ${MYSQL_DATABASE};"
    echo  "GRANT ALL ON ${MYSQL_DATABASE}.* TO '${MYSQL_USER}'@'%';"
} > /tmp/mysqld.init &

    exec tini -g -- "$@" --init-file="/tmp/mysqld.init"

【讨论】:

    【解决方案2】:

    我认为trap 是解决这个问题的最佳方案

    function interrupt(){
    
        local dir=$1
        [ -e ${dir} ] && rm -rf ${dir}
        exit 128
    }
    TMP_DIR=$(mktemp -d /tmp/entrypoint.XXXX)
    trap "interrupt ${TMP_DIR}" SIGINT SIGTERM
    trap "rm -rf ${TMP_DIR}" EXIT
    
    set -ex
    {
        echo  "CREATE USER IF NOT EXISTS '${MYSQL_USER}'@'%' IDENTIFIED BY '${MYSQL_PASSWORD}';"
        echo  "CREATE DATABASE IF NOT EXISTS ${MYSQL_DATABASE};"
        echo  "GRANT ALL ON ${MYSQL_DATABASE}.* TO '${MYSQL_USER}'@'%';"
    } > ${TMP_DIR}/mysqld-init.sql
    
    exec $@ --init-file="${TMP_DIR}/mysqld-init.sql"
    

    【讨论】:

    • 啊..它不起作用。它会删除exec 之前的文件。 [错误] mysqld:无法创建/写入文件'/tmp/entrypoint.aJkdJB/mysqld-init.sql'(错误代码:13“权限被拒绝”)2019-01-19 1:25:06 0 [错误]中止
    • 它说权限被拒绝。尝试将临时目录更改为具有适当权限的另一个文件夹
    • 我可以确认这与权限被拒绝无关。由于文件不存在或在 exec main 进程之前删除,因此 mysqld 显示此错误。
    • Can't create/write to file '/tmp/entrypoint.aJkdJB/mysqld-init.sql' 创建文件失败,所以不存在。玩它,添加调试消息等
    • 正如我在上面的评论中所说,我正确检查了它是否能够创建临时文件,但在执行 mysqld 命令之前会删除。我确定是因为我以 root 身份运行脚本。那是一个 mysqld 错误。
    猜你喜欢
    • 1970-01-01
    • 2019-04-18
    • 1970-01-01
    • 2016-09-14
    • 1970-01-01
    • 2013-04-14
    • 1970-01-01
    • 2022-01-17
    • 2016-11-13
    相关资源
    最近更新 更多