AICon上海|与字节、阿里、腾讯等企业共同探索Agent 时代的落地应用 了解详情
写点什么

超长可视化指南!你必须了解的 Kubernetes 部署的调试思路

  • 2020-03-02
  • 本文字数:6880 字

    阅读完需:约 23 分钟

超长可视化指南!你必须了解的Kubernetes部署的调试思路

本文将帮助你厘清在 Kubernetes 中调试 deployment 的思路。



当你希望在 Kubernetes 中部署一个应用程序,你通常需要定义三个组件:


  • Deployment——这是创建名为 Pods 的应用程序副本的方法

  • Serivce——内部负载均衡器,将流量路由到 Pods

  • Ingress——可以描述流量如何从集群外部流向 Service


接下来,我们通过图片快速回顾一下。



在 Kubernetes 中,你的应用程序通过两层负载均衡器暴露:内部和外部。



内部负载均衡器称为 Service,而外部负载均衡器则称为 Ingress。



Pod 未直接部署,因此,Deployment 创建 Pod 并监视它们。


假设你想部署一个简单的 Hello World 应用程序,那么对于此类应用程序,其 YAML 文件与以下类似:


apiVersion: apps/v1kind: Deploymentmetadata:  name: my-deployment  labels:    track: canaryspec:  selector:    matchLabels:      any-name: my-app  template:    metadata:      labels:        any-name: my-app    spec:      containers:      - name: cont1        image: learnk8s/app:1.0.0        ports:        - containerPort: 8080---apiVersion: v1kind: Servicemetadata:  name: my-servicespec:  ports:  - port: 80    targetPort: 8080  selector:    name: app---apiVersion: networking.k8s.io/v1beta1kind: Ingressmetadata:  name: my-ingressspec:  rules:  - http:    paths:    - backend:        serviceName: app        servicePort: 80      path: /
复制代码


这个定义很长,容易忽略组件之间的相互关系。


例如:


  • 你什么时候应该使用 80 端口,什么时候使用端口 8080?

  • 你是否应该为每个服务创建一个新端口,以免它们冲突?

  • 标签(label)名称重要吗?是否应该每一处都一样?


在进行 debug 之前,我们先来回顾一下这三个组件之间的关系如何。


首先,我们从 Deployment 和 Service 开始。

连接 Deployment 和 Service

实际上,Deployment 和 Service 根本没有连接。相反,该 Service 直接指向 Pod,并完全跳过 Deployment。所以,你应该关注的是 Pod 和 Service 是如何与彼此关联的。你应该记住三件事:


  1. Service selector 至少与 Pod 的一个标签匹配

  2. Serivce targetPort应该与 Pod 内的容器的containerPort相匹配

  3. Service port可以是任何数字。多个 Service 可以使用同一个端口,因为它们已经被分配了不同的 IP 地址


以下图片总结了如何连接端口:



考虑由 Service 暴露的 pod



当你创建一个 pod,你应该在你的 Pod 中为每个容器定义端口containerPort



当你创建一个 Service 时,你能够定义一个port和一个targetPort。但你应该将哪一个连接到容器呢?



targetPortcontainerPort应该能够匹配



如果你的容器暴露端口 3000,那么targetPort应该与该数字相匹配。


如果你查看了 YAML,标签与portstargerPort应该匹配:


apiVersion: apps/v1kind: Deploymentmetadata:  name: my-deployment  labels:    track: canaryspec:  selector:    matchLabels:      any-name: my-app  template:    metadata:      labels:        any-name: my-app    spec:      containers:      - name: cont1        image: learnk8s/app:1.0.0        ports:        - containerPort: 8080---apiVersion: v1kind: Servicemetadata:  name: my-servicespec:  ports:  - port: 80    targetPort: 8080  selector:    any-name: my-app
复制代码


那么在 Deployment 顶部的track: canary标签呢?也应该匹配吗?


那个标签属于 deployment,并且 Service selector 不使用它来路由流量。换言之,你可以安全地将其移除或者给它分配不同的值。


那么matchLabels selector 呢?它需要与 Pod 标签匹配并且 Deployment 使用它来跟踪 Pod。


假设你做了一个正确的更改,你应该如何测试它呢?你可以使用以下命令检查 Pod 是否拥有正确的标签:


kubectl get pods --show-labels
复制代码


或者如果你有属于多个应用程序的 Pod:


kubectl get pods --selector any-name=my-app --show-labels
复制代码


