1. 简介

Amazon Elastic Cloud Compute (EC2) 是 AWS 提供的一项基础服务,它以虚拟服务器(实例)的形式提供可扩展的计算资源,用于运行应用程序。

GitHub Actions 是一个 CI/CD 平台,允许开发者在 GitHub 仓库中直接自动化软件开发流程。它构建了一条流水线,使代码变更能够自动构建、测试并部署到生产环境,比如一个 EC2 实例。

使用 GitHub Actions 直接部署到 AWS EC2 的常见方式有:

在本教程中,我们将介绍 EC2 实例的配置、SSH 密钥管理、GitHub Actions 流水线的创建,以及确保部署安全可靠的最佳实践。

2. 环境准备

在部署应用之前,我们需要在 GitHub 和 AWS 上分别配置环境。

2.1. GitHub 环境配置

首先,在 GitHub 上创建一个名为 github-actions-ec2 的仓库(通过网页界面创建):

GitHub Actions EC2 仓库截图

然后克隆该仓库到本地:

$ git clone https://github.com/<username>/github-actions-ec2.git

进入项目目录并创建 .github/workflows 文件夹:

$ cd github-actions-ec2
$ mkdir -p .github/workflows

该目录用于存放 GitHub Actions 识别的流水线定义。

接着创建 deploy.yml 文件:

$ touch .github/workflows/deploy.yml

我们以一个简单的 Node.js + Express 应用为例,创建 simple-web-server 目录并进入:

$ mkdir -p github-actions-ec2/simple-web-server/
$ cd simple-web-server

初始化 npm 并安装 express:

$ npm init -y
$ npm install express

创建 server.js 文件内容如下:

const express = require('express');
const app = express();
const port = process.env.PORT || 3000;

app.get('/', (req, res) => {
  res.send('Hello World! This server is running on Node.js with Express.');
});

