-
## 一、K8S是什么? ### 1.1 概述 K8S全名Kubernetes。因k与s之间有8个字符,故缩写为K8S。 K8S是一个可自动实施 Linux 容器管理的可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。 ## 二、为什么需要K8S? 要了解这个问题,需要回顾一下应用程序的部署方式。 ### 2.1 传统部署 传统部署直接在物理服务器上运行应用程序。存在缺陷: + 无法为服务器中的应用程序定义资源边界,导致资源分配出现问题(一个程序占用大部分资源,其它程序性能下降)。 + 若将应用程序运行在不同物理服务器上,一方面导致资源浪费,另一方面提高成本。 ### 2.2 虚拟化部署 虚拟化技术允许我们在单个的物理服务器上运行多个虚拟机(VM),应用程序在VM之间完全隔离。 每个VM是一个完整的计算机,在虚拟化硬件上运行包括自己的操作系统在内的所有组件。VM共享主机硬件资源。 但因为VM需要运行硬件虚拟副本和完整的操作系统副本,会占用大量的系统资源。 ### 2.3 容器部署 容器将应用程序软件代码和所需的所有组件打包在一起,使得容器内的用意可以在任何基础架构上一致的运行。 + **隔离性**:容器同样可以虚拟化基础计算机,应用程序可在不同容器间实现进程级隔离。 + **轻量性**:每个容器共享物理服务器的OS内核,二进制文件和库,但具有自己的文件系统、CPU、内存、进程空间等。这样的共享可以大大减少重现操作系统代码的需求。因此容器非常轻量,容量小且启动快。 + **可移植**:容器与基础架构分离,可以实现跨云和OS发行版本进行移植。 **K8S**即是在大规模服务器环境中,负责部署和管理容器组,用于解决容器的复制,扩展,健康,启动,负载均衡等问题。只需告诉 Kubernetes 您希望在哪里运行软件,该平台就会负责执行部署和管理容器所需的几乎一切工作。 ## 三、K8S有哪些组件? 我们会在一组用于**运行容器化应用**的节点计算机(Node)的上部署K8S,这一组节点计算机即称为K8S集群。正常运行的K8S集群包含以下组件。 ### 3.1 集群相关术语 + **控制平面(Control Plane):**控制 Kubernetes 节点的进程的集合。所有任务分配都来自于此。 + **节点(Node):**这些机器负责执行由控制平面分配的请求任务。 + **容器集(Pod):**部署到单个节点上且包含一个或多个容器的容器组。容器集是最小、最简单的 Kubernetes 对象。 + **服务(Service):**一种将运行于一组容器集上的应用开放为网络服务的方法。它将工作定义与容器集分离。 + **卷(Volume):**一个包含数据的目录,可供容器集内的容器访问。Kubernetes 卷与所在的容器集具有相同的生命周期。卷的生命周期要长于容器集内运行的所有容器的生命周期,并且在容器重新启动时会保留相应的数据。 + **命名空间(Namespace):**一个虚拟集群。命名空间允许 Kubernetes 管理同一物理集群中的多个集群(针对多个团队或项目)。 ### 3.2 控制平面组件 控制平面的组件对集群做出全局决策(比如调度),以及检测和响应集群事件。控制平面组件可以在集群中的任何节点上运行。 然而,为了简单起见,设置脚本通常会**在同一个计算机上启动所有控制平面组件, 并且不会在此计算机上运行用户容器**。 + **kube-apiserver**:该组件开放 Kubernetes API。API服务器是K8S控制平面的前端。 + **etcd**:etcd 是兼具一致性和高可用性的键值数据库,可以作为保存 Kubernetes 所有集群数据的后台数据库 + **kube-scheduler**:该组件负责监视新创建的、为指定运行节点(node)的Pods,并选择节点让Pod在上面运行。 + **kube-controller-manager**:运行控制器进程的控制平面组件。多中控制器被编译到一个可执行文件,并在一个进程中进行运行。 + **cloud-controller-manager**:云控制器管理器是指嵌入特定云的控制逻辑的 [控制平面](https://kubernetes.io/zh/docs/reference/glossary/?all=true#term-control-plane)组件。 云控制器管理器使得你可以将你的集群连接到云提供商的 API 之上, 并将与该云平台交互的组件同与你的集群交互的组件分离开来。 ### 3.3 Node组件 节点组件在每个节点上运行,维护运行的Pod并提供Kubernetes 运行环境。 + **Kubelet**:每个节点上运行的代理。它保证容器都运行在Pod中。 + **kube-proxy**:kube-proxy 是集群中每个节点上运行的网络代理, 实现 Kubernetes [服务(Service)](https://kubernetes.io/zh/docs/concepts/services-networking/service/) 概念的一部分。它维护节点上的网络规则。这些网络规则允许从集群内部或外部的网络会话与 Pod 进行网络通信。 ### 3.4 容器运行时 容器运行环境是负责运行容器的软件。支持包括像Docker,iSula以及任何实现k8s CRI的容器运行环境。 ### 3.5 其它可用插件 插件并非严格意义上的必须组件。仅列举以下常用的两种。 + **DNS:**几乎所有 Kubernetes 集群都应该有集群DNS。 + **Web界面**:Dashboard 是 Kubernetes 集群的通用的、基于 Web 的用户界面。
-
hi, 大家好,如今几乎所有大厂都将容器和K8s列入未来的战略重心,K8s可能将成为下一代分布式操作系统,今天分享一篇很经典云原生文章(万字雄文),希望可以帮大家彻底了解到底什么是云原生。本文是一篇云原生的关键知识科普,希望给大家提供一扇云原生的“窗户”,传达三个目标:1、透过窗户看到一棵大树代表:云原生的蓝图全貌;2、树上会有很多核心树干代表:云原生的关键技术;3、希望树干上能摘到果实代表:云原生对我的启发。开始阅读文章前,请角色切换:设想你作为一位中小型 IT 公司 CTO,面对云原生技术决策,你需要回答两个问题: 1、为什么需要上云? 2、上云有何弊端?作为一家公司的技术决策者,必须理解上云的利与弊,并结合公司各阶段发展目标给出最适合的技术方案。 3、 云原生-概述 3.1 云原生-定义云原生的定义,业界也是“百家争鸣”各持观点,从技术视角理解云原生会相对清晰。云原生的关键技术包括:• 微服务架构:服务与服务之间通过高内聚低耦合的方式交互;• 容器:作为微服务的最佳载体,提供了一个自包含的打包方式;• 容器编排:解决了微服务在生产环境的部署问题;• 服务网络:作为基础设施,解决了服务之间的通信;• 不可变基础:设施提升发布效率,方便快速扩展;• 声明式 API:让系统更加健壮;命令式 API:可以直接发出让服务器执行的命令,例如:“运行容器”、”停止容器”等;声明式 API:可以声明期望的状态,系统将不断地调整实际状态,直到与期望状态保持一致。• DevOps:缩短研发周期,增加部署频率,更安全地方便:Culture :达成共识Automation:基础设施自动化Measurement:可度量Sharing:你中有我,我中有你【私人观点】云原生的定义:应用因云而生,即云原生。应用原生被设计为在云上以最佳方式运行,充分发挥云的优势,是上云的最短路径。 3.2 云原生-技术生态 3.3 云原生-关键技术云原生关键技术包括:微服务,容器,容器编排,服务网络,不可变基础,声明式 API。 3.3.1 微服务微服务是一种用于构建应用的架构方案。将一个复杂的应用拆分成多个独立自治的服务,服务与服务间通过“高内聚低耦合”的形式交互。微服务典型架构包括:服务重构:单体改造成符合业务的微服务架构;服务注册与发现:微服务模块间的服务生命周期管理;服务网关:身份认证、路由服务、限流防刷、日志统计;服务通信:通信技术方案如,RPC vs REST vs 异步消息;可靠性:服务优雅降级,容灾,熔断,多副本。 3.3.2 容器容器是一种打包应用的方式,可以打包应用中的所有软件和软件所依赖的环境,并可实现跨平台部署。容器关键技术:namespac 视图隔离,cgroups 资源隔离 ,Union File System 联合文件系统。容器优势:更高效的利用资源;更快速的启动时间;一致性的运行环境。 3.3.3 容器编排容器编排包括:自动化管理和协调容器的系统,专注于容器的生命周期管理和调度。核心功能:容器调度:依据策略完成容器与母机绑定;资源管理:CPU、MEM、GPU、Ports、Device;服务管理:负载均衡、健康检查。 3.3.4 服务网格服务网格(Service Mesh)是致力于解决服务间通讯的基础设施层。Service Mesh 应对云原生应用的复杂服务拓扑,提供可靠的通信传递;通过一组轻量级网络代理(Sidecar proxy),与应用程序代码部署在一起来实现,且对应用程序透明。Service Mesh 特点:应用程序间通讯的中间层;轻量级网络代理,应用程序无感知;解耦应用的重试、监控、追踪、服务发现。Service Mesh 主流组件:Istio、MOSN(Modular Open Smart Network)Linkerd。 3.3.5 不可变基础设施不可变基础设施(Immutable Infrastructure)(宠物 VS 牲畜)任何基础设施实例(服务器、容器等各种软硬件)一旦创建之后便成为一种只读状态,不可对其进行任何更改;如果需要修改或升级实例,唯一方式是创建一批新实例以替换。不可变基础设施的优势提升发布应用效率;没有雪花服务器;快速水平扩展。 3.3.6 声明式 API命令式 API:可直接发出让服务器执行的命令,例如:“运行容器”、“停止容器”等;声明式 API:可声明期望的状态,系统将不断地调整实际状态,直到与期望状态保持一致。为什么声明式使系统更加健壮?可以类比理解成自动化工程学的闭环自适应模型。 3.3.7 DevOpsDevOps 目标 :缩短开发周期,增加部署频率,更可靠地发布。从历史上开发和运维相对孤立到开发和运维之间建立合作,可以增加信任,更快速地发布新版本。DevOps 是一组过程,方法和系统的统称包括:Culture:文化是 DevOps 中的第一成功要素。由于目标不同,开发和运维形成一堵墙,DevOps 通过建立开发和运维之间合作和沟通的文化来消除墙。Automation:自动化软件的开发和交付,通常包含持续集成,持续交付和持续部署,云原生时代还包括基础架构的自动化,即 IaC(Infrastructureas code)。Measurement:度量尤其重要,通过客观的测量来确定正在发生的事情的真实性,验证是否按预期进行改变。并为不同职能部门达成一致建立客观基础。Sharing:开发和运维团队之间长期存在摩擦的主要原因是缺乏共同的基础。开发参与运维值班,参与软件的部署和发布,运维参与架构设计。 4 容器-Docker 4.1 Docker 概述为什么学习容器技术?云时代从业者:Docker 已成云平台运行分布式、微服务化应用的行业标准。作为有技术追求的程序员,有必要理解云原生的关键技术:容器。Docker 核心概念:镜像、容器、仓库。镜像(Image):一个只读模板;由一堆只读层(read-only layer)重叠;统一文件系统(UnionFileSystem)整合成统一视角。容器(Container):通过镜像创建的相互隔离的运行实例;容器与镜像区别:最上面那一层可读可写层;运行态容器定义:一个可读写的统一文件系统,加上隔离的进程空间,以及包含在其中的应用进程。仓库(Repository):集中存放镜像文件的地方;Docker Registry 可包含多个仓库(Repository),每个仓库可包含多个标签(Tag),每个标签对应一个镜像。 4.2 Docker 关键技术 4.2.1 Namespace 视图隔离Linux namespace 是一种内核级别的环境隔离机制,使得其中的进程好像拥有独立的系统环境。Network namespace 在 Linux 中创建相互隔离的网络视图,每个网络名字空间都有自己独立的网络配置,包括:网络设备、路由表、IPTables 规则,路由表、网络协议栈等。(默认操作是主机默认网络名字空间) 4.2.2 control groups(资源隔离)Linux Control Group 是内核用于限制进程组资源使用的功能。资源包括:CPU,内存,磁盘 IO 等。 4.2.3 Union File System(联合文件系统)Union File System, 联合文件系统:将多个不同位置的目录联合挂载(union mount)到同一个目录下。Docker 利用联合挂载能力,将容器镜像里的多层内容呈现为统一的 rootfs(根文件系统);Rootfs 打包整个操作系统的文件和目录,是应用运行所需要的最完整的“依赖库”。 4.3 Docker-网络技术Bridge 模式:Docker0 充当网桥,在默认情况下,被限制在 Network Namespace 里的容器进程,是通过 Veth Pair 设备 +宿主机网桥的方式,实现跟同其他容器的数据交换。一旦一张虚拟网卡被“插”在网桥上,它就会变成该网桥的“从设备”。从设备会被“剥夺”调用网络协议栈处理数据包的资格,从而“降级”成为网桥上的一个端口。而这个端口唯一的作用,就是接收流入的数据包,然后把这些数据包全部交给对应的网桥,由网桥完成转发或者丢弃。Veth 提供一种连接两个 network namespace 的方法。Veth 是 Linux 中一种虚拟以太设备,总是成对出现常被称为 Veth pair。可以实现点对点的虚拟连接,可看成一条连接两张网卡的网线。一端网卡在容器的 Network Namespace 上,另一端网卡在宿主机 Network Namespace 上。任何一张网卡发送的数据包,都可以对端的网卡上收到。在物理网络中,如果需要连接多个主机,会用交换机。在 Linux 中,能够起到虚拟交换机作用的网络设备,是网桥(Bridge)。它是一个工作在数据链路层的设备,主要功能是根据 MAC 地址学习来将数据包转发到网桥的不同端口(Port)上。Bridge 网桥类似交换机,两个以上 namespace 接入同一个二层网络。veth pair 一端虚拟网卡加入到 namespace,另一端到网桥上。路由 routing是通过互联的网络把信息从源地址传输到目的地址的活动,发生在 OSI 模型的第三层(网络层)。Linux 内核提供 IPForwarding 功能,实现不同子网接口间转发 IP 数据包。路由器工作原理:路由器上有多个网络接口,每个网络接口处于不同的三层子网上。根据内部路由转发表将从一个网络接口中收到的数据包转发到另一个网络接口,实现不同三层子网间互通。 5 容器编排-Kubernetes 5.1 概述&架构&核心组件我认为 Kubernetes 最大成功:让容器应用进入大规模工业生产。Kubernetes 的提供特性,几乎覆盖一个分布式系统在生产环境运行的所有关键事项。包括:Automated rollouts and rollbacks(自动化上线和回滚)使用 Kubernetes 描述已部署容器的所需状态,受控的速率将实际状态更改为期望状态。Self-healing(自我修复)Kubernetes 重新启动失败的容器、替换容器、杀死不响应用户定义的运行状况检查的容器,并且在准备好服务之前不将其通告给客户端。Service discovery and load balancing(服务发现与负载均衡)Kubernetes 可以使用 DNS 名称或自己的 IP 地址公开容器,如果进入容器的流量很大,Kubernetes 可以负载均衡并分配网络流量,从而实现部署稳定。Storage orchestration(存储编排)Kubernetes 允许你自动挂载选择的存储系统,例如本地存储、公厂商等。Automatic bin packing(自动装箱)Kubernetes 允许指定每个容器所需 CPU 和内存(RAM)。当容器指定资源请求时,Kubernetes 可以做出更好的决策来管理容器的资源。Secret and configuration management(安全和配置管理)Kubernetes 允许存储和管理敏感信息,例如密码、OAuth 令牌和 ssh 密钥。你可在不重建容器镜像的情况下部署和更新密钥和应用程序配置,也无需在堆栈配置中暴露密钥。API Service: Kubernetes 各组件通信中枢。资源操作的唯一入口,并提供认证、授权、访问控制、API 注册和发现等机制;为 Pod, Deployment, Service 等各种对象提供 Restful 接口;与 etcd 交互的唯一组件。Scheduler:负责资源调度,按照预定调度策略将 Pod 调度到相应的机器。Predicates(断言):淘汰制Priorities(优先级):权重计算总分。Controller manager:负责维护集群的状态,比如故障检测、自动扩展、滚动更新等。etcd:分布式的 K-V 存储,独立于 Kubernetes 的开源组件。主要存储关键的原数据,支持水平扩容保障元数据的高可用性;基于Raft 算法实现强一致性,独特的watch 机制是 Kubernetes 设计的关键。kubelet :负责维护 Pod 的生命周期,同时负责 Volume(CVI)和网络(CNI)的管理。kube-proxy:负责为 Service 提供 cluster 内部的服务发现和负载均衡kube-proxy 通过在节点上添加 iptables 规则以及从中移除这些规则来管理此端口重新映射过程。控制器模式的设计思想:容器类比集装箱,集装箱固然好用,但是如果它各面光秃秃的,吊车还怎么把它吊起来摆放好呢?Pod 对象其实就是容器的升级版,对容器进行组合,添加更多属性和字段。就好比在集装箱上安装了吊环,Kubernetes 这台“吊车”可以更轻松操作容器。然而Kubernetes 操作这些“集装箱”的逻辑都是由控制器完成的。Kubernetes 通过“控制器模式” 的设计思想,来统一编排各种对象和资源。 5.2 部署&资源控制&存储Kubernetes-集群部署架构所有组件通过 kubelet staticpod 的方式启动保证宿主机各组件的高可用,systemd 提供 kubelet 的高可用;每个 Master 的使用 hostNetwork 网络,controller-manager 和 scheduler 通过 localhost 连接到本节点 apiserver;controller-manager 和 scheduler 的高可用通过自身提供的 leader 选举功能(--leader-elect=true);apiserver 高可用,可通过经典的 haporxy+keepalived 保证,集群对外暴露 VIP;外部访问通过 TLS 证书,在 LB 节点做 TLS Termination,LB 出来 http 请求到对应 apiserver 实例。apiserver 到 kubelet、kube-proxy 类似。 5.3 Kubernetes-网络技术 3.3.1 对外服务Service是一个逻辑概念,一组提供相同功能 Pods 的逻辑集合,并提供四层负载统一入口和定义访问策略。交互流程:Service 可通过标签选取后端服务。匹配标签的 Pod IP 和端口列表组成 endpoints,有 kube-proxy 负责均衡到对应 endpoint。为什么需要 service?对外提供入口(容器如何被外部访问);克服 Pod 动态性(Pod IP 不一定可以稳定依赖);服务发现和稳定的服务( Pod 服务发现、负载、高可用)。Service Type 四种方式Cluster IP:配置 endpoint 列表;NodePort:默认端口范围:30000-32767,通过 nodeIP:nodePort 访问 ;LoadBalancer:适用于公有云,云厂商实现负载,配置 LoadBalance 到 podIP ;ExternalName:服务通过 DNS CNAME 记录方式转发到指定的域名。Service Type 为 Cluster IP:Kubernetes 的默认服务,配置 endpoint 列表,可以通过 proxy 模式来访问该对应服务;类似通过 Nginx 实现集群的 VIP。Service Type 为 Node Port:在集群所有节点上开放特定端口,任何发送到该端口流量借助 Service 的 Iptables 规则链发送到后端 Pod。注意事项:每个服务对应一个端口,端口范围只有 30000–32767;需要感知和发现节点变化,流量转发增加 SNAT 流程,Iptables 规则会成倍增长。适用场景:服务高可用性要求不高或成本不敏感,例如:样例服务或临时服务。Service Type 为 Load Balancer:对公网暴露服务建议采用此方式,Service 没有对其行为做任何规范,依赖云厂商 LB 具体实现(云厂商收费服务)如:腾讯公有云:CLB。Service Type 为 External Name :DNS 作为服务发现机制,在集群内提供服务名到 Cluster IP 的解析。CoreDNS :DNS 服务,CNCF 第 04 个毕业项目,KUBERNETES 的 1.11 版本已支持。CoreDNS 实现的高性能、插件式、易扩展的 DNS 服务端,支持自定义 DNS 记录及配置 upstream DNS Server,可以统一管理 Kubernetes 基于服务的内部 DNS。Ingress Controller:定义入流量规则,可做七层 HTTP 负载君合。Egress Controller:定义出流量规则。交互流程:通过与 Kubernetes API 交互,动态感知集群 Ingress 规则,按照自定义的规则生成(负载均衡器)配置文件,并通过 reload 来重新加载。 5.3.2 Underlay 与 Overlay 网络Underlay 网络模式: 底层承载网络,是网络通信的基础。优势:复用基建,网络扁平,性能优势;劣势:协作复杂,安全问题,管理成本。很多场景下业务方希望容器、物理机和虚拟机可以在同一个扁平面中直接通过 IP 进行通信,通过 Floating-IP 网络实现。Floating-IP 模式将宿主机网络同一网段的 IP 直接配置到容器中。这种模式为了保证容器与宿主机的交换机二层连通,需要在物理机上搭一个虚拟网桥。具体选择哪种网桥,主流有:Linux bridge、MacVlan、SRIOV 三种模式。BridgeBridge:设备内核最早实现的网桥,性能与 OVS 相当,可以使用到所有场景;MacVlan:一个简化版的 bridge 设备,为了隔离需要内核,实现时不允许 MacVlan 容器访问其宿主机 IP 和 ServiceCluster IP;SR-IOV 技术:一种基于硬件的虚拟化解决方案,可提高性能和可伸缩性;SR-IOV 标准允许在虚拟机之间高效共享 PCIe(快速外设组件互连)设备,并且它是在硬件中实现的,可以获得能够与本机性能媲美的 I/O 性能。Overlay 网络:是一种建立在另一网络之上的计算机网络。优势:独立自治,快速扩展,网络策略;劣势:复杂层级,性能损失,定制成本。Kubernetes 相当于云原生的操作系统。有人会问,凭什么云原生的操作系统这杆大旗?主要原因是:Kubernetes 解决了一个分布式操作系统最核心的计算、存储、网络三种资源。CNI 容器网络统一标准:CNCF 项目,为 Linux 容器提供配置网络接口的标准和以该标准扩展插件提供基础函数库;CNI 命令行调用规范,其插件在主机上直接切换进入容器网络命名空间,为容器创建网络设备,配置 IP,路由信息。CNI 规范内容:输入:ADD/DEL 控制指令,CNI 目录,容器 ID,网络命名空间,网卡名称。配置文件:标准部分:cniVersion,Name,Type,IPAM。输出:设备列表、IP 资源列表、DNS 信息。插件应用如:Bridge:Linux 网桥 CNI 实现,采用网卡对链接网桥和容器;Host-device:将主机设备直接移动到容器命名空间中;PTP:创建虚拟网卡对,采用路由方式实现对外互联;MacVlan:网卡多 Mac 地址虚拟技术完整支持 vlan;Vlan:Vlan 设备 CNI 实现,允许容器和主机分属不同 LAN;IPVlan:网卡上基于 IP 实现流量转发。 5.3.3 Overlay 网络-Flannel 方案CoreOS(被 Red Hat 收购)为 Kubernetes 专门定制设计的 overlay 网络方案。03 层网络方案实现:在每台主机部署 flanneld 进程实现网段分配,路由控制,采用多种转发机制实现流量跨机交互。Flannel 职责子网管理:每个主机分配唯一的子网;互联方式:为同 Overlay 平面容器分配唯一 IP。Etcd 存储:容器之间路由映射;SubNetManager:子网资源划分、IP 资源申请释放的接口定义;Backend:针对网络互联方式的接口定义。UDP,UDP 封包转发,建议仅调试使用;VxLAN(建议),使用内核 vxlan 特性实现封包转发;Host-GW,主机 2 层互联情况下较高性能互联方式;IPIP,使用 IPIP 隧道完成封包和转发;IPSec,使用 IPSecurity 实现加密封包转发;AliVPC,对接阿里云 VPC 路由表实现网络互联;AWSVPC,对接 Amazon VPC 路由表实现网络互联。Flannel 的单机互联方案:子网分配:充当虚拟交换机/网关角色,连接所有本机容器,完成虚拟子网构建;Bridge:通过 NAT 借助主机网络实现外部服务访问;Veth pair:一端设置到容器网络 namespace,一端链接 bridge 实现容器接入网络;对外访问:为每个节点分配独立不冲突的 24 位子网。Overlay 解决方案:跨 Node 的 Pod 之间通信通过 Node 之间的 Overlay 隧道。职责:路由控制,数据转发。主要流程:本节点设置:设备创建、本地路由创建、回写本地信息;监听其他节点信息:更新 ARP 信息、更新 FDB、更新路由信息。 5.3.4 Overlay 网络-Calico 方案Calico 项目:是纯三层的虚拟网络解决方案,旨在简化、扩展和保护云网络的容器方案。Calico 优势:可扩展性:采用 IP 路由支持大规模网络。扩展便利,容错性高;网络安全:支持 Kubernetes 网络策略,支持自定义网络策略;广泛集成:集成 Kubernetes ,Mesos,支持 OpenStack,AWS,GCE,Azure。Calico 不足:BGP 支持问题:需要网路设备支持 BGP 协议,否则需要追加 IPIP 隧道;规划 2 层直连:需要节点做良好的规划实现 2 层网络直接互联;大规模配置复杂:网络规划,手动部署 Route Reflector,增加 API 代理。关键组件:BGP Client:和其他节点互联,发布当前节点路由并学习其他节点路由;Confd:同步节点配置信息启动 BGPClient;Felix:负责虚拟设备监控,ACL 控制、状态同步的 agent;Calico:CNI 插件,负责容器设备创建;Calico-IPAM:CNI 插件,负责容器网段管理与 IP 地址管理;RouteReflector:对接 BGPclient 实现路由中转;Etcd/Kube-apiserver:Calico 数据存储;typha:应对大规模节点接入时作为数据缓存 proxy;RouteReflector 安装:集群超过100 个节点时强烈建议启用,通过 RR 中转全局路由信息。Calico 单机互联方案:Veth-pair:一端设置到容器,一端放置在主机上,为容器提供网络出入口;路由策略:针对 IP 和设备设置路由条目,在主机上实现互联。Calico 跨机互联方案:同网段/BGP 支持:主机之间通过 2 层直连或者网络支持路由转发至目标主机;跨网段 IPIP 互联:网络设备不支持 BGP 协议情况下,采用 IPIP 隧道实现跨网段互联;跨网段 VxLAN 互联(Cannel):集成 flannel,底层通过 VxLAN 实现跨机转发。*注:文章源自:https://blog.csdn.net/lianhunqianr1/article/details/118037321未完:一文带你理解云原生|云原生全景指南(下)———————————————————————————————————————————————【 AOC社区 】AOC (Agile Open Container)集成了华为网络云化平台,以及从网络运维中抽象总结出的业务框架,以Yang模型为基础,提供了对网络的开放可编程能力。社区为大家提供了关于数通网络开放可编程一站式学习、体验、认证、交流的平台。以视频为载体构建了在线学习AOC的整个学习、认证体系。另外还提供了SDK、demo样例、以及API手册、开发指导等文档的下载,方便大家进行新项目的开发。
-
获奖名单公布十年树木abcabc胡琦恭喜以上开发者,之前未填写获奖信息的开发者,请与11月5日16:00前完成获奖信息填写。为保证您顺利领取活动奖品,请您提前填写奖品收货信息,如您没有填写,视为放弃奖励。收货信息请【点击此处填写】活动奖励a. 奖励一:参与互动用户每人获得圆梦积分3分b. 奖励二:在所有参与互动用户中抽取3个幸运奖,奖品为《ModelArts人工智能应用开发指南》书籍1本。专家简介王泽锋华为云 云原生开源负责人华为云云原生开源负责人,Kubernetes社区Maintainer,KubeEdge和Volcano项目联合创始人,CNCF技术监督委员会贡献者。对云原生技术和开源生态有深入的见解。 直播简介 云原生已是大势所趋,但是对于企业客户而言,出于数据主权和安全隐私的考虑,企业客户会考虑使用多云混合云方式开展业务,然而不同云环境的基础设施能力、安全架构的差异会造成企业IT架构和运维体系的割裂,加大多云混合云实施的复杂性,提高了运维成本。华为云正式向CNCF捐赠Karmada项目,帮助企业构建多云混合云容器平台。 直播亮点1、了解业界云原生多云混合云的挑战和应对措施2、了解Karmada在多云混合云场景下的管理优势和核心特性原理3、了解如何参与Karmada社区项目 直播时间9月25日 11:00活动时间9月22日—10月7日互动方式直播前您可以在本帖留下您感兴趣的问题,专家会在直播时为您解答。直播后您可以继续在本帖留言,与专家互动交流,我们会在全部活动结束后对参与互动的用户进行抽奖。活动规则本次活动结束后,将由华为云工作人员将符合抽奖条件的用户名单导入至巨公摇号平台(https://www.jugong.wang/random-portal/)内,抽取各奖项,并截屏公示抽奖过程。如您不同意此抽奖规则,请勿参加本次活动。 Tips1、请务必使用个人账号参与活动(IAM、企业账号等账号参与无效)。2、所有获得华为电子产品奖项的获奖用户,请于获奖后3日内完成实名认证,否则视为放弃奖励。3、收货信息填写说明:1)为保证您顺利领取活动奖品,请您提前填写奖品收货信息,如您没有填写,视为放弃奖励。收货信息请【点击此处填写】2)填写时间截至2021年10月25日23:59。3)在HC2021开发者社区系列活动中完成一次填写即可。我们最终将会按照您填写的信息发放奖励。4、活动规则请戳https://bbs.huaweicloud.com/forum/thread-154048-1-1.html
-
通过Docker运行TensorFlow 该方式的优点是不用操心软件依赖问题。方法 首先,安装Docker,一旦Docker已经启动运行,可以通过命令启动一个容器:$ docker run -it b.gcr.io/tensorflow/tensorflow 该命令将启动一个已经安装好的TensorFlow及相关依赖的容器。其它镜像 默认的 Docker 镜像只包含启动和运行 TensorFlow 所需依赖库的一个最小集. 我们额外提供了 下面的容器, 该容器同样可以通过上述 docker run 命令安装: b.gcr.io/tensorflow/tensorflow-full: 镜像中的 TensorFlow 是从源代码完整安装的, 包含了编译和运行 TensorFlow 所需的全部工具。 在该镜像上, 可以直接使用源代码进行实验, 而不需要再安装上述的任何依赖.
-
活动时间:2021年9月16日~2021年10月20日 参与方式:完成下列实验,并在本帖中回复实验完成截图,即可视为完成任务,我们在活动结束后统一核对完成情况。 使用ModelArts实现花卉图像分类基于ModelArts JupyterLab在线调优钢筋检测基于IoT平台构建智慧路灯应用基于CCE进行云原生应用部署与运维管理基于容器实现一分钟自动化部署基于Spark实现车主驾驶行为分析MapReduce服务初体验使用华为云DevCloud实现20分钟一行代码上云基于DevCloud进行黑白棋实时对战游戏开发使用Python爬虫抓取图片和文字实验活动奖励:完成1个沙箱体验即可获得10积分(技能提升直通车中沙箱和微认证积分总和最高可获得100积分)活动规则:请严格按照实验要求体验,并回复沙箱实验截图Tips:1、请务必使用个人账号参与活动(IAM、企业账号等账号参与无效)。2、所有获得华为电子产品奖项的获奖用户,请于获奖后3日内完成实名认证,否则视为放弃奖励。3、收货信息填写说明:1)为保证您顺利领取活动奖品,请您提前填写奖品收货信息,如您没有填写,视为放弃奖励。收货信息请【点击此处填写】2)填写时间截至2021年10月25日23:59。3)在HC2021开发者社区系列活动中完成一次填写即可。我们最终将会按照您填写的信息发放奖励。4、活动规则请戳https://bbs.huaweicloud.com/forum/thread-154048-1-1.html
-
Volcano是一个基于Kubernetes的云原生批量计算平台,也是CNCF的首个批量计算项目。Volcano 主要用于AI、大数据、基因、渲染等诸多高性能计算场景,对主流通用计算框架均有很好的支持。它提供高性能计算任务调度,异构设备管理,任务运行时管理等能力。本篇文章将从Volcano架构、Volcano核心概念及功能、Volcano Code Tour、平台组件安装部署等方面来带大家认识Volcano。 Volcano架构 1、Volcano全景Volcano是基于Kubernetes的高性能批量计算平台,目前支持几乎所有的主流计算框架,包括MindSpore、TensorFlow、Kubeflow、MPI、PyTorch、飞浆、Spark、HOROVOD 等。Volcano支持的部分计算框架 计算框架遇到的问题:1)1:1的operator部署运维复杂2)不同框架对作业管理、并行计算等要求不同3)计算密集高,资源需求波动大,需要高级调度能力 Volcano面向主流计算框架提供:1)统一容器基础设施,提高资源利用率2)通用作业管理、队列Fair-share, Gang, bin-pack等高级调度算法3)简化运维管理 2、Volcano整体架构Volcano利用声明式的CRD定义我们的API,主要有3个核心的API,Volcano Job、PodGroup、Queue。Volcano Job 是对高性能任务的通用定义,PodGroup提供了Job中Task的管理能力,Queue 为任务的分类提供了基础。Volcano的架构 Volcano 核心组件主要包含三个:Admission、ControllerManager、Scheduler 。Admission对Volcano CRD API提供校验能力;ControllerManager负责对Volcano CRD进行资源管理;Scheduler对任务提供丰富的调度能力。 3、Volcano工作流程从零开始运行Volcano作业:1)用户创建一个 Volcano 作业2)Volcano Admission 拦截作业的创建请求,并进行合法性校验3)Kubernetes 持久化存储 Volcano Job 到 ETCD4)ControllerManager 通过 List-Watch 机制观察到Job 资源的创建,创建任务(Pod)5)Scheduler 负责任务的调度,绑定 Node6)Kubelet Watch 到 Pod的创建,接管 Pod 的运行7)ControllerManager 监控所有任务的运行状态,保证所有的任务在期望的状态下运行 Volcano核心概念及功能1、Volcano核心概念1)Queue:Queue的概念源于 Yarn,它是Cluster 级别的资源对象,可为其声明资源配额,也可由多namespace 共享,并且提供 soft isolation2)PodGroup:PodGroup是任务的分组,它与 queue 绑定,占用队列的资源。它与 Volcano Job 是一对一的关系;也可为其声明 Scheduling 条件3)Volcano Job:它是批量计算作业的定义,支持定义作业所属队列、生命周期策略、所包含的任务模板以及持久卷等信息 2、作业管理插件 svc:提供不同类型任务之间互访能力env:任务索引,例如 Tensorflow Worker indexssh:ssh 秘钥对创建及挂载,主要供 MPI 作业使用 3、Scheduler架构Scheduler支持动态配置和加载。 4、核心调度算法1)Gang Scheduling2)Fair Share3)Preempt & Reclaim4)Reserve & Backfill5)Topology Aware Scheduling6)GPU Sharing Volcano Code Tourcmd目录是Volcano所有组件启动的入口;config 是Volcano的配置;defs 是安装时的配置;docs 是Volcano的设计文档;example 提供了简单的例子,hack 提供安装时的脚本;installer 提供安装的模板。 pkg 是最重要的目录,里面包含了 api、controller、scheduler 、webhook 等代码。test 提供了e2e测试用例, vendor是依赖库。 安装部署1、Volcano InstallVolcano安装部署有多种方式:若已存在K8S集群,建议通过 Helm方式安装部署,该方式支持自定义安装配置;开发者建议通过Development Yaml方式部署。 对于开发者,Volcano已内置一键式安装部署脚本,路径为 volcano. sh/volcano/hack/local-up-volcano. sh。运行该脚本时,默认会使用kind创建 Docker in Docker的模拟集群,并安装部署Volcano。 2、Volcano 组件正确安装部署后,将生成4个组件,分别为:Volcano-admission、Volcano-admission-init、Volcano-controllers、 Volcano-scheduler ,其中admission-init以作业的方式生成证书。
-
KubeEdge即Kube+Edge,顾名思义就是依托K8s的容器编排能力和调度能力,实现云边协同、计算下沉、海量设备的平滑接入。本篇文章将从KubeEdge架构设计理念、KubeEdge代码目录概览、KubeEdge集群部署三方面带大家认识KubeEdge。 KubeEdge架构设计理念 1、Kubernetes的架构这里是一个经典的K8s架构,K8s相信大家已经了解比较多了,它主要是分为控制面和数据面,而现在K8s的生态已经非常火爆了,关于应用管理和容器管理已经形成了一套标准,这里列举了它的一些优势:只有API server可以访问etcd组件通过 API Server 访问集群状态API采用声明式设计API对象彼此互补、可组合优先使用事件监听而不是轮询… 2、基于Kubernetes构建边缘计算的优势与痛点 核心优势主要有4方面: 容器化应用封装现在已经成为应用交付的一个趋势,我可以把我的应用打包到容器里,我只打包一次,可以跑在各种地方,这种如果应用到我们IOT领域,我们传统有很多IOT嵌入式设备,它其实很多硬件和软件强相关的,如果换一个硬件,可能软件就要更改,如果说我这个容器化封装以后,设备可支持容器runtime,我可以将容器跑在任何IOT设备上。通用应用抽象定义:K8s的API,包括development、pod现在其实在业内已经形成一套标准,大家都比较了解和认可,其实我们基于这些应用做这个平台,大家也更能容易接受。 松耦合架构:它的可扩展性比较好,比如我们基于K8s之上可以通过CRD来定义一些API,像我们通过设备管理CRD来定义一些IOT里device的一些API,到时候我们可以直接通过K8s的一些方式来管理这些设备;还有一些可扩展,比如它的CIA可以对接各种runtime,我们有些边缘节点它的资源非常有限,我们就可以对接一些轻量化的runtime。 其关键痛点有:1)资源有限网关设备,128MB内存K8s集群需要至少1G内存 2)网络不畅边缘位于私有网络,无公网IP云边跨越公网,带宽有限,延迟高K8s的List-watch需要数据中心网络 3)边缘如何离线自治网络不稳,随时可能离线边缘业务离线可工作边缘离线可故障恢复 4)设备接入和管理缺少边缘设备抽象缺少边缘设备接入协议支持 3、KubeEdge 架构与核心理念我们这个架构主要是分了云、边、端三部分,云上边就是我们的控制面,边就是我们的边缘节点,端就是跑了我们的一些端侧设备,云上左边是一个K8s的master,是没有做过改动的原生的K8s控制面,后边我们加了我们的一个组件叫CloudCore,它云上的组件主要是会拿一些K8s控制面上的东西,通过EdgeController和DeviceController做一些处理,然后通过下边的Cloud Hub,Cloud Hub主要是跟边端通信的,边端有个EdgeHub和Cloud Hub通信,然后把数据拿下来。边端是主要做了一个应用管理和设备管理的能力,应用管理左边会有一个Edged,右边有DeviceTwin、EventBus,分别是应用管理和设备管理,左边有个DataStore,就是我们说的本地自治的能力,比如说我们这应用或者设备的元素从云上分发下来,我们是先把它存到一个数据库里,然后再到它的Edged或者设备里边,这样就能保证云边网络断开或者边缘节点重启了以后我应用的Edged它可以从数据库里把应用源数据拿出来,这样就能保证在故障的情况下业务可以正常恢复。 核心理念:1)云边可靠协同双向多路复用消息通道,支持边缘节点位于私有网络Websocket + 消息封装,大幅减少通信压力,高时延下仍可正常工作云边消息校验,网络不稳定时不丢数据 2)边缘离线自治 节点元数据持久化,实现节点级离线自治节点故障恢复无需List-watch,降低网络压力,快速ready 3)边缘极致轻量重组Kubelet功能模块,极致轻量化(~70mb内存占用)支持CRI集成Containerd、CRI-O,优化runtime资源消耗 4)边缘设备管理云端通过Kubernetes API管理边缘Device 4、KubeEdge 社区生态KubeEdge致力于将Kubernetes的能力拓展到边缘业界首个边缘容器平台项目Apache 2.0协议2019年3月捐给CNCF基金会2020年9月晋级为孵化级托管项目K8s IoT Edge WG参考架构基于Kubernetes构建,100%兼容K8s API11个特性版本,最新版本为v1.6.0(截止2021年3月)3600+ Star,900+ Fork,550+贡献者目前成立3个社区SIG: SIG Device IoT、SIG MEC、SIG AI参与社区贡献的企业包括:中国联通,ARM,中国移动,谐云,中国电信,时速云,JD.com,浙大SEL实验室,EMQ,InfoBlox,Inovex,Midokura等 KubeEdge代码目录概览 ADOPTERS就是我们社区的一些采纳者,比如说你用了KubeEdge,并且想成为参与者,建议者,你可以提一个PR,把你们写到这个ADOPTER里面去,下面的这些就是代码目录,主要就是cloud(云端)、edge(边缘端)、mappers(接入设备的mapper端),还有OWNERS是我们项目的一些matiner,主要负责核代码,比如你对我们社区贡献比较多,我们可以把你加到OWNERS,帮我们核代码和检视代码。 KubeEdge集群部署1、KubeEdge 集群部署工具—— keadm这个是借鉴了K8s的Kubeadm,可以一键部署KubeEdge集群,在部署KubeEdge集群时,要先装一个K8s的master,这个master用任何符合K8s的标准都可以,这个 keadm是基于K8s之上部署KubeEdge系统。 子命令参数:init:部署云端组件join:部署边缘端组件gettoken:从云端获取边缘端启动凭据reset:重置KubeEdge集群的云端和边缘端 2、KubeEdge 部署 —— 云端在已经装好的master上装我们的云端,用 init即可:重要参数:--kube-config:连接K8s Master的凭据--advertise-address:签发到边缘证书里的IP地址 3、KubeEdge 部署 —— 边缘端边缘端主要用我们的join命令:重要参数:--token:边缘端启动时访问云端的凭据--cloudcore-ipport:边缘端访问的云端IP地址
-
随着云原生技术的普及,使用Kubernetes部署应用已经成为常态,越来越多的企业已经步入多集群时代。随着集群数量的增长,对集群的运维、管理带来了新的挑战:集群繁多的重复劳动:运维工程师需要应对繁琐的集群配置、不同云厂商集群间的管理差异以及碎片化的API访问入口等问题;业务过度分散的维护难题:应用在各集群的差异化配置繁琐;业务跨云访问以及集群间的应用同步难以管理。集群的边界限制:应用的可用性受限于集群;资源调度、弹性伸缩受限于集群。厂商绑定:业务部署的黏性问题,缺少自动化故障迁移;缺少中立的开源多云容器编排项目。 Karmada结合了华为云多云容器平台MCP以及Kubernetes Federation核心实践,并融入了众多新技术:包括Kubernetes原生API支持、多层级高可用部署、多集群自动故障迁移、多集群应用自动伸缩、多集群服务发现等,并且提供原生Kubernetes平滑演进路径,让基于Karmada的多云方案无缝融入云原生技术生态,为企业提供从单集群到多云架构的平滑演进方案。Karmada项目全景上图为Karmada在开源社区技术全景,区别于kubefed只做多集群应用分发的局限,Karmada将以模块化的方式提供应用多集群部署、高可用调度、故障迁移、多集群服务发现和流量治理、多云集群生命周期管理等能力集,并面向多种典型的用户场景预置策略集,让用户可以结合企业实际情况自由定制适合自身的多云平台。 2、Karmada关键1)Kubernetes 原生 API兼容既有应用配置及基础设施无需改造,由单集群架构平滑升级到多集群(多云)架构,无缝集成Kubernetes现有工具链生态2)开箱即用面向多场景的内置策略集,包括两地三中心、同城双活、异地容灾等支持应用的跨集群上的自动伸缩、故障迁移和负载均衡3)集中式管理提供地域无关的集中式集群管理支持公有云、私有云或边缘集群4)丰富的多集群调度策略多集群亲和性调度、应用跨集群拆分、资源重新平衡多维度多层次的高可用部署:区域/可用区/集群/供应商等5)开放中立由多家互联网、金融、制造业、电信、云服务厂商共同发起以 CNCF 的开放治理为目标 3、Karmada架构设计Karmada 控制平面由以下几个组件组成:API 服务器(Karmada API Server)控制管理器(Karmada Controller Manager )调度器 (Karmada Scheduler)Karmada通过独立的API 服务器(Karmada API Server)提供与其他组件进行通信的 REST 接口,包含Kubernetes原生API及Karmada扩展API,而Karmada 控制管理器根据用户创建的 API 对象执行操作, Karmada 调度器则实现应用在多集群中的调度。Karmada 控制器运行各种控制器,控制器监视Karmada 的对象,然后与底层集群的 API 服务器通信,对Kubernetes资源进行全生命周期管理。集群控制器:聚焦集群管理,将 Kubernetes 集群附加到 Karmada,通过创建集群对象管理集群的生命周期。策略控制器:实现PropagationPolicy对象的生命周期。根据 PropagationPolicy中的resourceSelector 匹配对应Kubernetes资源对象,并为创建ResourceBinding以进行应用多集群调度。绑定控制器:实现 ResourceBinding 对象的生命周期,根据调度器的角度结果,为每个调度到目标集群的对应资源创建Work 对象;执行控制器:负责work对象与成员集群中实际资源对象的状态同步。 4、未来展望Karmada计划在今年Q4完成整体技术栈的能力开发,发布1.0版本,并捐赠CNCF。 小红书技术部负责人张雷表示:“小红书一直努力为云原生产业发展贡献自己的力量,希望通过Karmada项目,把小红书构建多云业务的实践经验贡献给社区,让更多企业能享受云原生技术的红利。”CNCF总经理Priyanka Sharma也对Karmada项目的开源作出了回应:“华为一直是云原生社区与开发者生态的重要参与者,此次发布的Karmada对所有企业构建多云业务架构至关重要,希望未来CNCF与华为云继续密切合作,持续帮助广大云原生开发者。” 未来,我们也希望越来越多的开发者能加入Karmada社区,共建多云生态!关于 Karmada 的更多技术细节,请查看项目仓库 https://github.com/karmada-io/karmada扫码添加小助手,发送“karmada”加群社区专家入驻,技术问题随时答疑
-
Kubernetes 是当前非常流行的容器编排框架,在其发展早期重点以微服务类应用为主。 但随着Kuberentes的用户越来越多,更多的用户希望在Kubernetes上运行BigData和AI框架,如Spark、TensorFlow等以构建统一的容器平台。但在Kubernetes运行这些高性能应用时,Kubernetes的默认调度器无法满足高性能应用的需求,例如:公平调度、优先级、队列等高级调度功能。由于Kubernetes的默认调度器是基于Pod进行调度,虽然在1.17中引入了调度框架,但仍无法满足高性能应用对作业级调度的需求。 针对云原生场景下的高性能应用场景,华为云容器团队推出了Volcano项目。Volcano是基于Kubernetes构建的一个通用批量计算系统,它弥补了Kubernetes在“高性能应用”方面的不足,支持TensorFlow、Spark、MindSpore等多个领域框架,帮助用户通过Kubernetes构建统一的容器平台。Volcano作为容器调度系统,不仅包括了作业调度,还包含了作业生命周期管理、多集群调度、命令行、数据管理、作业视图及硬件加速等功能。而在调度方面,Volcano 又对场景进行了细分、归类,并提供了相关的方案及算法;同时也为这些功能提供了调度框架,方便用户对调度器进行扩展。对于分布式计算或是并行计算来说,根据场景和作业属性的不同,也可以对其进行细分;在 《并行计算导论》 中将并行计算大致分为三类: 简单的并行简单的并行指多个子任务(tasks)之间没有通信也不需要同步,可以完全的并行的执行。比较著名的例子应该就属MapReduce了,它的两个阶段都属于这种类型:mapper任务在执行时并不会彼此通信同步运行状态;另一个常见的例子是蒙特·卡罗方法 ,各个子任务在计算随机数时也无需彼此通信、同步。由于这种并行计算有比较广泛的应用,例如 数据处理、VatR 等,针对不同的场景也产生了不同的调度框架,例如 Hadoop、DataSynapse 和 Symphony。同时,由于子任务之间无需信息和同步,当其中某几个计算节点(workers)被驱逐后,虽然作业的执行时间可能会变长,但整个作业仍可以顺利完成;而当计算节点增加时,作业的执行时间一般都会缩短。因此,这种作业也常常被称作 Elastic Job。 复杂的并行复杂的并行作业指多个子任务 (tasks) 之间需要同步信息来执行复杂的并行算法,单个子任务无法完成部分计算。最近比较有名的例子应该算是 Tensorflow 的 "ps-work模式" 和 ring all-reduce 了,各个子任务之间需要大量的数据交换和信息同步,单独的子任务无法独立完成。正是由于作业的这种属性,对作业调度平台也提出了相应的调度要求,比如 gang-scheduling、作业拓扑等。由于子任务之间需要彼此通信,因此作业在启动后无法动态扩展子任务,在没有checkpoint的情况下,任一子任务失败或驱逐,整个作业都需要重启,这种作业也常常被称作 Batch Job,传统的HPC场景多属于这种类型的并行作业,针对这种场景的调度平台为 Slurm/PBS/SGE/HTCondor 等。 流水线并行流水线并行是指作业的多个子任务之间存在依赖关系,但不需要前置任务完全结束后再开始后续的任务;比如 Hadoop 里有相应的研究:在 Map 没有完全结束的时候就部分开始 Reduce 阶段,从而提高任务的并行度,提高整体的运行性能。符合这种场景的应用相对来说比较少,一般都做为性能优化;因此没有针对这种场景的作业管理平台。需要区分一下工作流与流水线并行,工作流一般指作业之间的依赖关系,而流水线并行一般指作业内部多个任务之间的依赖。由于工作流中的作业差异比较大,很难提前开始后续步骤。 值得一提的是"二次调度"。由于简单并行的作业一般会有大量的子任务,而且每个子任务所需要的资源相对一致,子任务之间也没有通信和同步;使得资源的复用率相对比较高,因此二次调度在这种场景下能发挥比较大的作用;Hadoop的YARN,Symphony的EGO都属于这种类型。但是在面对复杂并行的作业时,二次调度就显得有也吃力;复杂并行作业一般并没有太多的子任务,子任务之间还经常需要同时启动,子任务之间的通信拓扑也可能不同 (e.g. ps/worker, mpi),而且作业与作业之间对资源的需求差异较大,因此导致了资源的复用率较低。 虽然针对两种不同并行作业类型有不同的作业、资源管理平台,但是根本的目标都是为作业寻找最优的资源;因此,Volcano一直以支持以多种类型的作业为目标进行设计。目前,Volcano可以同时支持 Spark、TensorFlow和MPI等多种类型的作业。常见调度场景组调度 (Gang-scheduling)运行批处理作业(如Tensorflow/MPI)时,必须协调作业的所有任务才能一起启动;否则,将不会启动任何任务。如果有足够的资源并行运行作业的所有任务,则该作业将正确执行;但是,在大多数情况下,尤其是在prem环境中,情况并非如此。在最坏的情况下,由于死锁,所有作业都挂起。其中每个作业只成功启动了部分任务,并等待其余任务启动。 作业级的公平调度 (Job-based Fair-share)当运行多个弹性作业(如流媒体)时,需要公平地为每个作业分配资源,以满足多个作业竞争附加资源时的SLA/QoS要求。在最坏的情况下,单个作业可能会启动大量的pod资源利用率低, 从而阻止其他作业由于资源不足而运行。为了避免分配过小(例如,为每个作业启动一个Pod),弹性作业可以利用协同调度来定义应该启动的Pod的最小可用数量。超过指定的最小可用量的任何pod都将公平地与其他作业共享集群资源。 队列 (Queue)队列还广泛用于共享弹性工作负载和批处理工作负载的资源。队列的主要目的是:1)在不同的“租户”或资源池之间共享资源2)为不同的“租户”或资源池支持不同的调度策略或算法 这些功能可以通过层次队列进一步扩展,在层次队列中,项目被赋予额外的优先级,这将允许它们比队列中的其他项目“跳转”。在kube批处理中,队列被实现为集群范围的CRD。这允许将在不同命名空间中创建的作业放置在共享队列中。队列资源根据其队列配置(kube batch#590)按比例划分。当前不支持分层队列,但正在进行开发。 集群应该能够在不减慢任何操作的情况下处理队列中的大量作业。其他的HPC系统可以处理成百上千个作业的队列,并随着时间的推移缓慢地处理它们。如何与库伯内特斯达成这样的行为是一个悬而未决的问题。支持跨越多个集群的队列可能也很有用,在这种情况下,这是一个关于数据应该放在哪里以及etcd是否适合存储队列中的所有作业或pod的问题。 面向用户的, 跨队列的公平调度 (Namespace-based fair-share Cross Queue)在队列中,每个作业在调度循环期间有几乎相等的调度机会,这意味着拥有更多作业的用户有更大的机会安排他们的作业,这对其他用户不公平。例如,有一个队列包含少量资源,有10个pod属于UserA,1000个pod属于UserB。在这种情况下,UserA的pod被绑定到节点的概率较小。 为了平衡同一队列中用户之间的资源使用,需要更细粒度的策略。考虑到Kubernetes中的多用户模型,使用名称空间来区分不同的用户, 每个命名空间都将配置一个权重,作为控制其资源使用优先级的手段。 基于时间的公平调度 (Fairness over time)对于批处理工作负载,通常不要求在某个时间点公平地分配资源,而是要求在长期内公平地分配资源。例如,如果有用户提交大作业,则允许用户(或特定队列)在一定时间内使用整个集群的一半, 这是可以接受的,但在下一轮调度(可能是作业完成后数小时)中,应惩罚此用户(或队列)而不是其他用户(或队列)。在 HTCondor 中可以看到如何实现这种行为的好例子。 面向作业的优先级调度 (Job-based priority)Pod优先级/抢占在1.14版本中被中断,它有助于确保高优先级的pod在低优先级的pod之前绑定。不过,在job/podgroup级别的优先级上仍有一些工作要做,例如高优先级job/podgroup应该尝试以较低优先级抢占整个job/podgroup,而不是从不同job/podgroup抢占几个pod。 抢占 (Preemption & Reclaim)通过公平分享来支持借贷模型,一些作业/队列在空闲时会过度使用资源。但是,如果有任何进一步的资源请求,资源“所有者”将“收回”。资源可以在队列或作业之间共享:回收用于队列之间的资源平衡,抢占用于作业之间的资源平衡。 预留与回填 (Reservation & Backfill)当一个请求大量资源的“巨大”作业提交给kubernetes时,当有许多小作业在管道中时,该作业可能会饿死,并最终根据当前的调度策略/算法被杀死。为了避免饥饿, 应该有条件地为作业保留资源,例如超时。当资源被保留时,它们可能会处于空闲和未使用状态。为了提高资源利用率,调度程序将有条件地将“较小”作业回填到那些保留资源中。保留和回填都是根据插件的反馈触发的:volcano调度器提供了几个回调接口,供开发人员或用户决定哪些作业应该被填充或保留。 Volcano 调度框架Volcano调度器通过作业级的调度和多种插件机制来支持多种作业;Volcano的插件机制有效的支撑了针对不同场景算法的落地,从早期的gang-scheduling/co-scheduling,到后来各个级别的公平调度。下图展示了Volcano调度器的总体架构: Cache 缓存了集群中Node和Pod信息,并根据PodGroup的信息重新构建 Job (PodGroup) 和 Task (Pod) 的关系。由于在分布式系统中很难保证信息的同步,因此调度器经常以某一时间点的集群快照进行调度;并保证每个调度周期的决定是一致的。在每个调度周期中,Volcano 通过以下几个步骤派发作业: 1、在每个调度周期都会创建一个Session对象,用来存储当前调度周期的所需的数据,例如,Cache 的一个快照。当前的调度器中仅创建了一个Session,并由一个调度线程执行;后续将会根据需要创建多个Session,并为每个Session分配一个线程进行调度;并由Cache来解决调度冲突。 2、在每个调度周期中,会按顺序执行 OpenSession, 配置的多个动作(action)和CloseSession。在 OpenSession中用户可以注册自定义的插件,例如gang、 drf,这些插件为action提供了相应算法;多个action根据配置顺序执行,调用注册的插件进行调度;最后,CloseSession负责清理中间数据。action是第一级插件,定义了调度周期内需要的各个动作;默认提供 enqueue、allocate、 preempt和backfill四个action。以allocate为例,它定义了调度中资源分配过程:根据 plugin 的 JobOrderFn 对作业进行排序,根据NodeOrderFn对节点进行排序,检测节点上的资源是否满足,满足作业的分配要求(JobReady)后提交分配决定。由于action也是基于插件机制,因此用户可以重新定义自己的分配动作,例如 基于图的调度算法firmament。plugin是第二级插件,定义了action需要的各个算法;以drf插件为例,为了根据dominant resource进行作业排序,drf插件实现了 JobOrderFn函数。JobOrderFn函数根据 drf 计算每个作业的share值,share值较低代表当前作业分配的资源较少,因此会为其优先分配资源;drf插件还实现了EventHandler回调函数,当作业被分配或抢占资源后,调度器会通知drf插件来更新share值。 3、Cache 不仅提供了集群的快照,同时还提供了调度器与kube-apiserver的交互接口,调度器与kube-apiserver之间的通信也都通过Cache来完成,例如 Bind。 同时,为了支持上面这些场景,Volcano的调度器还增加了多个Pod状态以提高调度的性能:Pending: 当Pod被创建后就处于Pending状态,等待调度器对其进行调度;调度的主要目的也是为这些Pending的Pod寻找最优的资源Allocated: 当Pod被分配空闲资源,但是还没有向kube-apiserver发送调度决策时,Pod处于Allocated状态。Allocated状态仅存在于调度周期内部,用于记录Pod和资源分配情况。当作业满足启动条件时 (e.g. 满足minMember),会向kube-apiserver提交调度决策。如果本轮调度周期内无法提交调度决策,由状态会回滚为Pending状态 Pipelined: 该状态与Allocated状态相似,区别在于处于该状态的Pod分配到的资源为正在被释放的资源 (Releasing)。该状态主要用于等待被抢占的资源释放。该状态是调度周期中的状态,不会更新到kube-apiserver以减少通信,节省kube-apiserver的qps。Binding: 当作业满足启动条件时,调度器会向kube-apiserver提交调度决策,在kube-apiserver返回最终状态之前,Pod一直处于Binding状态。该状态也保存在调度器的Cache之中,因此跨调度周期有效。Bound: 当作业的调度决策在kube-apiserver确认后,该Pod即为Bound状态。Releasing: Pod等待被删除时即为Releasing状态。Running, Failed, Succeeded, Unknown: 与Pod的现有含义一致。 状态之间根据不同的操作进行转换,见下图。 Pod的这些状态为调度器提供了更多优化的可能。例如,当进行Pod驱逐时,驱逐在Binding和Bound状态的Pod要比较驱逐Running状态的Pod的代价要小 (思考:还有其它状态的Pod可以驱逐吗?);并且状态都是记录在Volcano调度内部,减少了与kube-apiserver的通信。但目前Volcano调度器仅使用了状态的部分功能,比如现在的preemption/reclaim仅会驱逐Running状态下的Pod;这主要是由于分布式系统中很难做到完全的状态同步,在驱逐Binding和Bound状态的Pod会有很多的状态竞争。 Volcano调度实现Volcano调度器在支持上面这些主要场景时,分别使用了action和plugin两级插件。 总体来讲,带有动作属性的功能,一般需要引入 action 插件;带有选择 (包括排序) 属性的功能,一般使用 plugin 插件。因此,这些常见场景中,fair-sharing、queue、co-scheduling都通过plugin机制来实现:都带有选择属性,比如“哪些作业应该被优先调度”;而preemption、reclaim、backfill、reserve 则通过 action 机制来实现:都带有动作属性,比如“作业A 抢占 作业B”。 这里需要注意的是,action 与 plugin 一定是一同工作的;fair-sharing 这些 plugin 是借助 allocate 发展作用,而 preemption 在创建新的 action 后,同样需要 plugin 来选择哪些作业应该被抢占。 通过job-based fairness (DRF) 和 preempt 两个功能的实现来介绍action 和 plugin 两种插件机制的使用,其它功能类似:Job-based Fairness (DRF): 目前的公平调度是基于DRF,并通过 plugin 插件来实现。在 OpenSession 中会先计算每个作业的 dominant resource和每个作业share的初始值;然后注册 JobOrderFn回调函数,JobOrderFn 中接收两个作业对象,并根据对像的 dominant resource 的 share值对作业进行排序;同时注册EventHandler, 当Pod被分配或抢占资源时,drf根据相应的作业及资源信息动态更新share值。其它插件的实现方案也基本相似,在OpenSession中注册相应的回调,例如 JobOrderFn, TaskOrderFn,调度器会根据回调函数的结果决定如何分配资源,并通过EventHandler来更新插件内的调度数。Preemption: preempt是在allocate之后的一个action,它会为“高”优先级的Pending作业选取一个或多个“低”优先级的作业进行驱逐。由于抢占的动作与分配的动作不一致,因此新创建了preempt action来处理相应的逻辑;同时,在选取高低优先级的作业时,preempt action还是依赖相应的plugin插件来实现。其它动作插件的实现方式也类似,即根据需要创建整体的流程;将带有选择属性的问题转换为算法插件。深入了解VolcanoVolcano官网:https://volcano.shGithub : https://github.com/volcano-sh/volcano
-
基于容器和无服务器平台的云原生应用在正在快速地被全球的组织所部署。虽然说云原生应用会带来易延展性、无与伦比的韧性、以及快捷的开发速度,云原生应用同样会带来挑战。云原生应用会有大量的可移动成分,并且基于那些短暂的架构组件。这就会给运营和维护产生难度;除此以外,自然还有安全隐患。云原生安全需要新的解决思路、策略和工具。这里,有五个可以帮助改善企业云原生安全的小建议。什么是云原生?云原生应用为云而创建,而且整个软件开发生命周期——开发、部署、测试和升级,都会在云环境完成。“云”的概念不局限于公有云,也可以意味着远程和本地资源都有的混合云或者超过一个云供应商的多云环境。云原生计算基金会(CNCF)认为三种工具应该用于云原生计算中:容器化、微服务结构和动态编排。容器化意味着软件和其关联依赖绑定,从而实现软件可移动、可扩展;动态编排包括了使用Kubernetes等工具管理云端容器;而微服务结构能够优化资源。容器能够被另一项云原生计算能力——无服务器功能所替代。云原生的安全挑战云原生应用给基础设施和应用安全带来了额外挑战。以下是一些关键挑战:多个需要保护的实体:DevOps团队和基础设施团队会使用微服务来运行云原生应用。在过去,多个进程或者软件功能会在一个虚拟机上运行。现在,每个进程或者能力都会被包装成分离的容器或者无服务器功能。每个实体都易于被攻破,因此需要全开发周期的防护。多样的结构:云原生系统会涉及很多公有云和私有云、云服务、以及应用结构。每个结构都有不同的隐患和安全需求。安全团队必须理解这一复杂的攻击面,并且为每个不同的结构找到解决方案。不断变化的环境:公有云和私有云环境在持续变化。快速的软件发布周期意味着微服务应用的每个组件都必须每日进行升级。另外,使用不可变性和基础设施即代码意味着应用会被持续分解并重构。安全团队会发现很难在不减缓发布周期的情况下,保护这些技术应用。如何保护云原生应用有多种保护云原生应用的方式,包括:安全左移、在函数和容器级别应用边界安全、贯彻最小角色和最低权限、保护应用依赖,以及安全共责。1. 安全左移许多企业依然在使用已有的工具,却无法处理云原生应用环境的速度、规模和动态网络。如果再加上无服务器功能,会让整个基础设施变得更抽象,让问题更严重。网络攻击者会寻找容器和无服务器代码中的隐患,以及云基础设施中的错误配置,以接入包含敏感信息的实体,再用它们提升权限,攻击其他实体。另一个问题是企业在用CI/CD工具持续开发、测试和发布应用。当使用容器部署云原生应用的时候,开发者会从本地或者公共库当中获取镜像,但一般不会检查这些镜像是否包含安全隐患。一种解决方案是给安全团队提供一些工具,阻止不受信任的镜像进入CI/CD管道,以及启用一些机制让不受信任的镜像在进入生产前就避免产生安全问题。通过在开发流程早期扫描镜像的漏洞、恶意软件成分等,开发者可以贯彻安全标准。2. 在函数和容器级别应用边界安全在无服务器应用中,系统会被分解成几个能从不同资源接受项目触发的可调用组件。这就给了攻击者更大的攻击选择,以及更多实施恶意行为的途径。一个很重要的方式是使用为云原生环境而制作的API和应用安全工具。除此以外,一个很普遍的操作是在功能级别使用边界安全——识别功能是否被一个和平时不同的来源所触发,然后监控事件触发中存在的异常情况。在容器化环境里,一个重要点是在不同级别都要实现安全——编排控制面板、物理主机、pod和容器。编排的一些最佳安全实践包括节点隔离、限制和监测容器之间的流量、以及对API服务器使用第三方认证机制。3. 最小角色与最低权限云原生资源之间会有大量频繁的交互。如果能够对每个无服务器功能或者容易都能配置一些独特的许可,就能有极大概率提升安全性。可以通过基于每个函数使用IAM,或者对容器进行颗粒度的许可,加强接入控制。花一点时间创建最小角色,或者为每个函数或容器创建一系列的许可。这就确保了即使云原生结构中有一个点失陷,其造成的危害也是最小的,并且会防止其他元件产生提权问题。4. 保护应用依赖无服务器函数和应用的代码经常从npm或者PyPI的库中获取有依赖关系的包。为了保护应用的依赖,就需要包括完整开源组件以及其漏洞数据库的自动化工具。同样,还需要能够在开发流程中触发安全行为的云原生编排工具。通过持续运作这些工具,就可以防范产线上运行的有隐患的代码包或者容器。5. 安全共责在开发者、DevOps和安全团队之间建立亲密的关系。开发者并不是安全专家,但他们可以被教导安全操作知识,从而确保他们可以安全地编写代码。安全团队应该知道应用是如何开发、测试和部署的,还有哪些工具在流程中被使用,从而安全团队能够在这些流程中有效地加入安全元素。云原生要求各种企业管理安全和开发的方式,因此尽快让不同团队减少隔阂至关重要。云原生的启用对企业来说是一个形成合作和共享文化的罕见契机。结论这篇文章提及了云原生面临的挑战,包括大量需要保护的实体,以及持续变化的环境和结构。同样,也给出了五个能够改善云原生环境的最佳实践:安全左移,在问题进入产线前进行规避。在函数和容器级别应用边界安全。对云原生应用中的实体实行最小角色和最低权限。保护好应用依赖。鼓励开发、运营和安全团队之间的安全共责。点评业务节奏加快使得无服务器应用等云原生应用会越来越多被企业所启用,云原生的安全也会更多被注意。不难发现,本文提到的五个安全建议中,软件安全相关的建议占了大部分:无论是安全左移、应用依赖的防护、还是实现DevSecOps整个安全协同,最终都离不开开发安全相关。这一点来看,DevSecOps和API安全的重要性都会随着云原生的使用进一步地提升。来源:https://netsecurity.51cto.com/art/202108/677745.htm
-
【功能模块】容器模块【操作步骤&问题现象】1、主机把按要求添加映射,保存重启,但LTE0映射不进去容器2、本来主机有LTE0映射之后主机的LTE0也没了,关机等一段时间重新启动,主机的LTE0就有了【截图信息】【日志信息】(可选,上传日志内容或者附件)
-
对象定义你可以使用字符来定义和创建 JavaScript 对象:实例var person = {firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"};定义 JavaScript 对象可以跨越多行,空格跟换行不是必须的:实例var person = { firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"};对象属性可以说 "JavaScript 对象是变量的容器"。但是,我们通常认为 "JavaScript 对象是键值对的容器"。键值对通常写法为 name : value (键与值以冒号分割)。键值对在 JavaScript 对象通常称为 对象属性。Note JavaScript 对象是属性变量的容器。对象键值对的写法类似于:PHP 中的关联数组Python 中的字典C 语言中的哈希表Java 中的哈希映射Ruby 和 Perl 中的哈希表访问对象属性你可以通过两种方式访问对象属性:实例 1person.lastName;实例 2person["lastName"];对象方法对象的方法定义了一个函数,并作为对象的属性存储。对象方法通过添加 () 调用 (作为一个函数)。该实例访问了 person 对象的 fullName() 方法:实例name = person.fullName();如果你要访问 person 对象的 fullName 属性,它将作为一个定义函数的字符串返回:实例name = person.fullName; Note JavaScript 对象是属性和方法的容器。在随后的教程中你将学习到更多关于函数,属性和方法的知识。访问对象方法你可以使用以下语法创建对象方法:methodName : function() { // 代码 }你可以使用以下语法访问对象方法:实例objectName.methodName()通常 fullName() 是作为 person 对象的一个方法, fullName 是作为一个属性。如果使用 fullName 属性,不添加 (), 它会返回函数的定义:实例objectName.methodName
-
在NFS的基础之上,为了简便运维与管理,增加了持久卷的概念。PersistentVolume(PV):对存储资源创建和使用的抽象,使得存储作为集群中的资源管理PersistentVolumeClaim(PVC):让用户不需要关心具体的Volume实现细节。注:图片截取自李振良老师的视频课程上图是PV、PVC的使用逻辑,通俗的理解:一个企业雇一帮人工作(nfs),选个小组长(pv),再来个团队长(pvc),这样消费者就不会直接面对生产者,企业好管理,用户的服务也有保证。其实就是软件世界的官僚机构~PV使用方式:静态供给,需要K8s运维工程师提前创建一堆PV,供开发者使用。示例:[root@k8s-node2 /]# cat pv.yamlapiVersion: v1kind: PersistentVolumemetadata: name: my-pvspec: capacity: storage: 5Gi accessModes: - ReadWriteMany nfs: path: /ifs/kubernetes server: 192.168.0.21[root@k8s-node2 /]# cat deployment-pvc.yamlkind: DeploymentapiVersion: apps/v1metadata: name: deployment-pvcspec: selector: matchLabels: app: nginx-pvc replicas: 2 template: metadata: labels: app: nginx-pvc spec: containers: - name: nginx image: nginx volumeMounts: - name: wwwroot mountPath: /usr/share/nginx/html ports: - containerPort: 80 volumes: - name: wwwroot persistentVolumeClaim: claimName: my-pvc---apiVersion: v1kind: PersistentVolumeClaimmetadata: name: my-pvcspec: accessModes: - ReadWriteMany resources: requests: storage: 5Gi[root@k8s-node2 /]# 容器应用和卷需求模板写在了一个depolyment-pvc.yaml中,数据卷的定义写在了pv.yaml中。root@k8s-node2 /]# kubectl apply -f deployment-pvc.yamldeployment.apps/deployment-pvc createdpersistentvolumeclaim/my-pvc created[root@k8s-node2 /]# kubectl get pod -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESdeployment-pvc-84df7c6f46-b98wx 1/1 Running 0 55m 10.244.169.144 k8s-node2 <none> <none>deployment-pvc-84df7c6f46-d787b 1/1 Running 0 55m 10.244.169.143 k8s-node2 <none> <none>nginx-6799fc88d8-z76rk 1/1 Running 2 45h 10.244.169.142 k8s-node2 <none> <none>[root@k8s-node2 /]# curl 10.244.169.144hello //上一个实验中的index.html文件[root@k8s-node2 /]# cd ifs[root@k8s-node2 ifs]# cd kubernetes[root@k8s-node2 kubernetes]# echo hello world>index.html[root@k8s-node2 kubernetes]# curl 10.244.169.144 hello world[root@k8s-node2 kubernetes]#
-
最近复习了一遍Spring IOC容器的初始化过程,结合书籍《Spring源码深度解析》总结了一下,IOC容器的初始化过程,大概分为以下三点:1、定位资源: 定位相关的配置文件,扫描相关注解2、加载资源: 将配置信息加载到内存中3、注册: 根据载入的配置信息,初始化对象,并将其装载至容器中POM文件<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>springTest</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> </dependencies> </project>测试代码public class ServiceB { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); Object serviceA = context.getBean("serviceA"); System.out.println(serviceA); }xml配置<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> <context:component-scan base-package="com.donkeys.spring"/> <bean id="serviceA" class="com.donkeys.spring.service.ServiceA"></bean> </beans>ClassPathXmlApplicationContext构造方法 public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { super(parent); //根据传入的配置文件名称,调用父类的setConfigLocations方法,解析配置文件路径, setConfigLocations(configLocations); //refresh = true //refresh() 方法会重启整个容器 if (refresh) { refresh(); } } 构造方法中一共做了2件事,首先是设置配置文件的路径,然后对整个容器进行刷新。 这里我们重点关注refresh()方法;进入refresh()方法AbstractApplicationContext类的refresh()方法@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. //为刷新前做准备 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. //获取IOC容器,这里就是处理资源定位以配置文件加载/注册的方法 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } } 这里主要关注**obtainFreshBeanFactory()**方法/** * Tell the subclass to refresh the internal bean factory. * @return the fresh BeanFactory instance * @see #refreshBeanFactory() * @see #getBeanFactory() */ protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { //刷新IOC容器 //这里使用了委派设计模式,父类定义了抽象的refreshBeanFactory方法,具体调用实现调用子类的refreshBeanFactory方法 refreshBeanFactory(); //获取一个新的容器 ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; } **obtainFreshBeanFactory()**方法总共干了2件事, 重置容器,refreshBeanFactory()方法中会设置相关标志,清除旧的容器,同时为Spring上下文生成一个新的容器,获取一个新的容器AbstractRefreshableApplicationContext的refreshBeanFactory()方法 下面我们进入**refreshBeanFactory()**方法/** * This implementation performs an actual refresh of this context's underlying * bean factory, shutting down the previous bean factory (if any) and * initializing a fresh bean factory for the next phase of the context's lifecycle. * 该方法会将之前的bean工厂全部关闭,并初始化一个全新的bean 工厂类 用于Spring 上下文的生命周期 * bean工厂就是IOC容器 */ @Override protected final void refreshBeanFactory() throws BeansException { //判断是否之前也有容器 //如果有就销毁掉 if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { //创建一个新的工厂 DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); //读取Bean对象的定义 //这里也是使用的委派设计模式 loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } } 这里创建了新的容器工厂,同时将新的工厂传入了loadBeanDefinitions()方法中,下面来看一下在loadBeanDefinitions方法中具体做了什么操作。AbstractXmlApplicationContext的 loadBeanDefinitions(DefaultListableBeanFactory beanFactory)方法 在AbstractRefreshableApplicationContext类的refreshBeanFactory方法中,调用了loadBeanDefinitions方法,但是这个方法它的一个抽象方法,具体实现应由子类去实现,我们在程序启动时,使用的ClassPathXmlApplicationContext类。根据文章开头的类图可以知道,这里会调用子类AbstractXmlApplicationContext的loadBeanDefinitions方法去完成本次加载@Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. //使用默认的beanFactory去创建 XmlBeanDefinitionReader XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. //设置资源的加载环境 beanDefinitionReader.setEnvironment(this.getEnvironment()); //设置资源读取器 beanDefinitionReader.setResourceLoader(this); //设置实体解析器 beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. //初始化 bean对象定义读取器 initBeanDefinitionReader(beanDefinitionReader); //使用初始化完成的读取器,调用loadBeanDefinitions方法 loadBeanDefinitions(beanDefinitionReader); } 总的来说,这里只干了一件事,那就是初始化配置//设置资源读取器 beanDefinitionReader.setResourceLoader(this); //初始化 bean对象定义读取器 initBeanDefinitionReader(beanDefinitionReader); 设置资源读取器,这里设置的资源读取器就是当前这个对象本身 通过类图我们可以发现我们这个类的顶级父类ApplicationContext,继承自DefaultResourceLoader这个类,该类实现了ResourceLoader接口,说明这个类的实例化对象本身是具有资源读取器的功能的 初始化bean对象定义读取器,这里设置xml文件的校验方式 下面我们继续看**loadBeanDefinitions(XmlBeanDefinitionReader reader)**方法protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { //从子类对象中获取到资源定位 Resource[] configResources = getConfigResources(); if (configResources != null) { //XmlBeanDefinitionReader 读取器调用其父类的 reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } } 先看这一行//这行代码的具体实现是由子类完成的,通过类图可以知道AbstractXmlApplicationContext的子类为ClassPathXmlApplicationContext //这里主要将我们最开始在构造方法中设置好的配置文件进行返回 Resource[] configResources = getConfigResources(); 再看这一行//如果返回的配置文件不为空,就将返回的已经封装好的资源文件进行读取, if (configResources != null) { //XmlBeanDefinitionReader 读取器调用其父类的 reader.loadBeanDefinitions(configResources); } 至此。资源文件定位过程已经加载完成。后续就是读取和注册。整个IOC容器加载过程中最重要的是读取过程,我们可以从刚刚的定位过程来看,虽然叫定位过程,但是其实就是一个配置文件读取器的初始化过程,这个过程会设置相关的解析策略以及校验策略。最终读取器生成后,就可以将我们早早设置好的配置文件载入然后进行读取。
-
【功能模块】容器编译【操作步骤&问题现象】1、根据AR-CORE-220E开发指南容器制作步骤编译出容器;2、安装到AR-CORE-220E设备上;3、使用container status查看容器状态,此时容器ip是ipv6地址;4、等待几分钟后,再次查看,容器ip仍旧是ipv6地址【截图信息】【日志信息】(可选,上传日志内容或者附件)
上滑加载中
推荐直播
-
华为云码道Agent集成与鸿蒙实战2026/08/11 周二 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;彭江敏-华为云鸿蒙端云一体化开发专家
本次直播带你解读华为云码道7月份产品新特性、新功能。更有专家演示码道Agent Space × 钉钉机器集成实战,从0到1打通消息通道;码道鸿蒙端云一体化实战,快速搭建员工签到系统。
回顾中 -
华为云开发者AI素养直播课·第五期2026/09/04 周五 16:00-18:00
林华鼎-华为云AI开发者运营负责人;蒋春阳-华为云AI开发者案例开发专家
本期直播内容: AI工具体验营 · 第5-8课连讲。Agent-Team 多智能体协作完成毕业设计实践
回顾中 -
华为云开发者AI素养ClassRoom·第六期2026/09/08 周二 19:00-20:00
樊渊-2026华为软件挑战赛冠军
高手来了:看软挑高手解析二维排样问题—从工业难题到算法突破
回顾中
热门标签