云原生技术专题 | 云原生容器编排问题盘点,总结分享年度使用Kubernetes的坑和陷阱

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 随着云原生的兴起,越来越多的应用选择基于Kubernetes进行部署,可以说Kubernetes 是最流行的容器编排和部署平台。它的强大功能特性,可以保障在生产中可靠地运行容器化应用程序,相关的DevOps等工具也应运而生,下面就是小编简单化了一个Kubernetes的逻辑架构图。

Kubernetes与云原生

随着云原生的兴起,越来越多的应用选择基于Kubernetes进行部署,可以说Kubernetes 是最流行的容器编排和部署平台。它的强大功能特性,可以保障在生产中可靠地运行容器化应用程序,相关的DevOps等工具也应运而生,下面就是小编简单化了一个Kubernetes的逻辑架构图。

如何开发面向Kubernetes部署和运维的微服务应用是很多开发者与架构师要解决的问题。通过本文的阅读,作者介绍了在Kubernetes体系下构建高效、可靠的微服务应用所遇到的种种问题。希望这篇文章能够对您有所帮助。

总体问题大纲分布如下说是:

在接下来的内容中,我们将探讨今年个人遇到的5个常见的Kubernetes问题和错误。通过识别并避免这些挑战,您将能够提高应用程序的可扩展性、可靠性和安全性,同时更好地控制集群及其部署。

性能问题:忽略节点选择器导致调度效率低下

整个集群效能的表现关键在于Pod是否能被精准地部署至适宜的节点上。在众多的集群配置中,常常包含多样化的节点类型,比如那些专为常规应用程序设计的小型内存和低配CPU节点以及针对高密度后台服务所配置的大型内存和高配CPU节点

问题排查和分析

  • 首先,我们一定要侧重分析当前节点池的利用率和资源分配情况,确定是否存在未充分利用的较小节点。
  • 如果存在未充分利用的较小节点,使用自动化工具进行节点重分配。将该节点上运行的负载迁移到其他节点上,以实现节点资源的最优使用。
  • 最后,在节点迁移之前,需再三确保目标节点有足够的资源来承载额外的负载。

注意:考虑负载迁移对运行中应用的影响,并确保其在迁移过程中不会中断

解决方案

为了避免出现这个问题,我们可以使用一种有效的方法来管理Pod的调度,即通过在节点上设置标签,并使用节点选择器将Pod分配给兼容的节点。这种方法可以确保Pod被正确地调度到具备所需资源和能力的节点上。

案例介绍

首先,我们为节点设置适当的标签。标签可以根据节点的特性、硬件配置或其他自定义需求进行定义。

例如,可以为具备高性能GPU的节点设置一个标签,或者为具备特定版本的软件组件的节点设置一个标签。

接下来,在Pod的定义中添加一个节点选择器。节点选择器是一组标签键值对,用于指定Pod所需的节点属性或条件。

例如,可以指定Pod需要运行在具备某个特定标签的节点上。

当调度程序接收到新的Pod创建请求时,它将根据Pod的节点选择器进行匹配,并将Pod分配给满足条件的节点。这样,Pod就能够被正确、高效地调度到合适的节点上,避免了资源浪费和性能问题。

apiVersion: v1
kind: Pod
metadata:
  name: pod-node-selector-sample
spec:
  containers:
    - name: tomcat
      image: tomcat:latest
  nodeSelector:
    node-class: middleLevel

为了确保Pod只会调度到设置了标签的节点(例如node-class: middleLevel),我们可以使用kubectl命令在匹配的节点上设置标签。

首先我们先使用kubectl命令列出当前可用的节点

kubectl get nodes

之后,找到您想要为其添加标签的特定节点。使用kubectl命令在该节点上设置标签。你可以使用以下命令格式:

kubectl label nodes <节点名称> <标签键>=<标签值>

此外,如果节点的名称是node-1,要将标签node-class设置为middleLevel,您可以运行以下命令:

kubectl label nodes node-1 node-class=middleLevel

这将在节点node-1上设置了一个标签node-class,其值为middleLevel。

配置问题:应用服务端口与Service(KubectlProxy)控制的端口不一致

在我们的运行环境中,确保Service将流量路由到对应的Pod上的正确端口非常重要。为了解决这个问题,您需要确保Service的端口定义与Pod容器的端口一致。

以下是一个错误的配置Service和Pod的配置文件:

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  labels:
    app: test-app
spec:
  image: tomcat:latest
  ports:
    - containerPort: 8081

---

apiVersion: v1
kind: Service
metadata:
  name: test-service
spec:
  selector:
    app: test-app
  ports:
    - protocol: TCP
      port: 9000
      targetPort: 8082

