Ubuntu自托管GitHub Runner externals目录Node二进制文件权限拒绝问题
问题描述
在Ubuntu 20/22系统的自托管GitHub Runner上,工作流会随机因/opt/actions-runner/externals/node16/bin/node的权限问题执行失败。工作流已包含检查该二进制文件存在及可执行权限的步骤,且虚拟机已安装Node 16,但仍偶发以下报错:
Error: An error occurred trying to start process '/opt/actions-runner/externals/node16/bin/node' with working directory '/opt/actions-runner/_work/myfolder/myfolder'. Permission denied
工作流配置如下:
name: Run npm test on: workflow_dispatch: schedule: - cron: '*/30 * * * *' jobs: run-test: runs-on: [self-hosted, '${{ matrix.platform.os }}', x64, '${{ matrix.platform.label }}'] timeout-minutes: 40 strategy: fail-fast: false matrix: platform: [{ os: linux, label: aws-linux }] node-version: [18] steps: - name: Check for node executable run: | while [ ! -x "/opt/actions-runner/externals/node16/bin/node" ] do echo "/opt/actions-runner/externals/node16/bin/node file does not exist or does not have execute permissions." sleep 1 done - uses: actions/checkout@v3 - name: Use Node.js if: always() uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} registry-url: 'https://registry.npmjs.org/'
可能的原因及解决方案
1. 检查步骤与实际执行存在时间窗口
你的检查步骤仅在工作流早期验证了Node文件的权限,但从检查完成到actions/setup-node执行的这段时间里,可能有Runner自动更新、后台清理进程等操作临时修改了externals目录下文件的权限或属性,导致后续调用时权限失效。
解决思路:
- 将检查逻辑移到
actions/setup-node步骤的紧前面,缩短时间窗口:- name: Pre-check node executable run: | for i in {1..5}; do if [ -x "/opt/actions-runner/externals/node16/bin/node" ]; then echo "Node executable is ready" break fi echo "Waiting for node permissions to be available..." sleep 2 if [ $i -eq 5 ]; then echo "Node file still not executable after retries" exit 1 fi done - name: Use Node.js if: always() uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} registry-url: 'https://registry.npmjs.org/'
2. Runner进程的权限上下文不一致
GitHub自托管Runner通常以特定用户(如runner)运行,但如果工作流中某些步骤切换了用户,或者externals目录的父级权限设置异常,会导致实际执行node命令时的用户没有对应权限。
解决思路:
- 确认Runner服务运行的用户:执行
ps aux | grep actions-runner查看进程所属用户。 - 验证该用户对Node文件及父目录的权限:
sudo -u runner ls -l /opt/actions-runner/externals/node16/bin/node sudo -u runner ls -ld /opt/actions-runner/externals/node16/bin/ sudo -u runner ls -ld /opt/actions-runner/externals/ - 如果权限异常,手动修复:
sudo chown -R runner:runner /opt/actions-runner/externals/node16 sudo chmod -R 755 /opt/actions-runner/externals/node16/bin
3. Runner的externals目录自动更新机制
GitHub Runner会定期自动更新自身组件,包括externals目录下的Node版本。在更新过程中,旧的Node文件可能被临时替换或权限被修改,此时如果工作流刚好执行到调用Node的步骤,就会触发权限错误。
解决思路:
- 禁用Runner的自动更新(如果不需要):编辑Runner配置文件
.runner,添加disableUpdate: true,然后重启Runner服务。 - 或手动在Runner机器上安装Node 16到系统目录,工作流中直接使用系统Node,避免依赖Runner自带的版本。
4. 文件系统权限同步延迟
如果Runner机器使用了共享存储(如AWS EFS、NFS)作为/opt/actions-runner的存储介质,可能存在权限同步延迟:检查步骤执行时权限正常,但实际调用Node时,文件系统的权限还未同步完成,导致权限拒绝。
解决思路:
- 在检查步骤中增加多次重试逻辑,确保权限同步完成,参考第1点中的重试脚本。
内容的提问来源于stack exchange,提问作者AlexS

