Ubuntu环境下runit如何读取K8s注入的容器环境变量?
问题描述
我们在用于K8s部署的Docker镜像中使用runit /etc/service/,/etc/service路径下包含/etc/service/acme/run脚本,该脚本通过Dockerfile如下配置复制:
COPY --link=true --chmod=755 scripts/acme_server.sh /etc/service/acme/run
acme_server.sh脚本内容示例如下:
#!/bin/bash set -x exec 2>&1 export PATH="/opt/app_venv/bin:${PATH}" EV_ACME_REPOSITORY=`echo $ACME_REPOSITORY` if [[ -z "$EV_ACME_REPOSITORY" ]] then ln -s /app/ACME_repository /ACME iACME_PATH=${EV_ACME_REPOSITORY:-"/app/acme_repository"} /opt/unicornserver/bin/unicornserver --exit-on-error=false --acme-repository="${iACME_PATH}"
K8s部署配置中已设置环境变量:
env: - name: ACME_REPOSITORY value: "/var/www/acme/repository"
登录Pod后,通过env、printenv或echo $ACME_REPOSITORY均能看到该变量值,但runit启动的脚本未获取到ACME_REPOSITORY的值,最终使用了默认的错误路径,日志如下:
2023-05-15_04:45:09.65401 + EV_ACME_REPOSITORY= 2023-05-15_04:45:09.65401 + [[ -z '' ]] 2023-05-15_04:45:09.65402 + ln -s /app/ACME_repository /ACME 2023-05-15_04:45:09.65409 + iACME_PATH=/app/ACME_repository 2023-05-15_04:45:09.65410 + /opt/unicornserver/bin/unicornserver --exit-on-error=false --acme-repository=/app/ACME_repository
如何让runit启动的脚本正确获取到该环境变量的值?
解决方法
runit默认不会自动继承容器的全局环境变量到其管理的服务进程中,以下是几种可行的解决方式:
方法1:在run脚本中手动导入环境变量
直接在acme_server.sh开头添加环境变量导入逻辑,可从容器init进程的环境变量文件/proc/1/environ中读取:
#!/bin/bash set -x exec 2>&1 # 从容器init进程导入环境变量 while IFS='=' read -r key value; do export "$key=$value" done < <(tr '\0' '\n' < /proc/1/environ) export PATH="/opt/app_venv/bin:${PATH}" EV_ACME_REPOSITORY="$ACME_REPOSITORY" if [[ -z "$EV_ACME_REPOSITORY" ]] then ln -s /app/ACME_repository /ACME fi iACME_PATH=${EV_ACME_REPOSITORY:-"/app/acme_repository"} /opt/unicornserver/bin/unicornserver --exit-on-error=false --acme-repository="${iACME_PATH}"
如果你的镜像会将环境变量写入/etc/environment,也可以用更简洁的方式导入:
if [ -f /etc/environment ]; then source /etc/environment fi
方法2:使用runit自带的envdir工具传递变量
runit的envdir工具可以从指定目录加载环境变量(目录下文件名对应变量名,文件内容对应变量值):
- 在Dockerfile中创建环境变量存储目录:
RUN mkdir -p /etc/env.d/acme
- 修改K8s部署配置,通过init容器将环境变量写入该目录:
env: - name: ACME_REPOSITORY value: "/var/www/acme/repository" volumeMounts: - name: acme-env mountPath: /etc/env.d/acme volumes: - name: acme-env emptyDir: {} initContainers: - name: set-acme-env image: busybox command: ['sh', '-c', 'echo "$ACME_REPOSITORY" > /etc/env.d/acme/ACME_REPOSITORY'] env: - name: ACME_REPOSITORY value: "/var/www/acme/repository" volumeMounts: - name: acme-env mountPath: /etc/env.d/acme
- 修改
acme_server.sh,通过envdir加载变量后启动服务:
#!/bin/bash set -x exec 2>&1 exec envdir /etc/env.d/acme /opt/unicornserver/bin/unicornserver --exit-on-error=false --acme-repository="${ACME_REPOSITORY:-/app/acme_repository}"
方法3:修改runit启动命令,全局传递环境变量
如果runit是容器的ENTRYPOINT/CMD,可在启动runit前先导入所有环境变量,让所有runit管理的服务都能继承:
修改Dockerfile的CMD:
CMD ["/bin/sh", "-c", "export $(cat /proc/1/environ | tr '\\0' '\\n' | xargs) && runsvdir /etc/service"]
这种方式无需修改单个服务的run脚本,一次性解决所有服务的环境变量继承问题。
内容的提问来源于stack exchange,提问作者hare krshn
相关产品推荐
相关产品推荐

