云原生的定义
在了解和学习Kubernetes之前应该先了解一下什么是云原生(Cloud Native ),云原生是 Matt Stine 提出的一个概念,它是一个思想的集合,包括 DevOps 、持续交付(Continuous Delivery)、微服务(MicroServices)、敏捷基础设施(Agile Infrastructure)、康威定律(Conways Law)等,以及根据商业能力对公司进行重组。Cloud Native 既包含技术(微服务,敏捷基础设施),也包含管理(DevOps,持续交付,康威定律,重组等)。Cloud Native 也可以说是一系列技术、企业管理方法的集合。
云原生本质是以应用为中心,让应用能最大限度享受到云计算的红利。云原生是云计算的下一站,云原生架构是引领未来十年的新一代技术架构。云原生让云计算变得标准、开放、简单高效、触手可及。
云原生应用的12要素
如今,软件通常会作为一种服务来交付,它们被称为网络应用程序,或软件即服务(SaaS)。12-Factor 为构建如下的 SaaS 应用提供了方法论:
- 使用标准化流程自动配置,从而使新的开发者花费最少的学习成本加入这个项目。
- 和操作系统之间尽可能的划清界限,在各个系统中提供最大的可移植性。
- 适合部署在现代的云计算平台,从而在服务器和系统管理方面节省资源。
- 将开发环境和生产环境的差异降至最低,并使用持续交付实施敏捷开发。
- 可以在工具、架构和开发流程不发生明显变化的前提下实现扩展。
- 这套理论适用于任意语言和后端服务(数据库、消息队列、缓存等)开发的应用程序。
进一步了解云原生
云原生是一种行为方式和设计理念,目的是提高云上资源的利用率和应用交付效率。云原生本身甚至不能称为是一种架构,它首先是一种基础设施,运行在其上的应用称作云原生应用,只有符合云原生设计哲学的应用架构才叫云原生应用架构。
云原生应用程序被设计为在平台上运行,并设计用于弹性,敏捷性,可操作性和可观察性。
- 弹性是允许失败而不是试图阻止它们;它利用了在平台上运行的动态特性。
- 敏捷性允许快速部署和快速迭代。
- 可操作性从应用程序内部控制应用程序生命周期,而不是依赖外部进程和监视器。
- 可观察性提供信息来回答有关应用程序状态的问题。
云原生应用程序所需特性的常用方法:
- 微服务
- 健康报告
- 遥测数据
- 弹性
- 声明式的,而不是命令式的
为失败设计
唯一永远不会失败的系统是那些让你活着的系统(例如心脏植入物和刹车系统)。如果您的服务永远不会停止运行,您需要花费太多时间设计它们来抵制故障,并且没有足够的时间增加业务价值。您的 SLO 确定服务需要多长时间。您花费在工程设计上超出 SLO 的正常运行时间的任何资源都将被浪费掉。
您应该为每项服务测量两个值,即平均无故障时间(MTBF)和平均恢复时间(MTTR)。监控和指标可以让您检测您是否符合您的 SLO,但运行应用程序的平台是保持高 MTBF 和低 MTTR 的关键。
在任何复杂的系统中,都会有失败。您可以管理硬件中的某些故障(例如,RAID 和冗余电源),以及某些基础设施中的故障(例如负载平衡器)。但是因为应用程序知道他们什么时候健康,所以他们也应该尽可能地管理自己的失败。
设计一个以失败期望为目标的应用程序将比假定可用性的应用程序更具防御性。当故障不可避免时,将会有额外的检查,故障模式和日志内置到应用程序中。
知道应用程序可能失败的每种方式是不可能的。假设任何事情都可能并且可能会失败,这是一种云原生应用程序的模式。
您的应用程序的最佳状态是健康状态。第二好的状态是失败状态。其他一切都是非二进制的,难以监控和排除故障。 Honeycomb 首席执行官 CharityMajors 在她的文章 “Ops:现在每个人都在工作” 中指出:“分布式系统永远不会起作用;它们处于部分退化服务的持续状态。接受失败,设计弹性,保护和缩小关键路径。”
无论发生什么故障,云原生应用程序都应该是可适应的。他们期望失败,所以他们在检测到时进行调整。
有些故障不能也不应该被设计到应用程序中(例如,网络分区和可用区故障)。该平台应自主处理未集成到应用程序中的故障域。
容器技术
容器是云原生的基石。
容器技术的核心:
• 环境隔离:Linux namespace,使应用“以为”自己在一个独立的操作系统环境下,隔离性弱于虚拟机。 • 资源限制:Linux cgroup,限制容器可以使用的资源 • 环境依赖:rootfs,保证运行环境的一致性 • 容器镜像:分层
容器的本质:运行环境+应用代码 = 工作进程 => 在特定环境中运行的一个或多个进程。
容器类似于 VM,但是更宽松的隔离特性,使容器之间可以共享操作系统(OS)。 因此,容器比起 VM 被认为是更轻量级的。且与 VM 类似,每个容器都具有自己的文件系统、CPU、内存、进程空间等,每个容器之间互相隔离 ,容器之间进程不会相互影响,能区分计算资源。由于它们与基础架构分离,因此可以跨云和 OS 发行版本进行移植。
namespace资源隔离
- UTS(UNIX Time-Sharing) : 主机名和域名设置
- IPC(Interprocess Communication) : 信号量、消息队列和共享内存
- PID : 进程编号
- NETWORK : 网络设备、网络栈、端口、防火墙规则等
- Mount : 挂载点(文件系统)
- User : 用户和用户组
- Control group (cgroup)
- Time: 时间、
- syslog
容器优势总结:
- 快速创建/部署应用:与VM虚拟机相比,容器镜像的创建更加容易。
- 持续开发、集成和部署:提供可靠且频繁的容器镜像构建/部署,并使用快速和简单的回滚(由于镜像不可变性)。
- 开发和运行相分离:在build或者release阶段创建容器镜像,使得应用和基础设施解耦。
- 开发,测试和生产环境一致性:在本地或外网(生产环境)运行的一致性。
- 云平台或其他操作系统:可以在 Ubuntu、RHEL、 CoreOS、on-prem、Google Container Engine或其它任何环境中运行。
- Loosely coupled,分布式,弹性,微服务化:应用程序分为更小的、独立的部件,可以动态部署和管理。
- 资源隔离
- 资源利用:更高效
Kubernetes是什么
基于容器技术的分布式集群管理系统。Kubernetes 是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。
可以在物理或虚拟机的Kubernetes集群上运行容器化应用,Kubernetes能提供一个以“容器为中心的基础架构”,满足在生产环境中运行应用的一些常见需求,如:
- 多个进程(作为容器运行)协同工作
- 存储系统挂载和扩容,用于运行有状态的应用
- 应用健康检测,对应用实施状况检查和自我修复。
- 应用实例的复制,有效管控应用部署和更新,并实现自动化操作
- 对服务进行声明式管理,保证所部署的应用始终按照部署的方式运行
- 跨多台主机进行容器编排,Pod自动伸缩/扩展
- 负载均衡
- 滚动更新
- 资源监控
- 日志访问
- 提供认证和授权
Pod, 被译作“容器集”, Kubernetes 应用的最小单位,被部署在单个节点上且包含一个或多个容器的容器组。同一容器集中的容器将共享相同的计算资源,所有容器共享同一个 IP 地址、IPC、主机名称及其它资源。容器集将网络和存储从底层容器中抽象出来,能更加轻松地在集群中移动容器。
Kubenetes提供的功能:
- 快速部署应用
- 快速扩展应用
- 无缝对接新的应用功能
- 节省资源,优化硬件资源的使用
- 服务发现和负载均衡
- 存储编排
- 自动部署和回滚
- 自动调度
- 自我修复
- 密钥和配置管理
“编排”的定义是指执行一个预定的工作流:先执行A,之后B,然后C,但怎么样从A到C并不重要,达到目的就好。
Kubernetes的优势
- 可移植: 支持公有云,私有云,混合云,多重云(multi-cloud)
- 可扩展: 模块化, 插件化, 可挂载, 可组合
- 自动化: 自动部署,自动重启,自动复制,自动伸缩/扩展
Kubernetes 帮助你确保这些容器化的应用程序在你想要的时间和地点运行,并帮助应用程序找到它们需要的资源和工具。
- 将复杂的系统环境变得统一和简单:架构师、开发工程师、运维工程师面对的都是同一个系统环境(容器运行环境)
- 可以使用微服务解决复杂业务
- 更好的迁移、整合业务到任意环境、任意云,消除业务与环境或云商的绑定
- 服务弹性扩容,增加服务副本数量,可应对突发流量
- 横向扩容能力对集群进行扩容,增加集群的节点数量,可承载更多的服务和用户
应用的运行、配置、管理、所有生存周期将与当前操作系统不存在绑定关系,有利于应用的升级、更新、回滚等操作。
Kubenetes的核心
一个词:API
从Kubenetes的架构图来看,API Server出于架构的核心位置,API提供了资源操作的统一入口。
Kubernetes的架构
控制平面组件:、
- apiserver: 负责存储资源,并且提供查询、修改资源的接口
- etcd:一致且高度可用的键值存储,用作 Kubernetes 的所有集群数据的后台数据库
- scheduler:实现工作负载的调度
- controller: 负责管理本级和下级资源,将资源的当前状态转变为期望的状态。比如 deploymentController 就负责管理 deployment 资源 和下一级的 rs 资源
Node组件
- kubelet: 管理容器,确保这些的容器处于运行中
- kube-proxy:实现网络通信、过滤
- 容器运行时:负责运行容器,如containerd
插件组件
- 插件使用 Kubernetes 资源(DaemonSet、Deployment 等)实现集群功能。 因为这些插件提供集群级别的功能,插件中命名空间域的资源属于
kube-system
命名空间。 - 常见的插件:DNS,dashboard,
controller 和 kubelet 都只和 apiserver 通讯。controller 不断监听本级资源,然后修改下级资源的声明。kubelet 查询当前 node 所应部署的资源,然后执行清理和部署。
理想中,每一层管理器只管理本级和子两层资源。但因为每一个资源都是被上层创建的, 所以实际上每一层资源都对下层资源的定义有完全的了解,即有一个由下至上的强耦合关系。
Kubenetes的一些设计理念
分角色:manager nodes、worker nodes;apiserver、controller、kubelet;
高度抽象:Resource、Service
唯一标识:uid
利用标签:label、selector
容错性:污点和容忍度
扩展性:RC、RS
......
Kubernetes抽象的资源
资源对象的通用属性:版本、类别、名称、标签、注解
每一种资源在集群内都有唯一指定的名称和编号(UID)
可以通过命令 kubectl api-resources
查看Kubenetes集群中所有的资源,包括CRD。
命令
kubectl api-resources
可以查看一个资源的简称,利用简称可以简化命令的输入。比如 deployments 可以简称为 deploy,serviceaccounts 可以简化为 sa 。
API:API对象是K8s集群中的管理操作单元。K8s集群系统每支持一项新功能,引入一项新技术,一定会新引入对应的API对象,支持对该功能的管理操作。
Master:旧称,控制平面的节点
Node:工作节点,
Namespace:名字空间是 Kubernetes 用来支持隔离单个集群中的资源组的一种抽象
Deployment:管理多副本应用的一种 API 对象,通常通过运行没有本地状态的 Pod 来完成工作。
Service:将运行在一组 Pods上的应用程序公开为网络服务的抽象方法
Pod:Pod 是 Kubernetes 的原子对象。 Pod 表示你的集群上一组正在运行的容器(Container)。
Ingress:是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP。支持虚拟主机的HTTP代理服务,比如nginx
ConfigMap:ConfigMap 是一种 API 对象,用来将非机密性的数据保存到键值对中。使用时, Pods 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。
Secret:用于存储敏感信息,如密码、OAuth 令牌和 SSH 密钥。
Endpoint:负责记录与服务的选择器相匹配的 Pod 的 IP 地址。
Service Account:为在 Pod 中运行的进程提供标识。
Service Account 是 Kubenetes 进行权限分配的基本对象
Volume:包含可被 Pod 中容器访问的数据的目录。
Job:K8s用来控制批处理型任务的API对象
可参考:Kubernetes官方网站的词汇表
Master是控制节点,主要负责集群的管理,包括数据存储(etcd)、访问控制(api server)、资源管理(controller manager)和资源调度(scheduler)
Node是工作节点,负责Pod对应容器的创建、启停等(kubelet),Service的通信与负载均衡机制(kube-proxy),容器运行时(docker、containerd)
configMap和Secret
在K8S中,有两种方式管理资源的配置,分别是configmap和secret,他们的最大区别是:
- configmap用来管理明文配置
- secret用来管理密文配置(并非真正的加密,而是base64编码)
configMap的使用
- 创建configmap资源
- 在deploy中定义congfigmap类型的volumes
- 在deoloy的containers中挂载此volumes
其中常见的一种使用情况存放环境变量(envFrom)
Secret的使用
ConfigMap和Secret都可以通过volume或环境变量的方式使用
k8s secrets用于存储和管理一些敏感数据,比如密码,token,密钥等敏感信息
它把 Pod 想要访问的加密数据存放到 Etcd 中,然后用户就可以通过在 Pod 的容器里挂载 Volume 的方式或者环境变量的方式访问到这些 Secret 里保存的信息了
与ConfigMap类似,区别在于secret存储敏感数据,所有的数据都需要经过base64进行编码
使用secret主要存储的是凭据信息
Service Account会自动挂载Secret用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount 目录中
Service Account 中也可以自定义添加imagePullSecrets类型的secret,从私有仓库中拉取镜像
更新configmap
- 修改configmap资源清单并应用
- 修改deploy中使用的configmap或重启使用该configmap资源的pod
Kubernetes是如何描述资源的
Kubernetes 采用声明式描述, 使用 .yaml
格式的文件表示 Kubernetes 对象。
apiVersion:api版本
kind:类别,Namespace、Pod、Service、Deployment、Ingress、ConfigMap
metadata:元数据,包含注解、标签、名称、创建时间、资源版本号、selfLink、uid等
- name:名称
- annotations:注解,key - value 对,注解是对资源的进一步描述,是以键值对的形式给资源对象附加随机的无法标识的元数据。
- labels:标签,key - value 对,用来为对象设置可标识的属性标记。Kubernetes规定了一些公认的标签,比如
app.kubernetes.io/managed-by
,标签通常用于选择器
spec:规约,期望的状态描述,
status:状态,当前的状态描述,使用 phase(阶段)表示不同的状态
什么是CRD
CRD的全称为 CustomResourceDefinitions
,即自定义资源。k8s拥有一些内置的资源,比如说Pod,Deployment,ReplicaSet等等,而CRD则提供了一种方式,使用户可以自定义新的资源,以扩展k8s的功能。
CRD可以在不修改k8s源代码的基础上方便的扩展k8s的功能。
CRD至少包括如下属性:
- NAME:CRD的复数名称(通常是一个合法的DNS名称)
- SHORTNAMES:cli中使用的资源简称
- APIGROUP:API所使用的组名称
- NAMESPACED:是否具有namespace属性
- KIND:资源文件需要,用以识别资源
要使用CRD定义的资源,需要先创建CRD声明,得到CRD类型(Kind),然后就可以创建该CRD类型的资源了。
获取CRD资源列表:kubectl get crd
。
标签和选择器
标签可以动态添加或删除,可以通过给指定的资源对象绑定一个或多个不同的label来实现多维度的资源分组管理功能,以便灵活、方便地进行资源分配、调度、配置、部署等管理工作。例如部署不同的版本的应用到不同的环境中,以及监控、分析应用(日志记录、监控、告警)等。
常见标签:
app:应用名称标签
release:应用版本标签
选择器(选择算符)允许用户通过标签(labels)对一组资源对象进行筛选过滤,这对于集群资源的管理者和使用者来说是非常重要的功能。
利用标签和选择器,可以决定如何将 Pod 调度到指定的 Node (Label + nodeSelector)。
集群内部通信和集群外部通信
- 集群中的每个 pod 都有自己唯一的集群范围 IP 地址
同一个命令空间的pod可以通过pod IP互相访问。
- 所有 pod 都可以与集群内的每个 pod 通信
- 通信在没有 NAT 的情况下发生,这意味着目标 pod 可以看到源 pod 的真实 IP 地址。
在腾讯云tke容器服务集群中测试发现,node节点或同vpc的节点能访问pod的IP地址
Kubernetes 认为容器网络或在其上运行的应用程序是可信的,不需要在网络级别进行身份验证。
- 同一个节点内的访问
可以通过clusterIP+port访问
通过集群内部的DNS
- 不同节点的访问
可以通过clusterIP+port访问
- 访问集群外部服务
通过Endpoint将外部服务映射为Service
- 外部访问集群内部服务
使用nodeport和hostport
使用Ingress
pod常见的网络故障
Pod 最常见的网络故障有,网络不可达(ping 不通);端口不可达(telnet 不通);DNS 解析异常(域名不通)与大数据包丢失(大包不通)。
一些可以排错的工具:tcpdump、nsenter、mtr等
关于抓包节点和抓包设备 如何抓取有用的包,以及如何找到对应的接口,有以下建议
抓包节点:
通常情况下会在源端和目的端两端同时抓包,观察数据包是否从源端正常发出,目的端是否接收到数据包并给源端回包,以及源端是否正常接收到回包。如果有丢包现象,则沿网络链路上各节点抓包排查。例如,A 节点经过 c 节点到 B 节点,先在 AB 两端同时抓包,如果 B 节点未收到 A 节点的包,则在 c 节点同时抓包。
抓包设备:
对于 Kubernetes 集群中的 Pod,由于容器内不便于抓包,通常视情况在 Pod 数据包经过的 veth 设备,docker0 网桥,CNI 插件设备(如 cni0,flannel.1 etc..)及 Pod 所在节点的网卡设备上指定 Pod IP 进行抓包。选取的设备根据怀疑导致网络问题的原因而定,比如范围由大缩小,从源端逐渐靠近目的端,比如怀疑是 CNI 插件导致,则在 CNI 插件设备上抓包。从 pod 发出的包逐一经过 veth 设备,cni0 设备,flannel0,宿主机网卡,到达对端,抓包时可按顺序逐一抓包,定位问题节点。
服务的几种类型
- ClusterIP
ClusterIP 在生命周期内是固定不变的,svc通过selector找到后端的pod,从ClusterIP到Pod IP,是通过kube-proxy完成(目标地址转换DNAT:Kube-proxy 将目标IP地址更新为服务对应的 Pod 的IP地址)的。
每一个ClusterIP在DNS中都有一个唯一的名称对应
- NodePort
与docker展现不同,通过kubectl命令查询svc,service port在前,NodePort 在后
- LoadBalancer
LoadBalancer 类型的svc一般具有 external IP,而 ClusterIP 和 NodePort 没有 external IP
IP的几种类型
IP:普通的IP地址,比如Pod的IP就是这一类(kubectl get pod -o wide)
CLUSTER-IP:集群内部通信IP,比如 ClusterIP 类型的 Service 的 IP
INTERNAL-IP: 内部IP,比如节点的IP地址(kubectl get node -o wide)
EXTERNAL-IP:外部IP,比如节点的IP地址(kubectl get node -o wide)
LoadBalancer: 负载均衡类型的IP
每一个pod都有一个IP,这个IP不是ClusterIP
pod的IP在每次pod删除创建后都会变化
代理和端口转发
kubectl port-forward --address 0.0.0.0 svc/saas-pre43485 4000:80 -n tenant-43485
Kube-proxy 在每个节点上运行,并监视 Service 及其选择的 Pod(实际上是 Endpoint 对象)。
- 当节点上运行的 pod 向 ClusterIP 服务发出请求时,kube-proxy 会拦截它。
- 通过查看目的 IP 地址和端口,可以识别目的 ClusterIP 服务。并将此请求的目的地替换为实际 Pod 所在的端点地址。
如何选择Kubernetes的版本
- 听从Kubernetes官网的建议使用最新的稳定版本(第二个最新的小版本)
- 观察云服务商使用的Kubernetes版本
Kubernetes常见命令
核心命令:kubectl
kubectl 常用子命令:
- get 获取资源的摘要信息
- describe 描述资源的详细信息
- rollout 滑跑(上线)
- scale 改变
- apply 创建或更新资源
- create 创建资源
- delete 删除资源
kubectl 参常用数,可参见备忘录和命令参考
- -o wide
- -o yaml
- -o json
- -o jsonpath='{.users[*].name}'
- --all-namespaces
- -n default
例子:
Kubernetes环境和Docker环境的异同
- 容器运行环境的核心之一是容器镜像,只要容器镜像是相同的,那么通常容器中的应用的表现是一致的。因此测试镜像功能时无需在Kubernetes环境中测试,docker环境中一样可以测试。
- Kubernetes可以不通过Docker来控制、操作容器。在Kubernetes 1.20 后不再支持Docker作为基础运行时,而是使用containerd,使用ctrctl命令代替docker命令。
- 单机环境下推荐使用Docker简化操作,多个主机可以考虑使用Kubenetes,运行跨主机的服务。
一些提高使用Kubernetes效率的小技巧
- 使用alias和短名称,如用k代替kubectl,deploy代替deployment, ns代替namespace,sa代替serviceaccount
- 使用自动补全,支持bash和zsh
- 做好笔记
Helm - Kubernetes 应用的包管理器
Helm 是一个 Kubernetes 应用的包管理工具,用来管理 chart——预先配置好的安装包资源,有点类似于 Ubuntu 的 APT 和 CentOS 中的 YUM。2019 年 11 月 13 日,Helm 3 发布,2020 年 4 月 30 日,从 CNCF 中毕业。
使用Helm可以在Kubenetes安装、删除、更新、查找应用,具有应用版本管理功能。
通过Helm管理Kubernetes应用与维护Kubernetes各种资源的yaml相比:
- Helm组织得更合理、高效
- 通过1~2个命令完成安装
- 灵活的自定义应用的启动参数
- 更方便的分享、传输应用到其他集群环境
- Helm 回滚、升级应用更简单
Helm Chart是helm管理的应用的打包格式。Helm 通过Helm Chart 管理 Kubernetes 应用。它包括如下特征:
Helm Chart是对应用程序的进一步封装(相比Docker镜像),Chart中包括一系列的yaml格式的描述文件,为 Kubernetes yaml 清单文件提供了模板化的语法。
通过 Helm Chart 可以描述复杂的应用、管理应用的依赖
Helm Chart 易于创建、发版、分享和发布
一个Chart只用来部署单个的应用的,不应该过于复杂,不应该包含多个依赖,相当于一个微服务。 Chart有特定的目录结构,可以打包起来进行版本控制。
拥有微服务并不意味着您拥有云原生基础设施。虽然微服务是实现应用程序灵活性的一种方式,但它们不是云原生应用程序的必需条件。
关于微服务:作为单个实体进行管理和部署的应用程序通常称为单体应用。最初开发应用程序时,单体有很多好处。它们更易于理解,并允许您在不影响其他服务的情况下更改主要功能。 随着应用程序复杂性的增长,单体应用的益处逐渐减少。它们变得更难理解,而且失去了敏捷性,因为工程师很难推断和修改代码。 对付复杂性的最好方法之一是将明确定义的功能分成更小的服务,并让每个服务独立迭代。这增加了应用程序的灵活性,允许根据需要更轻松地更改部分应用程序。每个微服务可以由单独的团队进行管理,使用适当的语言编写,并根据需要进行独立扩缩容。 只要每项服务都遵守强有力的合约,应用程序就可以快速改进和改变。
Chart 仓库(repository)是一个用来托管index.yaml文件和打包好的chart文件的web服务器。 Helm 可以安装本地的Chart,也可以安装Helm 仓库中的Chart。
Helm 常用命令如下:
- helm create:在本地创建新的 chart
- helm dependency:管理 chart 依赖
- helm intall:安装 chart
- helm lint:检查 chart 配置是否有误
- helm list:列出所有 release
- helm package:打包本地 chart
- helm repo:列出、增加、更新、删除 chart 仓库
- helm rollback:回滚 release 到历史版本
- helm pull:拉取远程 chart 到本地
- helm search:使用关键词搜索 chart
- helm uninstall:卸载 release
- helm upgrade:升级 release
快速搭建Kubernetes环境
渠成平台是快速搭建Kubernetes环境的最佳开源工具之一。
- 通过渠成平台可以快速地将一个主机或虚拟机变为可用于生产环境的Kubernetes环境。
- 如果想快速搭建或练习Kubernetes、Helm,建议先从渠成平台开始。
- 另外渠成平台内置了许许多多的开源应用,比如禅道、Gitea、SonarQube、Jenkins等,并且还在持续更新中。
另外Kubenetes、Helm官网上推荐的一些部署工具,比如Minikube、K3S等也是一个不错的选择。
参考
- Kubernetes(K8S)中文文档_Kubernetes中文社区
- Kubernetes 基础知识入门
- 《Kubenetes 权威指南》 第5版