GitHub Actions 工作流 CI/CD 的“发布”

GitHub Actions 工作流 CI/CD 的"发布"

围绕你的 file-server-docker 项目,把五件事串起来:

  1. 镜像标签(Tag)
  2. Registry 登录
  3. docker tag
  4. docker push
  5. 版本回滚

第一步:理解发布的完整流程

先看整体链路:
flowchart TD A"GitHub 代码仓库\\n源代码 + Dockerfile" --> B"docker build\\n构建本地 Docker 镜像" --> C"docker tag\\n为同一个镜像增加仓库地址和版本标签" --> D"Registry 登录\\n获得向目标镜像仓库推送的权限" --> E"docker push\\n将镜像上传到阿里云 ACR" --> F"部署服务器\\n拉取指定版本,启动容器,验证健康状态"

注意:docker tag 不负责上传镜像,docker push 才负责上传;Registry 登录也不会自动帮你构建镜像。


第二步:镜像标签究竟是什么?

假设你构建了一个镜像:

bash 复制代码
docker build -t file-server:latest .

这里的:

text 复制代码
file-server:latest

是镜像名称和标签。

可以把镜像理解成一个应用的完整打包结果,而标签相当于给这个打包结果贴上的名字。

常见的标签有三类:

标签 示例 用途
浮动标签 latest 通常表示当前主推版本,但含义由发布流程约定
版本标签 v1.2.0 便于人工识别正式版本
提交标签 sha-a1b2c3d 将镜像与某次 Git 提交关联

为什么不建议只使用 latest?

假设你今天发布了:

text 复制代码
file-server:latest → 版本 A

明天又发布了:

text 复制代码
file-server:latest → 版本 B

同一个标签现在指向版本 B。

如果服务器之前运行版本 A,而你只记录了 latest,之后想回滚时,就很难仅凭这个标签确定之前到底运行的是哪个版本。

更好的方式是同时发布:

text 复制代码
file-server:latest
file-server:sha-a1b2c3d

下一次发布时:

text 复制代码
file-server:latest
file-server:sha-e4f5g6h

这样,latest 可以指向当前发布版本,而旧的提交标签仍然可以用于定位历史版本,前提是仓库没有删除或覆盖这些标签。

建议:生产部署使用明确的版本标签或镜像 digest,latest 只作为辅助标签。

第三步:Registry 登录到底做了什么?

Registry 就是 Docker 镜像仓库。你可以把它理解成存放镜像的远程服务器。

你当前项目使用的目标仓库命名空间是:

text 复制代码
registry.cn-hangzhou.aliyuncs.com/chenby

假设镜像仓库名为 file-server,完整镜像地址就可以写成:

text 复制代码
registry.cn-hangzhou.aliyuncs.com/chenby/file-server:sha-a1b2c3d

它由四部分组成:

字段 值
Registry 地址 registry.cn-hangzhou.aliyuncs.com
命名空间 / 用户或组织空间 chenby
镜像仓库名 file-server
镜像标签 sha-a1b2c3d

1. 登录命令

一般形式:

bash 复制代码
docker login registry.cn-hangzhou.aliyuncs.com

执行后,Docker 会要求输入用户名和密码或访问凭证。对于阿里云 ACR,具体凭证应使用该实例或仓库对应的登录凭证。

登录的作用是让 Docker 获得相应仓库的访问权限。它不会构建镜像,也不会上传镜像。

2. GitHub Actions 中怎样登录?

不要把仓库密码直接写进 YAML 文件,更不要提交到 GitHub 仓库。

在 GitHub 仓库的 Settings → Secrets and variables → Actions 中配置必要的 Secrets,例如:

  • ACR_USERNAME
  • ACR_PASSWORD

然后在 Workflow 中使用登录 Action:

yaml 复制代码
- name: Login to ACR
  uses: docker/login-action@v3
  with:
    registry: registry.cn-hangzhou.aliyuncs.com
    username: ${{ secrets.ACR_USERNAME }}
    password: ${{ secrets.ACR_PASSWORD }}