其中any-name=my-app是标签any-name: my-app。依旧存在问题?你也可以连接到 Pod。你可以在 kubectl 中使用命令port-forward连接到 Serivce 并测试连接。


kubectl port-forward service/<service name> 3000:80
复制代码


其中:


  • service/<service name>是 serivce 的名称——在当前 YAML 中,是“my-service”。

  • 3000 是你希望在你的电脑上打开的端口

  • 80 是 Service 在port字段中暴露的端口


如果你能够连接,那么设置就是正确的。如果你无法连接,你很有可能弄错了标签或者端口未匹配。

连接 Service 和 Ingress

暴露应用程序的下一步是配置 Ingress。Ingress 必须知道如何检索 Service,然后检索 Pod 并将流量路由到它们。Ingress 通过名称和暴露的端口来检索正确的 Service。


在 Ingress 和 Service 中应该匹配两件事:


  1. Ingress 的servicePort应该与 Service 的port匹配

  2. Ingress 的serviceName应该与 Service 的name相匹配


以下图片将总结如何连接端口:



你已经知道该服务暴露了一个端口



Ingress 有一个名为servicePort的字段。



Service port和 Ingress servicePort应该相匹配



如果你决定分配端口 80 给该 service,你应该同时更改servicePort为 80


实际操作中,你需要查看这些命令行:


apiVersion: v1kind: Servicemetadata:  name: my-servicespec:  ports:  - port: 80    targetPort: 8080  selector:    any-name: my-app---apiVersion: networking.k8s.io/v1beta1kind: Ingressmetadata:  name: my-ingressspec:  rules:  - http:    paths:    - backend:        serviceName: my-service        servicePort: 80      path: /
复制代码


你应该如何测试 Ingress 是否正常运行呢?你可以使用和之前相同的策略,即kubectl port-forward,但不是连接到 service,而是连接到 Ingress controller。


首先,使用以下命令为 Ingress controller 检索 Pod 名称:


kubectl get pods --all-namespacesNAMESPACE   NAME                              READY STATUSkube-system coredns-5644d7b6d9-jn7cq          1/1   Runningkube-system etcd-minikube                     1/1   Runningkube-system kube-apiserver-minikube           1/1   Runningkube-system kube-controller-manager-minikube  1/1   Runningkube-system kube-proxy-zvf2h                  1/1   Runningkube-system kube-scheduler-minikube           1/1   Runningkube-system nginx-ingress-controller-6fc5bcc  1/1   Running
复制代码


验证 Ingress Pod(可能在不同的命名空间)并且描述它以检索端口:


kubectl describe pod nginx-ingress-controller-6fc5bcc \ --namespace kube-system \ | grep PortsPorts:         80/TCP, 443/TCP, 18080/TCP
复制代码


最后,连接到 Pod:


kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system
复制代码


此时,每次你在你的电脑上访问端口 3000,请求就会被转发到在 Ingress controller Pod 上的端口 80。


如果你访问 http://localhost:3000,你应该能找到提供网页的应用程序。

简单回顾一下

现在,我们来快速回顾一下什么端口和标签需要匹配:


  1. Service selector 应该匹配 Pod 的标签

  2. Service targerPort应该匹配在 Pod 内容器的containerPort

  3. Service 端口可以是任意数字。多个 Service 可以使用同个端口,因为它们已经分配了不同的 IP 地址

  4. Ingress 的servicePort应该匹配在 Service 中的port

  5. Service 的名称应该匹配在 Ingress 中的serviceName的字段


了解如何构造 YAML 只是开始。那么,出了问题时会有什么表现?Pod 可能无法启动,或者直接崩溃。

3 步排查 K8S Deployment 故障

在我们深入研究有故障的 deployment 之前,必须有一个明确定义的模型,以了解 Kubernetes 的工作方式。


既然在每个 deployment 中都有那三个组件,你应该从底层开始按顺序调试它们。


  1. 你应该确保你的 Pod 正在运行

  2. 着重关注使 Service 将流量路由到 Pod

  3. 检查 Ingress 是否正确配置



你应该从底层开始排查 Deployment 故障。首先,检查 Pod 是否准备就绪并且正在运行



如果 Pod 已经准备就绪,你需要检查 Service 是否可以将流量分配到 Pod。



最后你应该检查 Service 和 Ingress 之间的连接。

1、 故障排查 Pod

在大多数情况下,问题出现在 Pod 本身。所以你应该确保 Pod 正在运行并准备就绪。应该如何检查呢?


