目录

推送镜像到 Docker Hub 与私有 Registry 教程:发布和下载镜像

在自己的电脑上构建好镜像后,如果要在服务器上运行或分享给团队,就需要将它推送到 Registry。最常用的是 Docker Hub,其次是 GitHub Container Registry(ghcr.io)以及各云平台的 Registry。

镜像名称决定推送到哪里

推送时,Docker 根据镜像名称决定要发送到哪个 Registry、哪个账号(命名规则见镜像):

名称推送到
yourname/mysite:1.0.0Docker Hub 的 yourname 账号
ghcr.io/yourname/mysite:1.0.0GitHub Container Registry
localhost:5000/mysite:1.0.0本地 5000 端口上的私有 Registry

因此,推送前要先用 docker tag 将镜像命名为对应的名称。

未登录就推送会怎样

先看看未登录时直接推送到 Docker Hub 的结果:

$ docker tag nginx:1.30 yourname/mysite:1.0.0

$ docker push yourname/mysite:1.0.0
The push refers to repository [docker.io/yourname/mysite]
f4616bb1be1c: Unavailable
f1a6a629b824: Unavailable
3d774efa34e3: Unavailable
ecc510c1e359: Unavailable
push access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed

push access denied ... authorization failed:Docker Hub 拒绝了推送,因为你尚未登录,而且 yourname 也不是你的账号。下面依次完成注册、登录和推送。

推送到 Docker Hub

1. 注册账号

前往 Docker 官网注册账号(可以使用 Email,也可以直接使用 Google 或 GitHub 账号)。Username 就是之后镜像名称前面的命名空间:

Docker 账号注册页面
Docker 账号注册页面(截取于 2026 年 10 月)

2. 创建访问令牌并登录

建议在 Docker Hub 的账号设置中创建 Personal Access Token,用它代替密码登录,并且可以限制权限(例如只允许读写,不允许删除)。

docker login -u yourname

按提示粘贴访问令牌。登录成功后会显示 Login Succeeded。

3. 创建储存库(可选)

首次推送时,Docker Hub 会自动创建储存库。如果想提前设置说明或将其设为私有,可以在 Docker Hub 网站上点击 Create repository:

Docker Hub 创建储存库页面
Docker Hub 的 Create repository 页面:输入名称和说明,选择 Public 或 Private。图片来源:Docker 官方文档(Apache-2.0)

Docker Hub 上的储存库默认是公开的。免费方案的私有储存库数量有限,详见 Docker Hub 的方案说明。

4. 标记并推送

docker build -t yourname/mysite:1.0.0 -t yourname/mysite:latest .
docker push yourname/mysite:1.0.0
docker push yourname/mysite:latest

-t 可以多次使用,一次为镜像命名多个标签。也可以使用 docker push --all-tags yourname/mysite 一次推送所有标签。推送输出的格式与下面“自建私有 Registry”中的实际示例相同。

推送后,在 Docker Hub 储存库的 Tags 选项卡中可以看到每个标签,以及供其他人下载的命令:

Docker Hub 储存库的 Tags 选项卡
Docker Hub 储存库的 Tags 选项卡,右侧是 docker pull 命令。图片来源:Docker 官方文档(Apache-2.0)

5. 在其他机器上使用

docker pull yourname/mysite:1.0.0
docker run -d -p 8080:80 yourname/mysite:1.0.0

自建私有 Registry:实际演示推送与下载

Docker 官方提供了 registry 镜像,可以快速搭建一个私有 Registry。这也是亲自体验“推送”最简单的方法,不需要任何账号:

$ docker run -d -p 5000:5000 --restart unless-stopped -v registry-data:/var/lib/registry --name registry registry:3
Unable to find image 'registry:3' locally
3: Pulling from library/registry
e2de96513ba9: Already exists
90764beeca7f: Pull complete
8dc2188d2a74: Pull complete
783ed5b12fca: Pull complete
2aef3a8beb68: Pull complete
Digest: sha256:ddf754342cfc8acc51a56d5d0ab6af06826461864460636d8bd5c546dab2a7b8
Status: Downloaded newer image for registry:3
c5d02febbf0fd6d8c17e6818990adb28fd0a97c380a0d4c0a58ec793f685e4a0

标记并推送:

$ docker tag nginx:1.30 localhost:5000/mysite:1.0.0

$ docker tag nginx:1.30 localhost:5000/mysite:latest

$ docker push localhost:5000/mysite:1.0.0
The push refers to repository [localhost:5000/mysite]
3d774efa34e3: Pushed
ecc510c1e359: Pushed
f4616bb1be1c: Pushed
f1a6a629b824: Pushed
cb44c3fe542b: Pushed
121907e00c1c: Pushed
220a6ac36368: Pushed
1.0.0: digest: sha256:6e2a172ae5503c0df64cd3294b57c86394ced402016a8cc45436086fa51f5d02 size: 2288

i Info → Not all multiplatform-content is present and only the available single-platform image was pushed
         sha256:9bf97bd7714f5e24c1ccd545ecb9eb5435cb6d109c97cebb15e7e455e0239edb -> sha256:6e2a172ae5503c0df64cd3294b57c86394ced402016a8cc45436086fa51f5d02

