Jenkins流水线中Terraform仅显示默认工作区的问题排查
问题场景
我通过Jenkins流水线执行Terraform操作,流水线依赖Python脚本完成任务,其中terraform workspace select相关的Python函数如下:
def terraform_plan(options): provider=get_cluster_info(options)['provider'].upper() # 返回"AWS" workspace=get_cluster_info(options)['terraform_workspace'] # 返回abc working_dir=f'{REPO_PATH}/{provider}/K8S' # 返回"./repo_path/AWS/K8S" run_subprocess(f"/usr/local/bin/terraform -chdir={working_dir} workspace list") run_subprocess(f"/usr/local/bin/terraform -chdir={working_dir} workspace select {workspace}")
注:
run_subprocess仅执行括号内命令并打印额外信息
流水线在执行上述函数前,已成功运行run_subprocess(f"/usr/local/bin/terraform -chdir={working_dir} init"),但运行时出现以下问题:
- 提示
abc工作区不存在 terraform workspace list仅显示默认工作区- 但在同一目录下通过终端执行
terraform workspace show能正常显示所有工作区
已尝试调整命令执行顺序、确认init成功、检查文件完整性,问题仍未解决。
问题原因
执行环境的用户与权限差异
Jenkins流水线默认以jenkins用户运行,而终端操作使用个人用户。Terraform的工作区数据存储在.terraform和terraform.tfstate.d目录中,若这两个目录的权限仅对个人用户开放,Jenkins用户无法读取已创建的工作区信息。Terraform后端配置不一致
虽然init输出显示成功,但Jenkins执行init时可能使用了与终端不同的后端配置。例如终端使用本地状态存储工作区,而Jenkins流水线的init配置了远程后端(如S3),远程后端中未提前创建abc工作区,导致选择失败。工作目录路径解析错误
代码中使用相对路径./repo_path/AWS/K8S指定工作目录,但Jenkins流水线的默认工作目录(由WORKSPACE环境变量定义)与终端执行时的当前目录不同,导致实际访问的目录并非预期的Terraform配置目录,自然找不到已创建的工作区。
修复方案
统一执行环境的权限与用户
- 切换到Jenkins用户验证工作区可见性:
sudo su - jenkins cd /path/to/your/repo/AWS/K8S /usr/local/bin/terraform workspace list - 若Jenkins用户看不到工作区,调整目录权限:
chown -R jenkins:jenkins /path/to/your/repo/AWS/K8S chmod -R 755 /path/to/your/repo/AWS/K8S/terraform.tfstate.d
- 切换到Jenkins用户验证工作区可见性:
验证并同步Terraform后端配置
- 在Jenkins流水线中添加命令,打印当前后端配置:
run_subprocess(f"/usr/local/bin/terraform -chdir={working_dir} backend config") - 将输出与终端执行结果对比,确保配置一致。若使用远程后端,需在对应环境中提前创建
abc工作区:terraform workspace new abc
- 在Jenkins流水线中添加命令,打印当前后端配置:
使用绝对路径指定工作目录
替换相对路径为绝对路径,避免目录解析错误。可通过Jenkins环境变量拼接:import os # 获取Jenkins工作区绝对路径,拼接目标目录 working_dir = os.path.join(os.environ['WORKSPACE'], provider, 'K8S')添加工作区存在性检查与创建逻辑
在执行select前先判断工作区是否存在,不存在则自动创建:def run_subprocess_with_output(cmd): # 实现捕获命令输出的函数 import subprocess result = subprocess.run(cmd, shell=True, capture_output=True, text=True) return result.stdout def terraform_plan(options): provider=get_cluster_info(options)['provider'].upper() workspace=get_cluster_info(options)['terraform_workspace'] working_dir=os.path.join(os.environ['WORKSPACE'], provider, 'K8S') # 检查工作区是否存在 list_cmd = f"/usr/local/bin/terraform -chdir={working_dir} workspace list" workspace_list = run_subprocess_with_output(list_cmd) if f"*{workspace}" not in workspace_list and workspace not in workspace_list: run_subprocess(f"/usr/local/bin/terraform -chdir={working_dir} workspace new {workspace}") run_subprocess(list_cmd) run_subprocess(f"/usr/local/bin/terraform -chdir={working_dir} workspace select {workspace}")
内容的提问来源于stack exchange,提问作者Tom Sebty