这里有两个重要区别:

  • registry 是仓库服务的地址,不是完整的镜像地址。
  • secrets.ACR_PASSWORD 是从 GitHub Secrets 读取凭证,不是 YAML 中的明文密码。

实际使用时,应为自动化任务创建权限尽可能小的专用凭证,并根据阿里云 ACR 的权限模型限制其访问范围。


第四步:docker tag 到底干了什么?

假设你先构建了本地镜像:

bash 复制代码
docker build -t file-server:latest .

查看本地镜像:

bash 复制代码
docker images

你可能看到:

text 复制代码
REPOSITORY     TAG       IMAGE ID
file-server    latest    a1b2c3d4e5f6

现在要把它发布到 ACR,需要为它增加一个完整的仓库地址。

执行:

bash 复制代码
docker tag file-server:latest \
  registry.cn-hangzhou.aliyuncs.com/chenby/file-server:sha-a1b2c3d

此时,你再执行:

bash 复制代码
docker images

可能看到:

text 复制代码
REPOSITORY                                               TAG           IMAGE ID
file-server                                              latest        a1b2c3d4e5f6
registry.cn-hangzhou.aliyuncs.com/chenby/file-server     sha-a1b2c3d    a1b2c3d4e5f6

注意两行的 IMAGE ID 相同。

这意味着 docker tag 通常只是给同一个本地镜像增加另一个名称,而不是重新构建一份镜像,也不是把镜像上传到网络。

可以把它想成给同一个文件增加一个新的引用名称:内容没变,只是增加了一个指向它的名字。

这里最容易出错的地方

docker tag 的格式是:

bash 复制代码
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
  • SOURCE_IMAGE:本地已经存在的镜像。
  • TARGET_IMAGE:准备使用的新名称。
  • TAG:可选的标签;如果省略,通常默认使用 latest。

如果源镜像不存在,就会报错。docker tag 不会替你从 Dockerfile 构建镜像。


第五步:docker push 才是真正上传

前面已经完成:

  1. 构建镜像。
  2. 登录 ACR。
  3. 为镜像添加完整地址和版本标签。

现在执行:

bash 复制代码
docker push \
  registry.cn-hangzhou.aliyuncs.com/chenby/file-server:sha-a1b2c3d

Docker 会将目标镜像所需的数据层上传到对应仓库,并发布该标签的引用。

流程是:
flowchart TD A"本地镜像\\nfile-server:latest" --> B"docker tag\\n增加 ACR 地址和版本标签" --> C"docker push\\n上传到远程镜像仓库" --> D"ACR 远程仓库\\n其他有权限的机器可以拉取该版本"

推送成功后,你可以在 ACR 控制台中查看镜像仓库和对应标签。

但是,推送成功只说明镜像已经发布到仓库,并不代表生产服务器已经运行这个版本。服务器还需要执行拉取和部署。

把这几个命令放在一起看

下面是一个从构建到推送的完整示例。请确保目标仓库 chenby/file-server 已经创建,并且你有相应权限。

bash 复制代码
# 1. 构建镜像
docker build -t file-server:latest .

# 2. 登录仓库
docker login registry.cn-hangzhou.aliyuncs.com

# 3. 添加版本标签
docker tag file-server:latest \
  registry.cn-hangzhou.aliyuncs.com/chenby/file-server:sha-a1b2c3d

# 4. 推送镜像
docker push \
  registry.cn-hangzhou.aliyuncs.com/chenby/file-server:sha-a1b2c3d

这四步各司其职:

命令 作用
docker build 构建本地镜像
docker login 认证仓库访问权限
docker tag 为镜像增加目标名称和标签
docker push 上传镜像到远程仓库

注意:上面的 sha-a1b2c3d 是示例标签。真实的 GitHub Actions 应当使用实际提交 SHA 或其他明确的版本标识,不能把示例字符串直接当作真实版本。


