docker相关知识和优化
关于dockerfile常用命令对比
CMD RUN ENTRYPOINT
RUN是构建时运行的命令
CMD ENTRYPOINT是运行时执行的命令 不同点在于 docker run 的参数 会直接替换CMD里命令
而 ENTRYPOINT 是直接追加在命令后 所以对于不想影响格式 固定执行的命令 使用 ENTRYPOINT
再通过ENTRYPOINT / CMD执行脚本文件 sh时 要注意使用 exec格式的写法 shell格式的写法 防止传入docker run 后续的执行命令无效
比如:
docker run --name ... npm run build
dockerfile内部ENTRYPOINT .sh 直接使用shell写法 会将命令处理为 /bin/sh -c 脚本.sh 内部脚本$@获取后续执行命令为空
如果直接使用exec写法 ENTRYPOINT [.sh] 则会自动传入$@ (推荐写法)
或者 写shell格式的时候 额外处理 显示的生命传入的执行命令 ENTRYPOINT .sh "$@"
docker工作目录 WORKDIR
定义的是 docker内部的工作目录
对于COPY [源路径 宿主机路径] [ 相对于工作目录的路径 ] 源路径不影响 源路径是相对于dockerfile的路径
传入环境变量的注意点:
兜底处理:
# 定义默认变量(可被-e覆盖) ENV APP_FILE=build.js ENV NODE_PATH=/var/lib/jenkins/nodejs16 # 复制脚本+赋权 COPY start.sh /usr/local/bin/ RUN chmod +x /usr/local/bin/start.sh # ✅ exec格式:脚本直接继承容器环境变量 ENTRYPOINT ["start.sh"]
#!/bin/bash set -e # 出错立即退出 # ========== 1. 验证变量是否接收(调试用)========== echo "📌 容器全局环境变量:" env | grep -E "APP_FILE|NODE_PATH" # 能看到-e传递的变量,证明未失效 # ========== 2. 变量兜底(防止未传)========== APP_FILE=${APP_FILE:-build.js} NODE_PATH=${NODE_PATH:-/var/lib/jenkins/nodejs16} # ========== 3. 执行核心命令(exec保证信号传递)========== exec $NODE_PATH/bin/node $NODE_PATH/$APP_FILE
关于容器间的网络通信:
最近进一步学习docker容器间的网络通信 发现除了上面的容器端口映射到宿主机 然后进行外部访问 还可以通过添加到自定义网络 即自定义bridge 进行容器间的网络访问 具体如下:
docker create network [net1] //这里的net1是指自定义网络的名字
docker run --name [contianer1] --network net1
docker run --name [contianer2] --network net1
假如contianer1为前端项目 container2为后端服务项目的容器名称 在前端项目的nginx配置中 直接通过
proxy_pass http://[contianer2]
通过容器名称直接进行容器间的自定义网络通信 ,这样的好处是 比容器端口映射到宿主机 进行端口和端口之间的访问相应要快的多
docker 网络通信
host模式 即容器和宿主机在同一个网络环境 不需要-p 端口映射 但是端口资源有限 会造成资源抢占
bridge模式 可以通过-p端口映射 或者 docker inspect <容器名> 获取ipadress 在nginx 里配置proxy_pass到后端ip
实际操作中的坑点:
1. 当环境为多用户环境时 有可能因为docker内外的用户 uid/gid不一致 导致denied permission 权限错误 可以使用gosu进行权限降级 注意传入的 -e变量 兜底处理
RUN cat > /usr/local/bin/ci-entrypoint.sh << 'EOF'
#!/bin/sh set -euo pipefail CLI_EXEC_UID= {CLI_EXEC_UID:-0} CLI_EXEC_GID={CLI_EXEC_GID:-0} mkdir -p /app && chown -R {CLI_EXEC_UID}:{CLI_EXEC_GID} /app || true
exec gosu {CLI_EXEC_UID}:{CLI_EXEC_GID} env "$@" EOF
RUN chmod +x /usr/local/bin/ci-entrypoint.sh
在镜像里增加脚本运行 EXTRYPOINT 对文件权限进行统一 和环境变量的转化对应处理 降权的目的是为了不影响容器运行(1.-v 绑定时 文件同步 对于CI纯部署测试 容器内文件同步----> 宿主机 所以需要在容器内给文件运行时 赋予和宿主机相同当前用户的文件权限 但是对于不同环境上操作 文件的操作权限可能不一致 直接docker run -e 指定运行的权限 传入当前用户权限 防止出现挂载后文件无法删除等问题 2.对于nginx 默认80端口 需要root权限,但是文件权限可能不是root ,需要开始使用root 运行nginx 时 通过指定 conf:usr 实现降权 worker进程运行的权限 将nginx 相关配置文件降权到同worker 相同的权限 gosu降权到普通用户权限 说白了 都是为了解决 -v文件挂载 但是容器内外的权限不统一 )
注意!!: -e 环境变量 和参数的区别 -e env1=$() 内部直接通过 $env 获取环境变量 run 尾部携带的是参数 内部通过 $@ 获取
(题外话 关于sh脚本的编写:可以使用echo + >/>> >是完全覆盖文件内容 >>是增加内容 用于逐行增加 或者'EOF' ...脚本内容......EOF 推荐EOF可读性更好)
docker run -e CLI_EXEC_UID
脚本里$@是完整接收docker run 外部参数 传给env防止多个参数造成格式混乱
2.对于依赖的漂移 (这个不属于镜像范畴但是需要注意管控)
再dockerfile内安装依赖 生产环境直接npm ci --no-dry 对依赖版本和package.json进行检测 如果不对应则报错退出
本地为了方便开发调试可以开放到 npm i --no save (不更新package.json -lock.json)但是需要对commit 进行commitlint 使用husky pre-commit钩子前
核心是 1. npm i --package-lock-only 根据当前的node_modules生成package.json 2. 通过diff比对有无版本飘移
具体的pre-commit如下
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
echo "🔍 正在校验 package-lock.json 是否同步(备份比对模式)..."
# 备份原始 lock 文件
cp package-lock.json package-lock.json.backup
# 生成标准 lock(只生成,不安装)
npm i --package-lock-only --silent
# 对比备份和新生成的文件
diff package-lock.json.backup package-lock.json > /dev/null
# 获取对比结果
RESULT=$?
# 还原原始文件(关键!不污染你的代码)
mv package-lock.json.backup package-lock.json
# 判断:不一致就拦截
if [ $RESULT -ne 0 ]; then
echo "========================================================="
echo "❌ 校验失败:package.json 与 package-lock.json 不一致!"
echo "❌ 或存在手动修改 lock 文件行为!"
echo "✅ 请运行:npm i 后重新提交"
echo "========================================================="
exit 1
fi
echo "✅ 校验通过!无版本漂移风险!"
其他关于多平台兼容问题可详见笔者另外一篇
参考内容:
更多推荐
所有评论(0)