kubectl get podsNAME                    READY STATUS            RESTARTS  AGEapp1                    0/1   ImagePullBackOff  0         47happ2                    0/1   Error             0         47happ3-76f9fcd46b-xbv4k   1/1   Running           1         47h
复制代码


以上部分,只有最后一个 Pod 是正在运行并且准备就绪的,而前两个 Pod 既没有 Running 也没有 Ready。那么,你应该如何定位是什么出了问题呢?


这里有 4 个十分有用的命令可以帮助你排查 Pod 的故障:


  • kubectl logs <pod name>能够帮助检索 Pod 的容器日志

  • kubectl describe pod <pod name>能够有效地检索与 Pod 相关的事件列表

  • kubectl get pod <pod name>对于提取存储在 Kubernetes 中的 Pod 的 YAML 定义十分有用

  • kubectl exec -ti <pod name> bash可以用于在 Pod 其中一个容器中运行一个交互式命令


你应该使用哪一个呢?实际上,没有一种命令是万能的,你可以根据实际情况结合使用。

常见的 Pod 错误

Pod 可能会出现启动和运行时的错误。


启动错误包括:


  • ImagePullBackoff

  • ImageInspectError

  • ErrImagePull

  • ErrImageNeverPull

  • RegistryUnavailable

  • InvalidImageName


运行时错误包括:


  • CrashLoopBackOff

  • RunContainerError

  • KillContainerError

  • VerifyNonRootError

  • RunInitContainerError

  • CreatePodSandboxError

  • ConfigPodSandboxError

  • KillPodSandboxError

  • SetupNetworkError

  • TeardownNetworkError


这些错误中,有些比其他错误更为常见。以下是最常见的错误以及如何修复它们:

ImagePullBackOff

当 Kubernetes 无法检索 Pod 其中之一的容器镜像时,将出现此错误。


有三种常见原因:


  • 镜像名称无效——例如,你错误拼写名称或镜像不存在

  • 你给这一镜像指定了一个不存在的 tag

  • 你所检索的镜像是私有仓库的,并且 Kubernetes 没有访问它的凭据


前两个原因可以通过更正镜像名称和 tag 解决。最后一个,你需要将凭据添加到“Secret”中的私有镜像仓库中,并在 Pod 中引用它。


官方文档可以让你更加清楚:


https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/

CrashLoopBackOff

如果容器无法启动,Kubernetes 状态将显示 CrashLoopBackOff 消息。


通常情况下,容器在以下场景中无法启动:



你应该尝试并检索该容器的日志以确定出现故障的原因。


如果由于你的容器重启过快而无法查看日志,你可以使用以下命令:


kubectl logs <pod-name> --previous
复制代码


它将从之前的容器中打印错误信息。

RunContainerError

容器不能启动时出现错误,甚至在容器内的应用程序启动之前就无法启动。


这个问题通常由于错误配置导致的,如:


  • 安装一个不存在的 volume,如 ConfigMap 或 Secret

  • 将只读 volume 安装为可读写


你应该使用kubectl describe pod <pod-name>来收集和分析错误。

Pod 处于 Pending 状态

当你创建一个 Pod 时,Pod 保持在 Pending 状态。这是为什么呢?假设你的调度组件运行了解,那么有以下几个原因:


  • 集群没有足够的资源来运行 Pod,如 CPU 和内存

  • 当前命名空间有一个 ResourceQuota 对象并且所创建的 Pod 会使该命名空间超过资源额度

  • Pod 与一个 Pending 状态的 PersistentVolumeClaim 绑定。


那么,最好的选择是使用命令kubectl describe检查事件:


kubectl describe pod <pod name>
复制代码


对于由于 ResourceQuotas 造成的错误,可以使用以下方法检查集群的日志:


kubectl get events --sort-by=.metadata.creationTimestamp
复制代码

Pod 不处于 Ready 状态

如果 Pod 正在运行但是不 Ready,这意味着 Readiness 探针出现故障。当 Readiness 探针出现故障时,Pod 无法附加到 Service 上,并且流量无法转发到实例上。


Readiness 探针故障是特定于应用程序的错误,因此使用kubectl describe来检查事件部分,以验证错误。

2、 排查 Service 故障

如果你的 Pod 正在运行并且准备就绪,但是你依旧无法接收来自应用程序的响应,你应该检查 Service 是否配置正确。


Service 旨在根据 pod 的标签将流量路由到 Pod。所以第一件事,你需要检查 Service target 多少个 Pod。可以通过检查 Service 中的 Endpoint 来完成此步骤:


