实战记录:Next.js 前端项目通过 GitHub Actions + 阿里云 ACR + Docker 自动化 CI/CD 部署到云服务器(全坑规避指南)
-
- 核心架构与流转过程
- 步骤一:新建Dockerfile
- [步骤二:阿里云容器镜像服务 (ACR) 配置](#步骤二:阿里云容器镜像服务 (ACR) 配置)
-
- [1.登录阿里云控制台,搜索并进入 "容器镜像服务 (ACR)"。](#1.登录阿里云控制台,搜索并进入 “容器镜像服务 (ACR)”。)
- [2.创建个人版实例。在"仓库管理" -> "命名空间"中创建一个命名空间(例如:yaojinhong)。](#2.创建个人版实例。在“仓库管理” -> “命名空间”中创建一个命名空间(例如:yaojinhong)。)
- [3.在"镜像仓库"中点击 "创建镜像仓库":](#3.在“镜像仓库”中点击 “创建镜像仓库”:)
- [4.进入实例概览页,复制 "公网" 后面的那长串实例域名(例如:crpi-xxxxx.cn-shanghai.personal.cr.aliyuncs.com),这就是你的 ALIYUN_REGISTRY 门牌号。](#4.进入实例概览页,复制 “公网” 后面的那长串实例域名(例如:crpi-xxxxx.cn-shanghai.personal.cr.aliyuncs.com),这就是你的 ALIYUN_REGISTRY 门牌号。)
- [5.在"访问凭证"中,设置你的固定登录密码,后续 GitHub Actions 需要用到。](#5.在“访问凭证”中,设置你的固定登录密码,后续 GitHub Actions 需要用到。)
- [步骤三: 服务器端 SSH 免密登录配置(ED25519 规范)](#步骤三: 服务器端 SSH 免密登录配置(ED25519 规范))
-
- 1.登录你的云服务器终端,执行以下命令生成专属密钥对(一路回车到底,不要设置密码):
- [2.将生成的公钥追加到系统的授权列表中(使用 >> 绝对不会覆盖已有的其他密钥,对旧业务无损):](#2.将生成的公钥追加到系统的授权列表中(使用 >> 绝对不会覆盖已有的其他密钥,对旧业务无损):)
- [3.打印并完整复制你的私钥内容(后续配置到 GitHub):](#3.打印并完整复制你的私钥内容(后续配置到 GitHub):)
- [步骤四:GitHub Secrets 环境变量配置](#步骤四:GitHub Secrets 环境变量配置)
- [步骤五:编写 GitHub Actions 工作流配置文件](#步骤五:编写 GitHub Actions 工作流配置文件)
核心架构与流转过程
整个自动化部署(CI/CD)的流转路径如下:
- 本地开发 :修改代码,通过
git push推送到 GitHub 仓库的main分支。 - 触发流水线 :GitHub 检测到分支变动,自动唤醒 GitHub Actions 虚拟运行环境。
- 镜像构建 :Actions 拉取最新代码,执行
docker build打包 Next.js 项目。 - 托管镜像 :Actions 自动登录阿里云镜像服务 (ACR),将打包好的镜像推送到云端仓库。
- 远程部署:Actions 通过 SSH 密钥安全登录你的云服务器,拉取最新镜像,停止并删除旧容器,重新运行新容器,完成无缝升级。
步骤一:新建Dockerfile
确保项目根目录下有标准的 Dockerfile,示例如下:
powershell
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app ./
EXPOSE 3000
CMD ["npm", "run", "start"]
步骤二:阿里云容器镜像服务 (ACR) 配置
1.登录阿里云控制台,搜索并进入 "容器镜像服务 (ACR)"。
2.创建个人版实例。在"仓库管理" -> "命名空间"中创建一个命名空间(例如:yaojinhong)。
3.在"镜像仓库"中点击 "创建镜像仓库":
1.填写仓库名称(例如:sumurai-web)。
2.仓库类型选择 "私有"。
3.关键点:在代码源页面,务必选择 "本地仓库"。因为我们将使用 GitHub Actions 来完成主动推送,不需要阿里云去拉取代码。
4.进入实例概览页,复制 "公网" 后面的那长串实例域名(例如:crpi-xxxxx.cn-shanghai.personal.cr.aliyuncs.com),这就是你的 ALIYUN_REGISTRY 门牌号。
5.在"访问凭证"中,设置你的固定登录密码,后续 GitHub Actions 需要用到。
步骤三: 服务器端 SSH 免密登录配置(ED25519 规范)
现代 Linux 系统(如 Ubuntu 22.04+)为了安全默认禁用了老旧的 ssh-rsa 加密算法。为了确保 GitHub 能顺利敲开服务器大门,建议直接在服务器上生成现代的 ed25519 密钥。
1.登录你的云服务器终端,执行以下命令生成专属密钥对(一路回车到底,不要设置密码):
bash
ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/github_action_key
2.将生成的公钥追加到系统的授权列表中(使用 >> 绝对不会覆盖已有的其他密钥,对旧业务无损):
bash
cat ~/.ssh/github_action_key.pub >> ~/.ssh/authorized_keys
3.打印并完整复制你的私钥内容(后续配置到 GitHub):
bash
cat ~/.ssh/github_action_key
注意:复制时要连同 -----BEGIN OPENSSH PRIVATE KEY----- 和 -----END OPENSSH PRIVATE KEY----- 这两行虚线一起完整复制。
步骤四:GitHub Secrets 环境变量配置
环境变量用于保护机密数据。进入你的 GitHub 项目仓库,依次点击 Settings -> Secrets and variables -> Actions -> New repository secret,添加以下 6 个密钥:
| Secret 名称 | 含义 / 填写规范 | 示例值 |
|---|---|---|
ALIYUN_REGISTRY |
阿里云 ACR 实例的公网域名(不带 https:// 和结尾的 /) |
crpi-xxx.cn-shanghai.personal.cr.aliyuncs.com |
ALIYUN_USERNAME |
登录阿里云镜像仓库的用户名 | 用户名... |
ALIYUN_PASSWORD |
阿里云镜像服务设置的固定访问密码 | ****** |
SERVER_HOST |
云服务器的纯公网 IP 地址(严禁 带 http:// 或尾部 /) |
服务器IP地址 |
SERVER_USERNAME |
平时登录服务器的用户名(通常是 root) |
root |
SERVER_SSH_KEY |
在服务器生成的 ed25519 私钥的完整内容 (包含 -----BEGIN OPENSSH... 头尾标记) |
-----BEGIN OPENSSH... |
步骤五:编写 GitHub Actions 工作流配置文件
在本地项目的根目录下,创建 .github/workflows/deploy.yml 文件,完整内容如下:
yaml
name: Deploy sumurai-web
on:
push:
branches: [main] # 监听推送到 main 分支时触发
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
# 1. 检出代码
- name: Checkout code
uses: actions/checkout@v4
# 2. 登录阿里云容器镜像服务
- name: Login to Aliyun Container Registry
uses: docker/login-action@v3
with:
registry: ${{ secrets.ALIYUN_REGISTRY }}
username: ${{ secrets.ALIYUN_USERNAME }}
password: ${{ secrets.ALIYUN_PASSWORD }}
# 3. 构建并推送 Web 镜像
- name: Build and push Web
uses: docker/build-push-action@v5
with:
context: . # Dockerfile 位于根目录
push: true
tags: ${{ secrets.ALIYUN_REGISTRY }}/yaojinhong/sumurai-web:latest
# 4. 部署到服务器
- name: Deploy to server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USERNAME }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
# 登录阿里云(服务器也需要登录才能拉取私有镜像)
docker login ${{ secrets.ALIYUN_REGISTRY }} -u ${{ secrets.ALIYUN_USERNAME }} -p ${{ secrets.ALIYUN_PASSWORD }}
# 拉取最新镜像
docker pull ${{ secrets.ALIYUN_REGISTRY }}/yaojinhong/sumurai-web:latest
# 停止并删除旧容器 (加上 || true 防止第一次运行因找不到容器而报错中断)
docker stop sumurai-web || true
docker rm sumurai-web || true
# 运行新容器 (映射 3000 端口,并设置开机自启)
docker run -d \
--name sumurai-web \
-p 3000:3000 \
--restart always \
${{ secrets.ALIYUN_REGISTRY }}/yaojinhong/sumurai-web:latest
# 清理服务器上积压的无用虚悬镜像,释放磁盘空间
docker image prune -f
最后只要你提交到Git上面他就会自动发布了