在上述示例中,Service的目标端口(targetPort)设置为8081,与Pod容器的实际端口(containerPort:8081)不一致。通过调整Service的配置,确保正确路由流量到Pod的适当端口,将有助于保证应用程序的正常运行和可靠性。

正确的配置如下所示:

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  labels:
    app: test-app
spec:
  image: tomcat:latest
  ports:
    - containerPort: 8081

---

apiVersion: v1
kind: Service
metadata:
  name: test-service
spec:
  selector:
    app: test-app
  ports:
    - protocol: TCP
      port: 9000
      targetPort: 8081

隔离问题:容器组件部署到K8S集群错误的命名空间或者默认空间(建议)

Kubernetes命名空间在集群中提供了一定程度的隔离,将一组服务逻辑分组在一起。在使用命名空间时,请记住为每个服务和kubectl命令指定目标命名空间。如果没有指定目标命名空间,将默认使用default命名空间。

如果服务没有部署在合适的命名空间下,就会导致相关的服务器请求无法到达,在这里给大家看一个逻辑结构图就可以了解到:

为了避免这个问题,请确保在部署和管理服务时,建议大家始终使用正确的命名空间。在执行kubectl命令时,可以使用--namespace参数来指定目标命名空间。例如:

kubectl get pods --namespace=test-namespace

这将列出位于test-namespace命名空间下的Pods。此外,在创建和管理服务时,也要确保正确指定目标命名空间。例如,在创建Deployment时,可以在yaml文件中使用namespace字段指定目标命名空间:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-app
  namespace: test-namespace
...

确保Deployment部署在test-namespace命名空间下。通过正确使用命名空间,可以保证每个服务被正确隔离,并且相关的服务器请求可以顺利到达。

资源问题:不进行设置资源请求和限制的Pod(命名空间也没有控制)

在Kubernetes集群中,正确地管理资源对于保持整个集群的稳定性非常重要。默认情况下,Pod并没有任何资源限制,除非我们显式地对其进行适当的配置,否则可能会导致Node节点的CPU和内存资源耗尽。

解决方案

在所有的Pod上设置适当的资源请求和限制,以减少资源竞争的问题。通过指定资源请求,Kubernetes可以为我们的Pod预留特定数量的资源,从而避免将其调度到无法提供足够容量的节点上。

设置资源限制

限制Pod使用的最大资源量,当Pod超过CPU或内存限制时,Kubernetes会对其进行限制,例如,限制超过CPU限制的Pod的处理能力,或者当达到内存限制时触发内存不足 (OOM) 来终止Pod的运行。下面是一个示例,展示如何在Pod的配置中设置资源请求和限制的参数:

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
  - name: test-server
    image: test-image
    resources:
      requests:
        cpu: "0.5"
        memory: "1Gi"
      limits:
        cpu: "1"
        memory: "2Gi"

参数解释:

  • limits:Pod对CPU和内存的最大限制。
  • requests:Pod对CPU和内存的最小需求
    • cpu: 0.5 或 500m:表示0.5个CPU核心或500毫核(mCPU)的CPU资源请求/限制。
    • 1:表示1个整数CPU核心的CPU资源请求/限制。

注意:请根据具体需求和应用程序的资源消耗情况,来设置适当的资源请求和限制,以确保集群的稳定性和有效的资源利用。

状态问题:优化和使用Liveness和Readiness探针

Kubernetes探针是一种能够增加应用程序弹性的重要工具。它们可以向Kubernetes Pod报告应用程序的健康状况。

Liveness探针

当容器出现问题时(例如内存溢出)或Liveness探针的请求超时,Liveness探针会通知Kubernetes重新启动容器,以确保应用程序的可用性。

Readiness探针

Kubernetes提供了Readiness探针来发现并处理这些情况。容器所在的Pod会报告其未就绪状态的信息,并且将不接收来自Kubernetes Service的流量。

例如:应用程序在启动时可能需要加载大量数据或配置文件,或者在启动后需要等待外部服务。在这种情况下,我们既不希望停止应用程序的运行,也不希望将请求发送到它。

通过合理配置 Liveness 和 Readiness 探针,我们能够更好地监测和管理应用程序的状态,提高应用程序的可用性,并确保容器在适当的时候进行重新启动,从而提高整体系统的稳定性。

以下是一个示例,展示了如何在 Pod 的配置中设置 Liveness 和 Readiness 探针:

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
  - name: test-server
    image: test-image
    livenessProbe:
      httpGet:
        path: /health
        port: 80
      initialDelaySeconds: 3
      periodSeconds: 5
    readinessProbe:
      httpGet:
        path: /readiness
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 10

所以首先探针一定要配置,此外要应对IO密集型以及CPU密集型等场景进行设置对应的参数值,切勿一套配置Cover主全场,那是不可能的。
对此我深有体会,总是出现服务负荷过高的时候,总是被探针Kill掉。

