介绍
Docker 是一个强大的容器化平台,它简化了应用程序的部署和管理。然而,用户在尝试拉取 Docker 镜像时,有时可能会遇到“pull access denied”(拉取访问被拒绝)的错误。本教程将全面指导你理解、排除故障并解决这个常见的 Docker 问题。
在整个实验(Lab)过程中,你将学习 Docker 镜像注册表(Docker image registries)的工作原理,了解为什么会出现访问被拒绝的错误,并培养解决身份验证问题的实用技能。通过本教程的学习,你将能够自信地处理容器化工作流程中的 Docker 镜像访问问题。
理解 Docker 注册表和基本镜像拉取
在探讨“pull access denied”(拉取访问被拒绝)错误之前,让我们先了解 Docker 注册表以及镜像拉取的工作原理。
什么是 Docker 注册表?
Docker 注册表是 Docker 镜像的存储系统。它允许你推送(上传)和拉取(下载)容器镜像。Docker Hub 是默认的公共注册表,但还有许多其他的注册表,包括组织用来存储专有镜像的私有注册表。
首先,让我们检查 Docker 是否已正确安装在你的系统上。打开一个终端并运行:
docker --version
你应该看到类似如下的输出:
Docker version 20.10.21, build baeda1f
从 Docker Hub 拉取公共镜像
现在,让我们尝试从 Docker Hub 拉取一个简单的公共镜像。拉取镜像的基本语法是:
docker pull [registry/][username/]repository[:tag]
让我们拉取官方的 Alpine Linux 镜像,它体积小且常用:
docker pull alpine:latest
你应该看到类似如下的输出:
latest: Pulling from library/alpine
c158987b0551: Pull complete
Digest: sha256:bc41182d7ef5ffc53a40b044e725193bc10142a1243f395ee852a8d9730fc2ad
Status: Downloaded newer image for alpine:latest
docker.io/library/alpine:latest
这确认了你可以成功拉取公共镜像。让我们通过列出你所有的 Docker 镜像来验证镜像是否已下载:
docker images
你应该在列表中看到 alpine 镜像:
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest 9c6f07244728 2 weeks ago 5.54MB
Docker 镜像命名约定
理解 Docker 镜像命名约定对于解决访问问题至关重要:
- Registry:注册表所在的 hostname(默认是 Docker Hub)
- Username/Organization:拥有 repository 的账户
- Repository:镜像的名称
- Tag:镜像的特定版本(默认是 "latest")
例如,在 docker.io/nginx:1.21 中,registry 是 docker.io,repository 是 nginx,tag 是 1.21。
当你没有指定 registry 时,Docker 假定你正在使用 Docker Hub。当你没有指定 username 或 organization 时,Docker 会在 "library" 命名空间中查找,该命名空间包含官方镜像。
遇到“Pull Access Denied”(拉取访问被拒绝)错误
现在你已经了解了 Docker 镜像拉取的基础知识,让我们来探讨“pull access denied”(拉取访问被拒绝)错误。当你尝试拉取你无权访问的镜像时,通常会发生此错误。
创建一个场景来遇到此错误
让我们尝试拉取一个不存在或私有的镜像,以故意触发“pull access denied”(拉取访问被拒绝)错误。我们将尝试拉取一个虚构的私有镜像:
docker pull labex/private-repo:latest
你应该看到类似如下的错误消息:
Error response from daemon: pull access denied for labex/private-repo, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
此错误发生的原因可能是:
- 该 repository 不存在
- 该 repository 存在但为私有,并且你未通过身份验证
- 你已通过身份验证,但没有权限访问此 repository
理解 Docker 注册表的身份验证
Docker 使用一个简单的身份验证系统来处理私有注册表。在拉取私有镜像之前,你需要使用 docker login 命令进行身份验证:
docker login [registry-url]
如果未提供 registry URL,Docker 假定你正在登录 Docker Hub。
让我们尝试登录 Docker Hub(如果你有自己的 Docker Hub 帐户,可以使用它,或者只是查看提示,然后按 Ctrl+C 取消):
docker login
你将看到一个提示,要求你输入用户名和密码:
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username:
由于我们在此练习中实际上不需要登录,你可以按 Ctrl+C 取消登录过程。
“Pull Access Denied”(拉取访问被拒绝)错误的常见原因
“pull access denied”(拉取访问被拒绝)错误可能由于多种原因而发生:
- Repository 名称不正确:你可能拼错了 repository 的名称
- Repository 不存在:你尝试访问的 repository 不存在
- 需要身份验证:repository 是私有的,需要登录
- 权限不足:你已通过身份验证,但没有访问权限
- 速率限制:Docker Hub 限制未通过身份验证用户的拉取次数
检查 Docker 守护程序日志
在排除访问问题时,检查 Docker 守护程序日志通常很有帮助:
sudo journalctl -u docker | tail -n 20
这将显示 Docker 系统日志的最后 20 行,其中可能包含有关访问被拒绝错误的更多信息。
解决“Pull Access Denied”(拉取访问被拒绝)错误
现在我们了解了导致“pull access denied”(拉取访问被拒绝)错误的原因,让我们学习如何解决它们。我们将根据最常见的原因,逐步介绍几种解决方案。
解决方案 1:验证 Repository 名称和 Tag
访问错误最常见的原因之一是简单地使用了不正确的 repository 名称或 tag。始终仔细检查你的镜像名称是否有拼写错误。
让我们尝试使用特定 tag 拉取一个有效的镜像:
docker pull nginx:1.21.0
输出应该显示成功的拉取:
1.21.0: Pulling from library/nginx
a330b6cecb98: Pull complete
b847ebd0aed4: Pull complete
543e2db69aaf: Pull complete
... (more lines)
Digest: sha256:2f1cd90e00fe2a0aa8969938c6a4135443ac6c7e50d255a54b57ba1a21086ce3
Status: Downloaded newer image for nginx:1.21.0
docker.io/library/nginx:1.21.0
解决方案 2:使用 Registry 进行身份验证
如果你尝试访问私有 repository,你需要首先进行身份验证:
docker login [registry-url]
成功身份验证后,Docker 将凭据存储在 ~/.docker/config.json 的配置文件中。让我们检查此文件是否存在:
ls -la ~/.docker/
如果你之前已登录,你应该看到 config.json 文件被列出。
解决方案 3:检查 Registry 速率限制
Docker Hub 对拉取施加了速率限制:
- 匿名用户:每 6 小时每个 IP 地址 100 次拉取
- 已通过身份验证的用户:每 6 小时每个帐户 200 次拉取
如果你遇到了速率限制,请进行身份验证以增加你的限制:
docker login
解决方案 4:使用显式的 Registry URL
有时,指定完整的 registry URL 可以帮助解决访问问题:
docker pull docker.io/library/ubuntu:20.04
这种显式格式有助于 Docker 正确识别要连接的 registry。
通过拉取另一个公共镜像来测试你的访问权限
让我们通过拉取不同的镜像来验证你是否仍然可以拉取公共镜像:
docker pull hello-world
你应该看到确认成功拉取的输出:
Using default tag: latest
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:6e8b6f026e0b9c419ea0fd02d3905dd0952ad1feea67543f525c73a0a790fefb
Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest
现在运行 hello-world 容器以验证一切是否正常工作:
docker run hello-world
你应该看到来自 Docker 的欢迎消息:
Hello from Docker!
This message shows that your installation appears to be working correctly.
...
故障排除清单
当你遇到“pull access denied”(拉取访问被拒绝)错误时,请遵循此清单:
- 验证镜像名称和 tag 是否正确
- 检查 repository 是否存在(在 Docker Hub 上搜索)
- 如果 repository 是私有的,请进行身份验证
- 检查速率限制问题
- 检查 Docker 守护程序日志以获取详细的错误消息
- 验证与 registry 的网络连接
使用私有 Registry
在许多实际场景中,你需要使用私有 Docker registry。这些 registry 需要身份验证和仔细的凭据管理。让我们学习如何有效地使用它们。
私有 Registry 的类型
有几种可用的私有 registry 选项:
- Docker Hub 私有 Repositories:Docker Hub 上的私有 repository
- Docker Registry:Docker 的开源 registry 实现
- **Docker Trusted Registry (DTR)**:Docker Enterprise 的一部分
- 第三方 registry:例如 AWS ECR、Google Container Registry、GitHub Container Registry 等
设置用于测试的简单本地 Registry
为了学习,让我们设置一个本地 Docker registry。这将帮助你理解私有 registry 的工作原理:
docker run -d -p 5000:5000 --name registry registry:2
此命令在端口 5000 上启动一个私有 registry 容器。如果成功,你应该看到一个容器 ID 输出。
将镜像推送到你的本地 Registry
让我们修改一个现有的镜像并将其推送到我们的本地 registry:
- 首先,使用我们的本地 registry 地址标记一个现有的镜像:
docker tag nginx:1.21.0 localhost:5000/my-nginx:v1
- 将镜像推送到本地 registry:
docker push localhost:5000/my-nginx:v1
你应该看到显示推送进度的输出:
The push refers to repository [localhost:5000/my-nginx]
72a69066d2fe: Pushed
1e7cb45d18ab: Pushed
c8db6be2bb1a: Pushed
... (more layers)
v1: digest: sha256:... size: 1570
- 现在让我们删除本地镜像并尝试从我们的 registry 中拉取它:
docker image rm localhost:5000/my-nginx:v1
docker pull localhost:5000/my-nginx:v1
你应该看到镜像从你的本地 registry 中成功拉取。
使用 Registry 身份验证
对于生产环境中的私有 registry,你需要正确处理身份验证。登录私有 registry 时,Docker 会将凭据存储在你的配置文件中。
要使用私有 registry 进行身份验证:
docker login [registry-url]
身份验证后,你可以正常拉取镜像:
docker pull [registry-url]/[repository]:[tag]
出于安全原因,完成后你应该注销:
docker logout [registry-url]
安全地存储 Registry 凭据
对于自动化系统,安全地存储凭据非常重要。你可以使用:
- Docker 凭据助手
- 带有 docker login 的环境变量
- Docker secrets(在 swarm 模式下)
让我们检查当前的凭据存储:
cat ~/.docker/config.json | grep -v auth
你应该看到有关你的 Docker 设置的配置详细信息。
清理
让我们停止并删除我们的测试 registry:
docker stop registry
docker rm registry
这将删除我们为测试创建的本地 registry 容器。
防止访问问题的最佳实践
在你学会了如何解决“拉取访问被拒绝”错误后,让我们来探索一下未来如何避免这些问题。
使用完全限定的镜像名称
始终使用完全限定的镜像名称以避免歧义:
docker pull docker.io/library/ubuntu:20.04
这清楚地表明了你试图访问的注册表、仓库和标签。
设置凭证助手 (Credential Helpers)
Docker 凭证助手可以安全地存储你的注册表凭证。为你的操作系统安装合适的助手:
对于 Ubuntu,你可以使用基于 pass 的凭证助手:
sudo apt-get update
sudo apt-get install -y pass
然后生成一个 GPG 密钥(出于演示目的,你可以按 Enter 键接受默认设置):
gpg --generate-key
使用你的 GPG 密钥 ID 初始化 pass(请替换为前一个输出中的实际密钥 ID):
pass init "Your GPG Key ID"
安装 Docker 凭证助手:
sudo apt-get install -y docker-credential-pass
配置默认注册表设置
你可以在 Docker daemon 配置文件中配置默认注册表设置。让我们创建一个简单的配置:
sudo mkdir -p /etc/docker
echo '{
"registry-mirrors": ["https://registry-mirror.example.com"]
}' | sudo tee /etc/docker/daemon.json
注意:这只是一个示例。如果需要,你应将镜像 URL 替换为真实的 URL。
使用 Docker Compose 进行一致性部署
Docker Compose 有助于确保跨环境的一致性镜像引用。让我们创建一个简单的 docker-compose.yml 文件:
mkdir -p ~/project/compose-demo
cd ~/project/compose-demo
现在创建一个 docker-compose.yml 文件:
cat > docker-compose.yml << 'EOF'
version: '3'
services:
web:
image: nginx:1.21.0
ports:
- "8080:80"
redis:
image: redis:6.2
EOF
首先,让我们确保你的系统上安装了 Docker Compose:
docker compose version
如果未安装 Docker Compose,你可能需要安装它。在 Ubuntu 上,你可以使用以下命令安装:
sudo apt-get update
sudo apt-get install -y docker-compose-plugin
使用此文件,你可以通过一个命令启动两个服务:
docker compose up -d
你应该会看到显示容器正在创建的输出:
Creating network "compose-demo_default" with the default driver
Creating compose-demo_web_1 ... done
Creating compose-demo_redis_1 ... done
验证服务是否正在运行:
docker compose ps
你应该会看到两个服务都处于“Up”状态。
清理你的 Docker 环境
让我们通过停止并移除容器来清理我们的环境:
docker compose down
cd ~/project
这会停止并移除我们使用 Docker Compose 创建的容器。
最佳实践总结
- 始终使用完全限定的镜像名称
- 在拉取私有镜像之前进行身份验证
- 设置安全的凭证存储
- 使用 Docker Compose 进行一致性部署
- 定期审计你的 Docker 配置
- 使用镜像摘要 (image digests) 进行不可变引用
- 为注册表访问实现适当的网络配置
通过遵循这些最佳实践,你将最大限度地减少“拉取访问被拒绝”错误,并创建一个更可靠的容器化环境。
总结
在这个实验中,你已经学会了如何理解、排除故障和解决 Docker 中的“pull access denied”(拉取访问被拒绝)错误。你现在拥有以下方面的实践经验:
- 理解 Docker registry 和镜像拉取基础知识
- 识别“pull access denied”(拉取访问被拒绝)错误的常见原因
- 通过适当的身份验证和故障排除来解决访问问题
- 使用私有 registry,包括设置本地测试 registry
- 实施最佳实践以防止将来出现访问问题
这些技能对于在你的 Docker 环境中顺利进行容器部署和管理至关重要。当你继续使用 Docker 时,你会发现,适当的访问管理是容器操作的一个基本方面,尤其是在具有私有 registry 的企业环境中。
记住解决访问问题的关键步骤:
- 验证镜像名称和 tag
- 检查身份验证要求
- 查看 Docker 守护程序日志
- 确保适当的网络连接
- 应用凭据管理方面的最佳实践
你现在已经掌握了在你的容器化工作流程中自信地处理 Docker 镜像访问挑战的知识。