kubectl describe service <service-name> | grep Endpoints
复制代码


一个 endpoint 是一对<ip address:port>,并且当 Service(至少)target 一个 pod 时。至少有一对。


如果“Endpoint”部分是空的,那么有两种解释:


  1. 任何正在运行的 Pod 没有正确的 label(提示:你需要检查以下你是否在正确的命名空间内)

  2. 在 Service 的selector标签中有错别字


如果你看到了 endpoint 列表,但依旧无法访问你的应用程序,那么你的 Service 中的targetPort可能是罪魁祸首。


你应该怎么测试 Service?无论 Service 类型是什么,都可以使用kubectl port-forward连接到它:


kubectl port-forward service/<service-name> 3000:80
复制代码


其中:


  • <service-name>是 Service 的名称

  • 3000是你想要在电脑上打开的端口

  • 80是由 Service 暴露的端口

3、 排查 Ingress 故障

如果你走到了这个部分,这意味着:


  • Pod 正在运行并且准备就绪

  • Service 可以分发流量给 Pod


但你依旧无法接收 app 的响应。那么这很有可能是 Ingress 配置出现错误。


由于使用的 Ingress controller 是集群中的第三方组件,那么根据 Ingress controller 的类型会由不同的调试技术。但是在深入研究 Ingress 特定的工具之前,你可以使用一些简单的方法检查。


Ingress 使用serviceNameservicePort连接 Service。你应该检查那些是否正确配置。你可以使用以下命令检查 Ingress 是否正确配置:


kubectl describe ingress <ingress-name>
复制代码


如果 Backend 列是空的,那么配置中肯定存在错误。


如果你能在 Backend 列中看到 endpoint,但依旧无法访问应用程序,那么可能是以下问题:


  • 你将 Ingress 暴露于公网的方式

  • 你将集群暴露于公网的方式


你可以通过直接连接到 Ingress Pod 将基础设施问题与 Ingress 隔离开来。


首先,为你的 Ingress Controller 检索 Pod(可能位于不同的命名空间中):


kubectl get pods --all-namespacesNAMESPACE   NAME                              READY STATUSkube-system coredns-5644d7b6d9-jn7cq          1/1   Runningkube-system etcd-minikube                     1/1   Runningkube-system kube-apiserver-minikube           1/1   Runningkube-system kube-controller-manager-minikube  1/1   Runningkube-system kube-proxy-zvf2h                  1/1   Runningkube-system kube-scheduler-minikube           1/1   Runningkube-system nginx-ingress-controller-6fc5bcc  1/1   Running
复制代码


描述它以检索端口:


kubectl describe pod nginx-ingress-controller-6fc5bcc --namespace kube-system \ | grep Ports
复制代码


最后,连接到 Pod:


kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system
复制代码


此时,每次你在电脑上访问端口 3000,请求将会转发到 Pod 上的端口 80。


那么,现在能够正常运行了吗?


如果正常工作,问题就出在基础设施。你应该检查流量如何路由到你的集群。


如果无法正常工作,问题就在 Ingress controller。你应该调试 Ingress。


如果仍然无法使 Ingress controller 正常工作,则应该开始对其进行调试。市场有许多不同版本的 Ingress controller。比较流行的包括 Nginx、HAProxy、Traefik 等。


你应该查阅 Ingress controller 的文档以查找故障排查指南。


既然 Ingress Nginx 是最流行的 Ingress controller,那么在下一个部分我们将介绍一些相关的技巧。

调试 Ingress Nginx

Ingress-nginx 有 kubectl 的官方插件,你可以访问以下网址查看:


https://kubernetes.github.io/ingress-nginx/kubectl-plugin/


你可以使用kubectl ingress-nginx来进行以下操作:


  • 检查日志、Backend、证书等

  • 连接到 Ingress

  • 检查当前的配置


你还可以尝试以下三个命令:


  • kubectl ingress-nginx lint这是用来检查nginx.conf

  • kubectl ingress-nginx backend来检查 Backend (与kubectl describe ingress <ingress-name>类似)

  • kubectl ingress-nginx logs来检查日志


请注意,你需要使用--namespace <name>来指定正确的命名空间。

总结

如果你毫无头绪,那么在 Kubernetes 中进行故障排除可能是一项艰巨的任务。


你应该永远记住以从下至上的顺序解决问题:现检查 Pod,然后向上移动堆栈至 Service 和 Ingress。


