Ale*_* F. 6 shell docker alpine-linux
标题几乎说明了一切(但也许还有更险恶的东西在起作用。)我知道在您登录/etc/profile.d/*.sh时运行的脚本,但当您只是启动一个 shell 时,它似乎并没有按预期工作。这是一个使用 docker 的示例:
创建一个小脚本:
$ echo "echo hello world" > startup.sh
Run Code Online (Sandbox Code Playgroud)
运行安装了脚本的 alpine shell,如下所示:
$ docker run -it --rm -v `pwd`/startup.sh:/etc/profile.d/statup.sh alpine sh
Run Code Online (Sandbox Code Playgroud)
您将得到的只是一个 shell 提示符:
/ #
Run Code Online (Sandbox Code Playgroud)
当你从这里开始时,它确实会打印“hello world” su -:
/ # su -
hello world
2bf679a5677d:~#
Run Code Online (Sandbox Code Playgroud)
但简单地sh启动一个 shell 是不行的:
/ # sh
/ #
Run Code Online (Sandbox Code Playgroud)
那么,这里有什么问题呢?它是一个不起眼的 Alpine Linux 东西吗?它是一个不起眼的 Alpine Linux Docker 镜像吗?
DockerfileRUN命令和主容器CMD不会在任何 shell、任何基础 Linux 发行版上运行任何 shell 点文件。即使您的基础映像包含 GNU bash 或者您已手动重置SHELL以运行 bash 而不是标准的,情况也是如此sh。
GNU Bash 参考手册可能对点文件何时被读取有最好的描述。存在三种情况: shell 可以是非交互式 shell;它可以是交互式 shell,但不是登录 shell;或者它可以是专门的登录 shell。在 Docker 容器中,您遇到的 shell 通常不是交互式 shell,即使是,也不是登录 shell。
重要的推论是,在 Dockerfile 中编写 shell 点文件通常是不正确的。大多数在容器中运行命令的路径都不会读取它们。如果需要设置环境变量,请使用ENV指令。
一些例子:
CMD ["/usr/local/bin/my_program"]
Run Code Online (Sandbox Code Playgroud)
此exec 形式 CMD根本不运行 shell。没有sh进程,也没有任何东西会读取任何 shell 点文件。
CMD my_program
# CMD ["/bin/sh", "-c", "my_program"]
Run Code Online (Sandbox Code Playgroud)
此shell 形式 CMD自动包装在 中/bin/sh -c '...',但生成的 shell 是非交互式 shell,并且不读取点文件。
docker run --rm my_image my_program
Run Code Online (Sandbox Code Playgroud)
再次强调,这并不运行 shell。
docker run --rm my_image sh -c 'my_program'
Run Code Online (Sandbox Code Playgroud)
这明确提供了一个 shell 作为命令字符串的一部分,但它不是一个交互式 shell。
docker run --rm -it my_image sh
Run Code Online (Sandbox Code Playgroud)
主容器命令是一个shell,你没有给它命令,但你提供了一个stdin;所以在本例中它是一个交互式 shell。如果是 bash,它将读取.bashrc但不会读取任何其他点文件。
docker run --rm -it my_image bash --login
Run Code Online (Sandbox Code Playgroud)
如果您明确请求,交互式 shell 只是一个登录 shell。几乎只有在这个调用中,才会读取完整的 shell 点文件集。
/etc/profile.d它本身并不是一个标准的 shell 功能。这是某些发行版提供的便利,但 bash 手册中没有特别提到。比较例如
docker run --rm ubuntu cat /etc/profile
docker run --rm bash cat /etc/profile
docker run --rm alpine cat /etc/profile
docker run --rm busybox cat /etc/profile
Run Code Online (Sandbox Code Playgroud)
请注意,在前三种情况下,/etc/profile文件是不同的,但它们都包含读取/etc/profile.d目录的逻辑。您的调用未运行登录 shell,因此不会读取该文件。
在正常情况下,容器运行的东西不会是 shell。预构建的镜像如docker run postgres或docker run nginx是典型的例子:镜像中打包了一些特定的软件,并且运行容器恰好运行该软件。启动 Nginx HTTP 服务器不需要 shell,也不会读取 shell 点文件。
正如“调用”man ash部分中所告诉您的,环境变量可用于指定 shell 启动期间要获取的文件。ENV
在你的 Dockerfile 中:
ENV ENV=/home/youruser/.rc
Run Code Online (Sandbox Code Playgroud)
...然后你的 shell 将在启动期间执行 的内容/home/youruser/.rc。
在 bash 中,BASH_ENV(不在 POSIX 模式下使用)甚至可以针对非交互式 shell 运行;当 bash 处于 POSIX 模式时,它ENV仅针对交互式 shell 运行(这是唯一需要ENV遵守 POSIX 规范的情况)。