由于网络问题, 在服务器上直接
docker pull ghcr.io
会有问题, 所以以下的方式我们采用打包镜像然后同步到服务器的方式来解决这个问题.
核心功能定位
概念 | 技术本质 | 核心作用 | 归属 |
---|---|---|---|
Tag | Git 的轻量标签(Lightweight Tag) | 标记仓库中的特定提交 (如 git tag v1.0.0 ) |
Git 原生功能 |
Release | GitHub 的增强型发布管理 | 基于 Tag 封装可分发版本(含说明 / 二进制文件等) | GitHub 平台功能 |
Actions | GitHub 的 CI / CD 引擎 | 通过工作流(Workflow)自动化构建、测试、部署 | GitHub 平台服务 |
创建预定义变量

写工作流文件
arduino
# tree
├─.github
│ └─workflows
│ └─deploy.yml
├─Dockerfile
Copy
bash
## .github/workflows/deploy.yml
name: deploy
on:
push:
branches: ['main']
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
IMAGE_TAG: ${{ github.run_id }}
IMAGE_FULL_NAME: ghcr.io/${{ github.repository }}:${{ github.run_id }}
# !!! 容器名字
CONTAINER_NAME: test-ci
# 镜像保存名字
IMAGE_FILE: ${{ github.run_id }}.tar
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
# This is used to complete the identity challenge
# with sigstore/fulcio when running outside of PRs.
id-token: write
steps:
- name: 检出仓库
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.0.0
- name: 登录
uses: docker/login-action@v3.0.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: 提取镜像名
id: meta
uses: docker/metadata-action@v5.0.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: 构建镜像并推送
id: build-and-push
uses: docker/build-push-action@v5.0.0
with:
context: .
## 因为网络不好, 所以不能直接 docker pull, 需要打包然后同步到服务器
push: false
load: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: 打包镜像为 tar 文件
run: |
docker save -o ${{ env.IMAGE_FILE }} ${{ env.IMAGE_FULL_NAME }}
du -sh ${{ env.IMAGE_FILE }}
- name: 同步镜像到服务器
uses: appleboy/scp-action@v1
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: ${{ secrets.SSH_PORT }}
source: ${{ env.IMAGE_FILE }}
target: /tmp/
- name: ssh 部署
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: ${{ secrets.SSH_PORT }}
script: |
# 加载 Docker 镜像
echo ${{ env.CONTAINER_NAME }}
echo ${{ env.IMAGE_FULL_NAME }}
docker load -i /tmp/${{ env.IMAGE_FILE }}
# 清理旧容器
docker stop ${{ env.CONTAINER_NAME }} &>/dev/null || true
docker rm -f ${{ env.CONTAINER_NAME }} &>/dev/null || true
## 启动容器
docker run --name ${{ env.CONTAINER_NAME }} --restart=always ${{ env.IMAGE_FULL_NAME }}
# 清理临时文件
rm /tmp/${{ env.IMAGE_FILE }}
echo "Deployment completed successfully!"