10进阶:推送与自动化构建

1238 字
6 分钟
10进阶:推送与自动化构建

第 10 关 推送与自动化构建#

本关的产出:把镜像推到一个别人也能拉的地方,给它定一套经得起用的标签,再让机器替你构建和推送。

10.1 镜像怎么出门:仓库#

前面九关,镜像都只躺在这台机器上(docker images 里那些)。要让它「出门」——给别人用、给服务器用、给 CI 用——就得放进一个仓库(registry)里:你往里推,别人从里拉。

最常用的仓库是 Docker Hub;此外还有 GitHub 的 ghcr.io、GitLab 的、云厂商的,也能自己搭一个。

第 3 关说 FROM nginx 时「本地没有它会先去拉」——它去的就是 Docker Hub。那些镜像,正是别人推上去的。

推之前先登录:

docker login

不带参数就是登 Docker Hub,会让你输用户名和密码。正经场景该用 access token,不是账号密码(10.5 会用上)。

10.2 推送的三步#

先看要推的东西叫什么:

docker images

REPOSITORY 那一列就是镜像的名字。而一个完整的名字有四段:

[仓库地址/] 命名空间/ 名字 : 标签

第 3 关打的 mysite:1.0,前两段都省了——省掉时默认是 Docker Hub、和你的账号。

第一步,给镜像打上「仓库认的那个名字」:

docker tag mysite:1.0 <你的用户名>/mysite:1.0

docker tag 不复制镜像,只是给同一个镜像再挂一个名字——原来的 mysite:1.0 还在。

第二步,推:

docker push <你的用户名>/mysite:1.0

第三步,换台机器拉:

docker pull <你的用户名>/mysite:1.0

易踩的坑:docker push 时,名字必须带上仓库里的那段路径。直接 docker push mysite:1.0 会报错——mysite:1.0 在 Docker Hub 上没有归属,它不知道该往谁那儿推。

10.3 latest 不是「最新」#

第 3 关留的那个坑,在这儿收:latest 不是「最新版本」,它只是「没写标签时的默认标签」。

  • docker build -t mysite . → 实际名字是 mysite:latest;
  • docker run nginx → 实际是 nginx:latest;
  • docker pull nginx → 拿的也是 latest。

麻烦在于:它不保证是最新的,而且随时会变。CI 每推一次都覆盖 latest,于是——

  • 今天 docker pull app:latest 和明天拉的,可能是两个完全不同的程序;
  • 服务器上跑的那份,你没法从「它写的是 latest」反推是哪个版本;
  • 想回滚时,latest 指向哪儿,你说了不算。

所以生产上别用 latest,用明确的版本:mysite:1.0,或者干脆用提交号 mysite:sha-a1b2c3d。

配一条约定:同一个名字下,一个版本标签推上去就不再动它(发了 1.0 就别再覆盖 1.0),要改就发新号。这样 1.0 永远指同一份东西,能复现、能回滚。

10.4 digest:指向「这一份内容」#

版本标签是你起的名字,靠上面的约定保证它不变。还有一种编号是内容自己算出来的,叫 digest:

nginx@sha256:...

它由镜像内容哈希得来,内容变一个字节,digest 就变——所以它天生不可变,没有「指着同一份、其实变了」这回事。

看一个镜像的 digest:

docker inspect --format '{{index .RepoDigests 0}}' nginx

要「绝对确保跑的就是这一份」,就用 digest 引用。日志、事故报告、锁死的生产版本,都该记 digest 而不是标签。(日常还是用版本标签,好念;digest 是较真时的最后一道保险。)

10.5 让机器来推:CI 与多架构#

手动 build 再 push 迟早会忘。交给 CI——推一个 tag 或合并到主分支,机器自动构建、自动推。

以 GitHub Actions 为例,仓库里放一个 .github/workflows/build.yml:

name: build-and-push
on:
push:
tags: ["v*"] # 只在推 v 开头的 tag 时触发
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- uses: docker/build-push-action@v7
with:
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/mysite:${{ github.ref_name }}

三点:

  1. 凭据不写进文件,放 GitHub 仓库的 secrets 里,用 ${{ secrets.xxx }} 取;CI 里用的是 access token(就是 10.1 提的那个)。
  2. tags: 用 github.ref_name——即触发的那个 tag 名(如 v1.0)。这正是 10.3 说的「用明确版本」。
  3. 整件事不在你的电脑上发生——全在 CI 的一台临时机器上。镜像从源码直接进仓库,不经过你。

多架构:同一份镜像要让 Intel 服务器和 ARM 服务器(Apple 芯片、新云主机)都能跑,得分别构建、再合成一个「多架构镜像」。这一步交给 buildx,加两行:

- uses: docker/setup-buildx-action@v4
- uses: docker/build-push-action@v7
with:
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ secrets.DOCKERHUB_USERNAME }}/mysite:${{ github.ref_name }}

推上去仍是一个名字。docker pull 的时候,Docker 自动挑跟当前机器匹配的那个架构——拉的人不用管。

这一关的产出:镜像能推到仓库、标签定得起经得起用、构建交给 CI。下一关换个方向——容器跑起来之后,它的日志和磁盘会悄悄长大,那是另一类日常麻烦。

本关命令速查#

镜像的推送与标签,见 命令速查表 · 镜像。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

打赏
10进阶:推送与自动化构建
https://hecloud.top/posts/tech/docker/10推送与自动化构建/
作者
贺小云
发布于
2026-10-13
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
贺小云
热爱技术与折腾的博客 Dancing with uncertainty. 与不确定性共舞
公告
出于成本考虑,贺云已全面转型Serverless架构
分类
标签
碎碎念
站点统计
文章
91
分类
5
标签
44
总字数
103,192
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
Cloudflare Pages
博客版本
Firefly v6.16.5
文章许可
CC BY-NC-SA 4.0