第六步:服务器怎样拉取并运行指定版本?

镜像推送到 ACR 后,服务器可以执行:

bash 复制代码
docker pull \
  registry.cn-hangzhou.aliyuncs.com/chenby/file-server:sha-a1b2c3d

然后通过 Docker Compose 指定该版本。

例如,Compose 文件可以使用环境变量:

yaml 复制代码
services:
  file-server:
    image: ${FILE_SERVER_IMAGE}
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - ./uploads:/data/uploads

这里的端口、容器路径和服务名称都是示例,必须与你项目的实际配置一致。

部署时可以这样指定镜像:

bash 复制代码
export FILE_SERVER_IMAGE="registry.cn-hangzhou.aliyuncs.com/chenby/file-server:sha-a1b2c3d"

docker compose pull
docker compose up -d

docker compose pull 会拉取 Compose 配置中指定的镜像,docker compose up -d 会按配置创建或更新容器。

有个细节要注意:export 只在当前 Shell 会话及其子进程中生效。如果你在另一个终端或另一次 SSH 会话中执行命令,需要重新设置变量,或者使用专门的部署环境文件。


第七步:如何实现版本回滚?

假设你先后发布了两个版本:
flowchart TD A"旧版本:sha-a1b2c3d\\n已验证可用,应该保留作为回滚目标。" --> B"新版本:sha-e4f5g6h\\n已经推送并尝试部署,但健康检查失败。" --> C"恢复旧版本\\n重新指定旧标签,拉取并更新服务,然后再次验证健康状态。"

如果 Compose 使用前面的 FILE_SERVER_IMAGE 变量,回滚可以是:

bash 复制代码
export FILE_SERVER_IMAGE="registry.cn-hangzhou.aliyuncs.com/chenby/file-server:sha-a1b2c3d"

docker compose pull
docker compose up -d

这会将 Compose 配置指向旧版本。前提是旧镜像仍然存在于仓库中,且服务器可以访问它。

回滚并不等于删除新镜像。 新镜像可以留在仓库中供排查问题;真正重要的是让服务重新运行已知可用的版本。

还要特别注意:

  • 用户上传的文件应存放在持久化卷或可靠的外部存储中。
  • 如果新版本修改了数据库结构或文件格式,单纯回滚镜像可能不够。
  • docker compose up -d 返回成功后,还需要检查容器健康状态和业务接口。
  • 如果部署过程中旧容器已经被替换,恢复旧版本仍可能产生短暂中断。需要更高可用性时,要设计新旧实例并行运行、流量切换等策略。

第八步:把整个发布流程记成一句话

构建镜像 → 登录 Registry → 为镜像打版本标签 → 推送镜像 → 服务器拉取指定版本 → 部署并检查 → 失败则恢复旧版本。

你可以用下面的交互小测验检验一下自己是否真正理解了。

发布流程小测验

你已经执行了 docker build 和 docker tag,并且成功登录了 ACR。接下来要把镜像真正上传到仓库,应该执行哪个命令?

  • A. docker run
  • B. docker push
  • C. docker tag
  • D. docker compose up -d

点击查看答案

正确答案:B. docker push

docker push 会将本地镜像推送到远程 Registry。前面的 docker tag 只是为镜像增加目标名称,并不会上传。

  • docker run:用于创建并启动容器,不是上传镜像。
  • docker tag:只修改镜像引用名称,不负责网络上传。
  • docker compose up -d:用于根据 Compose 配置创建或更新服务,不负责推送镜像到 ACR。

关于

https://www.oiox.cn/

https://www.oiox.cn/index.php/start-page.html

CSDN、GitHub、知乎、开源中国、思否、掘金、简书、华为云、阿里云、腾讯云、哔哩哔哩、今日头条、新浪微博、个人博客

全网可搜《小陈运维》

文章主要发布于微信公众号:《Linux运维交流社区》