分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > IT知识

kubernetes部署失败的原因

发布时间:2023-09-06 01:46责任编辑:傅花花关键词:kubernetes

1.错误的容器镜像/非法的仓库权限

其中两个最普遍的问题是:(a)指定了错误的容器镜像,(b)使用私有镜像却不提供仓库认证信息。这在首次使用 Kubernetes 或者绑定 CI/CD 环境时尤其棘手。

让我们看个例子。首先我们创建一个名为fail的 deployment,它指向一个不存在的 Docker 镜像:

$ kubectl run fail --image=rosskukulinski/dne:v1.0.0

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

$ kubectl get pods
NAME READY STATUS RESTARTS AGE
fail-1036623984-hxoas 0/1ImagePullBackOff 0 2m

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

$ kubectl describe pod fail-1036623984-hxoas

查看describe命令的输出中Events这部分,我们可以看到如下内容:

Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
5m 5m 1 {default-scheduler } Normal Scheduled Successfully assigned fail-1036623984-hxoas to gke-nrhk-1-default-pool-a101b974-wfp7
5m 2m 5 {kubelet gke-nrhk-1-default-pool-a101b974-wfp7} spec.containers{fail} Normal Pulling pulling image"rosskukulinski/dne:v1.0.0"
5m 2m 5 {kubelet gke-nrhk-1-default-pool-a101b974-wfp7} spec.containers{fail} Warning Failed Failed to pull image"rosskukulinski/dne:v1.0.0": Error: image rosskukulinski/dnenot found
5m 2m 5 {kubelet gke-nrhk-1-default-pool-a101b974-wfp7} Warning FailedSync Error syncing pod, skipping: failed to"StartContainer"for"fail"with ErrImagePull:"Error: image rosskukulinski/dne not found"
5m 11s 19 {kubelet gke-nrhk-1-default-pool-a101b974-wfp7} spec.containers{fail} Normal BackOff Back-off pulling image"rosskukulinski/dne:v1.0.0"
5m 11s 19 {kubelet gke-nrhk-1-default-pool-a101b974-wfp7} Warning FailedSync Error syncing pod, skipping: failed to"StartContainer"for"fail"with ImagePullBackOff:"Back-off pulling image \"rosskukulinski/dne:v1.0.0\""

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

为什么 Kubernetes 拉不下来镜像?除了网络连接问题外,还有三个主要元凶:

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

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

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

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


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


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

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

2. 应用启动之后又挂掉

无论你是在 Kubernetes 上启动新应用,还是迁移应用到已存在的平台,应用在启动之后就挂掉都是一个比较常见的现象。

我们创建一个 deployment,它的应用会在1秒后挂掉:

$ kubectl run crasher --image=rosskukulinski/crashing-app

我们看一下 Pods 的状态:

$ kubectl get pods
NAME READY STATUS RESTARTS AGE
crasher-2443551393-vuehs 0/1CrashLoopBackOff 2 54s

CrashLoopBackOff告诉我们,Kubernetes 正在尽力启动这个 Pod,但是一个或多个容器已经挂了,或者正被删除。

让我们describe这个 Pod 去获取更多信息

$ kubectl describe pod crasher-2443551393-vuehs
Name: crasher-2443551393-vuehs
Namespace: fail
Node: gke-nrhk-1-default-pool-a101b974-wfp7/10.142.0.2
Start Time: Fri, 10 Feb 2017 14:20:29 -0500
Labels: pod-template-hash=2443551393
run=crasher
Status: Running
IP: 10.0.0.74
Controllers: ReplicaSet/crasher-2443551393
Containers:
crasher:
Container ID: docker://51c940ab32016e6d6b5ed28075357661fef3282cb3569117b0f815a199d01c60
Image: rosskukulinski/crashing-app
Image ID: docker://sha256:cf7452191b34d7797a07403d47a1ccf5254741d4bb356577b8a5de40864653a5
Port:
State: Terminated
Reason: Error
Exit Code: 1
Started: Fri, 10 Feb 2017 14:22:24 -0500
Finished: Fri, 10 Feb 2017 14:22:26 -0500
Last State: Terminated
Reason: Error
Exit Code: 1
Started: Fri, 10 Feb 2017 14:21:39 -0500
Finished: Fri, 10 Feb 2017 14:21:40 -0500
Ready: False
Restart Count: 4
...

好可怕,Kubernetes 告诉我们这个 Pod 正被Terminated,因为容器里的应用挂了。我们还可以看到应用的Exit Code是1。后面我们可能还会看到一个OOMKilled错误。

