• [技术干货] Forrester:华为云容器是容器混合云最佳选择
    近日,国际权威咨询机构Forrester发布《The Forrester New WaveTM: Public Cloud Enterprise Container Platforms, Q3 2019》报告,报告显示:华为云容器进入"强劲表现者"象限,稳居全球容器产品TOP阵营,是客户使用容器混合云的最佳选择。社区贡献亚洲第一、全球第三华为云从2015年起就开始投入云原生产业,是云原生基金会(CNCF)的初创会员、白金会员,在Kubernetes社区的贡献一直稳居亚洲第一、全球第三,是全球首批Kubernetes认证服务提供商。同时,华为云在Kubernetes社区拥有10个Maintainer席位,并负责Kubernetes调度、集群联邦、网络、架构、安全等多个特性,是相关技术在社区的领导者。领先的云容器全栈解决方案基于华为多年在云原生领域的持续贡献与积累,华为云基于容器基础设施服务,打造了一套完整的云容器全栈解决方案,覆盖容器基础设施、容器运维管理和行业容器解决方案,为客户提供最优、最丰富的云容器服务选择。"华为云容器具备强大的安全和应用生命周期管理能力,安全能力覆盖面很广,CI/CD流水线及微服务使得云原生开发非常高效"——Forrester报告1、容器基础设施:包括Kubernetes容器(CCE)和Serverless容器(CCI),以及基于这两个基础服务衍生出的裸金属容器、GPU容器等。为用户提供最基本的容器集群、应用管理能力。2、容器运维管理:一套覆盖端到端的容器运维管理体系,涵盖资源编排、容器应用持续交付、应用生命周期管理、镜像安全扫描以及日常运维监控能力,通过这些工具,可以降低容器使用门槛,极大的提升传统IT向云原生转型的效率,以及云原生转型后的IT运维管理效率。3、行业解决方案:面向基因、AI、边缘等业务场景打造的解决方案,将云原生与业务场景融合,帮助客户业务快速实现云原生转型。目前华为云容器全栈服务已经在互联网、金融、资讯、基因、游戏、渲染等行业得到广泛应用。混合云容器最佳选择"华为云的多云管理平台(MCP)以及私有云服务(HCSO)可以在混合云场景下使用,如果企业在寻找(容器)混合云解决方案,那么华为云是最佳选择。"——Forrester报告2019年3月22日,在华为全球生态伙伴大会上,华为云发布了多云混合云解决方案,这是全球首个容器混合云解决方案,为客户提供容器集群及云原生应用的跨云管理能力,不但为客户解决了平台供应商锁定的问题,还可轻松对应跨云应用自动容灾、峰值流量智能分担、业务地域化策略运营的诉求,是一种更优的跨云解决方案。业界首发鲲鹏容器2019年7月23日,华为云发布鲲鹏Kubernetes容器和鲲鹏Severless容器,是目前业界首发支持华为鲲鹏平台的容器服务,支持X86和鲲鹏节点的混合管理,基于强大的应用生命周期管理能力,实现原有应用到鲲鹏平台的无感迁移,同时在性能较业界有极大提升,容器发放速度可达每秒1000个,领先业界10倍,服务请求转发效率领先业界50%,整体性价比提升30%。华为云将持续大力投入云原生领域,并坚持以客户为中心的服务理念,为客户提供领先的、贴合行业的技术和商业解决方案,更好的服务客户。
  • [技术干货] k8s的性能指标监控
    K8s本身的监控,也可以理解为使用K8s的成本。Node监控主要包括四个部分监控:Node资源利用率、Node数量、每个Node运行Pod数量以及资源对象状态。Pod监控主要包括三个部分: Pod总数量及每个控制器预期数量、 Pod状态和容器资源利用率(CPU、内存、网络)。K8s性能监控实现思路:Pod kubelet的节点使用cAdvisor提供的metrics接口获取该节点所有Pod和容器相关的性能指标数据。 指标接口:https://NodeIP:10250/metrics/cadvisorNode 使用node_exporter收集器采集节点资源利用率。 项目地址:https://github.com/prometheus/node_exporterK8s资源对象 kube-state-metrics采集了k8s中各种资源对象的状态信息。 项目地址:https://github.com/kubernetes/kube-state-metricsPrometheus,用来采集和管理k8s的性能数据,Grafana用来进行数据的可视化呈现,两者一起监控K8s性能。
  • [经验交流] 致运维:关于 Kubernetes 的架构,看完这篇你就明白了
    打开这篇文章的同学,想必对 docker 都不会陌生。docker 是一种虚拟容器技术,它上手比较简单,只需在宿主机上起一个 docker engine,然后就能愉快的玩耍了,如:拉镜像、起容器、挂载数据、映射端口等等。相对于 Kubernetes(K8S)的上手,可谓简单很多。 那么 K8S 是什么,又为什么上手难度大?K8S 是一个基于容器技术的分布式集群管理系统,是谷歌几十年来大规模应用容器技术的经验积累和升华的一个重要成果。所以为了能够支持大规模的集群管理,它承载了很多的组件,而且分布式本身的复杂度就很高。又因为 K8S 是谷歌出品的,依赖了很多谷歌自己的镜像,所以对于国内的同学环境搭建的难度又增加了一层。 下面,我们带着问题,一步步来看 K8S 中到底有哪些东西? 首先,既然是个分布式系统,那势必有多个 Node 节点(物理主机或虚拟机),它们共同组成一个分布式集群,并且这些节点中会有一个 Master 节点,由它来统一管理 Node 节点。如图所示:问题一:主节点和工作节点是如何通信的呢?首先,Master 节点启动时,会运行一个 kube-apiserver 进程,它提供了集群管理的 API 接口,是集群内各个功能模块之间数据交互和通信的中心枢纽,并且它也提供了完备的集群安全机制(后面还会讲到)。 在 Node 节点上,使用 K8S 中的 kubelet 组件,在每个 Node 节点上都会运行一个 kubelet 进程,它负责向 Master 汇报自身节点的运行情况,如 Node 节点的注册、终止、定时上报健康状况等,以及接收 Master 发出的命令,创建相应 Pod。 在 K8S 中,Pod 是最基本的操作单元,它与 docker 的容器有略微的不同,因为 Pod 可能包含一个或多个容器(可以是 docker 容器),这些内部的容器是共享网络资源的,即可以通过 localhost 进行相互访问。 关于 Pod 内是如何做到网络共享的,每个 Pod 启动,内部都会启动一个 pause 容器(google的一个镜像),它使用默认的网络模式,而其他容器的网络都设置给它,以此来完成网络的共享问题。 如图所示: 问题二:Master 是如何将 Pod 调度到指定的 Node 上的?该工作由 kube-scheduler 来完成,整个调度过程通过执行一些列复杂的算法最终为每个 Pod 计算出一个最佳的目标 Node,该过程由 kube-scheduler 进程自动完成。常见的有轮询调度(RR)。当然也有可能,我们需要将 Pod 调度到一个指定的 Node 上,我们可以通过节点的标签(Label)和 Pod 的 nodeSelector 属性的相互匹配,来达到指定的效果。 如图所示: 问题三:各节点、Pod 的信息都是统一维护在哪里的,由谁来维护?从上面的 Pod 调度的角度看,我们得有一个存储中心,用来存储各节点资源使用情况、健康状态、以及各 Pod 的基本信息等,这样 Pod 的调度来能正常进行。 在 K8S 中,采用 etcd 组件 作为一个高可用强一致性的存储仓库,该组件可以内置在 K8S 中,也可以外部搭建供 K8S 使用。 集群上的所有配置信息都存储在了 etcd,为了考虑各个组件的相对独立,以及整体的维护性,对于这些存储数据的增、删、改、查,统一由 kube-apiserver 来进行调用,apiserver 也提供了 REST 的支持,不仅对各个内部组件提供服务外,还对集群外部用户暴露服务。 外部用户可以通过 REST 接口,或者 kubectl 命令行工具进行集群管理,其内在都是与 apiserver 进行通信。如图所示:问题四:外部用户如何访问集群内运行的 Pod ?前面讲了外部用户如何管理 K8S,而我们更关心的是内部运行的 Pod 如何对外访问。使用过 docker 的同学应该知道,如果使用 bridge 模式,在容器创建时,都会分配一个虚拟 IP,该 IP 外部是没法访问到的,我们需要做一层端口映射,将容器内端口与宿主机端口进行映射绑定,这样外部通过访问宿主机的指定端口,就可以访问到内部容器端口了。那么,K8S 的外部访问是否也是这样实现的?答案是否定的,K8S 中情况要复杂一些。因为上面讲的 docker 是单机模式下的,而且一个容器对外就暴露一个服务。在分布式集群下,一个服务往往由多个 Application 提供,用来分担访问压力,而且这些 Application 可能会分布在多个节点上,这样又涉及到了跨主机的通信。这里,K8S 引入了 service 的概念,将多个相同的 Pod 包装成一个完整的 service 对外提供服务,至于获取到这些相同的 Pod,每个 Pod 启动时都会设置 labels 属性,在 service 中我们通过选择器 selector,选择具有相同 name 标签属性的 Pod,作为整体服务,并将服务信息通过 apiserver 存入 etcd 中,该工作由 Service Controller 来完成。 同时,每个节点上会启动一个 kube-proxy 进程,由它来负责服务地址到 Pod 地址的代理以及负载均衡等工作。如图所示:问题五:Pod 如何动态扩容和缩放?既然知道了服务是由 Pod 组成的,那么服务的扩容也就意味着 Pod 的扩容。通俗点讲,就是在需要时将 Pod 复制多份,在不需要后,将 Pod 缩减至指定份数。K8S 中通过 Replication Controller 来进行管理,为每个 Pod 设置一个期望的副本数,当实际副本数与期望不符时,就动态的进行数量调整,以达到期望值。期望数值可以由我们手动更新,或自动扩容代理来完成。如图所示:问题六:各个组件之间是如何相互协作的?最后,讲一下 kube-controller-manager 这个进程的作用。我们知道了 ectd 是作为集群数据的存储中心, apiserver 是管理数据中心,作为其他进程与数据中心通信的桥梁。而 Service Controller、Replication Controller 这些统一交由 kube-controller-manager 来管理,kube-controller-manager 作为一个守护进程,每个 Controller 都是一个控制循环,通过 apiserver 监视集群的共享状态,并尝试将实际状态与期望不符的进行改变。关于 Controller,manager 中还包含了 Node 节点控制器(Node Controller)、资源配额管控制器(ResourceQuota Controller)、命名空间控制器(Namespace Controller)等。如图所示:总结本文通过问答的方式,没有涉及任何深入的实现细节,从整体的角度,概念性的介绍了 K8S 中涉及的基本概念,其中使用相关的包括有:NodePodLabelSelectorReplication ControllerService ControllerResourceQuota ControllerNamespace ControllerNode Controller以及运行进程相关的有:kube-apiserverkube-controller-managerkube-schedulerkubeletkube-proxypause来源:https://github.com/jasonGeng88/blog
  • [技术干货] Deployment部署业务流程简介
    工作负载控制器是K8s的一个抽象概念,用于更高级层次对象,部署和管理Pod。常用工作负载控制器:• Deployment : 无状态应用部署• StatefulSet : 有状态应用部署• DaemonSet : 确保所有Node运行同一个Pod• Job : 一次性任务• Cronjob : 定时任务同时,工作负载控制器也是k8s的资源类型元素,可以直接使用yaml文件拉起(应用)。Deployment是最常用的工作负载控制器,其主要的功能有:• 管理Pod和RS副本集;• 具有上线部署、副本设定、滚动升级、回滚等功能• 提供声明式更新,例如只更新一个新的Image第一步:部署镜像• kubectl apply -f xxx.yaml• kubectl create deployment web --image=nginx:1.15 支持两种命令方式部署,其中create是单次运行,而apply是动态刷新,所以apply更常用。第二步:应用升级,更新镜像• kubectl apply -f xxx.yaml• kubectl set image deployment/web nginx=nginx:1.16• kubectl edit deployment/web 滚动升级在K8s中的实现:• 1个Deployment• 2个ReplicaSet1个RS 控制增加副本数,另一个相应减少副本数,从而达到动态滚动自动升级的效果。第三步:水平扩缩容(启动多实例,提高并发)• 修改yaml里replicas值,再重新apply拉起• kubectl scale deployment web --replicas=10第四步:回滚(发布失败恢复之前正常运行的版本)kubectl rollout history deployment/web # 查看历史发布版本kubectl rollout undo deployment/web # 回滚上一个版本kubectl rollout undo deployment/web --to-revision=2 # 回滚历史指定版本注:回滚是重新部署某一次部署时的状态,即当时版本所有配置最后,项目下线:kubectl delete deploy/webkubectl delete svc/web
  • [技术干货] kubeconfig配置文件的作用
    使用用kubeadm快速部署k8s后,在node节点上执行kubectl命令,会报错。[root@k8s-node1 ~]# kubectl get nodeThe connection to the server localhost:8080 was refused - did you specify the right host or port?这是因为kube-apiserver有两种访问方式:1.localhost:8080 这个是kube-apiserver非安全端口,不需要认证,在master上面可以执行成功是因为kubeadm运行过程中默认会生成配置文件。2.master EIP:6443 外网的方式访问master上的kube-apiserver监听的6443安全端口。[root@k8s-master ~]# netstat -tpln | grep 6443tcp6       0      0 :::6443                 :::*                    LISTEN      92617/kube-apiserve  kubectl默认先连接8080,如果你配置kubeconfig(.kube/config)就直接走这个配置连接的安全端口。kubeadm最后的命令提示中的第二步就是将配置文件拷贝到k8s里面。mkdir -p $HOME/.kube  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config  sudo chown $(id -u):$(id -g) $HOME/.kube/config可以看到读取到的是该配置文件 关闭8080端口就是希望你使用配置文件去连接安全端口,这样是安全的,非安全端口是绝对不能对外提供服务的,因为如果对外提供服务别人扫描到你api做一些恶意的操作,整个集群可能就挂了,即使有这个端口也是监听在本地,也就是只能这台机器去连接。 为了让Node使用kubectl命令,可以通过scp将master的配置文件传到node的相关目录下。[root@k8s-master ~]# scp /root/.kube/config  root@192.168.x.x:~ [root@k8s-node1 ~]# lsanaconda-ks.cfg  config[root@k8s-node1 ~]# kubectl get node --kubeconfig=config NAME         STATUS   ROLES    AGE    VERSIONk8s-master   Ready    master   3d7h   v1.19.0k8s-node1    Ready       3d6h   v1.19.0kubeconfig生成与文件结构kubeconfig这个文件是通过kubectl config指令生成的clusters:- cluster:    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM1ekNDQWMrZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJd01URXhOVEEyTlRZeU5sb1hEVE13TVRFeE16QTJOVFl5Tmxvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBSmZsCmtaVVhUcVJ3ZjJVeDdqS1pjQURvaHV1aHNXcHAvK2NIOEF1MVpmR3JqN0lTb3VoelVISkZ5cGR5ekdoTDFBRHgKMTkxVlVCN1ZCWlk4cXBDRHYyRnZvWkRFbFVYR1JrTFFDT0lxc1hOVUt3ZU0xdnJqZnpZVW5ZNGN6NDhKNDdpTgpnUjJHRGtsWUlrZFpGZEU1ekN2eitldEtEVVUzdE5GV0djL00yZFE0NUIxNGZlTldpTUR3T0l3dTBSSWRvYmpnCndmSnhoVlJHMmgzdEplL0RpUjQ2cXI1NEdMVUU2VXNDUGJvZ0JxNTVBakt2c2NiOWUzeGdzMVJhZW1BdFZhd08KSFNjRkRDYWhBZDVPUlgzMlIzSGNoRnY2QmFwczgyb0dqUDBLOEY1RXNQWkFYQXFoK3c0UTFMRWQ2aHRuQWhyWAoxcmJ5cTF4eUNESnhhbENaSHBjQ0F3RUFBYU5DTUVBd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZPZXFad29TeUxrVDVKWXlRNURMamUzRFRHUjJNQTBHQ1NxR1NJYjMKRFFFQkN3VUFBNElCQVFCemtMRXMzUGhIN08wYWs5VWlTbFhDVTljK1RoYlZaTmZVUStKS1JpQU5KQys5Qm8vZApLdUlLYWhxQlE5UkprSk53TmVwT0NJOWxzcGJ4TGtHK3ArYktHV29Yb25CME5RdnZoZTRQd0p0dmdUcGlhVmVYCmNLejhUMDBRT1YyRzR0WEtmaTViK0dvZDA3NktlZm4zbm00U0l1VDh6bmNDclUxeHRpQTRSU3RQRVZZZTRQalAKY2p6MHJVS3BnTmhJL0lYc2JPVDNYV0hFNE4vU0VLcmtIYkRJNFpEUGRYa2gxd3piM1FZODFuZTh1enBNQVJ5VwpLbkx6R1NRaGJ0WTlWRUZkdlhGK0wreWFrQjcrR29xa1lJa1BNdURveFRoeTBuMFJjZStSTUhtZkFQSEh2RDFyCjdSNC9xdlpBLzA4Q0hxb3ZDcCsxUzNXbFE5WE5MRzE3TWExTAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==    server: https://192.168.x.x:6443  name: kubernetes在上面部分是配置集群的,即要连接的k8s集群主节点IP是多少,并且里面包含了相关证书。Context指定上下文,和指定当前使用哪个上下文。在配置文件当中可能会存在多个集群,这是只有一个集群。如果你再搭建一个集群,是可以将两个配置文件进行合并,两个配置文件合并在一个配置文件里面。合并在一起就可以使用这一个配置文件去切换着连接两个不通的集群,切换的操作实际上就是指定上下文的操作。上下文引用了集群信息,和客户端信息。
  • [技术干货] k8s查询资源列表
    使用kubectl api-resources命令可以查看k8s的资源,以及其缩写。[centos@k8s-master ~]# kubectl api-resourcesNAME                              SHORTNAMES   APIGROUP                       NAMESPACED   KINDbindings                                                                      true         Bindingcomponentstatuses                 cs                                          false        ComponentStatusconfigmaps                        cm                                          true         ConfigMapendpoints                         ep                                          true         Endpointsevents                            ev                                          true         Eventlimitranges                       limits                                      true         LimitRangenamespaces                        ns                                          false        Namespacenodes                             no                                          false        Nodepersistentvolumeclaims            pvc                                         true         PersistentVolumeClaimpersistentvolumes                 pv                                          false        PersistentVolumepods                              po                                          true         Podpodtemplates                                                                  true         PodTemplatereplicationcontrollers            rc                                          true         ReplicationControllerresourcequotas                    quota                                       true         ResourceQuotasecrets                                                                       true         Secretserviceaccounts                   sa                                          true         ServiceAccountservices                          svc                                         true         Service几种常见的资源:Endpoints: 用于记录每个service的pod的真实物理ip和port的对应关系,包括service是TCP还是UDP等。Namespace: 是一个全局的list,保存集群中所有的命名空间。Node: 是一个全局的list,详细记录了每个节点的name, labels, PodCIDR, host IP, hostname, 总资源(cpu,内存),可分配资源,各心跳状态(网络,内存,硬盘,PID数量,kubelet等),kubelet的物理port,各k8s组件image信息,node环境信息(os, CRI version, kubeProxy version, kubelet version等)。PersistentVolume: 是一个全局的object,记录了所有的持久化存储设备的信息(类似于node)Pod: 是对于使用k8s的开发者而言最重要的资源,其中包含ownerReference (Node, Demonset等),containers相关信息(image,启动命令,probe,资源信息,存储信息,结束时行,是否接受service注入环境变量为等),网络设置(dns设置,port设置等),集群调度相关信息(优先级,tolerations,affinity,重启规则等),pod状态(hostIP,podIP,启动时间等)Replication Controller: 是系统内建的最常用的controller,用来保证Pod的实际运行数量满足定义。如果不足则负责创建,如果过多则通知一些pod terminate。Service: 非常重要且常见的资源,用于对外提供统一的Service IP和port,将流量负载均衡调整至集群中多个pod。Daemenset: 常见的Pod set种类,用于控制每种pod状态,在定义的范围内,且在每node上最多有一个。Replicaset: 常见的Pod set种类但现在基本上不直接使用,用于控制每种pod的状态。在定义的范围内。一个Replicasets中的各个pod都应是等同的、可互换的,即对外表现完全相同。Deployment: 最常见的Pod set种类,可以拥有Replicasets和Pod。用于控制拥有的资源的状态。StatefulSet: 常见的Pod set种类。和Deployment的区别之处是它控制的pod不是可互换的而是在整个生命周期有不变的标签。这样,每个pod可以有自己的DNS名,存储等。即使pod被删除后这些信息也会被恢复。CronJob: 定时运行Job pod的资源。Job: 常见的Pod set种类,会创建一定数量的pod,仅当特定数量的pod成功结束后这个Job才算成功结束。创建的pod在结束后不会被重启。
  • [技术干货] k8s的高可用架构原理
    k8s的高可用架构,也就是扩容多Master架构。这是因为,k8s作为容器集群系统,通过健康检查+重启策略实现了Pod故障自我修复能力,通过调度算法实现将Pod分布式部署,监控其预期副本数,并根据Node失效状态自动在正常Node启动Pod,实现了应用层的高可用性。Node节点是不需要考虑高可用架构。而Master节点扮演着总控中心的角色,通过不断与工作节点上的Kubelet和kube-proxy进行通信来维护整个集群的健康工作状态。如果Master节点故障,将无法使用kubectl工具或者API任何集群管理而Master节点主要有三个服务kube-apiserver、kube-controller-mansger和kube-scheduler,其中kube-controller-mansger和kube-scheduler组件自身通过选择机制已经实现了高可用,就是说,如果集群里配置了多个kube-controller-mansger和kube-scheduler组件,他们会根据自己的竞争机制选出主用组件。所以Master高可用主要针对kube-apiserver组件,而该组件是以HTTP API提供服务,因此对他高可用实际上与Web服务器类似,增加负载均衡器(如nginx)对其负载均衡即可,而且可以继续水平扩容。针对Kubernetes集群,高可用性还应包含以下两个层面的考虑:Etcd数据库的高可用性和K8s Master组件的高可用性。 而Etcd已经采用多个节点组建集群实现高可用,所以对Master节点高可用就等同于对kube-apiserver的负载均衡的部署实施。
  • [技术干货] [转]Kubernetes 资源预留配置
    Kubernetes 的节点可以按照节点的资源容量进行调度,默认情况下 Pod 能够使用节点全部可用容量。这样就会造成一个问题,因为节点自己通常运行了不少驱动 OS 和 Kubernetes 的系统守护进程。除非为这些系统守护进程留出资源,否则它们将与 Pod 争夺资源并导致节点资源短缺问题。 当我们在线上使用 Kubernetes 集群的时候,如果没有对节点配置正确的资源预留,我们可以考虑一个场景,由于某个应用无限制的使用节点的 CPU 资源,导致节点上 CPU 使用持续100%运行,而且压榨到了 kubelet 组件的 CPU 使用,这样就会导致 kubelet 和 apiserver 的心跳出问题,节点就会出现 Not Ready 状况了。默认情况下节点 Not Ready 过后,5分钟后会驱逐应用到其他节点,当这个应用跑到其他节点上的时候同样100%的使用 CPU,是不是也会把这个节点搞挂掉,同样的情况继续下去,也就导致了整个集群的雪崩,集群内的节点一个一个的 Not Ready 了,后果是非常严重的,或多或少的人遇到过 Kubernetes 集群雪崩的情况,这个问题也是面试的时候镜像询问的问题。 要解决这个问题就需要为 Kubernetes 集群配置资源预留,kubelet 暴露了一个名为 Node Allocatable 的特性,有助于为系统守护进程预留计算资源,Kubernetes 也是推荐集群管理员按照每个节点上的工作负载来配置 Node Allocatable。 本文的操作环境为 Kubernetes V1.17.11 版本,Docker 和 Kubelet 采用的 cgroup 驱动为 systemd。 Node AllocatableKubernetes 节点上的 Allocatable 被定义为 Pod 可用计算资源量,调度器不会超额申请 Allocatable,目前支持 CPU, memory 和 ephemeral-storage 这几个参数。 我们可以通过 kubectl describe node 命令查看节点可分配资源的数据:$ kubectl describe node ydzs-node4......Capacity:  cpu:                4  ephemeral-storage:  17921Mi  hugepages-2Mi:      0  memory:             8008820Ki  pods:               110Allocatable:  cpu:                4  ephemeral-storage:  16912377419  hugepages-2Mi:      0  memory:             7906420Ki  pods:               110......可以看到其中有 Capacity 与 Allocatable 两项内容,其中的 Allocatable 就是节点可被分配的资源,我们这里没有配置资源预留,所以默认情况下 Capacity 与 Allocatable 的值基本上是一致的。下图显示了可分配资源和资源预留之间的关系: Node AllocatableKubelet Node Allocatable 用来为 Kube 组件和 System 进程预留资源,从而保证当节点出现满负荷时也能保证 Kube 和 System 进程有足够的资源。目前支持 cpu, memory, ephemeral-storage 三种资源预留。Node Capacity 是节点的所有硬件资源,kube-reserved 是给 kube 组件预留的资源,system-reserved 是给系统进程预留的资源,eviction-threshold 是 kubelet 驱逐的阈值设定,allocatable 才是真正调度器调度 Pod 时的参考值(保证节点上所有 Pods 的 request 资源不超过Allocatable)。节点可分配资源的计算方式为:Node Allocatable Resource = Node Capacity - Kube-reserved - system-reserved - eviction-threshold配置资源预留Kube 预留值首先我们来配置 Kube 预留值,kube-reserved 是为了给诸如 kubelet、容器运行时、node problem detector 等 kubernetes 系统守护进程争取资源预留。要配置 Kube 预留,需要把 kubelet 的 --kube-reserved-cgroup 标志的值设置为 kube 守护进程的父控制组。 不过需要注意,如果 --kube-reserved-cgroup 不存在,Kubelet 不会创建它,启动 Kubelet 将会失败。 比如我们这里修改 node-ydzs4 节点的 Kube 资源预留,我们可以直接修改 /var/lib/kubelet/config.yaml 文件来动态配置 kubelet,添加如下所示的资源预留配置:apiVersion: kubelet.config.k8s.io/v1beta1......enforceNodeAllocatable:- pods- kube-reserved  # 开启 kube 资源预留kubeReserved:  cpu: 500m  memory: 1Gi  ephemeral-storage: 1GikubeReservedCgroup: /kubelet.slice  # 指定 kube 资源预留的 cgroup修改完成后,重启 kubelet,如果没有创建上面的 kubelet 的 cgroup,启动会失败:$ systemctl restart kubelet$ journalctl -u kubelet -f......Aug 11 15:04:13 ydzs-node4 kubelet[28843]: F0811 15:04:13.653476   28843 kubelet.go:1380] Failed to start ContainerManager Failed to enforce Kube Reserved Cgroup Limits on "/kubelet.slice": ["kubelet"] cgroup does not exist上面的提示信息很明显,我们指定的 kubelet 这个 cgroup 不存在,但是由于子系统较多,具体是哪一个子系统不存在不好定位,我们可以将 kubelet 的日志级别调整为 v=4,就可以看到具体丢失的 cgroup 路径:$ vi /var/lib/kubelet/kubeadm-flags.envKUBELET_KUBEADM_ARGS="--v=4 --cgroup-driver=systemd --network-plugin=cni"然后再次重启 kubelet:$ systemctl daemon-reload$ systemctl restart kubelet再次查看 kubelet 日志:$ journalctl -u kubelet -f......Sep 09 17:57:36 ydzs-node4 kubelet[20427]: I0909 17:57:36.382811   20427 cgroup_manager_linux.go:273] The Cgroup [kubelet] has some missing paths: [/sys/fs/cgroup/cpu,cpuacct/kubelet.slice /sys/fs/cgroup/memory/kubelet.slice /sys/fs/cgroup/systemd/kubelet.slice /sys/fs/cgroup/pids/kubelet.slice /sys/fs/cgroup/cpu,cpuacct/kubelet.slice /sys/fs/cgroup/cpuset/kubelet.slice]Sep 09 17:57:36 ydzs-node4 kubelet[20427]: I0909 17:57:36.383002   20427 factory.go:170] Factory "systemd" can handle container "/system.slice/run-docker-netns-db100461211c.mount", but ignoring.Sep 09 17:57:36 ydzs-node4 kubelet[20427]: I0909 17:57:36.383025   20427 manager.go:908] ignoring container "/system.slice/run-docker-netns-db100461211c.mount"Sep 09 17:57:36 ydzs-node4 kubelet[20427]: F0909 17:57:36.383046   20427 kubelet.go:1381] Failed to start ContainerManager Failed to enforce Kube Reserved Cgroup Limits on "/kubelet.slice": ["kubelet"] cgroup does not exist注意:systemd 的 cgroup 驱动对应的 cgroup 名称是以 .slice 结尾的,比如如果你把 cgroup 名称配置成 kubelet.service,那么对应的创建的 cgroup 名称应该为 kubelet.service.slice。如果你配置的是 cgroupfs 的驱动,则用配置的值即可。无论哪种方式,通过查看错误日志都是排查问题最好的方式。现在可以看到具体的 cgroup 不存在的路径信息了:The Cgroup [kubelet] has some missing paths: [/sys/fs/cgroup/cpu,cpuacct/kubelet.slice /sys/fs/cgroup/memory/kubelet.slice /sys/fs/cgroup/systemd/kubelet.slice /sys/fs/cgroup/pids/kubelet.slice /sys/fs/cgroup/cpu,cpuacct/kubelet.slice /sys/fs/cgroup/cpuset/kubelet.slice]所以要解决这个问题也很简单,我们只需要创建上面的几个路径即可:$ mkdir -p /sys/fs/cgroup/cpu,cpuacct/kubelet.slice$ mkdir -p /sys/fs/cgroup/memory/kubelet.slice$ mkdir -p /sys/fs/cgroup/systemd/kubelet.slice$ mkdir -p /sys/fs/cgroup/pids/kubelet.slice$ mkdir -p /sys/fs/cgroup/cpu,cpuacct/kubelet.slice$ mkdir -p /sys/fs/cgroup/cpuset/kubelet.slice创建完成后,再次重启:$ systemctl restart kubelet$ journalctl -u kubelet -f......Sep 09 17:59:41 ydzs-node4 kubelet[21462]: F0909 17:59:41.291957   21462 kubelet.go:1381] Failed to start ContainerManager Failed to enforce Kube Reserved Cgroup Limits on "/kubelet.slice": failed to set supported cgroup subsystems for cgroup [kubelet]: failed to set config for supported subsystems : failed to write 0 to hugetlb.2MB.limit_in_bytes: open /sys/fs/cgroup/hugetlb/kubelet.slice/hugetlb.2MB.limit_in_bytes: no such file or directory可以看到还有一个 hugetlb 的 cgroup 路径不存在,所以继续创建这个路径:$ mkdir -p /sys/fs/cgroup/hugetlb/kubelet.slice$ systemctl restart kubelet重启完成后就可以正常启动了,启动完成后我们可以通过查看 cgroup 里面的限制信息校验是否配置成功,比如我们查看内存的限制信息:$ cat /sys/fs/cgroup/memory/kubelet.slice/memory.limit_in_bytes1073741824  # 1Gi现在再次查看节点的信息:$ kubectl describe node ydzs-node4......Addresses:  InternalIP:  10.151.30.59  Hostname:    ydzs-node4Capacity:  cpu:                4  ephemeral-storage:  17921Mi  hugepages-2Mi:      0  memory:             8008820Ki  pods:               110Allocatable:  cpu:                3500m  ephemeral-storage:  15838635595  hugepages-2Mi:      0  memory:             6857844Ki  pods:               110......可以看到可以分配的 Allocatable 值就变成了 Kube 预留过后的值了,证明我们的 Kube 预留成功了。系统预留值我们也可以用同样的方式为系统配置预留值,system-reserved 用于为诸如 sshd、udev 等系统守护进程争取资源预留,system-reserved 也应该为 kernel 预留 内存,因为目前 kernel 使用的内存并不记在 Kubernetes 的 pod 上。但是在执行 system-reserved 预留操作时请加倍小心,因为它可能导致节点上的关键系统服务 CPU 资源短缺或因为内存不足而被终止,所以如果不是自己非常清楚如何配置,可以不用配置系统预留值。 同样通过 kubelet 的参数 --system-reserved 配置系统预留值,但是也需要配置 --system-reserved-cgroup 参数为系统进程设置 cgroup。请注意,如果 --system-reserved-cgroup 不存在,kubelet 不会创建它,kubelet 会启动失败。驱逐阈值上面我们还提到可分配的资源还和 kubelet 驱逐的阈值有关。节点级别的内存压力将导致系统内存不足,这将影响到整个节点及其上运行的所有 Pod,节点可以暂时离线直到内存已经回收为止,我们可以通过配置 kubelet 驱逐阈值来防止系统内存不足。驱逐操作只支持内存和 ephemeral-storage 两种不可压缩资源。当出现内存不足时,调度器不会调度新的 Best-Effort QoS Pods 到此节点,当出现磁盘压力时,调度器不会调度任何新 Pods 到此节点。 我们这里为 ydzs-node4 节点配置如下所示的硬驱逐阈值:# /var/lib/kubelet/config.yaml......evictionHard:  # 配置硬驱逐阈值  memory.available: "300Mi"  nodefs.available: "10%"enforceNodeAllocatable:- pods- kube-reservedkubeReserved:  cpu: 500m  memory: 1Gi  ephemeral-storage: 1GikubeReservedCgroup: /kubelet.slice......我们通过 --eviction-hard 预留一些内存后,当节点上的可用内存降至保留值以下时,kubelet 将尝试驱逐 Pod,$ kubectl describe node ydzs-node4......Addresses:  InternalIP:  10.151.30.59  Hostname:    ydzs-node4Capacity:  cpu:                4  ephemeral-storage:  17921Mi  hugepages-2Mi:      0  memory:             8008820Ki  pods:               110Allocatable:  cpu:                3500m  ephemeral-storage:  15838635595  hugepages-2Mi:      0  memory:             6653044Ki  pods:               110......配置生效后再次查看节点可分配的资源可以看到内存减少了,临时存储没有变化是因为硬驱逐的默认值就是 10%。也是符合可分配资源的计算公式的:Node Allocatable Resource = Node Capacity - Kube-reserved - system-reserved - eviction-threshold到这里我们就完成了 Kubernetes 资源预留的配置。                                                     原文链接:https://mp.weixin.qq.com/s/oYBzI9Zh-_RtKgtyXCO8kQ
  • [问题求助] kubernetes操作文档错误,此处的源是404
  • [认证交流] 关于 kubernetes的微认证的问题
    这个topic是需要自己搞的?你们是自己购买的,还是使用了代金券啊
  • [认证交流] 【我与华为云认证】微认证之轻松玩转Kubernetes
    Kubernetes作为容器编排工具,简化容器管理,提升工作效率而颇受青睐,我们可以借助云容器引擎CCE平台快速搭建 Kubernetes环境,轻松玩转 Kubernetes。什么是容器?容器为Ap提供独立的、受控的运行环境,是_种轻量级的操作系统虚拟Concept for create environment for software, without disturbing the rest of the core operating system running job filesystem简单的容器: SandBox(沙盒、沙箱)Kubernetes-大海航行的舵手K8s集群主要包括两个部分: Master节点(管理节点)和Node节点(计算节点)Master节点主要还是负责管理和控制。Node节点是工作负载节点,里面是具体的容器。Master节点Master节点提供的集群控制,对集群做出全局性决策,例如调度等。通常在 master节点上不运行用户容器。Master节点包括AP| Server、 Scheduler、 Controller manager、etcdAPI Server:整个系统的对外接囗Scheduler:集群内部的资源进行调度Controller Manager:负责管理控制器etd: Kubernetes的后端存储Node节点节点组件运行在每一个Node节点上,维护运行的pod并提供 kubernetes运行时环境。Node节点包括Pod、 Docker、 kubelet、kube-proy、 Fluent、kube-dns(可选)Pod: Kubernetes最基本的操作单元;Docker:创建容器;Kubelet:负责监视指派到它所在Node上的Pod,包括创建、修改、监控、删除等Kube-proxy:负责为Pod对象提供代理  Fluent:主要负责日志收集、存储与查询。Kubernetes最小管理单元-PoDPod是 Kubernetes管理的最小基础单元。一个Pod中封装了:一个或多个紧耦合的应用容器,存储资源,独立的IP,容器运行的选项相同Pod中的任何容器都将其享相同的名称空间和本地网络。容器可以很容易地与其他容器在相同的容器中进行通信。有状态应用和无状态应用无状态应用有状态的服务,从部署开始,这些容器就开始与上游镜像不同了,时间越长它们的差异越大,每个运行的应用程序都至少有一个小状态,(差异),但对于“无状态”应用程序来说,状态(差异)很小,而目可以进行快速替换有状态应用无状态服务,易于部署且易于扩展。如果流量上升,则只需添加更多的负载平衡上游容器镜像和基础架构中正在运行的容器其实几乎没有区别;可以随时被替代,而且容器实例切换过程中几乎不需要耗费“切换成本
  • [技术干货] 改善 Kubernetes 上的 JVM 预热问题
    JVM 预热是一个非常头疼而又难解决的问题。基于 JVM 的应用程序在达到最高性能之前,需要一些时间来“预热”。当应用程序启动时,通常会从较低的性能开始。这归因于像即时(JIT)编译这些事儿,它会通过收集使用配置文件信息来优化常用代码。最终这样的负面影响是,与平均水平相比,预热期间接收的 request 将具有非常高的响应时间。在容器化、高吞吐量、频繁部署和自动伸缩的环境中,这个问题可能会加剧。在这篇文章中,我们将讨论在运行在 Kubernetes 集群中的 Java 服务如何解决 JVM 预热问题的经验。起因几年前,我们逐步从整体中分离出服务,开始在 Kubernetes 上进行迁移到基于微服务的体系结构。大多数新服务都是在 Java 中开发的。当我们在印度市场上运行一个这样的服务时,我们第一次遇到了这个问题。我们通过负载测试进行了通常的容量规划过程,并确定 N 个 Pod 足以处理超过预期的峰值流量。尽管该服务在轻松处理高峰流量,但我们在部署过程中发现了问题。我们的每个 Pod 在高峰时间处理的 RPM 都超过 10k,而我们使用的是 Kubernetes 滚动更新机制。在部署过程中,服务的响应时间会激增几分钟,然后再稳定到通常的稳定状态。在我们的仪表板中,会看到类似的图表:与此同时,我们开始收到来自部署时间段内的大量投诉,几乎都关于高响应时间和超时错误。第一步:花钱解决问题我们很快意识到这个问题与 JVM 预热阶段有关,但当时有其他的重要事情,因此我们没有太多时间进行调查,直接尝试了最简单的解决方案——增加 Pod 数量,以减少每个 Pod 的吞吐量。我们将 Pod 数量增加了近三倍,以便每个 Pod 在峰值处理约 4k RPM 的吞吐量。我们还调整了部署策略,以确保一次最多滚动更新 25%(使用 maxSurge 和 maxUnavailable 参数)。这样就解决了问题,尽管我们的运行容量是稳定状态所需容量的 3 倍,但我们能够在我们的服务中或任何相关服务中没有问题地进行部署。随着后面几个月里更多的迁移服务,我们开始在其他服务中常常看到这个问题。因此我们决定花一些时间来调查这个问题并找到更好的解决方案。第二步:预热脚本在仔细阅读了各种文章后,我们决定尝试一下预热脚本。我们的想法是运行一个预热脚本,向服务发送几分钟的综合请求,来完成 JVM 预热,然后再允许实际流量通过。为了创建预热脚本,我们从生产流量中抓取了实际的 URL。然后,我们创建了一个 Python 脚本,使用这些 URL 发送并行请求。我们相应地配置了 readiness 探针的 initialDelaySeconds,以确保预热脚本在 Pod 为 ready 并开始接受流量之前完成。令人吃惊的是,尽管结果有一些改进,但并不显著。我们仍然经常观察到高响应时间和错误。此外,预热脚本还带来了新的问题。之前,Pod 可以在 40-50 秒内准备就绪,但用了脚本,它们大约需要 3 分钟,这在部署期间成为了一个问题,更别说在自动伸缩期间。我们在预热机制上做了一些调整,比如允许预热脚本和实际流量有一个短暂的重叠期,但也没有看到显著的改进。最后,我们认为预热脚本的收益太小了,决定放弃。第三步:启发式发现由于预热脚本想法失败了,我们决定尝试一些启发式技术-GC(G1、CMS 和 并行)和各种 GC 参数堆内存CPU 分配经过几轮实验,我们终于取得了突破。测试的服务配置了 Kubernetes 资源 limits: 我们将 CPU request 和 limit 增加到 2000m,并部署服务以查看影响,可以看到响应时间和错误有了巨大的改进,比预热脚本好得多。 第一个 Deployment(大约下午 1 点)使用 2 个 CPU 配置,第二个 Deployment (大约下午 1:25)使用原来 1 个 CPU 配置 为了进一步测试,我们将配置升级到 3000m CPU,令我们惊讶的是,问题完全消失了。正如下面看到的,响应时间没有峰值。 具有 3 个 CPU 配置的 Deployment 很快,我们就发现问题出在 CPU 节流上。在预热阶段,JVM 需要比平均稳定状态下更多的 CPU 时间,但 Kubernetes 资源处理机制(CGroup)根据配置的 limits,从而限制了 CPU。 有一个简单的方法可以验证这一点。Kubernetes 公开了一个每个 Pod 的指标,container_cpu_cfs_throttled_seconds_total 表示这个 Pod 从开始到现在限制了多少秒 CPU。如果我们用 1000m 配置观察这个指标,应该会在开始时看到很多节流,然后在几分钟后稳定下来。我们使用该配置进行了部署,这是 Prometheus 中所有 Pod 的 container_cpu_cfs_throttled_seconds_total 图: 正如预期,在容器启动的前 5 到 7 分钟有很多节流,大部分在 500 秒到 1000 秒之间,然后稳定下来,这证实了我们的假设。 当我们使用 3000m CPU 配置进行部署时,观察到下图: CPU 节流几乎可以忽略不计(几乎所有 Pod 都不到 4 秒)。第四步:改进尽管我们发现了这个问题的根本,但就成本而言,该解决方案并不太理想。因为有这个问题的大多数服务都已经有类似的资源配置,并且在 Pod 数量上超额配置,以避免部署失败,但是没有一个团队有将 CPU 的 request、limits 增加三倍并相应减少 Pod 数量的想法。这种解决方案实际上可能比运行更多的 Pod 更糟糕,因为 Kubernetes 会根据 request 调度 Pod,找到具有 3 个空闲 CPU 容量的节点比找到具有 1 个空闲 CPU 的节点要困难得多。它可能导致集群自动伸缩器频繁触发,从而向集群添加更多节点。我们又回到了原点 但是这次有了一些新的重要信息。现在问题是这样的:       在最初的预热阶段(持续几分钟),JVM 需要比配置的 limits(1000m)更多的 CPU(大约 3000m)。预热后,即使 CPU limits 为 1000m,JVM 也可以充分发挥其潜力。Kubernetes 会使用 request 而不是 limits 来调度 Pod。我们清楚地了解问题后,答案就出现了——Kubernetes Burstable QoS。 Kubernetes 根据配置的资源 request 和 limits 将 QoS 类分配给 Pod。 到目前为止,我们一直在通过指定具有相等值的 request 和 limits(最初是 1000m,然后是 3000m)来使用 Guaranteed QoS。尽管 Guaranteed QoS 有它的好处,但我们不需要在整个 Pod 生命周期中独占 3 个 CPU,我们只需要在最初的几分钟内使用它。Burstable QoS 允许我们指定小于 limits 的 request,例如: 由于 Kubernetes 使用 request 中指定的值来调度 Pod,它会找到具有 1000m CPU 容量的节点来调度这个 Pod。但是由于 3000m 的 limits 要高得多,如果应用程序在任何时候都需要超过 1000m 的 CPU,并且该节点上有空闲的 CPU 容量,那么就不会在 CPU 上限制应用程序。如果可用,它最多可以使用 3000m。 这非常符合我们的问题。在预热阶段,当 JVM 需要更多的 CPU 时,它可以获取需要的 CPU。JVM 被优化后,可以在 request 范围内全速运行。这允许我们使用集群中的冗余的资源(足够可用时)来解决预热问题,而不需要任何额外的成本。 最后,进行假设测试。我们更改了资源配置并部署了应用程序,成功了!我们做了更多的测试以验证结果一致。此外,我们监控了 container_cpu_cfs_throttled_seconds_total 指标,以下是其中一个 Deployment 的图表: 正如我们所看到的,这张图与 3000m CPU 的 Guaranteed QoS 设置非常相似。节流几乎可以忽略不计,它证实了具有 Burstable QoS 的解决方案是有效的。为了使 Burstable QoS 解决方案正常工作,节点上需要有可用的冗余资源。这可以通过两种方式验证:就 CPU 而言,节点资源未完全耗尽;工作负载未使用 request 的 100% CPU。结论尽管花了一些时间,最终找到了一个成本效益高的解决方案。Kubernetes 资源限制是一个重要的概念。我们在所有基于 Java 的服务中实现了该解决方案,部署和自动扩展都运行良好,没有任何问题。要点:在为应用程序设置资源限制时要仔细考虑。花些时间了解应用程序的工作负载并相应地设置 request 和 limits。了解设置资源限制和各种 QoS 类的含义。通过 monitoring/alertingcontainer_cpu_cfs_throttled_seconds_total 来关注 CPU 节流。如果观察到过多的节流,可以调整资源限制。使用 Burstable QoS 时,确保在 request 中指定了稳定状态所需的容量。文章来源:K8sMeetup社区译者:Bach
  • [技术干货] 深入研究Kubernetes的基础架构
    架构首先,建议你的架构尽可能模块化,以便在将来有需要时可以灵活地进行增量更改。入口点:DNS在任何典型的基础架构中(无论是否为云原生),DNS服务器都必须首先解析请求消息以返回服务器的IP地址。设置DNS应该基于所需的可用性。如果你需要更高的可用性,则要根据可用性级别,将服务器分布在多个云提供商中。内容分发网络(CDN)在某些情况下,你可能需要为用户提供尽可能短的延迟,并减少服务器上的负载。这是内容分发网络(CDN)发挥主要作用的地方。客户端是否经常从服务器请求一组静态资源?你是否需要提高向用户交付内容的速度,同时减少服务器上的负载?在这种情况下,为一组静态资源提供服务的CDN有助于减少用户的延迟和服务器上的负载。你所有的内容都是动态的吗?你是否需要以一定程度的延迟为用户提供内容以降低复杂性?还是你的应用流量很少?在这种情况下,使用CDN可能没有太大意义,你可以将所有流量直接发送到Global Load Balancer。CDN提供商包括 Cloudfare CDN, Fastly, Akamai CDN, Stackpath,以及云提供商–Google云平台的Cloud CDN ,亚马逊的 CloudFront , 微软的Azure CDN 等 。负载均衡器如果有你的CDN无法满足的请求,则该请求将接下来到达你的负载均衡器。负载均衡器是具有区域性的IP,也可以是全局性的Anycast IP。在某些情况下,你还可以使用负载均衡器来管理内部流量。除了将流量路由和代理到适当的后端服务之外,负载均衡器还可以负责SSL终止,与CDN集成甚至管理网络流量的某些方面。尽管确实存在硬件负载均衡器,但软件负载均衡器提供了更大的灵活性,低成本和可伸缩性。与CDN相似,云提供商也提供负载均衡(例如GCP的GLB,AWS的ELB,Azure的ALB等)。尽管你应该始终从小做起,但是负载均衡器将允许你逐步扩展:网络和安全架构在你的体系结构中要注意的下一件重要事情是网络本身。如果要提高安全性,则可能需要使用私有集群。在那里,你可以管理入站和出站流量,在NAT之后屏蔽IP地址,隔离跨VPC具有多个子网的网络,等等。设置网络的方式通常取决于你需要的灵活性程度以及实现方式。建立正确的网络关系就是尽可能减少攻击面,同时仍然允许常规操作。使用网络来保护你的基础架构还涉及使用正确的规则和限制来设置防火墙,以便你仅允许进出各自后端服务的入站和出站流量。在许多情况下,可以通过设置堡垒机来保护这些专用集群,因为你需要向公共网络公开的只有堡垒机(通常是在与集群相同的网络)。一些云提供商还提供了针对零信任安全性的定制解决方案。例如,GCP为用户提供了身份识别代理(IAP),可以代替典型的VPN。一旦处理完所有这些,联网的下一步就是根据你的情况在集群本身内设置联网。它可能涉及以下任务:在集群内设置服务发现(可由CoreDNS处理)。根据需要设置服务网格(例如LinkerD,Istio,Consul等)设置入口控制器和API网关(例如Nginx,Ambassador,Kong,Gloo等)使用CNI设置网络插件,以促进集群内的联网。设置网络策略以简化服务间通信,并使用各种服务类型根据需要公开服务。使用协议和工具(例如GRPC,Thrift或HTTP)在各种服务之间建立服务间通信。设置A/B测试,如果你使用Istio或Linkerd之类的服务网格,则可以更加轻松。Kubernetes如果你使用的是GKE,EKS,AKS,AKS等托管集群,则Kubernetes会自动进行管理,从而使用户摆脱了很多麻烦。如果你自己管理Kubernetes,则需要注意很多事情,例如备份和加密etcd存储,在集群中的各个节点之间建立网络,定期为节点打补丁,管理集群升级。仅当你有足够的能力进行此工作时,才建议这样做。站点可靠性工程(SRE)当你维护复杂的基础架构时,拥有正确的可观察性非常重要,这样你就可以提前发现错误,并预测可能的变化,识别异常,深入探究问题所在。现在,这将需要你使用代理。这些代理公开应用程序的指标。如果你将服务网格与Sidecar一起使用,它们通常会附带指标而无需你自己进行任何自定义开发。在任何这种情况下,像Prometheus这样的工具都可以充当时间序列数据库来为你收集所有指标,而像OpenTelemetry这样的工具可以通过内置导出程序从应用程序和各种工具中获取指标。Alertmanager之类的工具可以将通知和警报发送到多个渠道,而Grafana将提供仪表板以在一处可视化所有内容,从而使用户可以整体了解整个基础架构。总而言之,以下涉及Prometheus的可观察性系统:具有这样的复杂系统还需要使用日志聚合系统,以便将所有日志都可以流式传输到单个位置,以便于调试。在这里,人们倾向于将ELK或EFK堆栈与Logstash或FluentD一起使用,以根据你的约束为你进行日志聚合和过滤。在这个领域中也有新工具出现,例如Loki和Promtail。使用FluentD这样的日志聚合系统可以简化我们的基础架构:但是如何跟踪跨越多个微服务和工具的请求呢?在这里,分布式跟踪也变得非常重要,特别是考虑到微服务所带来的复杂性。Zipkin和Jaeger等工具一直是该领域的先驱,最近进入该领域的是Tempo。虽然日志聚合可以提供来自各种来源的信息,但不一定提供请求的上下文,这在进行跟踪时真正有用。但是请记住,添加跟踪会增加请求的开销,因为上下文必须与请求一起在服务之间传播。但是,站点的可靠性并不仅限于监视,可视化和警报。你必须准备好使用常规备份和故障转移来处理系统任何部分中的任何故障,以便不丢失数据或将数据丢失的程度降至最低。这就是Velero等工具发挥主要作用的地方。Velero可以帮助你维护集群中各个组件的定期备份,包括工作负载,存储等。Velero的架构如下所示:如你所注意到的,有一个备份控制器定期备份对象,并根据你设置的时间表将它们推送到特定的目的地。由于几乎所有对象都已备份,因此可以将其用于故障转移。存储有许多不同的存储供应商和文件系统可用,而且在云提供商之间可能有很大的不同。这就需要像容器存储接口(CSI)这样的标准,从而使大多数数据卷插件易于集成、维护和发展而不会成为核心瓶颈。CSI支持各种存储插件:集群存储,扩展以及分布式存储附带的其他各种问题,如何解决呢?这就需要Ceph类的文件系统,但是考虑到Ceph并不是在考虑Kubernetes的情况下构建的,并且很难部署和管理,就需要使用Rook这样的项目中也。尽管Rook没有与Ceph耦合,并且还支持EdgeFS,NFS等其他文件系统,但是Rook与Ceph CSI就像是天作之合。如你所见,Rook负责在Kubernetes集群中安装,配置和管理Ceph。根据用户首选项,存储空间自动分配。所有这一切都不会使应用程序面临任何复杂性。镜像仓库镜像仓库为你提供了一个用户界面,你可以在其中管理各种用户帐户,推送/拉取镜像,管理配额,通过Webhooks接收事件通知,进行漏洞扫描,对推送的镜像进行签名以及处理镜像或镜像复制等操作。多个镜像仓库。如果你使用云提供商,则很有可能他们已经将镜像仓库作为一项服务(例如GCR,ECR,ACR等),这消除了很多复杂性。如果你的云服务提供商不提供服务,那么你也可以使用Docker Hub,Quay等第三方镜像仓库。但是,如果你想托管自己的镜像仓库怎么办?如果你要在本地部署镜像仓库,想要对镜像仓库本身进行更多控制,或者想减少与漏洞扫描等操作相关的成本,则可能需要使用像Harbor这样的私有镜像仓库。Harbor是一个由OCI兼容的镜像仓库,由各种开源组件组成,包括Docker镜像仓库V2,Harbor UI,Clair和Notary。CI/CD体系结构Kubernetes是一个很好的平台,可以托管任何规模的各种类型的工作负载,但这也要求采用简单便捷的持续集成/持续交付(CI/CD)工作流程来部署应用程序。一些第三方服务(例如Travis CI,Circle CI,Gitlab CI或Github Actions) 包括自己的CI运行程序。你只需定义要构建的流水线中的步骤。这通常涉及:构建镜像,扫描镜像以查找可能的漏洞,运行测试并将其推送到镜像仓库,在某些情况下还提供预览功能。结论如上所述,各种工具可解决基础架构的不同问题。它们就像乐高积木一样,每个积木都着眼于特定的问题,为你节省了很多复杂性。这使用户可以使用增量方式利用Kubernetes,而不必一次全部使用,而仅使用整个系统中所需的工具,具体取决于你的需求。文章来源:K8s中文社区翻译:王延飞原文链接:https://thenewstack.io/a-deep-dive-into-architecting-a-kubernetes-infrastructure/
  • Serverless在前端工程化的实践
    为什么要做 Serverless 平台触发这件事情的原因有两部分,第一是趋势,因为前端发展趋势使得前端工程师的工程化效率正在降低,作为基础软件团队,需要思考能否从基础软件层面解决前端的困扰,第二部分是当前前端工程师正面临服务端渲染的问题。首先说趋势,体现在整个前端发展过程中。从以前的 Web 工程师,到前端工程师的职位的出现,当时还只是逻辑分工。第三阶段是前端工程师时代,是一个前后端分离的时代。到我们目前正在处于的前后端(BFF)时代,前端工程师需要去负责部分后端的数据。甚至有些公司已经到了全栈工程师的时代,前端工程师需要负责后端所有的数据。第二阶段和第三阶段,前端人员不需要关心后端资源,只需要把自己的代码写好,由后端或者是运维帮他们去做发布。但是目前所处的阶段,前端人员是需要去关心后端数据的,将来的全栈工程师时代,他们还需要去直接从数据库里边获取 / 操作数据,这个时候我们会发现,他需要操心低层的资源,因为他需要把他的程序跑在服务端的后端,而前端工程师实际上不擅长操作和运维后端资源,因此会使得前端工程师的工程化效率降低。第二点是我们当前正在面临的问题,因为前端工程师目前在做服务端渲染(SSR),采用这个技术的时候他需要自己申请机器,自己部署,同时他还得关注机器的状态,并且他还得时常地翻阅基础设施提供一些运维指南去做运维,其实这个事情是他们很不擅长的,并且对他们来说是一个负担。同时从后端运维的视角来看,前端工程师是在浪费资源。这有两个原因,第一,很多业务属于活动类型的;第二,前端工程师在申请机器的时候,他往往按照上限来预留资源,这就导致了大量的浪费。因此这就产生了“前端工程师在浪费资源”的问题。但其实前端工程师不是故意的,因为他们不擅长运维服务器。因此我们需要解决前端工程师正在面临的痛点。从前端工程师的角度,他们的核心诉求就是只写代码,聚焦核心业务,去创造核心价值,把一些服务端后端运维的事情完全交付给基础设施去做,他们不需要去 care 这个事情。Serverless 的先进理念,其精华正是复杂度转移,使得业务人员能够聚焦他的核心场景,所以我们想打造一款 Serverless 产品,来解决前端工程师当前的困扰。如何打造 Serverless 平台 技术选型打造 Serverless 平台之前,首先要对这个目标做拆解,然后再去做产品选型、技术选型。首先看目标拆解,第一点业务层的需求是即用即上,也就是说前端他想上线一个业务,他不需要去关心太多,他想什么时候上线就可以什么时候上线;第二点就是前端工程师不想去做后端资源的运维;第三点实际上不是前端工程师的需求,而是基础设施层面的一个需求,就是尽量地能支撑好业务,同时也能够省机器省钱。这相对应的目标拆解为:即用即上——需要在技术上具备一键部署的能力;免运维——需要把具体的运维沉淀到基础设施层;节省开支——要求我们这个业务状态相对来说是无状态的,具备高弹性的能力。因此我们的 Serverless 平台要能够集成 CI/CD,同时也能够进行容器化,工作在 Kubernetes 上,具备自动扩缩容的能力。再看产品选型。既然公有云 Serverless 做得这么成熟,我们能否直接采用公有云产品来满足我们业务开发需求?我们的回答是 NO,因为我们需要去满足一些定制化的用户需求,而公有云的 Serverless 产品会受到很多资源包括使用的一些限制;第二个因素是我们的业务存在一些环境依赖,前端所依赖的一些数据库、中间件,都是运行在公司的私有云环境中,这些东西公有云环境上都没有;第三点也是追求技术自由,避免厂商锁定。 所以,我们需要在私有云平台中打造自己的 Serverless 平台。在技术选型上,我们基于三个原因选型了 Knative。底层要基于 Kubernetes: 因为数帆对 Kubernetes 的运维手段比较成熟,本身有大量的业务运行在 Kubernetes 上,我们有专业的团队来做相应的支撑。基于镜像去构建 Serverless: 因为本身的业务是比较灵活多变的,会存在一些程序启动时间比较长的业务,这种业务不是很适合 FaaS。因此我们考虑让它把整个启动过程压缩,通过镜像打包的一种方式来去解决。另外我们还要求易扩展成 FaaS。这些 Knative 都能满足。背景深厚:Knative 后面还有 Google、IBM、Redhat 这些大厂作为支撑。 平台构建轻舟 Serverless 平台设计全景图如下,从下往上有基础设施层、服务层、应用编排层和业务层。其中我们比较关注的是应用编排层和服务层。整个 Serverless 平台工作在已有的基础设施之上,并且我们通过这个 Serverless 平台后端,把它所需要的资源纳入平台组件能力,比如说 CI/CD、Knative API 网关,把这些资源结合起来,满足我们 Serverless 的具体需求。轻舟 Serverless 平台具体的构成,从下图可以看到,Serverless 的核心,我们可以理解成额外做的核心组件,包括一个 Serverless 前端控制台和一个 Serverless 后端。这个核心负责把现有的一些组件联合起来:通过 CI 去完成镜像构建的需求;通过 Knative 去做部署;通过 API 网关去做具体业务的数据链路打通;同时还需要 Gitlab 来存储代码;为了更高的开发效率,需要集成 Web IDE,这样前端开发人员可以只在一个浏览器上就完成他所有的需求;同时为了运维能力,需要去支持平台层面的日志平台,以及监控告警的平台;还需要一些预警,就是 Serverless 跑批和预警的一些组件。轻舟 Serverless 平台在这样的构成下,它具体的流程,我们从业务开发者的视角来看,业务开发者先通过 Web IDE,或者是其他的本地开发工具来完成编码,再把代码 Push 到 GitLab 上去,然后就会触发构建镜像,或者他可以选择手动触发,或者是通过命令行触发。当然这一步也可以把相关的一些资源,降级的静态资源,构建到放到对象存储里面去。Serverless 控制台构建完镜像以后,会通过 Knative 的 Service 去发布这个程序。整个发布过程它会主动地拉取刚才构建的镜像,去做应用的部署和数据链路的打通。这就完成了整个业务的一键部署。一键部署的业务流量模型,首先流量从外网打到外层的基于 Envoy 的 API 网关,API 网关会把流量发给内层的 Knative 网关。随着访问压力的增大,我们要求它能够扩容;而随着资源处在访问的低档期,为了能腾出更多的资源,我们要求它具备缩容的能力。同时这个 Serverless 平台还必须考虑,当这一部分产生了异常的情况下,是否具备降级的能力。我们通过外层的 API 网关去做降级和和静态资源的获取,通过这种方式,如果 Serverless 平台或者 Knative 这一层出了问题,用户可以一键切到已经准备好的静态资源中,不至于让业务产生异常。 产品形态的思考打造 Serverless 平台还有很多必要的考虑。首先平台构建形态方面,为了满足用户的效率需求,我们支持了 FaaS 层平台;为了满足业务复杂又多变的需求,我们支持了传统工程的形态。其中 FaaS 形态最主要的目的是让我们的业务方,特别是前端开发者,可以完全在 Web 浏览器上编码、发布,也就是说他只要身边有一台电脑,通过浏览器就可以随时随地完成他的业务目标,不需要安装一些开发环境。除了这种方式以外,考虑传统使用者的诉求,我们也支持集成到 VS Code 中,同时还支持最传统的通过命令行直接构建 FaaS 的方式,当前我们支持的还只是 Node.js,这个是属于我们用得比较多的技术栈。对于传统工程形态这种方式,Knative 当前是支持的,这种方式最主要的作用是,用户不需要学习新知识就可以直接使用 Serverless,可以像以前一样开发代码,同时它的运营实施比较灵活。一些启动过程很慢的业务,也完全可以采用传统工程形态去做,这样不至于说这类业务没有办法在这个平台上运行。所以说,我们做了这两种产品形态来满足业务方在不同状况下的使用需求。 数据路径的适配因为 Knative 网关只能通过子域名的方式去做业务区分,而我们传统业务,特别是现有的很多线上业务,往往是使用 Host+Path 这种方式去做区分的。为了满足用户的这种使用习惯,我们当然可以修改 Knative 层的开源实现,但是开源又是在不断迭代的,我们考虑再三,做了一些框架结构,通过外置的一层 API 网关去做具体的 Host+Path 的区分,然后转换成 Knative 所支持的子域名方式去做应用区分。同时,我们引入外层的 API 网关还有另一个好处,当 Knative 这一层出问题时,我们可以通过这一层网关去做灰度降级,来保证业务的稳定性。当然,加一层外置网关也会导致数据链路变长,它从外层 API 网关,到内层 Knative 网关,再到 Activator 组件,甚至到 QueueProxy,最后才到业务容器。这样会导致 QPS 比较低,这方面后文我们会给出轻舟团队具体的解决办法。 平台能力的集成平台需要的日志、监控告警、BaaS 等能力,由于轻舟平台已有现成的封装,Serverless 平台直接集成。此外,为了适应 Serverless 这种业务场景,我们额外开发了一个预警的组件,去模拟前端业务方发布一个业务,发布之后把它给部署到 Serverless 平台上,然后检查它能否很好地完成扩缩容。Knative 的实践踩坑和优化接下来分享在打造轻舟 Serverless 平台的过程中,我们对选型的 Knative 这个开源组件所做的事情,主要分为三个部分,第一部分是我们在数据面上做了哪些东西,第二部分是我们在控制面做了哪些优化,第三部分是说使用了 Knative 组件,我们遇到了哪些问题,又是如何解决的。 数据面的优化我们在数据面做的主要工作是数据链路调优。上文也提到 Knative 整个数据链路比较长,我们通过对 Knative 的压测,确定 Knative 的性能有很大的问题。我们通过以下的 5 个步骤来做优化:在整个的数据路径上,把 Activator 从数据路径上去除,因为我们是面向 Web 场景,去除之后不会产生任何业务问题。把 Knative 做升级,从以前的 0.9 升级到 0.14。通过 1 和 2,整个 QPS 提升了大概 50%。为了满足我们一些核心业务对延迟或者是对高性能的需求,我们采用 Fast HTTP 优化了 QueueProxy,把 QueueProxy 的 CPU 使用率降了 50%,同时在降低 CPU 使用率的情况下,它的延迟也降了 30% 左右,QPS 也提升了 30%,也就说使用更少的 CPU,反而带来更多的 QPS 和更低的延迟效果。同时我们做了一个 Revision Deployment 级别的灰度,来降低修改 QeueuProxy 带来的业务风险。在第 3 步优化完 QueueProxy 以后,我们引入了的 Sockops 组件来做框架优化,通过 eBPF 技术实现 QueueProxy 和业务容器之间的 Sidecar 方式的链路优化,QPS 可以在之前的基础上再额外提升 20%,同时延迟降低 8% 左右。针对一些特殊业务需求,我们选型更高性能的容器网络,叫 SR-IOV 网络,来满足它的需求。从我们的实测来看,SR-IOV 容器网络在延迟方面比普通的容器网络大概要降低 10%,同时它的 QPS 是接近物理机的。通过这 5 个步骤,我们满足了不同的业务方的需求。一般来讲,做完 1 和 2 能满足差不多满足一半的业务需求,做完 3 和 4 基本上能满足绝大部分需求,第 5 步是满足一些特殊的业务场景的需求。 控制面的优化控制面上我们主要解决了 Knative ksvc Ready 时间变长的问题。Knative ksvc Ready 时间变长有两个原因。第一个原因是 Serverless Knative 网关,我们采用的是轻舟的 API 网关,它的控制面是依赖于 Pilot,而我们的业务集群又是和服务网格在一起运行的,在默认情况下,Knative 的 Pilot 能感知到服务网格的 VS、DR、SE 这些资源,这就导致了它去做一些无关的资源运算,从而 Knative ksvc Ready 时间变长。第二原因,Knative 有一个组件叫做 network-istio,这个组件需要对整个数据路径去做健康检查,只有在健康检查成功以后它才把 ksvc 置成 Ready 状态。但健康检查有一个特点,它是指数级别回退的,这就导致了如果 5 秒内它没有检查通过,它就只能在 10 秒内才能发现这个东西是健康的;如果它在 10 秒内还没有解决这个问题,检查出来业务已经 Ready 了,它就只能在 20 秒内才能发现业务已经 Ready,这就导致 ksvc Ready 时间变得更长。我们解决的办法有两种,第一种是针对于第一个问题,Knative 网关它只 care 自己的 Namespace 级别的资源,去做一些资源隔离,它不 care 同一个集群内的服务网格的相关的其他资源。第二种就是我们调整了 network-istio 健康检查回退机制,调整成前 20 秒内每秒钟检查一次,20 秒以后才进行指数级回退,通过这种方法防止 ksvc Ready 时间慢的问题。 遇到的困难和解法Knative 层我们主要遇到了如下的困难:Knative 的一个 Autoscaler 组件,它是不支持 HA 的,但是 Knative Autoscaler 组件是扩缩容的核心组件,因此这是业务无法忍受的。一个老生常谈的冷启动问题,我们经过实测,整个的冷启动过程需要 5 秒以上,如果算上拉镜像的时间,甚至可能需要 6~7 秒。做 Knative 适配的时候,和我们内部的容器网络有些冲突,它会导致 Knative 的一些 Webhook 启动失败。适配轻舟 API 网关的时候出现 503 问题。net-isito 组件做完健康检查以后它的连接不会释放,这就导致它的连接大量的堆积,最终导致业务异常。我们的解法如下:针对 Autoscaler 不支持 HA 的问题,我们通过 Pick Knativ0.19 这个版本的一些代码去解决。针对冷启动,我们通过一些预留和一个默认实例来避免冷启动。Webhook 这个问题,最主要是和我们内部容器网络的冲突,我们通过调整网络方式为 hostNetwork 来规避。适配轻舟 API 网关出现 503,最主要也是 Knative 本身的一些问题,因为网关的控制面上存在一些特殊符号,它没有办法识别,这种情况下 0.14 版本的 Network-isito 就没有办法继续往下工作,不过这个问题在 Knative0.15 得到了修复。健康检查连接不释放,这也在 Knative 0.15 得到了解决。当然我们在一开始踩这个坑的时候,Knative 社区还没有解决这些问题,后面我们解决完问题以后,发现社区也已经解决了。所以说我们也是通过检验了,因为我们是尽量地少动 Knative 本身的代码,也是通过这种升级的方式来解决的。    收益    目前轻舟 Serverless 平台在内部已经上线了大概 200 多个前端应用,当然在 2020 年的 Q4 我们也 Release 了一个商业化版本满足对外的需求。我们做完这个事情以后,前端人员的体验是怎么样的呢?首先,我们从前端人员那边收集到的数据,他们以前去部署环境,新员工可能要两周左右,老员工也要三天左右,有了 Serverless 平台,整个部署时间统一降低到三分钟内搞定。其次,因为 Serverless 平台的一些封装使得了前端人员不再需要关注后端资源,所以说他们从业务选型上,可以考虑一些服务端渲染的技术来提升业务的首屏体验。再次,从趋势上来说,免去运维的困扰更加符合前端趋势,这让前端人员可以轻松地去开发 BFF 层的一些需求,甚至可以支撑他们往全栈工程师去过渡,通过这些支持给前端提供一个更大的灵活度。未来展望展望未来,我们需要在公司内部业务场景继续打磨轻舟 Serverless 平台,让它变得更加稳定,功能更加强大,主要聚焦三个方面:首先我们会提升 Serverless 平台的产品能力,考虑使用 Knative 的 Eventing 组件,去融合我们的轻舟中间件、对象存储这些底层设施的资源,来满足业务更加多变的需求。其次是我们 Serverless 平台上线以后,前段时间业务方反馈它整个的调试化过程的效率降低了,所以我们打算提供一些本地的调试套件去解决调试的困扰。最后,我们会紧跟着 Knative 社区,关注 Knative FaaS Kn 的实现,同时也考虑去对接公有云的一些 Serverless Framwork,一些 API 规范标准,这样将来如果业务方有需求,它完全可以无感地从私有云平台上迁到公有云平台上,所以我们打算做这么一层封装。
  • [技术干货] 混合云、边缘计算走向主流
    2021年3月22日,业界应用最为广泛的企业级Kubernetes管理平台Rancher发布了2020年Kubernetes行业调研报告,研究结果表明,2020年,更多的受访者在混合云环境中使用Kubernetes 运行容器,与此同时,更多的企业将功能和服务部署至边缘,最终进一步推动企业IT现代化的进程。2019年和2020年,Rancher分别对近1,000名专业人员展开了调查。调查结果表明,Kubernetes在不同行业连续两年保持了90%以上的采用率,而生产环境中的容器采用率从2019年的85%增长至2020年的87%。“从调研结果可以清晰地看到,用户持续推动容器在混合云和多云环境落地,92%的受访者将容器作为DevOps、IT运维、IT架构、应用程序开发和基础架构转型的关键部分。”Kubernetes和云:真实环境下的真实工具近1,000名在技术、工程、电信、银行、网络安全和咨询等行业工作的专业人员的反馈,他们主要专注于实现DevOps、IT运维、IT架构、应用程序开发和基础架构转型,92%的受访者选择使用容器来实现这些目标。另一方面,这些受访者均更倾向于采用Rancher所推出的Kubernetes发行版。36%的受访者将RKE作为其Kubernetes发行版,而32%的受访者使用K3s。受访者指出,在容器快速发展的大前提下,多层级控制和功能是RKE被广泛采用的关键原因。推动传统IT架构现代化受访者表示,容器化是推动传统IT现代化的关键路径。49%的受访者通过容器实现传统IT应用程序的现代化,而67%的受访者利用容器设计基于微服务的应用程序。通过使用Kubernetes,企业可以将使用了数十年的传统IT系统转化为基于微服务的容器应用程序,并通过Kubernetes进行编排。迁移到Kubernetes还可以使开发团队并行工作,从而减少了重复的可能性,简化开发并加速部署。在混合云环境中,开发团队还可以通过云托管集群完全替代某些本地工作负载,这些集群可以在像Rancher一样的Kubernetes管理平台上运行和管理,进一步实现IT架构现代化的战略。推动边缘环境生产落地容器在生产环境中的采用率逐步增长,也覆盖到了应用端。基于此,许多受访者使用容器来为客户提供各种服务,包括应用程序、边缘计算、混合/多云应用程序、内部应用程序、传统应用程序现代化和将传统应用程序迁移上云等。K3s等体积较小的Kubernetes已经使企业可以更容易地将功能和服务部署至边缘,它赋予了组织从试点项目转向生产环境的能力,并使其能够根据需要进行扩展。2020年,62%的受访者在边缘使用K3s,去年这一比例仅为50%。随着混合云网络的成熟,客户可以部署面向客户的云原生微服务应用程序,所需的维护量更少,迭代次数更多,并且可以随时间轻松添加新功能。我们完全有理由相信,在面向客户的环境中几乎完全采用由Kubernetes管理的容器的这一趋势将持续发展。结论随着公司将他们的网络、应用程序和流程发展成为一个更现代的框架,他们发现无论环境如何,Kubernetes 都可以随之改变。世界各地的组织正在利用 Kubernetes 解决方案来创建一个云原生微服务集群。他们还对单体系统进行现代化,建立强大的云架构,同时无缝管理现有集群。这是向加速和保护应用程序的时代迈进的一步,同时赋予了DevOps和工程团队利用未来“更聪明地工作”而不是“更努力地工作”的能力。“容器及Kubernetes是混合云时代软件定义基础架构的最佳选择,它们不仅能帮助企业实现传统IT基础架构的容器化改造,还能帮助企业释放混合云的全部价值。”通过结合容器及Kubernetes的可靠性和灵活性推动企业在任意场景进行无限创新,从而推动创新无处不在。”文章转载自:https://tech.china.com/article/20210325/032021_738288.html