GitHub Actions 工作流 CI/CD 的"发布"
围绕你的 file-server-docker 项目,把五件事串起来:
- 镜像标签(Tag)
- Registry 登录
docker tagdocker push- 版本回滚
第一步:理解发布的完整流程
先看整体链路:
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_USERNAMEACR_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 才是真正上传
前面已经完成:
- 构建镜像。
- 登录 ACR。
- 为镜像添加完整地址和版本标签。
现在执行:
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/index.php/start-page.html
CSDN、GitHub、知乎、开源中国、思否、掘金、简书、华为云、阿里云、腾讯云、哔哩哔哩、今日头条、新浪微博、个人博客
全网可搜《小陈运维》
文章主要发布于微信公众号:《Linux运维交流社区》