Kubernetes环境Jenkins流水线/var/jenkins_home写入权限问题求助
Jenkins或容器进程尝试写入/var/jenkins_home时缺少必要的文件系统权限。在Kubernetes上运行的Jenkins流水线通过共享podTemplate动态定义容器和卷,其中一个阶段使用Jenkins的withCredentials步骤绑定GCP服务账号密钥文件(类型为Secret file),执行gcloud auth activate-service-account --key-file=$GCLOUD_KEY完成谷歌云认证。
尽管已将/var/jenkins_home挂载为emptyDirVolume,但流水线在尝试访问$GCLOUD_KEY时仍失败,报错:
hudson.remoting.ProxyException: java.nio.file.AccessDeniedException: /var/jenkins_home
日志显示credentials-binding插件尝试将密钥文件写入$JENKINS_HOME(默认路径为/var/jenkins_home),但因写入权限不足导致文件创建失败。尝试将流水线限定在dir("${WORKSPACE}")范围内指定可写路径,但Jenkins内部仍指向$JENKINS_HOME,未能解决问题。容器以root用户运行,但卷挂载的所有权问题依然存在。不想通过securityContext将runAsUser、runAsGroup和fsGroup都设置为0(不希望所有进程以root运行,不符合最佳实践),且配置为jenkins用户时容器无法启动——因为容器需要以root启动dockerd。
流水线withCredentials代码片段:
withCredentials([file(credentialsId: 'key-sa-prd', variable: 'GCLOUD_KEY')]) { key_json = readFile("${GCLOUD_KEY}") } writeFile file: 'key.json', text: key_json sh "cat key.json" sh "gcloud auth activate-service-account --key-file=key.json" sh "gcloud auth configure-docker ${registry}"
当前使用的Pod模板YAML:
apiVersion: v1 kind: Pod metadata: labels: ecosystem: ${ecosystem} job_name: ${job_name} spec: containers: - name: ${containerName} image: ${dImage} command: - dockerd tty: true securityContext: privileged: true volumeMounts: - name: jenkins-home mountPath: /var/jenkins_home readOnly: false securityContext: fsGroup: 1000 initContainers: - name: init-jenkins-home image: alpine command: - sh - -c - "addgroup -g 1000 jenkins && adduser -D -u 1000 -G jenkins jenkins && chown -R 1000:1000 /var/jenkins_home && chmod -R 777 /var/jenkins_home" volumeMounts: - name: jenkins-home mountPath: /var/jenkins_home enableServiceLinks: "false" volumes: ${volumes} tolerations: ${tolerations} nodeSelector: ${nodeSelector}
1. 自定义Credentials绑定的临时目录
credentials-binding插件默认使用$JENKINS_HOME存储临时密钥文件,可通过指定自定义路径规避权限问题:
// 提前在工作目录创建可写的临时凭证目录 def credsTempDir = "${WORKSPACE}/.jenkins-creds" sh "mkdir -p ${credsTempDir} && chmod 700 ${credsTempDir}" // 在withCredentials中指定密钥写入的目标目录 withCredentials([file( credentialsId: 'key-sa-prd', variable: 'GCLOUD_KEY', targetDirectory: credsTempDir )]) { key_json = readFile("${GCLOUD_KEY}") }
2. 调整Pod模板的卷权限配置
修改init容器的权限设置,确保root用户(容器运行用户)能写入/var/jenkins_home,同时保留fsGroup的安全配置:
initContainers: - name: init-jenkins-home image: alpine command: - sh - -c - "addgroup -g 1000 jenkins && adduser -D -u 1000 -G jenkins jenkins && chown -R root:jenkins /var/jenkins_home && chmod -R 775 /var/jenkins_home" volumeMounts: - name: jenkins-home mountPath: /var/jenkins_home
此配置将目录所有者设为root用户、jenkins组,权限775允许root用户和jenkins组写入,结合fsGroup:1000确保容器进程对卷文件拥有组权限。
3. 改用Secret text类型凭证,避免写入Jenkins_home
将GCP服务账号密钥保存为Secret text类型(直接粘贴JSON内容),跳过credentials-binding插件写入文件的步骤:
withCredentials([string(credentialsId: 'key-sa-prd', variable: 'GCLOUD_KEY_JSON')]) { writeFile file: 'key.json', text: GCLOUD_KEY_JSON } sh "gcloud auth activate-service-account --key-file=key.json" sh "gcloud auth configure-docker ${registry}"
这种方式直接在工作目录生成密钥文件,彻底规避/var/jenkins_home的权限问题。
4. 容器启动权限分离
如果必须用root启动dockerd,但希望Jenkins agent以非root用户运行,可修改容器启动命令实现权限切换:
containers: - name: ${containerName} image: ${dImage} command: - sh - -c - "dockerd & sleep 5 && su jenkins -c '/usr/local/bin/jenkins-agent'" tty: true securityContext: privileged: true
此配置让dockerd以root运行,Jenkins agent切换为jenkins用户运行,兼顾服务启动需求和权限安全。
内容的提问来源于stack exchange,提问作者Manish Gupta