$ docker push --all-tags localhost:5000/mysite
The push refers to repository [localhost:5000/mysite]
220a6ac36368: Layer already exists
3d774efa34e3: Layer already exists
ecc510c1e359: Layer already exists
f4616bb1be1c: Layer already exists
f1a6a629b824: Layer already exists
cb44c3fe542b: Layer already exists
121907e00c1c: Layer already exists
1.0.0: digest: sha256:6e2a172ae5503c0df64cd3294b57c86394ced402016a8cc45436086fa51f5d02 size: 2288
220a6ac36368: Layer already exists
3d774efa34e3: Layer already exists
ecc510c1e359: Layer already exists
f4616bb1be1c: Layer already exists
f1a6a629b824: Layer already exists
cb44c3fe542b: Layer already exists
121907e00c1c: Layer already exists
latest: digest: sha256:6e2a172ae5503c0df64cd3294b57c86394ced402016a8cc45436086fa51f5d02 size: 2288

i Info → Not all multiplatform-content is present and only the available single-platform image was pushed
         sha256:9bf97bd7714f5e24c1ccd545ecb9eb5435cb6d109c97cebb15e7e455e0239edb -> sha256:6e2a172ae5503c0df64cd3294b57c86394ced402016a8cc45436086fa51f5d02

i Info → Not all multiplatform-content is present and only the available single-platform image was pushed
         sha256:9bf97bd7714f5e24c1ccd545ecb9eb5435cb6d109c97cebb15e7e455e0239edb -> sha256:6e2a172ae5503c0df64cd3294b57c86394ced402016a8cc45436086fa51f5d02
  • 首次推送时,每一层都会显示 Pushed(已推送)。
  • 使用 --all-tags 推送 latest 时,所有层都显示 Layer already exists:1.0.0 和 latest 是同一个镜像,Registry 中已经有这些层,无需重新上传。
  • 最后的 Info 是 Docker 29 的提示:本地只下载了 linux/amd64 这个平台的 nginx,因此推送的也只有这个平台。要推送多平台镜像,请参见多平台镜像。

使用 Registry 的 API 确认内容:

$ curl -s http://localhost:5000/v2/_catalog
{"repositories":["mysite"]}

$ curl -s http://localhost:5000/v2/mysite/tags/list
{"name":"mysite","tags":["1.0.0","latest"]}

删除本地版本,再从自己的 Registry 下载回来:

$ docker rmi localhost:5000/mysite:1.0.0 localhost:5000/mysite:latest
Untagged: localhost:5000/mysite:1.0.0
Untagged: localhost:5000/mysite:latest

$ docker pull localhost:5000/mysite:1.0.0
1.0.0: Pulling from mysite
Digest: sha256:6e2a172ae5503c0df64cd3294b57c86394ced402016a8cc45436086fa51f5d02
Status: Downloaded newer image for localhost:5000/mysite:1.0.0
localhost:5000/mysite:1.0.0

这样搭建的 Registry 没有账号验证,也没有 HTTPS,只适合在本地或内部网络中测试。可以直接使用 localhost Registry;Docker 会拒绝其他地址的 HTTP Registry,需要另外配置 insecure-registries。正式使用时请添加 TLS 和验证,或使用云平台提供的 Registry(例如 AWS ECR、Google Artifact Registry、Azure Container Registry)。

推送到 GitHub Container Registry(ghcr.io)

适合代码存放在 GitHub 上的项目。先在 GitHub 创建一个具有 write:packages 权限的 Personal Access Token,然后执行:

echo $GITHUB_TOKEN | docker login ghcr.io -u 你的GitHub账号 --password-stdin
docker tag mysite ghcr.io/你的账号/mysite:1.0.0
docker push ghcr.io/你的账号/mysite:1.0.0

--password-stdin 从标准输入读取密码,避免密码出现在命令历史记录中。

标签命名建议

做法示例说明
语义化版本1.4.2、1.4、1同时推送多个层级,让用户自行选择更新幅度
Git commitsha-3f2a1c9每个镜像都能对应到确切的代码
环境staging、production可变标签,指向当前部署的版本
latestlatest方便试用,但生产环境不要依赖它

正式部署时请使用固定的版本号,这样才能知道服务器上运行的是哪个版本,也能快速回退到上一版(参见部署到云主机)。

登出与凭据

docker logout
docker logout ghcr.io

登录信息默认保存在 ~/.docker/config.json。Docker Desktop 会改用操作系统的凭据管理器(Windows 凭据管理器、macOS 钥匙串)保存,更安全。

重点回顾

  • 镜像名称的前缀决定推送到哪个 Registry。
  • 使用访问令牌(Access Token)登录,不要使用账号密码。
  • 使用 docker tag 添加目标名称,再执行 docker push。
  • 生产环境使用固定版本号标签,不要依赖 latest。

动手练习

练习 1:按照本章的方法启动本地 Registry(registry:3,对应 5000 端口),将 alpine:3.23 推送上去,删除本地副本后再下载回来。

答案
docker run -d -p 5000:5000 --name registry registry:3
docker tag alpine:3.23 localhost:5000/alpine:3.23
docker push localhost:5000/alpine:3.23
docker rmi localhost:5000/alpine:3.23
docker pull localhost:5000/alpine:3.23

常见问题

推送时出现 denied: requested access to the resource is denied?

通常是因为尚未登录,或者镜像名称中的账号部分不是你的账号。名称应写成 你的账号/储存库:tag,并先执行 docker login。

Docker Hub 的私有储存库要付费吗?

免费账号可以创建少量私有储存库,数量和限制以 Docker Hub 官方方案说明为准。也可以改用 GitHub Container Registry。

可以自动推送吗?

可以使用 GitHub Actions,在每次推送代码或创建版本标签时自动构建并推送,参见 [GitHub Actions 自动构建](/zh/docker/ci-cd/)。

更新于 2026年10月14日