1. 简介
Amazon Elastic Cloud Compute (EC2) 是 AWS 提供的一项基础服务,它以虚拟服务器(实例)的形式提供可扩展的计算资源,用于运行应用程序。
GitHub Actions 是一个 CI/CD 平台,允许开发者在 GitHub 仓库中直接自动化软件开发流程。它构建了一条流水线,使代码变更能够自动构建、测试并部署到生产环境,比如一个 EC2 实例。
使用 GitHub Actions 直接部署到 AWS EC2 的常见方式有:
- 使用 SSH(Secure Shell)
- 使用
easingthemes/ssh-deploy
第三方 Action
在本教程中,我们将介绍 EC2 实例的配置、SSH 密钥管理、GitHub Actions 流水线的创建,以及确保部署安全可靠的最佳实践。
2. 环境准备
在部署应用之前,我们需要在 GitHub 和 AWS 上分别配置环境。
2.1. GitHub 环境配置
首先,在 GitHub 上创建一个名为 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
查看运行效果:
最后提交代码:
$ git add .
$ git commit -m "NodeJS-Express Application"
$ git push
2.2. AWS 环境配置
创建一个名为 github-actions-ec2-instance
的 EC2 实例:
选择 Ubuntu AMI,实例类型为 t2.micro
:
创建 RSA 类型的密钥对,格式为 .pem
:
下载密钥文件 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 实例公网 DNSREMOTE_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 页面确认流水线运行成功:
✅ 部署成功!
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 扩展打下坚实基础。