格式注意事项
我已经回去并在我的具体问题中添加了粗体文本,因为我觉得细节导致问题丢失。然而,为了理解为什么最简单的解决方案不一定有效,细节是必要的。
背景
最近在 StackOverflow 上问了这样的问题,他们并没有友好地对待它,因为它与严格意义上的编程无关。我的公司正在向云进行重大转变,并使用 Docker 而不是在本地构建所有内容。总的来说,这很好,但我们正在努力做正确的事情™。为了实现这一目标,我学到了很多有关 Unix/Linux 的深度及其工作原理的知识,但我不一定了解何时一种方法比另一种方法更可取。
编辑
在马库斯提供了丰富的信息后,我意识到我需要添加更多背景信息。因此,我们使用 GitLab CI/CD 将代码部署到云端。管道的设计不留给各个存储库,因为我们有很高的安全要求,并且不能允许有人跳过安全扫描或其他类似性质的操作。为了给我们这种级别的控制,我们将管道作为外部存储库,然后该管道具有可以被其他管道项目挂钩的扩展点(通过合并请求提升到主管道)。
管道扩展由两部分组成:YAML 配置和 Docker 映像。为了保持 YAML 简短,我们采取了将特定管道阶段的所有逻辑放入其运行的容器中的方法。在这样做的早期,我们看到很多脚本都移动到像/usr/local/bin
.但是,它仍然导致一些笨拙的实现,例如以下命令:
docker compose up
timeout $SERVICE_READY_TIMEOUT sh -c \
"until curl --output /dev/null --silent --fail $SERVICE_READY_ENDPOINT; do \
sleep 1; \
done"
# run the integration test after service is ready
相反,我添加了一个脚本,/etc/profile.d
内容如下:
#!/bin/sh
## Define functions to be loaded into the shell environment
pollUrl() {
endpoint="$1"
until curl --output /dev/null --silent --fail "$endpoint"; do
sleep 1;
done
}
waitForLive() {
max_duration=$1
endpoint="$2"
timeout $max_duration sh -c "pollUrl '$endpoint'"
}
我试图解决的另一个具体问题是在一个阶段存储环境变量以在另一个阶段使用。是的,最简单的解决方案是将其复制到这两个地方。问题是它是两个独立的版本。我正在捕获的变量是在 Docker 映像的构建中提供的,但稍后会在实际的管道扩展中使用它。我目前的方法/etc/profile.d
也让我把它写下来。
但接下来我们又回到了最初的问题:您如何ENV
为用户定义以便加载他们的个人资料?
问题
就启动 shell 时发生的事情而言,什么时候是/etc/init.d
首选,与什么时候比较/etc/profile.d
,以及我如何定义$ENV
以便最初加载正确的配置文件?更重要的是,什么类型的东西去哪里?示例:要加载到 shell 中以供重复使用的函数、用于配置 NPM/Yarn 等工具的环境变量,尤其是$ENV
决定 shell 启动方式的因素。
如果有一个正式的文档描述这些事情,那将会非常有帮助,因为我对整个 Linux 还比较陌生。我已经下载了 Linux 文档项目 (PDF),并经常访问那里的各种 Linux 手册页网站,但大多数来源都偏向 Bash,这并不总是适合我的选择。
更新的问题
因此,这就是我提出这些问题的理由。在 Shell 中定义不特定于相关 shell(Bash、ZSH 等)的函数和环境变量的 POSIX 兼容方法是什么?您可以提供什么指导来判断何时应该使用是在一个系统中还是在另一个系统中?
附加信息
我知道一些 shell,比如 ZSH 和 Bash,提供了一个运行命令文件.<name>rc
,以及其他约定,比如.<name>_profile
或 只是.profile
.这些约定要么特定于该 shell,要么不被普遍阅读。这让我了解到ENV=/etc/profile
Dockerfile 中的设置将加载以当前用户/etc/profile.d
结尾*.sh
且可由当前用户执行的目录中的任何内容。然而,在我能够根据自己的喜好自定义它的 WSL 环境中,我无法ENV
在进入 shell 之前预加载该值,特别是当我尝试使用它/bin/sh
来测试跨平台的脚本兼容性时(我们有使用 ZSH 的 Mac 用户,因此我的 Bash 脚本经常在他们这边崩溃)。
答案1
就启动 shell 时发生的事情而言,什么时候首选 /etc/init.d,什么时候首选 /etc/profile.d
他们做完全不同的事情。
profile.d 包含由 shell 获取的用于设置公共环境的脚本; init.d 包含(在 sys V 下)脚本,由引导控制程序启动,用于启动、停止、重新启动或重新加载服务配置,具体取决于传递给这些脚本的参数。
请注意,如果您的公司现在正在迁移到云,云 VM 的典型发行版(OpenSUSE、Alma Linux/Rocky Linux/Oracle Linux/Red Hat Enterprise Linux 或 Ubuntu)会执行此操作。不是使用 Sys V。(他们通过仿真层支持它。)
这些发行版实际上利用了 systemd 的更细粒度的控制、并行性和弹性功能。
其他典型的云部署基于在容器中启动单一服务,因此通常还不依赖于这些容器中的 sysvinit。
所以,真正的问题是,在考虑云服务时,为什么你会在 2024 年阅读 sysvinit。
示例:要加载到 shell 中以供重复使用的函数、用于配置 NPM/Yarn 等工具的环境变量,尤其是像 $ENV 这样的东西,它们决定了 shell 的启动方式。
这些都是开发/使用的事情,听起来不像你想在云服务器上做的事情。您通常将特定服务运行所需的环境变量放在服务文件中(在 systemd 情况下)。对于 sys v 初始化脚本,管理员过去常常修改它们。改变方式没有什么意义全部当您只想修改一个,并且希望避免不可预见的副作用时,可能会启动 apache http 服务器(仅是一个示例)。
一般来说,我个人认为 systemd 服务文件是一种更简洁的方法,对于控制服务新贵的 Linux 系统来说,全面采用它是有充分理由的。一个很小但口头上的用户社区认为 systemd 是邪恶的。好的。
但是,在我可以根据自己的喜好自定义它的 WSL 环境中,我无法在进入 shell 之前预加载 ENV 值,特别是当我尝试使用 /bin/sh 来测试脚本兼容性时跨平台(我们有使用 ZSH 的 Mac 用户,所以我的 Bash 脚本经常在他们这边崩溃)。
这些都是您机器上的本地内容。把你的配置你的个人 shell 位于您的个人 ~/.zshrc 中。