Docker基础镜像构建需求实现问题:如何兼顾非root用户运行、CA证书预加载与指定用户执行命令
问题分析
你的问题出在entrypoint.sh里硬编码了su-exec node "$@"——不管你通过docker run -u指定什么用户,脚本都会强制切换到node用户执行后续命令,这就是为什么即使指定-u root,输出还是node的原因。
另外,你的证书加载逻辑(复制证书到/usr/local/share/ca-certificates、执行update-ca-certificates)需要root权限,所以这部分操作必须以root身份完成,之后再切换到目标用户运行应用——这一点你的原有配置是对的,但缺少了动态指定目标用户的灵活性。
解决方案:通过环境变量指定运行用户(推荐)
这个方案既能保证证书加载的root权限要求,又能让你灵活指定应用运行的用户,完全符合你的需求。
1. 修改entrypoint.sh
修改后的脚本会先以root处理证书,然后根据环境变量RUN_AS_USER的值切换到目标用户(默认是node):
#!/bin/sh DIR_CRT="/home/node/certificates" # 仅当以root运行时处理证书(保证权限) if [ "$(id -u)" -eq 0 ]; then if [ "$(ls -A ${DIR_CRT})" ]; then cp -r "${DIR_CRT}/." /usr/local/share/ca-certificates/ update-ca-certificates echo "******* Updated CA certificates *******" fi # 读取目标用户,默认使用node TARGET_USER=${RUN_AS_USER:-node} # 切换到目标用户执行命令 exec su-exec "${TARGET_USER}" "$@" else # 如果非root启动,直接报错(因为无法加载证书) echo "ERROR: Entrypoint must run as root to load certificates. Use RUN_AS_USER env var instead of -u." exit 1 fi
2. 更新Dockerfile
添加RUN_AS_USER的默认环境变量,让镜像默认以node用户运行:
FROM node:14.15.1-alpine3.11 # Specify node/npm related envs ENV NPM_CONFIG_LOGLEVEL=warn \ NO_UPDATE_NOTIFIER=1 \ RUN_AS_USER=node # 新增:默认运行用户 # Change cwd for next commands WORKDIR /home/node/code # Set local registry RUN echo "registry=http://192.168.100.175:4873" > /home/node/.npmrc && \ chown -R node:node /home/node && \ apk add --update --no-cache tzdata=2021a-r0 ca-certificates=20191127-r2 su-exec=0.2-r1 # Need root to update CA certificates in entrypoint.sh and then switch back to restricted user USER root COPY entrypoint.sh entrypoint.sh ENTRYPOINT [ "./entrypoint.sh" ] # Execute the service entrypoint CMD ["sh"]
使用方式
- 默认以
node用户运行:docker run --rm -it your-image whoami # 输出:node - 指定以
root用户运行:docker run --rm -it -e RUN_AS_USER=root your-image whoami # 输出:root - 指定以其他已存在的用户运行(比如
myuser):docker run --rm -it -e RUN_AS_USER=myuser your-image whoami # 输出:myuser
备选方案:兼容docker run -u参数(不推荐,存在证书加载风险)
如果你一定要用docker run -u参数,也可以调整脚本,但这种方式在指定非root用户时会跳过证书加载(违反你“必须加载证书”的需求),仅作参考:
修改后的entrypoint.sh:
#!/bin/sh DIR_CRT="/home/node/certificates" if [ "$(id -u)" -eq 0 ]; then # 以root运行时处理证书 if [ "$(ls -A ${DIR_CRT})" ]; then cp -r "${DIR_CRT}/." /usr/local/share/ca-certificates/ update-ca-certificates echo "******* Updated CA certificates *******" fi # 识别docker run -u指定的用户,默认node TARGET_USER="${USER:-node}" # 如果指定的是root,直接执行(不需要切换) if [ "${TARGET_USER}" = "root" ]; then exec "$@" else exec su-exec "${TARGET_USER}" "$@" fi else # 非root运行时,警告无法加载证书并继续执行 echo "WARNING: Running as non-root user, cannot update CA certificates. This may break certificate-dependent features." exec "$@" fi
使用这个方案时,docker run -u root your-image whoami会输出root,且证书会被加载;但docker run -u myuser your-image whoami会输出myuser,但证书加载会失败并给出警告。
内容的提问来源于stack exchange,提问作者Marco Stramezzi
相关产品推荐
相关产品推荐

