K8S 镜像拉取 之 toomanyrequests 的解决方法

摘要

  • 本文介绍 K8S 镜像拉取 的 toomanyrequests 的解决方法 ,本文以 CentOS 8 为例。

  • K8S官网

  • k8s Github

toomanyrequests 介绍

  • 当我们通过k8s创建pod时需要从 dockerhub 上拉取镜像,但是 dockerhub 的api请求是有限制的,未认证用户限制为100/6h,如果超过这个限制就会返回429 Too Many Requests响应Docker Hub的使用和限制

  • 我们可以进行用户认证,这样可以将限制提高到2000/6h。如果还需要进一步提高请求限制,可以申请dockerhub的pro plan。

dockerhub 认证

  • 创建 Docker Registry Secret

1
2
3
4
5
6
7
8
9
10
11
# 指定 namespace, 默认命名空间是 default
kubectl create secret docker-registry \
dockerhub-secret \ # 创建 secret 名称
--namespace=你的命名空间 \ # 创建 secret 所在的命名空间
--docker-server=https://index.docker.io/v1/ \ # 指定 docker registry 地址,默认就是这个,其它仓库或私服请更改为对应的url
--docker-username=你的用户名 \ # 仓库 的用户名
--docker-password=你的密码或访问令牌 \ # 仓库 的密码或访问令牌
--docker-email=你的邮箱 # 仓库 的邮箱

# 查看 secret
kubectl get secret dockerhub-secret -o yaml -n <namespace>
  • 可以在创建 pod 或 deployment 时指定凭证

pod

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: myapp
image: username/repository:tag
imagePullSecrets: # 添加凭证
- name: dockerhub-secret

deployment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: username/repository:tag
imagePullSecrets: # 添加凭证
- name: dockerhub-secret
  • 将 Secret 添加到 ServiceAccount,这样 Pod 创建的时候,会自动将 Secret 挂载到 Pod 中

每个 namespace 下 都有一个 名称为 default 的 ServiceAccount

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 查看 pod 的 ServiceAccount
$ k describe pod pi-n65gn | grep "Service Account"
Service Account: default

# 指定 namespace 下的 Pod 使用这个凭证
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "dockerhub-secret"}]}' -n <namespace>

# 添加多个凭证,这会覆盖之前的设置,多个 secret 按顺序生效,k8s 会逐个尝试去拉取镜像
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "dockerhub-secret"}, {"name": "harbor-secret"}, {"name": "aliyun-secret"}]}' -n <namespace>

# 追加一个凭证,不会覆盖原有的设置
kubectl patch serviceaccount default --type='json' -p='[{"op": "add", "path": "/imagePullSecrets/-", "value": {"name": "new-secret"}}]' -n <namespace>

# 查看当前 imagePullSecrets 的索引,以下命令会输出凭证的名称,索引从 0 开始
kubectl get sa default -o jsonpath='{.imagePullSecrets[*].name}' -n <namespace>

# 删除一个凭证: 删除 index 为 1 的凭证
kubectl patch serviceaccount default --type=json -p='[{"op": "remove", "path": "/imagePullSecrets/1"}]' -n <namespace>

# 清空所有凭证
kubectl patch sa default -p '{"imagePullSecrets": []}' -n <namespace>


# 为所有 namespace 下的 Pod 添加凭证
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
kubectl patch serviceaccount default -n $ns \
--type=merge \
-p '{"imagePullSecrets": [{"name": "dockerhub-secret"}]}'
done

# 查看 ServiceAccount
$ kubectl get serviceaccount default -o yaml -n <namespace>
apiVersion: v1
imagePullSecrets:
- name: dockerhub-secret
kind: ServiceAccount
metadata:
creationTimestamp: "2025-06-29T14:41:35Z"
name: default
namespace: default
resourceVersion: "361001"
uid: cb3a0f99-5804-4f21-816a-70533cc3d29d

提高下载频率的其他建议

  • 1.使用镜像缓存:

    • 设置集群内镜像缓存(如 Harbor, Nexus Registry)
    1
    2
    3
    # 修改集群的镜像仓库配置(vim)
    kubectl edit configmap -n kube-system
    # 找到 imageRepository: 替换为你的仓库地址
    • 使用 Docker Hub 镜像加速器(如果在中国大陆)
      • 如果 k8s 使用的是 docker,则在/etc/docker/daemon.json添加镜像加速器配置
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      sudo mkdir -p /etc/docker
      sudo tee /etc/docker/daemon.json <<-'EOF'
      {
      "registry-mirrors": [
      "https://docker.1ms.run",
      "https://docker.xuanyuan.me",
      "https://docker.m.daocloud.io"
      ]
      }
      EOF
      sudo systemctl daemon-reload
      sudo systemctl restart docker
      • 如果 k8s 使用的是 containerd,则在/etc/containerd/config.toml添加镜像加速器配置
      1
      2
      3
      4
      5
      6
      7
      8
      9
      sudo vi /etc/containerd/config.toml

      # 找到 registry.mirrors 字段,添加加速器,比如:
      [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
      [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
      endpoint = ["https://docker.1ms.run", "https://docker.xuanyuan.me", "https://docker.m.daocloud.io"]

      # 修改后重启 containerd
      sudo systemctl restart containerd
  • 2.升级 Docker Hub 订阅:

    • 免费账户:200 pulls/6小时(匿名用户100 pulls/6小时)
    • Pro/Team 账户:无限制拉取
  • 3.使用多个账户:

    • 为不同节点配置不同的 Docker Hub 凭证
  • 4.减少不必要的拉取:

    • 使用 imagePullPolicy: IfNotPresent
    • 尽量使用固定版本标签而非 latest