Exec 未替换 Docker 入口点脚本中的 bash shell

Aar*_*ley 5 bash uwsgi docker docker-entrypoint

我正在尝试从 Docker 容器运行 UWSGI 服务器。我已经取得了成功,但我遇到了一个问题,因为我的入口点脚本在容器启动后仍将以 PID 1 的 root 身份运行,而我宁愿将初始进程/bin/bash替换为 UWSGI 进程:

bash-4.4# ps aux
PID   USER     TIME  COMMAND
    1 root      0:00 {docker-entrypoi} /bin/bash /usr/local/bin/docker-entrypoint.sh
   19 myuser    0:00 uwsgi --ini /opt/mysite/uwsgi.ini
   21 myuser    0:00 uwsgi --ini /opt/mysite/uwsgi.ini
   22 myuser    0:00 uwsgi --ini /opt/mysite/uwsgi.ini
   24 myuser    0:02 python3 ./manage.py qcluster
   28 myuser    0:00 python3 ./manage.py qcluster
   29 myuser    0:00 python3 ./manage.py qcluster
   30 myuser    0:00 python3 ./manage.py qcluster
   31 myuser    0:00 python3 ./manage.py qcluster
   32 myuser    0:00 python3 ./manage.py qcluster
   33 myuser    0:00 python3 ./manage.py qcluster
   34 myuser    0:00 python3 ./manage.py qcluster
Run Code Online (Sandbox Code Playgroud)

我已经尝试了exec和 的一些变体su-exec,但我仍然遇到了上面的问题。我需要在启动时向 UWSGI 提供 PEM 密码,因此我一直使用如下语法:

echo $PEM_PASSPHRASE | exec uwsgi --ini /opt/mysite/uwsgi.ini
Run Code Online (Sandbox Code Playgroud)

这可以很好地启动和运行,但我仍然让 PID 1/bin/bash进程运行,UWSGI 进程作为下面的子进程。我觉得我错过了一些明显的细节,无法通过exec.

无论如何,我只在 Dockerfile 中使用 ENTRYPOINT,而不是 CMD:

ENTRYPOINT ["docker-entrypoint.sh"]
Run Code Online (Sandbox Code Playgroud)

任何正确方向的指示将不胜感激。

Gor*_*son 5

管道中的 Shell 命令(包括exec在子 shell 中运行)。因此,echo ... | exec uwsgi ...创建两个子进程,一个正在运行echo(实际上可能是一个运行 shell 内置的子 shell),另一个子 shell 立即将其自身替换为uwsgi.

我还没有在 docker 中对此进行测试,但以下任一方法应该可以工作:

exec uwsgi --ini /opt/mysite/uwsgi.ini <<<"$PEM_PASSPHRASE"
exec uwsgi --ini /opt/mysite/uwsgi.ini < <(echo "$PEM_PASSPHRASE")
Run Code Online (Sandbox Code Playgroud)

写完这篇文章后,我想到在 bash v4.3 及更高版本中,它实际上更容易,因为lastpipeshell 选项将告诉 bash 在当前 shell 中运行管道的最后一个元素而不是子 shell:

shopt -s lastpipe
echo "$PEM_PASSPHRASE" | exec uwsgi --ini /opt/mysite/uwsgi.ini
Run Code Online (Sandbox Code Playgroud)

然而,由于这是我们正在讨论的密码,因此存在关于这些如何暴露密码的安全考虑。第一个选项(“此处字符串”)创建一个存储密码的临时文件(在磁盘上!),打开它进行输入,然后立即取消链接。这意味着在任何正常文件路径下都无法访问它,但它会无限期地存储在磁盘上(并且不会被安全删除)。具有计算机物理访问权限的人(或在某些系统上,可以通过 /proc 直接读取)。所以不太好。

(此处文档也可以做同样的事情。)

第二个(从“进程替换”重定向)和第三个(lastpipe)可能更好......或更糟。在 bash 中,echo是一个内置函数,因此进程替换(<( )部分)创建一个子 shell,将echo内置函数运行到管道中...然后退出。哪个更好。但在没有内置命令的 shell 中echo,它将运行一个单独的echo进程,并且它的参数列表(即密码)实际上是公共信息(例如通过命令ps)。这可能更糟。

所以我的建议是使用第二个或第三个,并确保你在 bash 下运行它。