GitHub Actions部署无法访问目录?排查与解决方案
2025-03-21 08:09:43
GitHub Actions 部署时无法访问 /var/www/todo-app 目录的排查与解决
在用 GitHub Actions 把应用部署到 VPS 上时, 顺利执行到尝试访问远程服务器上的 /var/www/todo-app
目录那一步, 卡住了。GitHub Actions 报错,显示无法访问 /var/www/todo-app
,错误信息如下:
*** System restart required ** *
cd: cannot access '/var/www/todo-app': No such file or directory
我用的是 root 用户进行 SSH 连接,并且在远程服务器和 GitHub Action 中都使用了 ls -l
命令检查。远程服务器的输出结果是:
drwxr-xr-x 2 root root 4096 Jan 14 09:38 html
drwxr-xr-x 5 root root 4096 Jan 15 16:27 todo-app
而 GitHub Action 中的输出(部分):
drwxr-xr-x 2 *** ** * 4096 Jan 5 21:36 html
我可以成功访问 /var/www/html
,但 /var/www/todo-app
目录却好像访问不了, 明明服务器上有一个名为 todo-app
的 Git 仓库。我猜想问题可能出在目录路径或者权限上,尝试过在远程服务器上设置todo-app
的权限, 没用。这是我的 ci.yml
文件的内容:
name: Deploy to VPS
on:
workflow_run:
workflows: [ "Docker Image CI" ]
types:
- completed
jobs:
deploy:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Get SSH key and set permissions
run: |
mkdir -p ~/.ssh
echo "${{ secrets.REMOTE_PRIVATE_KEY }}" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.REMOTE_HOST }} >> ~/.ssh/known_hosts
- name: SSH to the server and Redeploy
run: |
ssh -i ~/.ssh/id_rsa ${{ secrets.REMOTE_USERNAME }}@${{ secrets.REMOTE_HOST }}
cd /var/www/todo-app
git pull origin main
echo "DATABASE_URL=${{ secrets.PG_URL }}" > .env
echo "POSTGRES_USER=${{ secrets.PG_USER }}" >> .env
echo "POSTGRES_PASSWORD=${{ secrets.PG_PASSWORD }}" >> .env
echo "POSTGRES_DB=${{ secrets.PG_DB }}" >> .env
docker compose build
docker compose up -d
exit
接下来看看具体怎么解决。
一、 问题原因分析
-
run
指令的误区: 在 GitHub Actions 中,每个run
指令都是在一个新的 shell 中执行的。这意味着,上一个run
中的cd
命令对下一个run
是无效的。 在提供的 YAML 文件里,ssh
,cd
,git pull
等操作都在同一个run
块下面才对. -
用户上下文: 虽然已经以
root
用户进行 SSH 连接,但在run
的指令中,默认的用户上下文可能会发生变化。 虽然可能性比较小, 但需要排除一下。 -
实际路径偏差: 即使服务器上显示
/var/www/todo-app
存在,也需要排除一下路径的细微偏差。有时候由于各种奇怪的原因(比如误操作,之前的残留配置),导致目录的实际路径和你认为的有细微差异。 -
服务器重启: 服务器提示
System restart required
, 虽然跟这个问题可能没直接关系,但最好还是重启下服务器. 保证服务器处于一个"干净"的状态。
二、 解决方案
1. 合并 SSH 指令
最直接的修改,把所有需要在远程服务器上执行的命令,合并到一个 run
块内,通过 ssh
的方式一起执行。
原理: 利用 SSH 的远程命令执行功能,将一系列命令作为单个字符串传递给远程 shell 执行,从而保证命令执行的上下文一致。
代码示例:
- name: SSH to the server and Redeploy
run: |
ssh -i ~/.ssh/id_rsa ${{ secrets.REMOTE_USERNAME }}@${{ secrets.REMOTE_HOST }} "
cd /var/www/todo-app &&
git pull origin main &&
echo \"DATABASE_URL=${{ secrets.PG_URL }}\" > .env &&
echo \"POSTGRES_USER=${{ secrets.PG_USER }}\" >> .env &&
echo \"POSTGRES_PASSWORD=${{ secrets.PG_PASSWORD }}\" >> .env &&
echo \"POSTGRES_DB=${{ secrets.PG_DB }}\" >> .env &&
docker compose build &&
docker compose up -d
"
说明:
- 将所有远程命令用双引号括起来,作为一个整体传递给
ssh
。 - 使用
&&
连接多个命令,确保它们按顺序执行,并且前一个命令成功才会执行下一个。 - 注意
.env
文件中的环境变量需要用双引号包裹, 防止特殊字符引起问题。
2. 明确指定用户上下文
在 ssh
命令中明确指定以哪个用户的身份执行命令, 以免默认用户出现问题。
原理: 确保所有命令都在正确的用户上下文中执行。
代码示例 (在方法1的基础上修改):
- name: SSH to the server and Redeploy
run: |
ssh -i ~/.ssh/id_rsa ${{ secrets.REMOTE_USERNAME }}@${{ secrets.REMOTE_HOST }} "
whoami && # 打印当前用户
cd /var/www/todo-app &&
# ... 其他命令 ...
"
说明 : 使用了whoami
确定一下当前用户. 如果whoami
打印的不是root
, 可以把ssh
指令改为:
ssh -i ~/.ssh/id_rsa root@${{ secrets.REMOTE_HOST }}
3. 验证远程目录的绝对路径
在远程服务器上, 执行pwd
命令,确认一下 /var/www/todo-app
这个路径是不是正确的。
操作步骤:
-
直接通过 SSH 手动连接到 VPS:
ssh -i ~/.ssh/id_rsa ${{ secrets.REMOTE_USERNAME }}@${{ secrets.REMOTE_HOST }}
-
进入可能存在问题的目录:
cd /var/www ls -l cd todo-app pwd
记录pwd
命令的输出结果. 确认这是正确的绝对路径. 如果输出的不是/var/www/todo-app
, 在 GitHub Action 的 yaml 文件中使用pwd
给出的实际路径.
4. 重启服务器(可选)
有时候系统状态有问题。虽然重启不是必须的, 但重启能排除干扰项.
操作步骤:
直接在你的ssh终端中执行 sudo reboot
解释: 重启VPS 可以保证服务在一个稳定干净的状态下运行, 避免未知的干扰。
进阶使用技巧: 使用 SSH Action (可选)
如果上面几个方案还是不行,可以试试GitHub 官方市场的一些第三方 SSH Actions,例如 appleboy/ssh-action
。这些 Actions 提供了更方便的 SSH 操作方式, 更容易调试。
原理: 这些 Actions 封装了 SSH 的常用操作, 并提供了错误处理和日志记录功能。
代码示例:
- name: SSH Remote Commands
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.REMOTE_HOST }}
username: ${{ secrets.REMOTE_USERNAME }}
key: ${{ secrets.REMOTE_PRIVATE_KEY }}
script: |
cd /var/www/todo-app
git pull origin main
echo "DATABASE_URL=${{ secrets.PG_URL }}" > .env
echo "POSTGRES_USER=${{ secrets.PG_USER }}" >> .env
echo "POSTGRES_PASSWORD=${{ secrets.PG_PASSWORD }}" >> .env
echo "POSTGRES_DB=${{ secrets.PG_DB }}" >> .env
docker compose build
docker compose up -d
安全提示 : 使用第三方 Actions 需要注意来源是否可信,尽量用官方推荐或者使用量大的.
通过以上这些分析和方法, 基本上能解决 GitHub Actions 部署时无法访问指定目录的问题了。 最常见的情况是由于指令分散在不同的 run
块导致的, 把它们合并到一起通常就能搞定. 此外,确认一下远程服务器的实际目录路径和用户权限,也能避免一些低级错误。