使用 GitHub Actions 通过跳板机部署应用
在某些情况下,目标服务器无法直接通过 GitHub 访问。这时,我们可以使用跳板机(Bastion Host)来实现自动部署。以下是通过 GitHub Actions 配置跳板机部署的步骤:
1. 在本机生成 ed25519 密钥对
1 2
| ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N "" cat ~/.ssh/id_ed25519.pub
|
为了防止跳板机和目标服务器之间无法通过 SSH 连接,我们需要在本机生成 ed25519 密钥对,并将其公钥添加到跳板机和目标服务器的 authorized_keys
文件中。其实这个秘钥对在跳板机或者目标服务器上生成都可以,只要能互相通信就行。
2. 在跳板机和目标服务器上添加新生成的公钥
在跳板机和目标服务器上,您需要将新生成的公钥添加到 ~/.ssh/authorized_keys
文件中,以便允许通过 SSH 进行无密码登录。以下是具体步骤:
2.1 登录到跳板机:
1
| ssh ${BASTION_USER}@${BASTION_HOST}
|
2.2. 将公钥添加到跳板机的 authorized_keys
文件:
1 2
| echo "新生成的公钥内容" >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys
|
2.3. 然后,登录到目标服务器:
1
| ssh ${TARGET_USER}@${TARGET_HOST}
|
2.4. 同样地,将公钥添加到目标服务器的 authorized_keys
文件:
1 2
| echo "新生成的公钥内容" >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys
|
BASTION_HOST
:跳板机的 IP 地址或主机名
BASTION_USER
:跳板机的用户名
TARGET_HOST
:目标服务器的 IP 地址或主机名
TARGET_USER
:目标服务器的用户名
SSH_PRIVATE_KEY
:用于 SSH 连接的私钥
这样,您就可以通过跳板机无密码地访问目标服务器了。
注意:使用哪个登录用户创建的秘钥对,就使用哪个登录用户登录跳板机和目标服务器。
3.将本机生成的私钥id_ed25519拷贝到跳板机~/.ssh/目录下,因为目标服务器的公钥也是使用的本机私钥生成的,所以需要将本机私钥拷贝到跳板机。
1
| scp ~/.ssh/id_ed25519 ${BASTION_USER}@${BASTION_HOST}:~/.ssh/
|
4.测试跳板机和目标服务器是否可以无密码通信
1
| ssh -i ~/.ssh/id_ed25519 ${TARGET_USER}@${TARGET_HOST}
|
如果可以无密码通信,则说明跳板机和目标服务器可以无密码通信。
注意:使用哪个登录用户创建的秘钥对,就使用哪个登录用户登录跳板机和目标服务器。
5. 将私钥id_ed25519的内容添加到GitHub仓库的Secrets and variables中,命名为JUMP_SERVER_SSH_KEY。
6. 创建 GitHub Actions 工作流
在 .github/workflows
目录下创建一个新的工作流文件,例如 deploy.yml
,并添加以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
name: Publish To Production
on: push: branches: [main]
env: NODE_VERSION: "16.14.2" JUMP_SERVER: "xxx.xxx.xxx.xxx" TARGET_SERVER: "yyy.yyy.yyy.yyy" SERVER_USER: "ubuntu" REMOTE_PATH: "/var/www/html/myapp/dist" ALERT_URL: "https://example.com/notify" PROJECT_NAME: "测试环境"
jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies run: yarn install --frozen-lockfile
- name: Build run: yarn build
- name: Install SSH Keys uses: shimataro/ssh-key-action@v2 with: key: ${{ secrets.JUMP_SERVER_SSH_KEY }} name: jump_server known_hosts: unnecessary if_key_exists: replace
- name: Setup SSH Config run: | mkdir -p ~/.ssh chmod 700 ~/.ssh echo "Host jumpserver HostName ${{ env.JUMP_SERVER }} User ${{ env.SERVER_USER }} IdentityFile ~/.ssh/jump_server StrictHostKeyChecking=no
Host targetserver HostName ${{ env.TARGET_SERVER }} User ${{ env.SERVER_USER }} ProxyCommand ssh -W %h:%p jumpserver StrictHostKeyChecking=no IdentityFile ~/.ssh/jump_server" > ~/.ssh/config chmod 600 ~/.ssh/config
- name: Debug SSH Connection run: | ssh -v targetserver "echo 'Connection test'"
- name: Check SSH Setup run: | ls -la ~/.ssh/ ssh-keygen -l -f ~/.ssh/jump_server || echo "Key not found"
- name: Deploy with rsync continue-on-error: true run: | ssh targetserver "sudo find ${{ env.REMOTE_DIR }} -not -name '.user.ini' -exec chown ${{ env.SERVER_USER }}:${{ env.SERVER_USER }} {} +" rsync -avz --delete \ --exclude='.user.ini' \ -e "ssh -o StrictHostKeyChecking=accept-new -i ~/.ssh/jump_server" \ ./dist/ \ targetserver:${{ env.REMOTE_DIR }}
- name: Notify Deployment End if: always() run: | if [ ${{ job.status }} == 'success' ]; then STATUS="success" else STATUS="failed" fi
curl -X POST ${{ env.NOTIFICATION_URL }} \ -H "Content-Type: application/json" \ -d "{\"status\":\"$STATUS\", \"project\":\"${{ env.PROJECT_NAME }}\"}"
|
补充说明:
- 本机生成的私钥id_ed25519拷贝到跳板机~/.ssh/目录下,因为目标服务器的公钥也是使用的本机私钥生成的,所以需要将本机私钥拷贝到跳板机。
- 本机生成的公钥id_ed25519.pub拷贝到目标服务器的~/.ssh/authorized_keys文件中。
- 本机生成的公钥id_ed25519.pub拷贝到跳板机的~/.ssh/authorized_keys文件中。
- 本机生成的私钥id_ed25519拷贝到GitHub仓库的Secrets and variables中,命名为JUMP_SERVER_SSH_KEY。
7.目标服务器的访问权限问题
需要检查目标服务器的用户是否有访问目标目录的权限,否则无法进行rsync操作。如果没有权限,则需要给目标服务器的用户设置目标目录的读写权限。