错误的容器镜像/非法的仓库权限解决方案:

kubectl get pods 状态为ErrImagePull && ImagePullBackOff (一直在restarting)

当我们创建一个名字为myapp的deployment的时候,它指向的是一个不存在的docker镜像:

最常见的有两个问题:

(a)指定了错误的容器镜像

(b)使用私有镜像却不提供仓库认证信息

$ kubectl run myapp --image=prod-nexus/myapp:v1.0

然后我们查看 Pods,可以看到有一个状态为 ErrImagePull 或者 ImagePullBackOff 的 Pod:

$ kubectl get pods
NAME                      READY           STATUS             RESTARTS      AGE
myapp-102132443982-dsafx   0/1       ImagePullBackOff           0          3m

想查看更多信息,可以 describe 这个失败的 Pod:

$ kubectl describe pod myapp-102132443982-dsafx

显示错误的那句话:Failed to pull image "prod-nexus/myapp:v1.0": Error: image prod-nexus/myapp not found 告诉我们 Kubernetes无法找到镜像 prod-nexus/myapp:v1.0。

因此问题变成:为什么 Kubernetes 拉不下来镜像?

除了网络连接问题外,还有三个主要元凶:

  • 镜像 tag 不正确
  • 镜像不存在(或者是在另一个仓库)
  • Kubernetes 没有权限去拉那个镜像

如果你没有注意到你的镜像 tag 的拼写错误,那么最好就用你本地机器测试一下。

通常我会在本地开发机上,用 docker pull 命令,带上 完全相同的镜像 tag,来跑一下。比如上面的情况,我会运行命令 docker pull prod-nexus/myapp:v1.0

  • 如果这成功了,那么很可能 Kubernetes 没有权限去拉取这个镜像。参考镜像拉取 Secrets 来解决这个问题。
  • 如果失败了,那么我会继续用不显式带 tag 的镜像测试 - docker pull prod-nexus/myapp - 这会尝试拉取 tag 为 latest 的镜像。如果这样成功,表明原来指定的 tag 不存在。这可能是人为原因,拼写错误,或者 CI/CD 的配置错误。


如果 docker pull prod-nexus/myapp(不指定 tag)也失败了,那么我们碰到了一个更大的问题:我们所有的镜像仓库中都没有这个镜像。默认情况下,Kubernetes 使用 Dockerhub 镜像仓库,如果你在使用 Quay.ioAWS ECR,或者 Google Container Registry,你要在镜像地址中指定这个仓库的 URL,比如使用 Quay,镜像地址就变成 prod-nexus/myapp:v1.0

如果你在使用 Dockerhub,那你应该再次确认你发布镜像到 Dockerhub 的系统,确保名字和 tag 匹配你的 deployment 正在使用的镜像。

注意:观察 Pod 状态的时候,镜像缺失和仓库权限不正确是没法区分的。其它情况下,Kubernetes 将报告一个 ErrImagePull 状态。

####################################################################################################

在此之上,你都没解决的话,还有个致命的坑:

日志中类似的错误如下:kubectl describe pod 你的deployment 中的pod名

Jun 12 17:02:06 k8s kubelet[1345]: E0612 17:02:06.942588 1345 docker_manager.go:2295] container start failed: ImagePullBackOff: Back-off pulling image “reg.docker.lc/share/nginx:latest”

Jun 12 17:02:06 k8s kubelet[1345]: E0612 17:02:06.942643 1345 pod_workers.go:184] Error syncing pod cb61d30a-4f4d-11e7-8ea8-000c29e9277a, skipping: failed to “StartContainer” for “nginx” with ImagePullBackOff: “Back-off pulling image \”reg.docker.lc/share/nginx:latest\””

主要问题还是在于yaml配置文件的写法问题。

具体的参数:imagePullPolicy: Always (这是默认的参数)即镜像的拉取策略:总是拉取。由于我的yaml中没有添加这个选项,所以就默认设置为always,也就是说他会默认自动去远程拉取镜像,并不使用本地的镜像。

