一、 环境背景与架构设计
在本项目中,我们构建了一套基于 GitHub Actions 和 阿里云容器镜像服务(ACR)的自动化部署流程(CI/CD)。
1. 核心架构
- 代码仓库:GitHub
- 自动化工具:GitHub Actions
- 镜像仓库:阿里云容器镜像服务(个人版)
- 部署环境:阿里云 ECS(Ubuntu/CentOS),运行 Docker Compose
- 自动更新:Watchtower 容器,负责监控镜像变动并重启服务
2. 技术栈
- 前端:Vite + Vue(打包为静态资源)
- 网关/服务器:Nginx(容器化部署)
- 后端:Spring Boot(端口 8084,Context-Path: /my-server)
二、 自动化部署标准步骤
1. 编写 Dockerfile (前端)
由于 GitHub 所在的海外环境拉取 Docker Hub 镜像常遇到限流,建议在 GitHub Actions 中配置登录后再进行构建。
dockerfile
FROM nginx:stable-alpine
# 移除默认配置并复制自定义配置与打包后的静态文件
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d/
COPY dist/ /usr/share/nginx/html/pjone/
EXPOSE 802. 配置 GitHub Actions 工作流
在项目根目录 .github/workflows/frontend.yml 中配置双登录策略:先登录 Docker Hub 避开限流,再登录 阿里云 推送镜像。
yaml
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to Ali-Registry
run: docker login --username=${{ secrets.ALI_USERNAME }} --password=${{ secrets.ALI_PASSWORD }} ${{ secrets.ALI_REGISTRY }}
- name: Build and Push
run: |
IMAGE_NAME=${{ secrets.ALI_REGISTRY }}/your-space/my-web:latest
docker build -t $IMAGE_NAME .
docker push $IMAGE_NAME3. 服务器 Docker Compose 配置
配置 Watchtower 实现无人值守自动更新,核心在于挂载认证文件。
yaml
web:
image: registry.cn-hangzhou.aliyuncs.com/your-space/my-web:latest
container_name: my-web
restart: always
ports:
- "8081:80"
watchtower:
image: containrrr/watchtower
container_name: my-watchtower
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /root/.docker/config.json:/config.json:ro
command: --interval 30 --cleanup三、 实战遇到的问题汇总
1. Nginx 转发导致后端 404
- 现象:Postman 直接访问后端端口成功,但通过 Nginx 转发后报 404。
- 原因:
proxy_pass路径拼接逻辑错误。在配置中使用了proxy_pass http://server:8084/;(带末尾斜杠),导致 Nginx 剥离了 location 匹配的前缀,而后端接口恰好需要该前缀。 - 报错日志:Nginx error log 显示找不到请求路径或后端 Tomcat 抛出 404 页面。
2. Docker Hub 镜像拉取限流 (429 Too Many Requests)
- 现象:GitHub Actions 在执行
docker build时,拉取FROM nginx失败。 - 原因:GitHub Actions 公用 IP 被 Docker Hub 判定为匿名请求过多,触发限流。
3. Watchtower 无法自动更新 (Up 2 days)
- 现象:Actions 显示成功推送到阿里云,但服务器容器启动时间未更新。
- 原因:Watchtower 运行在隔离容器内,没有宿主机的阿里云登录凭证(config.json),无法拉取私有仓库镜像。
四、 最终解决方案
1. 修正 Nginx 转发配置
取消 proxy_pass 目标地址末尾的斜杠,实现路径完整透传。
nginx
location /my-server/ {
proxy_pass http://server:8084; # 去掉末尾斜杠
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}2. 实施 Docker Hub 登录策略
在 GitHub 项目 Settings 中添加 DOCKERHUB_USERNAME 与 DOCKERHUB_TOKEN。在 Workflow 中增加登录步骤,确保以身份校验状态拉取基础镜像,彻底规避 429 报错。
3. 挂载 Watchtower 认证凭证
在服务器执行一次 docker login 后,将产生的 /root/.docker/config.json 挂载至 Watchtower 容器内部的 /config.json 路径,并赋予只读权限。这是实现私有镜像自动更新的关键步骤。
通过以上方案,系统实现了从代码推送、自动化镜像构建、私有仓库托管到服务器无感自动更新的完整闭环。