标题几乎说明了一切(但可能还有更险恶的东西在发挥作用。(我知道当你登录时会运行/etc/profile.d/*.sh
脚本,但当你只是启动一个shell时,它似乎并没有像预期的那样工作。这里有一个docker的例子:
创建一个小脚本:
$ echo "echo hello world" > startup.sh
运行alpine shell,脚本安装如下:
$ docker run -it --rm -v `pwd`/startup.sh:/etc/profile.d/statup.sh alpine sh
你只会得到一个shell提示:
/ #
它确实打印了";你好世界";当你从这里su -
时:
/ # su -
hello world
2bf679a5677d:~#
但是一个简单的sh
启动一个shell是不行的:
/ # sh
/ #
那么,这里的问题是什么?这是一个晦涩难懂的Alpine Linux吗?这是一个晦涩难懂的Alpine Linux Docker镜像吗?
DockerfileRUN
命令和主容器CMD
不会在任何shell、任何基础Linux发行版上运行任何shell点文件。即使您的基本映像包含GNUbash,或者您手动重置SHELL
以运行bash而不是标准sh
,也是如此。
GNUBash参考手册可能对何时读取点文件有最好的描述。有三种情况:shell可以是非交互式shell;它可以是一个交互式shell,但不能是一个登录shell;或者它可以是一个登录shell。在Docker容器中,您遇到的shell通常不是交互式shell,如果是,它们就不是登录shell。
重要的推论是,在Dockerfiles中编写shell点文件通常是不正确的。在容器中运行命令的大多数路径都不会读取它们。如果需要设置环境变量,请改用ENV
指令。
一些例子:
CMD ["/usr/local/bin/my_program"]
这个exec表单CMD
根本不运行shell。没有sh
进程,也不会读取任何shell点文件。
CMD my_program
# CMD ["/bin/sh", "-c", "my_program"]
这个shell表单CMD
自动包装在/bin/sh -c '...'
中,但生成的shell是非交互式shell,不读取点文件。
docker run --rm my_image my_program
同样,这不会运行shell。
docker run --rm my_image sh -c 'my_program'
这显式地提供了一个shell作为命令字符串的一部分,但它不是一个交互式shell。
docker run --rm -it my_image sh
主容器命令是一个shell,您没有给它一个命令,而且您提供了一个stdin;所以在这种情况下,它是一个交互式shell。如果是bash,它将读取.bashrc
,但不会读取任何其他点文件。
docker run --rm -it my_image bash --login
如果你明确请求,交互式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
请注意,在前三种情况下,/etc/profile
文件是不同的,但它们都包含读取/etc/profile.d
目录的逻辑。您的调用没有运行登录shell,因此无法读取该文件。
在正常情况下,容器运行的东西不会是shell。像docker run postgres
或docker run nginx
这样的预构建映像就是典型的例子:映像中封装了一些特定的软件,运行容器恰好运行该软件。启动NginxHTTP服务器不需要shell,也不读取shell点文件。
正如man ash
在调用部分中告诉您的那样,环境变量ENV
可用于在shell启动期间指定要源代码的文件。这甚至适用于非交互、非登录的shell。
在您的Dockerfile:
ENV ENV=/home/youruser/.rc
然后您的shell将在启动期间执行CCD_ 21的内容。
这不是ash
行为或Alpine行为;所有POSIX-sh实现都是如此。(bash使用BASH_ENV
,但在sh兼容模式下运行时除外,此时它也会使用ENV
(。
对于任何使用alpine
-linux或特别是通过WSL来到这里的人,只需将.profile
文件添加到根目录中。
apk update
apk add nano
cd ~
nano .profile
---
alias test='I work'
source ~/.profile
test
>>> I work