详见参数可选项见官方文档:https://kubernetes.io/docs/concepts/containers/images/

默认情况是会根据配置文件中的镜像地址去拉取镜像,如果设置为IfNotPresent 和Never就会使用本地镜像

IfNotPresent :如果本地存在镜像就优先使用本地镜像。
Never:直接不再去拉取镜像了,使用本地的;如果本地不存在就报异常了。

参数的具体用法:

spec: 
  containers: 
    - name: nginx 
      image: image: reg.docker.lc/share/nginx:latest 
      imagePullPolicy: IfNotPresent   #或者使用Never

因为此参数默认为:imagePullPolicy: Always ,如果你yaml配置文件中没有定义那就是使用默认的。

更改完之后,再次利用kubectl启动一个deployment,就可以创建成功了。

如有其它高见,欢迎留言补充!

补充1:https://blog.csdn.net/u013641234/article/details/103481464

1.检查问题所在

Kubectl describe po pod-name

Failed create pod sandbox: rpc error: code = Unknown desc = failed pulling image ...

Error response from daemon: pull access denied for ...

repository does not exist or may require 'docker login'

这是因为没有正确配置导致pull权限所致

~/.docker/config.json 无效

这是一个坑,因为和docker swarm完全不同的是在yaml和helm 中pull镜像的时候完全不会去参考config.json这个文件

解决方案:

使用 imagePullSecrets(注意:这个也是看namespace的)

kubectl create secret docker-registry regcred \
    --docker-server=harbor.shub.us/\
    --docker-username=<your name> \
    --docker-password=<your pword> \
    --namespace=<your namespace>

有的时候创建了还是不行

即使创建了 secrets 、配置了 imagePullSecrets ,有时仍然无法 pull 镜像。 比如 Calico 的相关镜像,如果被同步到了本地一个私有Registry中,一般配置时无效的。

这是因为, Calico 属于系统Network组件, Namespace 是 kube-system 。 而一般创建的 secrets ,属于 default 。 通过以下命令可以查看特定 secrets 的详细信息。

# kubectl get secret regcred -o yaml
apiVersion: v1
data:
  .dockerconfigjson: eyJhdXRocyI6eyJodHRwOi8vaGFyYm9yLnR1cmluZy1jaS5oaXNpbGljb24uY29tIjp7IlVzZXJuYW1lIjoiY2hyaXN0b3BoZXIiLCJQYXNzd29yZCI6IlFpZGRZYWZkQmF2YTYjIiwiRW1haWwiOiJ5MDA0NDU0ODBAbm90ZXNtYWlsLmh1YXdlaS5jb20ifX19
kind: Secret
metadata:
  creationTimestamp: "2019-01-10T08:51:03Z"
  name: regcred
<mark>  namespace: default</mark>
  resourceVersion: "100110"
  selfLink: /api/v1/namespaces/default/secrets/regcred
  uid: dc96580b-14b4-11e9-9f81-e435c87f8d90
type: kubernetes.io/dockerconfigjson

 

这边还会出现一个问题,就是每个文件中都要添加这个secret 才能正常的下载镜像,这个其实比较繁琐,利用patch 就可以解决这个问题。

kubectl patch serviceaccount fat -p '{"imagePullSecrets": [{"name": "regcred"}]}'

这个就相当于在fat这个命名空间下所有的pull 操作都会具备这个regcred这个账户的吗。

完全做到和docker login一样。

某些特例的场景例如calico的环境下就必须老老实实的去写imagePullSecrets.

对k8s系统镜像无效

系统镜像中, kube-proxy 、 pause 是在所有Slave节点都需要使用的。 如果这些系统镜像被设为私有,则无法下载。 以上方法无效,原因不明。

所以,k8s系统镜像,即使同步到了本地Registry,也不要设为私有。

如有其它高见,欢迎继续留言补充(现补充数1)!

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