我的建议是:对于敏感度不高,且不是核心数据服务(无状态化的),可以酌量调大一些。肺腑之言。

最后总结

以上是作者根据个人经验和使用中出现的一些问题和错误的总结。希望其他开发者能够从中受益,避免犯类似的错误。我们选择使用Kubernetes的原因之一就是它具备弹性扩容的能力。正确的配置可以使Kubernetes在需求高峰期自动添加新的Pod和节点,实现动态的水平扩容和垂直扩容。然而,不幸的是,许多团队在自动扩容方面存在一些不可预测性的问题。

相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。 &nbsp; &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
1月前
|
Kubernetes Docker Python
Docker 与 Kubernetes 容器化部署核心技术及企业级应用实践全方案解析
本文详解Docker与Kubernetes容器化技术,涵盖概念原理、环境搭建、镜像构建、应用部署及监控扩展,助你掌握企业级容器化方案,提升应用开发与运维效率。
445 108
|
16天前
|
监控 Cloud Native Java
Quarkus 云原生Java框架技术详解与实践指南
本文档全面介绍 Quarkus 框架的核心概念、架构特性和实践应用。作为新一代的云原生 Java 框架,Quarkus 旨在为 OpenJDK HotSpot 和 GraalVM 量身定制,显著提升 Java 在容器化环境中的运行效率。本文将深入探讨其响应式编程模型、原生编译能力、扩展机制以及与微服务架构的深度集成,帮助开发者构建高效、轻量的云原生应用。
113 44
|
4月前
|
人工智能 Cloud Native 安全
云原生+AI 为企业出海提供全新技术引擎!明天见
5月22日 14:00「飞天发布时刻」,阿里云云原生应用平台产品负责人李国强将重磅揭晓面向 AI 场景的云原生产品体系升级,通过弹性智能的全球一体化架构、开箱即用的云原生 AI 工程化能力,为中国企业出海提供全新技术引擎。
|
18天前
|
存储 Kubernetes 网络安全
关于阿里云 Kubernetes 容器服务(ACK)添加镜像仓库的快速说明
本文介绍了在中国大陆地区因网络限制无法正常拉取 Docker 镜像的解决方案。作者所在的阿里云 Kubernetes 集群使用的是较旧版本的 containerd(1.2x),且无法直接通过 SSH 修改节点配置,因此采用了一种无需更改 Kubernetes 配置文件的方法。通过为 `docker.io` 添加 containerd 的镜像源,并使用脚本自动修改 containerd 配置文件中的路径错误(将错误的 `cert.d` 改为 `certs.d`),最终实现了通过多个镜像站点拉取镜像。作者还提供了一个可重复运行的脚本,用于动态配置镜像源。虽然该方案能缓解镜像拉取问题,
160 3
|
19天前
|
Kubernetes Devops Docker
Kubernetes 和 Docker Swarm:现代 DevOps 的理想容器编排工具
本指南深入解析 Kubernetes 与 Docker Swarm 两大主流容器编排工具,涵盖安装、架构、网络、监控等核心维度,助您根据团队能力与业务需求精准选型,把握云原生时代的技术主动权。
138 1
|
2月前
|
Cloud Native 中间件 调度
云原生信息提取系统:容器化流程与CI/CD集成实践
本文介绍如何通过工程化手段解决数据提取任务中的稳定性与部署难题。结合 Scrapy、Docker、代理中间件与 CI/CD 工具,构建可自动运行、持续迭代的云原生信息提取系统,实现结构化数据采集与标准化交付。
103 1
云原生信息提取系统:容器化流程与CI/CD集成实践
|
4月前
|
存储 缓存 分布式计算
StarRocks x Iceberg:云原生湖仓分析技术揭秘与最佳实践
本文将深入探讨基于 StarRocks 和 Iceberg 构建的云原生湖仓分析技术,详细解析两者结合如何实现高效的查询性能优化。内容涵盖 StarRocks Lakehouse 架构、与 Iceberg 的性能协同、最佳实践应用以及未来的发展规划,为您提供全面的技术解读。 作者:杨关锁,北京镜舟科技研发工程师
StarRocks x Iceberg:云原生湖仓分析技术揭秘与最佳实践
|
2月前
|
缓存 Cloud Native Java
Java 面试微服务架构与云原生技术实操内容及核心考点梳理 Java 面试
本内容涵盖Java面试核心技术实操,包括微服务架构(Spring Cloud Alibaba)、响应式编程(WebFlux)、容器化(Docker+K8s)、函数式编程、多级缓存、分库分表、链路追踪(Skywalking)等大厂高频考点,助你系统提升面试能力。
132 0

相关产品

  • 容器服务Kubernetes版
  • 推荐镜像

    更多