环境信息
说明: 本文为配置思路与示例整理,不代表作者已在自己的服务器上逐项验证全部命令。执行涉及公网暴露、账户权限、数据删除或服务重启的操作前,请先备份,并结合官方文档与实际环境核验。
| 组件 | 版本/说明 |
|---|---|
| GitHub Actions | Ubuntu latest runner |
| Docker Buildx | 0.24+ |
| VPS 系统 | Debian 12 / Ubuntu 22.04 |
| Docker Compose | v2.x |
为什么需要 CI/CD
手动部署的典型流程:
- 本地
docker build→ 2.docker push到镜像仓库 → 3. SSH 到 VPS → 4.docker pull→ 5.docker-compose up -d
这套流程每一步都可能出错,而且每次发版都要重复。GitHub Actions 可以把这 5 步压缩成一次 git push。
基础 Workflow:构建 + 推送到 GitHub Container Registry
在项目根目录创建 .github/workflows/deploy.yml:
name: Build and Deploy
on:
push:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha
type=raw,value=latest
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}关键点:
GITHUB_TOKEN是 GitHub 自动提供的,不需要手动配置tags用sha+latest,既保留版本追溯又方便部署permissions.packages: write是推送 ghcr.io 的必要权限
添加 VPS 自动部署
镜像推送成功后,通过 SSH 连到 VPS 拉取新镜像并重启容器:
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
image_tag: ${{ steps.meta.outputs.version }}
steps:
# ... (上面的构建步骤) ...
deploy:
needs: build-and-push
runs-on: ubuntu-latest
steps:
- name: Deploy to VPS
uses: appleboy/ssh-action@v1.2.0
with:
host: ${{ secrets.VPS_HOST }}
username: root
key: ${{ secrets.VPS_SSH_KEY }}
port: 22
script: |
cd /opt/myapp
docker compose pull
docker compose up -d
docker image prune -f
echo "Deployed $(date)" >> /var/log/deploy.log
配置 Secrets
在 GitHub 仓库 → Settings → Secrets and variables → Actions 中添加:
| Secret | 说明 | 示例 |
|---|---|---|
VPS_HOST |
VPS IP 或域名 | 192.0.2.1 |
VPS_SSH_KEY |
私钥内容(完整复制) | -----BEGIN OPENSSH PRIVATE KEY-----... |
踩坑:SSH 私钥必须包含头尾行,复制时容易丢换行符。建议用 cat ~/.ssh/id_ed25519 | pbcopy 粘贴。
优化:构建缓存加速
Docker 构建慢?用 GitHub Actions cache 把构建层缓存起来:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=maxmode=max 可以缓存更多构建层,但实际构建耗时取决于项目内容、缓存命中情况与 runner 环境,需在自己的流水线中观察。
进阶:Matrix 多平台构建
如果需要同时构建 amd64 和 arm64(比如自用 NAS 是 ARM 架构):
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max注意:多平台构建耗时会翻 2-3 倍(ARM 用 QEMU 仿真),如果不是必须,建议分开构建。
踩坑记录
1. docker compose vs docker-compose
GitHub Actions runner 上预装的是 Docker Compose v2(docker compose)。如果你的部署脚本用的是旧版 docker-compose(v1),会报 command not found。
解决:部署脚本统一用 docker compose(空格),或在 workflow 中先安装:
- name: Install Docker Compose v2
run: |
mkdir -p ~/.docker/cli-plugins/
curl -SL https://github.com/docker/compose/releases/latest/download/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose
chmod +x ~/.docker/cli-plugins/docker-compose
2. SSH 私钥格式
GitHub Actions 的 ssh-action 对私钥格式比较严格。如果用的是传统 RSA 密钥:
-----BEGIN OPENSSH PRIVATE KEY-----和新版格式:
-----BEGIN RSA PRIVATE KEY-----两种都能用,但 不能有额外的 passphrase。部署用的密钥建议专门生成一对:
ssh-keygen -t ed25519 -f deploy_key -N "" -C "github-actions-deploy"私钥放 Secrets,公钥加到 VPS 的 ~/.ssh/authorized_keys。
3. 网络问题导致 VPS 拉取 ghcr.io 镜像超时
国内 VPS 访问 ghcr.io 经常超时。解决思路:
# 在 VPS 上配置 registry mirror
cat > /etc/docker/daemon.json << 'EOF'
{
"registry-mirrors": [
"https://mirror.ccs.tencentyun.com",
"https://docker.m.daocloud.io"
]
}
EOF
systemctl restart docker如果 mirror 也不稳定,可以在 CI 中构建后直接 docker save + scp 到 VPS,避免依赖外网仓库。
4. 触发条件:避免重复运行
默认 push 到 main 会触发 workflow。但如果同时推送多个 commit,可能触发多次部署。加个并发控制:
concurrency:
group: deploy-production
cancel-in-progress: falsecancel-in-progress: false 表示不取消正在运行的部署(取消可能导致部署到一半的脏状态),而是排队执行。
完整 Workflow 模板
name: Build and Deploy
on:
push:
branches: [main]
concurrency:
group: deploy-production
cancel-in-progress: false
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
image_tag: ${{ steps.meta.outputs.version }}
steps:
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha
type=raw,value=latest
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy:
needs: build-and-push
runs-on: ubuntu-latest
steps:
- name: Deploy to VPS
uses: appleboy/ssh-action@v1.2.0
with:
host: ${{ secrets.VPS_HOST }}
username: root
key: ${{ secrets.VPS_SSH_KEY }}
script: |
export IMAGE_TAG=${{ needs.build-and-push.outputs.image_tag }}
cd /opt/myapp
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Deployed tag: $IMAGE_TAG" >> /var/log/deploy.log
小结
GitHub Actions 的 CI/CD 核心就是三件事:构建镜像、推送到仓库、SSH 部署到服务器。用好缓存和并发控制,日常发版从手动 5 分钟变成一次 git push。对于个人项目和小团队来说,这套方案零成本、免维护,比 Jenkins 之类的自建 CI 省心太多。
本文示例基于 GitHub Actions latest runner + Docker 27.x 环境整理,实际以项目具体需求为准。
评论
游客无需注册即可评论。
你提交的昵称、邮箱、网址和评论内容会保存在服务端,用于展示评论身份、接收回复及必要的安全审计。
浏览器会本地保存已填游客信息和评论草稿,方便下次免填。
回复提醒会通过站内消息和邮件通知。