app.get('/info', (req, res) => {
  res.json({
    name: 'Simple Web Server',
    version: '1.0.0',
    uptime: process.uptime()
  });
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

更新 package.json 添加启动脚本:

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
  "start": "node server.js"
}

创建 .gitignore 文件排除 node_modules

$ cat .gitignore
simple-web-server/node_modules/

本地运行应用测试:

$ npm start

访问 http://localhost:3000 查看运行效果:

Node.js 本地运行截图

最后提交代码:

$ git add .
$ git commit -m "NodeJS-Express Application"
$ git push

2.2. AWS 环境配置

创建一个名为 github-actions-ec2-instance 的 EC2 实例:

EC2 实例名称截图

选择 Ubuntu AMI,实例类型为 t2.micro

AMI 和实例类型截图

创建 RSA 类型的密钥对,格式为 .pem

EC2 密钥对截图

下载密钥文件 github-actions-ec2.key 到本地。

配置安全组,允许 SSH(端口 22)和 TCP(端口 3000)访问:

安全组配置截图

确认实例已运行:

实例运行状态截图

3. 使用 SSH 部署

本节演示如何使用 GitHub Actions 和 SSH 构建持续部署流水线。

3.1. 配置密钥变量

GitHub Secrets 是用于安全存储敏感信息(如 API Key、SSH 私钥)的加密变量。我们需要将 EC2 的主机名、用户名和私钥配置为 Secrets。

  • 用户名:通常为 ubuntu(Ubuntu AMI)
  • 主机名:EC2 实例的 Public DNS 名称
  • 私钥:之前下载的 .pem 文件内容

将以下信息分别保存为 GitHub Secrets:

  • EC2_USER
  • EC2_HOST
  • EC2_PRIVATE_KEY

3.2. 编写部署脚本

deploy.yml 中添加如下内容:

name: Deploy to EC2

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    
    - name: Deploy to EC2
      env:
        PRIVATE_KEY: ${{ secrets.EC2_PRIVATE_KEY }}
        HOST: ${{ secrets.EC2_HOST }}
        USER: ${{ secrets.EC2_USER }}
      run: |
        echo "$PRIVATE_KEY" > github-ec2.pem && chmod 600 github-ec2.pem
        ssh -o StrictHostKeyChecking=no -i github-ec2.pem ${USER}@${HOST} '
        echo "Current directory: $(pwd)"
        echo "Listing home directory:"
        ls -la ~

        echo "Installing Node.js..."
        if ! command -v nvm &> /dev/null; then
          curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
          export NVM_DIR="$HOME/.nvm"
          [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
        fi
        nvm install node

        echo "Installing PM2..."
        if ! command -v pm2 &> /dev/null; then
        npm install -g pm2
        fi

        REPO_URL="https://github.com/afkzoro/github-aws-ec2.git"
        BRANCH="main"
        REPO_DIR="$HOME/github-aws-ec2"

        if [ -d "$REPO_DIR/.git" ]; then
          cd "$REPO_DIR"
          git pull origin "$BRANCH"
        else
          git clone "$REPO_URL" "$REPO_DIR"
          cd "$REPO_DIR"
        fi

        cd "$REPO_DIR/simple-web-server"
        npm install

        cd ~/github-aws-ec2/simple-web-server
        git pull origin main
        npm install

        echo "Starting/restarting application..."
        pm2 restart server.js || pm2 start server.js
        '

提交并推送代码后,GitHub Actions 会自动触发部署流程。

3.3. 验证部署

使用浏览器访问 EC2 实例的公网 IP + 端口 3000:

浏览器访问截图

或使用命令行验证:

$ curl <ec2_ip_addr>:3000
Hello Baeldung! This server is running on Node.js with Express. v1

✅ 部署成功!

4. 使用 easingthemes/ssh-deploy Action

easingthemes/ssh-deploy 是一个 GitHub Action,它通过 SSH 和 rsync 将代码自动部署到服务器。

4.1. 配置参数说明

变量名 描述 是否必填
SSH_PRIVATE_KEY SSH 私钥(PEM 格式) ✅ 必填
REMOTE_HOST 远程主机名或 IP 地址 ✅ 必填
REMOTE_USER 远程用户名 ✅ 必填
REMOTE_PORT SSH 端口,默认为 22 ❌ 可选
ARGS rsync 参数 ❌ 可选
SOURCE 源目录(相对路径) ❌ 可选
TARGET 目标目录(远程服务器路径) ❌ 可选
EXCLUDE 排除路径(逗号分隔) ❌ 可选
SCRIPT_BEFORE rsync 前执行的脚本 ❌ 可选
SCRIPT_AFTER rsync 后执行的脚本 ❌ 可选

4.2. 在 Workflow 中使用

创建以下 Secrets:

  • SSH_PRIVATE_KEY:SSH 私钥
  • REMOTE_HOST:EC2 实例公网 DNS
  • REMOTE_USER:登录用户名
  • REMOTE_TARGET:远程目标路径,如 ~/simple-web-server

更新 deploy.yml 内容如下:

name: Node CI

on: [push]

jobs:
  build-and-deploy:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - name: Deploy to Server
      uses: easingthemes/ssh-deploy@main
      with:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
          ARGS: "-rlgoDzvc -i --delete"
          SOURCE: "simple-web-server/"
          REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
          REMOTE_USER: ${{ secrets.REMOTE_USER }}
          TARGET: ${{ secrets.REMOTE_TARGET }}
          EXCLUDE: "/dist/, /node_modules/"
          SCRIPT_BEFORE: |
            whoami
            ls -al
            mkdir -p ${{ secrets.REMOTE_TARGET }}
          SCRIPT_AFTER: |
            cd ${{ secrets.REMOTE_TARGET }}
            ls -al

            echo "Installing Node.js..."
            if ! command -v nvm &> /dev/null; then
              curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
              export NVM_DIR="$HOME/.nvm"
              [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
            fi
            nvm install node

            echo "Installing PM2..."
            if ! command -v pm2 &> /dev/null; then
            npm install -g pm2
            fi

            npm install

            echo "Starting/restarting application..."
            pm2 restart server.js || pm2 start server.js

4.3. 验证部署结果

提交并推送代码:

$ git add .
$ git commit -m "Deploy to EC2 using easingthemes/ssh-deploy"
$ git push

查看 GitHub Actions 页面确认流水线运行成功:

Action 运行截图

✅ 部署成功!

5. 总结

本教程演示了如何使用 GitHub Actions 直接部署 Node.js 应用到 AWS EC2 实例。我们介绍了两种方式:

  • 使用 SSH 命令直接部署
  • 使用 easingthemes/ssh-deploy Action 自动化部署

两种方式各有优劣:

方式 优点 缺点
SSH 命令部署 灵活、可控性强 需要手动编写脚本
easingthemes/ssh-deploy 简洁、自动化程度高、易于维护 依赖第三方 Action,灵活性略差

✅ 推荐做法:使用 easingthemes/ssh-deploy 提升部署效率和可维护性,同时保留 SCRIPT_AFTER 等钩子用于自定义部署后操作。

使用 GitHub Actions 不仅节省时间,还能减少人为错误,为后续的 CI/CD 扩展打下坚实基础。


原始标题:Deploy Directly to AWS EC2 Using GitHub Actions