我们的应用正在挂掉?为什么?

首先我们查看应用日志。假定你发送应用日志到stdout(事实上你也应该这么做),你可以使用kubectl logs看到应用日志:

$ kubectl logs crasher-2443551393-vuehs

不幸的是,这个 Pod 没有任何日志。这可能是因为我们正在查看一个新起的应用实例,因此我们应该查看前一个容器:

$ kubectl logs crasher-2443551393-vuehs --previous

什么!我们的应用仍然不给我们任何东西。这个时候我们应该给应用加点启动日志了,以帮助我们定位这个问题。我们也可以本地运行一下这个容器,以确定是否缺失环境变量或者挂载卷。

3. 缺失 ConfigMap 或者 Secret

Kubernetes 最佳实践建议通过ConfigMaps或者Secrets传递应用的运行时配置。这些数据可以包含数据库认证信息,API endpoints,或者其它配置信息。

一个常见的错误是,创建的 deployment 中引用的 ConfigMaps 或者 Secrets 的属性不存在,有时候甚至引用的 ConfigMaps 或者 Secrets 本身就不存在。

缺失 ConfigMap

第一个例子,我们将尝试创建一个 Pod,它加载 ConfigMap 数据作为环境变量:

# configmap-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod
spec:
containers:
- name:test-container
image: gcr.io/google_containers/busybox
command: ["/bin/sh","-c","env"]
env:
- name: SPECIAL_LEVEL_KEY
valueFrom:
configMapKeyRef:
name: special-config
key: special.how

让我们创建一个 Pod:kubectl create -f configmap-pod.yaml。在等待几分钟之后,我们可以查看我们的 Pod:

$ kubectl get pods
NAME READY STATUS RESTARTS AGE
configmap-pod 0/1RunContainerError 0 3s

Pod 状态是RunContainerError。我们可以使用kubectl describe了解更多:

$ kubectl describe pod configmap-pod
[...]
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
20s 20s 1 {default-scheduler } Normal Scheduled Successfully assigned configmap-pod to gke-ctm-1-sysdig2-35e99c16-tgfm
19s 2s 3 {kubelet gke-ctm-1-sysdig2-35e99c16-tgfm} spec.containers{test-container} Normal Pulling pulling image"gcr.io/google_containers/busybox"
18s 2s 3 {kubelet gke-ctm-1-sysdig2-35e99c16-tgfm} spec.containers{test-container} Normal Pulled Successfully pulled image"gcr.io/google_containers/busybox"
18s 2s 3 {kubelet gke-ctm-1-sysdig2-35e99c16-tgfm} Warning FailedSync Error syncing pod, skipping: failed to"StartContainer"for"test-container"with RunContainerError:"GenerateRunContainerOptions: configmaps \"special-config\" not found"

Events章节的最后一条告诉我们什么地方错了。Pod 尝试访问名为special-config的 ConfigMap,但是在该 namespace 下找不到。一旦我们创建这个 ConfigMap,Pod 应该重启并能成功拉取运行时数据。
在 Pod 规格说明中访问 Secrets 作为环境变量会产生相似的错误,就像我们在这里看到的 ConfigMap错误一样。
但是假如你通过 Volume 来访问 Secrets 或者 ConfigMap会发生什么呢?

缺失 Secrets

下面是一个pod规格说明,它引用了名为myothersecret的 Secrets,并尝试把它挂为卷:

# missing-secret.yaml
apiVersion: v1
kind: Pod
metadata:
name: secret-pod
spec:
containers:
- name:test-container
image: gcr.io/google_containers/busybox
command: ["/bin/sh","-c","env"]
volumeMounts:
- mountPath:/etc/secret/
name: myothersecret
restartPolicy: Never
volumes:
- name: myothersecret
secret:
secretName: myothersecret

让我们用kubectl create -f missing-secret.yaml来创建一个 Pod。

几分钟后,我们 get Pods,可以看到 Pod 仍处于ContainerCreating状态:

$ kubectl get pods
NAME READY STATUS RESTARTS AGE
secret-pod 0/1ContainerCreating 0 4h

这就奇怪了。我们describe一下,看看到底发生了什么:

$ kubectl describe pod secret-pod
Name: secret-pod
Namespace: fail
Node: gke-ctm-1-sysdig2-35e99c16-tgfm/10.128.0.2
Start Time: Sat, 11 Feb 2017 14:07:13 -0500
Labels:
Status: Pending
IP:
Controllers:
[...]
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
18s 18s 1 {default-scheduler }&nb
我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved