如何让 ash 在启动时加载一些环境变量?
只需将它们放入 /etc/profile 中即可
/etc/profile 仅为登录 shell 读取;使用 docker(使用 alpine>busybox>ash)时频繁弹出的非登录 shell 又如何呢?
如果在环境变量 ENV 中指定,非登录 shell 将读取文件
太好了,我怎样才能确保 ENV 已设置?它本身是一个环境变量,默认为空。
本质上,我正在寻找一些保证 ash 能够读取的总体配置文件。优先选择 busybox 使用的 ash 版本(BusyBox v1.28.4,如果你想准确的话)。这样的事情存在吗?是的,我知道 docker 中的 ENV 指令,它可用于在构建 docker 映像时设置 $ENV;我仍然想知道这在 docker 之外是否可行。
顺便说一句,有人能解释高山的这种奇怪行为吗?
$docker run -it alpine
/ # echo $CHARSET #proof /etc/profile has not run
/ # echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
/ # env -i sh -c 'echo $PATH'
/sbin:/usr/sbin:/bin:/usr/bin
/ # echo $ENV
/ #
当我们可以显示 /etc/profile 还没有添加时,与新 shell 的默认 PATH 设置相比,PATH 中添加了哪些内容?这也不是 docker dickery,alpine 的 Dockerfile 故意最小化:
FROM scratch
ADD rootfs.tar.xz / #Automatically extracts, and I’m pretty sure that’s all
CMD ["/bin/sh"]
我之所以提到这一点,是因为看起来有人找到了一种在非登录 shell 中保留环境变量而不使用 $ENV 的方法。
我很欣赏任何信息或背景,无论多么无关紧要。
答案1
当你运行 docker 容器时,你正在运行孤立来自调用环境。变量不是直接继承的。
我们可以看到一个“干净”的环境,我们可以通过创建一个完全最小的容器来看到它。
例如一个go
程序:
package main
import "os"
import "fmt"
func main() {
for _, e := range os.Environ() {
fmt.Println(e)
}
}
我们可以将其构建到一个小容器中:
FROM scratch
ADD tester /
ENTRYPOINT ["/tester"]
如果我们运行这个:
$ docker run tst
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=e598bf727a26
HOME=/root
这些是由 docker 引擎创建的变量运行。
因此,当您run .. /bin/sh
运行一个非登录 shell 时,它只会继承 docker 创建的环境。由于它不是登录 shell,/etc/profile
因此不会运行。 /bin/sh
如果它们不存在,它本身会创建一些默认变量。
$ docker run -it alpine
/ # env
HOSTNAME=51667ed06110
SHLVL=1
HOME=/root
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
因此,您可以通过多种方法来做到这一点。我的脑海里浮现出两个想法:
您可以使用 docker 命令行在 docker 命令行上传递环境变量-e
。
$ docker run -e myvariable=testing -it alpine /bin/sh
/ # echo $myvariable
testing
您可以使用以下命令基于 alpine 构建自己的镜像ENV
:
$ cat Dockerfile
FROM alpine
ENV myothervar=anothertest
$ docker build -t myalpine .
...
$ docker run -it myalpine
/ # echo $myothervar
anothertest
基本上,您看到的是 docker 运行时提供一些变量,/bin/sh
提供其他变量,并与调用环境隔离。