Skip to content

Jenkins in Docker:workspace 挂 tmpfs 后,宿主机为什么「看不到」checkout?

仲灏2026-07-01约 1 分钟

一句话结论

是的。 在 Jenkins 容器里把 /var/jenkins_home/workspace 挂成 tmpfs 之后,checkout 出来的文件只存在于 Jenkins 容器内的内存文件系统;你在 宿主机 上打开 jenkins_home/workspace/...,往往是空目录,嵌套的 docker run -v 宿主机路径 也会报 No such file or directory

这不是 Git 没拉下来,而是 挂载层级被 tmpfs「盖住」了


背景

典型 homelab 栈:Jenkins 跑在 Docker 里,通过 docker.sock 在 Pipeline 里再启构建容器(Docker-outside-of-Docker)。某次为了「省磁盘 / 加快 IO / 改网络」调整 compose 时,给 workspace 加了 tmpfs——CI 从「全绿」变成「20 秒就挂」,报错类似:

text
chmod: ./build.sh: No such file or directory

Jenkins 日志里 checkout 明明成功,容器内 ls 也能看到文件,唯独宿主机路径和嵌套 docker run 读不到。


架构:三层路径,别混为一谈

text
宿主机磁盘
  └── /srv/stack/jenkins/jenkins_home/workspace/job-name/   ← 你以为文件在这里

           │  bind mount: jenkins_home → /var/jenkins_home

Jenkins 容器
  └── /var/jenkins_home/workspace/job-name/                 ← tmpfs 盖在这一层上!

           │  volumes-from 或 -v 宿主机路径

构建 sidecar 容器 (docker:27-cli)
  └── 需要读到 build.sh、Dockerfile…

当 compose 写了:

yaml
volumes:
  - ./jenkins_home:/var/jenkins_home
tmpfs:
  - /var/jenkins_home/workspace:rw,exec,size=8192m

tmpfs 会在 bind mount 之上再挂一层内存盘,覆盖 workspace 子树。于是:

观察位置能否看到 checkout 文件
Jenkins 容器内 /var/jenkins_home/workspace/...✅ 能
宿主机 ./jenkins_home/workspace/...❌ 通常不能(目录空或只有占位)
docker run -v $(pwd):$(pwd)(pwd 在 Jenkins 容器里)❌ 映射到宿主机空路径
Docker Pipeline agent { docker { volumes-from jenkins } }✅ 能(共享 Jenkins 容器挂载命名空间)

所以:不是「文件消失了」,而是文件在容器内的 tmpfs 里,宿主机 bind mount 那条链路被截断。


怎么自己验证

在 Jenkins 容器里:

bash
# 1. workspace 是否是 tmpfs
docker exec jenkins cat /proc/self/mountinfo | grep workspace

# 典型问题输出含 tmpfs,例如:
# ... /var/jenkins_home/workspace ... tmpfs ...

# 2. 容器内有、宿主机无
docker exec jenkins ls -la /var/jenkins_home/workspace/my-job/build.sh
ls -la /srv/stack/jenkins/jenkins_home/workspace/my-job/build.sh   # 宿主机路径

若第一条是 tmpfs,第二条「容器有、宿主机无」,就可以确认是 tmpfs 覆盖,而不是权限或 Git 问题。


为什么以前能过、改 compose 后就不行

构建方式tmpfs workspace 下的行为
agent { docker { reuseNode true } } + Docker Pipeline 自动 volumes-from往往 仍能工作(sidecar 继承 Jenkins 容器挂载,包括 tmpfs)
宿主机 sh 里手写 docker run -v "$PWD:$PWD"容易失败(PWD 解析到宿主机空目录)
宿主机 docker run -v /srv/.../workspace/job:$PWD失败(宿主机目录里没有 checkout)

因此:tmpfs 不是绝对不能跑 CI,但一旦 Pipeline 改成「从宿主机路径 bind mount workspace」,或你在宿主机上调试「为什么 workspace 是空的」,就会踩坑。

本次故障里还叠加了:清 Docker 缓存后 sidecar 偶发 process apparently never started(Durable Task 插件 + 嵌套容器),容易误判成「网络 / 代理 / Dockerfile」问题——先用 mountinfo 排除 tmpfs 能省很多时间。


修复建议

1. 去掉 workspace 的 tmpfs(推荐)

yaml
tmpfs:
  - /var/jenkins_home/caches:rw,exec,size=512m
  - /var/jenkins_home/logs:size=128m
  # 不要:- /var/jenkins_home/workspace:...

caches / logs 用 tmpfs 通常没问题;workspace 应落在 jenkins_home 的 bind mount 磁盘上,方便持久化、宿主机排查、嵌套 docker 挂载。

改完后:

bash
cd /srv/stack/jenkins && docker compose up -d jenkins
ls /srv/stack/jenkins/jenkins_home/workspace/my-job/build.sh   # 下一次构建后应存在

2. 若坚持 workspace 用 tmpfs

  • Pipeline 继续用 Docker Pipeline 的 agent { docker { reuseNode true } },依赖 volumes-from不要手写 -v 宿主机workspace
  • 接受 workspace 重启 Jenkins 即丢(需每次重新 checkout)。

3. 其他配套

  • Jenkins 容器内要用 BuildKit / buildx 时,挂载宿主机 docker cli-plugins(否则容器里只有 docker 没有 buildx)。
  • 清盘时避免 docker system prune -af,以免删掉 docker:cli 等工具镜像。
  • 构建已成功但 post 阶段通知超时,应用 catchError 包裹,避免「部署成功、Jenkins 标红」。

小结

问题答案
workspace 被 tmpfs 覆盖,宿主机能看到文件吗?一般看不到(bind mount 的 workspace 子树被内存盘覆盖)
Jenkins 容器内能看到吗?
为什么 checkout 日志正常却 build.sh 不存在?嵌套容器挂的是宿主机空路径,不是 Jenkins 容器内的 tmpfs
怎么修?删除 workspace tmpfs,让 checkout 落盘到 jenkins_home 卷

延伸阅读


本文为 homelab CI 实践脱敏整理,IP、域名、路径均为示例或占位,不包含真实生产环境信息。