而本文中的 debug 技术在其他地方也是通用的,例如:


  • 出现故障的 Jobs 和 CronJobs

  • StatefulSets 和 DaemonSets


希望大家都没有 bug!


本文转载自公众号 RancherLabs(ID:RancherLabs)。


原文链接


https://mp.weixin.qq.com/s/-vQUbP5c1bubWGKwy9orVw


2020-03-02 09:452327

评论

发布
暂无评论
发现更多内容

电科申泰加入龙蜥社区并成为理事单位,共创基础软硬件生态新未来

OpenAnolis小助手

开源 理事单位 申威 软硬件

一站式运维管理工具平台 OCP 到底有多好用,看这篇文章就够了!

OceanBase 数据库

零基础学编程?从这本豆瓣评分9.2的入门级神作开始

图灵社区

Python 零基础

国内首届DataOps+MLOps meetup回顾

星策开源社区

人工智能 机器学习 DevOps Meetup MLOps

数字化时代,如何做好用户体验与应用性能管理

云智慧AIOps社区

监控宝 监控工具 自动化运维 数字化经济

【直播回顾】OpenHarmony知识赋能第四期第二课——GPIO驱动开发

OpenHarmony开发者

OpenHarmony GPIO 驱动开发

私有云与公有云,哪种云模型最适合企业的需求

Ethereal

【三级等保】三级等保服务费用一年大概要多少?一年需要测评一次嘛?

行云管家

网络安全 等保 等级保护 三级等保

两小时,掌握四个数字化工具!

明道云

企业帮助中心的搭建步骤

小炮

帮助中心

抓到Netty一个隐藏很深的内存泄露Bug | 详解Recycler对象池的精妙设计与实现

bin的技术小屋

中间件 池化技术 java netty 内存池

一个 测试岗 面了 30 多人,不能再真实了...

六十七点五

软件测试 面试题 自动化测试 经验总结 测试工程师

抖音获客,抖音SEO询盘系统源码开发,思路分享,开发者掏心窝的说......

yunluohd168

短视频获客 抖音获客系统源码 大数据获客 抖音SEO获客源码

数据对接 - 大屏云极简使用手册

shulinwu

可视化 数据可视化 大屏可视化 数据可视化控件 大屏

HSC推出「万物生长计划」 赋能虎符交易所HOO新应用场景

区块链前沿News

Hoo 虎符交易所 虎符智能链

资产管理系统开发解决方案

低代码小观

企业管理 资产管理 CRM系统 企业管理软件

全新 OceanBase 社区版开发者中心 ODC 核心功能解读

OceanBase 数据库

oceanbase OceanBase 开源 OceanBase 社区版

测试开发【Mock平台】01开篇:平台设计和整体规划

MegaQi

测试开发 测试平台开发教程 测试干货

2022年济南正规等保测评公司名单(排名不分先后)

行云管家

等保 等保测评 等保2.0 济南

OceanBase 存储引擎详解

OceanBase 数据库

鸿蒙开发必备书籍【收藏】

坚果

鸿蒙 3月月更

OceanBase 在线体验环境,现已上线!

OceanBase 数据库

Linux性能优化—内存实战篇

Linux服务器开发

性能优化 内存管理 Linux服务器开发 Linux内核 内核源码

恒源云(Gpushare)_【存储优化】/hy-tmp可以扩/缩容啦

恒源云

云计算 存储 tmp

Apifox才是最强Postman替代品,看看国产软件到底有对牛!

Liam

后端 Postman API swagger java开发工具

详解4种微服务框架接入Istio方案

华为云开发者联盟

微服务 k8s istio 服务治理 微服务框架

如何使用 Checkmk 监控 SSL TLS 证书?

Ethereal

并发异步编程之争:协程(asyncio)到底需不需要加锁?(线程/协程安全/挂起/主动切换)Python3

刘悦的技术博客

多线程 协程 Python3 协程原理

Map-Reduce 思想在 ABAP 编程中的一个实际应用案例

汪子熙

mapreduce abap CRM系统 企业级应用 3月月更

Meetup预告| AIOps指标相关算法体系分享

云智慧AIOps社区

机器学习 大数据 算法 AIOPS 智能运维

ZEGO 自研客户端配置管理系统 —— 云控

ZEGO即构

后台开发 客户端配置 音视频架构

超长可视化指南!你必须了解的Kubernetes部署的调试思路_容器_Rancher_InfoQ精选文章