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 imagesREPOSITORY 那一列就是镜像的名字。而一个完整的名字有四段:
[仓库地址/] 命名空间/ 名字 : 标签第 3 关打的 mysite:1.0,前两段都省了——省掉时默认是 Docker Hub、和你的账号。
第一步,给镜像打上「仓库认的那个名字」:
docker tag mysite:1.0 <你的用户名>/mysite:1.0docker 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-pushon: 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 }}三点:
- 凭据不写进文件,放 GitHub 仓库的 secrets 里,用
${{ secrets.xxx }}取;CI 里用的是 access token(就是 10.1 提的那个)。 tags:用github.ref_name——即触发的那个 tag 名(如v1.0)。这正是 10.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。下一关换个方向——容器跑起来之后,它的日志和磁盘会悄悄长大,那是另一类日常麻烦。
本关命令速查
镜像的推送与标签,见 命令速查表 · 镜像。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!





