Kubernetes

Kubernetes 简介

Kubernetes是一个全新的基于容器技术的分布式架构领先方案, 它是Google在2014年6月开源的一个容器集群管理系统,使用Go语言开发,Kubernetes也叫K8S。K8S是Google内部一个叫Borg的容器集群管理系统衍生出来的,Borg已经在Google大规模生产运行十年之久。K8S主要用于自动化部署、扩展和管理容器应用,提供了资源调度、部署管理、服务发现、扩容缩容、监控等一整套功能。2015年7月,Kubernetes v1.0正式发布,截止到2017年9月29日最新稳定版本是v1.8。Kubernetes目标是让部署容器化应用简单高效。

Kubernetes最初源于谷歌内部的Borg,提供了面向应用的容器集群部署和管理系统。Kubernetes 的目标旨在消除编排物理/虚拟计算,网络和存储基础设施的负担,并使应用程序运营商和开发人员完全将重点放在以容器为中心的原语上进行自助运营。Kubernetes 也提供稳定、兼容的基础(平台),用于构建定制化的workflows 和更高级的自动化任务。

Kubernetes 具备完善的集群管理能力,包括多层次的安全防护和准入机制、多租户应用支撑能力、透明的服务注册和服务发现机制、内建负载均衡器、故障发现和自我修复能力、服务滚动升级和在线扩容、可扩展的资源自动调度机制、多粒度的资源配额管理能力。Kubernetes 还提供完善的管理工具,涵盖开发、部署测试、运维监控等各个环节。

Kubernetes 是什么

Kubernetes 提供了很多的功能,它可以简化应用程序的工作流,加快开发速度。通常,一个成功的应用编排系统需要有较强的自动化能力,这也是为什么 Kubernetes 被设计作为构建组件和工具的生态系统平台,以便更轻松地部署、扩展和管理应用程序。

用户可以使用 Label 以自己的方式组织管理资源,还可以使用 Annotation 来自定义资源的描述信息,比如为管理工具提供状态检查等。

此外,Kubernetes 控制器也是构建在跟开发人员和用户使用的相同的 API 之上。用户可以编写自己的控制器和调度器,也可以通过各种插件机制扩展系统的功能。这种设计使得用户可以方便地在 Kubernetes 之上构建各种应用系统。

Kubernetes 不是什么

Kubernetes 不是一个传统意义上,包罗万象的 PaaS(平台即服务)系统。它给用户预留了选择的自由。

Kubernetes 通过声明式的 API 和一系列独立、可组合的控制器保证了应用总是在期望的状态,而用户并不需要关心中间状态是如何转换的。这使得整个系统更容易使用,而且更强大、更可靠、更具弹性和可扩展性。

主要功能

Kubernetes是docker容器用来编排和管理的工具,它是基于Docker构建一个容器的调度服务,提供资源调度、均衡容灾、服务注册、动态扩缩容等功能套件。Kubernetes提供应用部署、维护、 扩展机制等功能,利用Kubernetes能方便地管理跨机器运行容器化的应用,其主要功能如下:

数据卷Pod中容器之间共享数据,可以使用数据卷。

应用程序健康检查容器内服务可能进程堵塞无法处理请求,可以设置监控检查策略保证应用健壮性。

复制应用程序实例控制器维护着Pod副本数量,保证一个Pod或一组同类的Pod数量始终可用。

弹性伸缩根据设定的指标(CPU利用率)自动缩放Pod副本数。

服务发现使用环境变量或DNS服务插件保证容器中程序发现Pod入口访问地址。

负载均衡一组Pod副本分配一个私有的集群IP地址,负载均衡转发请求到后端容器。在集群内部其他Pod可通过这个ClusterIP访问应用。

滚动更新更新服务不中断,一次更新一个Pod,而不是同时删除整个服务。

服务编排通过文件描述部署服务,使得应用程序部署变得更高效。

资源监控Node节点组件集成cAdvisor资源收集工具,可通过Heapster汇总整个集群节点资源数据,然后存储到InfluxDB时序数据库,再由Grafana展示。

提供认证和授权支持角色访问控制(RBAC)认证授权等策略。

 

除此之外, Kubernetes主要功能还体现在: - 使用Docker对应用程序包装(package)、实例化(instantiate)、运行(run)。 - 将多台Docker主机抽象为一个资源,以集群的方式运行、管理跨机器的容器,包括任务调度、资源管理、弹性伸缩、滚动升级等功能。 - 使用编排系统(YAML File)快速构建容器集群,提供负载均衡,解决容器直接关联及通信问题 - 解决Docker跨机器容器之间的通讯问题。 - 自动管理和修复容器,简单说,比如创建一个集群,里面有十个容器,如果某个容器异常关闭,那么,会尝试重启或重新分配容器,始终保证会有十个容器在运行,反而杀死多余的。Kubernetes的自我修复机制使得容器集群总是运行在用户期望的状态. 当前Kubernetes支持GCE、vShpere、CoreOS、OpenShift。

kubernetes的集群至少有两个主机组成:master + node ,即为master/node架构。master为集群的控制面板,master主机需要做冗余,一般建议为3台;而node主机不需要做冗余,因为node的主要作用是运行pod,贡献计算能力和存储能力,而pod控制器会自动管控pod资源,如果资源少,pod控制器会自动创建pod,即pod控制器会严格按照用户指定的副本来管理pod的数量。客户端的请求下发给master,即把创建和启动容器的请求发给master,master中的调度器分析各node现有的资源状态,把请求调用到对应的node启动容器。

可以理解为kubernetes把容器抽象为pod来管理1到多个彼此间有非常紧密联系的容器,但是LAMP的容器主机A,M,P只是有关联,不能说是非常紧密联系,因此A,M,P都要运行在三个不同的pod上。在kubernetes中,要运行几个pod,是需要定义一个配置文件,在这个配置文件里定义用哪个控制器启动和控制几个pod,在每个pod里要定义那几台容器,kubernetes通过这个配置文件,去创建一个控制器,由此控制器来管控这些pod,如果这些pod的某几个down掉后,控制器会通过健康监控功能,随时监控pod,发现pod异常后,根据定义的策略进行操作,即可以进行自愈。

 

 

 

 

基本对象

Node

K8s集群中的计算能力由Node提供,最初Node称为服务节点Minion,后来改名为Node。K8s集群中的Node也就等同于Mesos集群中的Slave节点,是所有Pod运行所在的工作主机,可以是物理机也可以是虚拟机。不论是物理机还是虚拟机,工作主机的统一特征是上面要运行kubelet管理节点上运行的容器。

Pod

Pod是最小部署单元,一个Pod有一个或多个容器组成,Pod中容器共享存储和网络,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。在同一台Docker主机上运行。

Pod是k8s进行资源调度的最小单位,每个Pod中运行着一个或多个密切相关的业务容器,这些业务容器共享这个Pause容器的IP和Volume,我们以这个不易死亡的Pause容器作为Pod的根容器,以它的状态表示整个容器组的状态。一个Pod一旦被创建就会放到Etcd中存储,然后由Master调度到一个Node绑定,由这个Node上的Kubelet进行实例化。每个Pod会被分配一个单独的Pod IP,Pod IP + ContainerPort 组成了一个Endpoint

K8s中的业务主要可以分为长期伺服型(long-running)、批处理型(batch)、节点后台支撑型(nodedaemon)和有状态应用型(stateful application);分别对应的小机器人控制器为Deployment、Job、DaemonSet和StatefulSet

Service

Service一个应用服务抽象, YAML 或 JSON 定义了Pod逻辑集合和访问这个Pod集合的策略。

一个Pod只是一个运行服务的实例,随时可能在一个Node上停止,在另一个Node以一个新的IP启动一个新的Pod,因此不能以确定的IP和端口号提供服务。

Service代理Pod集合对外表现是为一个访问入口,分配一个集群IP地址,来自这个IP的请求将负载均衡转发后端Pod中的容器。

Service通过Lable Selector选择一组Pod提供服务。

Volume

存储卷,共享Pod中容器使用的数据及持久化数据。K8s的存储卷的生命周期和作用范围是一个Pod。每个Pod中声明的存储卷由Pod中的所有容器共享。

Namespace

命名空间也称为虚拟集群。命名空间为K8s集群提供虚拟的隔离作用,K8s集群初始有两个命名空间,分别是默认命名空间default和系统命名空间kubesystem,除此以外,管理员可以创建新的命名空间满足需要。

命名空间将对象逻辑上分配到不同Namespace,可以是不同的项目、用户等区分管理,并设定控制策略,从而实现多租户。

Lable

标签用于区分对象(比如Pod、Service),键/值对存在;每个对象可以有多个标签,通过标签关联对象。

用户帐户(User Account)和服务帐户(Service Account) 用户帐户为人提供账户标识,而服务账户为计算机进程和K8s集群中运行的Pod提供账户标识。用户帐户和服务帐户的一个区别是作用范围;用户帐户对应的是人的身份,人的身份与服务的namespace无关,所以用户账户是跨namespace的;而服务帐户对应的是一个运行中程序的身份,与特定namespace是相关的。

基本对象的更高层次抽象

ReplicaSet(RS)

下一代Replication Controller(RC)。确保任何给定时间指定的Pod副本数量,并提供声明式更新等功能。

RC与RS唯一区别就是lable selector支持不同,RS支持新的基于集合的标签,RC仅支持基于等式的标签。

Deployment

Deployment是一个更高层次的API对象,它管理ReplicaSet和Pod,并提供声明式更新等功能。

官方建议使用Deployment管理ReplicaSets,而不是直接使用ReplicaSets,这就意味着可能永远不需要直接操作ReplicaSet对象。

实际是创建一个新的RS,然后逐渐将新RS中副本数增加到理想状态,将旧RS中的副本数减小到0的复合操作;这样一个复合操作用一个RS是不太好描述的,所以用一个更通用的Deployment来描述。

StatefulSet 有状态服务集(StatefulSet)适合持久性的应用程序,有唯一的网络标识符(IP),持久存储,有序的部署、扩展、删除和滚动更新。

StatefulSet中的每个Pod的名字都是事先确定的,不能更改。

对于RC和RS中的Pod,一般不挂载存储或者挂载共享存储,保存的是所有Pod共享的状态,Pod像牲畜一样没有分别;对于StatefulSet中的Pod,每个Pod挂载自己独立的存储,如果一个Pod出现故障,从其他节点启动一个同样名字的Pod,要挂载上原来Pod的存储继续以它的状态提供服务。

适合于StatefulSet的业务包括数据库服务MySQL和PostgreSQL,集群化管理服务Zookeeper、etcd等有状态服务。

DaemonSet

后台支撑服务集(DaemonSet)确保所有(或一些)节点运行同一个Pod。当节点加入Kubernetes集群中,Pod会被调度到该节点上运行,当节点从集群中移除时,DaemonSet的Pod会被删除。删除DaemonSet会清理它所有创建的Pod。

典型的后台支撑型服务包括,存储,日志和监控等在每个节点上支撑K8s集群运行的服务。

Job Job是K8s用来控制批处理型任务的API对象,用于执行一次性任务,运行完成后Pod销毁,不再重新启动新容器。还可以任务定时运行。

成功完成的标志根据不同的spec.completions策略而不同:单Pod型任务有一个Pod成功就标志完成;定数成功型任务保证有N个任务全部成功;工作队列型任务根据应用确认的全局成功而标志成功。

RBAC 相对于基于属性的访问控制(Attribute-based Access Control,ABAC),RBAC主要是引入了角色(Role)角色绑定(RoleBinding)的抽象概念。在ABAC中,K8s集群中的访问策略只能跟用户直接关联;而在RBAC中,访问策略可以跟某个角色关联,具体的用户在跟一个或多个角色相关联。

 

 

架构图

 

最上层是kubectl,用户通过这个工具来管理整个集群。用户通过kubectl来调用master上的kube api接口。

基础组件

核心组件

Kubernetes 主要由以下几个核心组件组成:

Master组件

Node组件

第三方服务

组件间通信

controller manager、scheduler、kube-proxy 和 kubelet 等均通过 apiserver watch API 监测资源变化情况,并对资源作相应的操作。

用户创建一个pod的过程

 

  1. 用户通过 REST API 创建一个 Pod;
  2. apiserver 将其写入 etcd;
  3. scheduluer 检测到未绑定 Node 的 Pod,开始调度并更新 Pod 的 Node 绑定;
  4. kubelet 检测到有新的 Pod 调度过来,通过 docker 运行该 Pod;
  5. kubelet 通过 docker 取到 Pod 状态,并更新到 apiserver 中;

技术核心和API对象

API对象 API对象是K8s集群中的管理操作单元。K8s集群系统每支持一项新功能,引入一项新技术,一定会新引入对应的API对象,支持对该功能的管理操作。例如副本集Replica Set对应的API对象是RS。

每个API对象都有3大类属性:元数据metadata、规范spec和状态status。

K8s中所有的配置都是通过API对象的spec去设置的,也就是用户通过配置系统的理想状态来改变系统。

元数据metadata 元数据是用来标识API对象的,每个对象都至少有3个元数据:namespace,name和uid;除此以外还有各种各样的标签labels用来标识和匹配不同的对象。

例如用户可以用标签env来标识区分不同的服务部署环境,分别用env=dev、env=testing、env=production来标识开发、测试、生产的不同服务。

规范spec 规范描述了用户期望K8s集群中的分布式系统达到的理想状态(Desired State)。例如用户可以通过复制控制器Replication Controller设置期望的Pod副本数为3。

状态status status描述了系统实际当前达到的状态(Status)。例如系统当前实际的Pod副本数为2;那么复制控制器当前的程序逻辑就是自动启动新的Pod,争取达到副本数为3。

 

除了核心组件,还有一些推荐的 Add-ons:

组件详细介绍

etcd

etcd 是 CoreOS 基于 Raft 开发的分布式 key-value 存储,可用于服务发现、共享配置以及一致性保障(如数据库选主、分布式锁等)。

etcd主要功能:

kube-apiserver

docs

kube-apiserver 是 Kubernetes 最重要的核心组件之一,主要提供以下的功能:

kube-controller-manager

Controller Manager 由 kube-controller-manager 和 cloud-controller-manager 组成,是 Kubernetes 的大脑,它通过 apiserver 监控整个集群的状态,并确保集群处于预期的工作状态。

kube-controller-manager由一系列的控制器组成:

cloud-controller-manager

在 Kubernetes 启用 Cloud Provider 的时候才需要,用来配合云服务提供商的控制,也包括一系列的控制器,如:

kube-scheduler

kube-scheduler 负责分配调度 Pod 到集群内的节点上,它监听 kube-apiserver,查询还未分配 Node 的 Pod,然后根据调度策略为这些 Pod 分配节点(更新 Pod的 NodeName 字段)。

调度器需要充分考虑诸多的因素:

Kubelet

每个节点上都运行一个 kubelet 服务进程,默认监听 10250 端口,接收并执行 Master 发来的指令,管理 Pod 及 Pod 中的容器。每个 kubelet 进程会在 API Server 上注册节点自身信息,定期向 Master 节点汇报节点的资源使用情况,并通过 cAdvisor 监控节点和容器的资源。

Container runtime

容器运行时(Container Runtime)是 Kubernetes 最重要的组件之一,负责真正管理镜像和容器的生命周期。Kubelet 通过 Container Runtime Interface(CRI)与容器运行时交互,以管理镜像和容器。

kube-proxy

每台机器上都运行一个 kube-proxy 服务,它监听 API server 中 Service 和 Endpoint 的变化情况,并通过 iptables 等来为服务配置负载均衡(仅支持 TCP 和 UDP)。

kube-proxy 可以直接运行在物理机上,也可以以 static pod 或者 DaemonSet 的方式运行。

kube-proxy 当前支持一下几种实现:

Kubernetes 架构

Kubernetes 设置由几个部分组成,其中一些是可选的,一些是整个系统运行所必需的。下面是 Kubernetes 的全局架构图:

8.png

Kubernetes 有两个不同的部分构成,一个是 Master,一个是 Node。Master 负责调度资源和为客户端提供 API,客户端可以是 UI 界面或者 CLI 工具,在 Kubernetes 中 CLI 工具通常为 kubectl。 Kubernetes Master 接受使用 YAML 定义的配置文件,根据配置文件中相关信息将容器分配到其中一个 Node 上。另外,镜像库在 Kubernetes 中也起到一个很重要的角色,Kubernetes 需要从镜像库中拉取镜像基于这个镜像的容器才能成功启动。常用的镜像库有 dockerhub、阿里云镜像库等。下面图片为 Master 的架构图:

9.png

Master 有三个组件:API Server、Scheduler、Controller。API Server 提供了友好易用的 API 供外部调用,同时有很多强大的工具使得 API 调用更加简单,如 kubectl 封装了大量 API 调用,使得部署、配置更加简单。Kubernetes-dashboard 可以让用户在界面上操作 Kubernetes,而无需手动输入各个 API 的调用地址参数等信息。

当 API Server 收到部署请求后,Scheduler 会根据所需的资源,判断各节点的资源占用情况分配合适的 Node 给新的容器。判断依据包括内存、CPU、磁盘等。

Controller 负责整个集群的整体协调和健康,保证每个组件以正确的方式运行。

在图的最下边是 etcd 数据库。如前文所述 etcd 是分布式存储数据库,其作为 Kubernetes 的中央数据库,存储了集群的状态,组件可以通过查询 etcd 了解集群的状态。

Kubernetes Master 分配容器到 Node 执行,Node 将会承受压力,通常情况下新容器不会运行在 Master 上。或者说 Master 是不可调度的,但是你也可以选择把 Master 同时也作为 Node,但是这并不是地道的用法。下面的为 Node 的架构图:

1564391710654

Kube-proxy 在 Node 中管理网络,其左右至关重要。Kube-proxy 通过管理 iptables 等方式使得 Pod 到 Pod 之间,和 Pod 到 Node 之间网络能够互通。实质上在跨主机的 Pod 之间网络也能够互通。

Kubelet 负责向 api server 报告信息,并把健康状态、指标和节点状态信息存入 etcd 中。

Docker 上文已详细介绍这里就不多做阐述。

Supervisord 保证 Docker 和 kubelet 一直在运行中,supervisord 并不是必须组件,可以使用其他类似组件替换。

Pod 是可以在 Kubernetes 中创建和管理的最小可部署计算单元。一个 Pod 中可以包含多个容器,但 Kubernetes 仅管理 Pod。如果多个容器运行在一个 Pod 中,就相当于这些容器运行在同一台主机中,需要注意端口占用问题。

Kubeadm

Kubeadm是什么

Kubeadm是一个提供Kubeadm init 和 Kubeadm join命令,用于创建Kubernetes集群的最佳实践“快速路径”工具。

Kubeadm可以在多种设备上运行,可以是Linux笔记本电脑,虚拟机,物理/云服务器或Raspberry Pi。这使得Kubeadm非常适合与不同种类的配置系统(例如Terraform,Ansible等)集成。

开发者可以在支持安装deb或rpm软件包的操作系统上非常轻松地安装Kubeadm。SIG集群生命周期SIG Cluster Lifecycle Kubeadm的SIG相关维护者提供了预编译的这些软件包,也可以在其他操作系统上使用。

如果你想和更多Kubernetes技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态。

Kubeadm的目标

Kubeadm的目标是在不安装其他功能插件的基础上,建立一个通过Kubernetes一致性测试Kubernetes Conformance tests的最小可行集群。它在设计上并不会安装网络解决方案,而是需要用户自行安装第三方符合CNI的网络解决方案(如:Flannel、Calico、Weave network等)。

Kubeadm的子任务

Kubeadm的安装

安装Kubeadm需要手动安装Kubelet和Kubectl,因为Kubeadm是不会安装和管理这两个组件的。

Ubuntu

CentOS

 

容器接口

自2014年发布以来,Kubernetes发展迅速,从最开始以源自Google最佳实践的容器管理平台亮相, 再与Docker SwarmMesos一起争夺容器编排领域的主导位置,到最近开始整合整个容器生态的上下游。 Kubernetes始终保持着小步快跑的节奏,在每个Release当中不断推出新的Feature。 同时Kubernetes背后的组织CNCF还在不断吸收Kubernetes生态圈中的优秀开源项目,解决最终用户在生产部署中所存在的监控、 日志搜集等需求。

如今,Kubernetes已经超越了单纯的容器编排工具,企业选择Kubernetes本质上是拥抱以Kubernetes为核心的云原生最佳实践。 其中包含了网络、存储、计算等运行资源的调度,还涵盖了监控、日志搜集、应用分发、系统架构等研发和运维的操作流程。

容器引擎接口(Container Runtime Interface)

众所周知,KubernetesDocker是既合作又竞争的关系。Kubernetes使用Docker Engine作为底层容器引擎,在容器编排领域与Docker Swarm展开竞争。为了减少对Docker的依赖,同时满足生态中其他容器引擎与Kubernetes集成的需要,Kubernetes制定了容器引擎接口CRI。 随后Kubernetes发布了cri-o项目,开始研发自己的Docker兼容容器引擎。目前已经有Docker,rkt,cri-o三款容器引擎支持CRI接口。 此外支持CRI的还有Hyper.sh主导的frakti项目以及Mirantis主导的virtlet项目, 它们为Kubernetes增加了直接管理虚拟机的能力。

CRI的发布将Docker推到了一个非常难受的位置,如果不支持CRI,面临着在Kubernetes体系当中被其他容器引擎所替换的风险。 如果支持CRI,则意味着容器引擎的接口定义被竞争对手所主导,其他容器引擎也可以通过支持CRI来挑战Docker在容器引擎领域的事实标准地位。 最终,为了不被边缘化,Docker只能妥协,选择将containerd项目捐献给CNCF。在同一天,CoreOS也宣布将rkt项目捐献给CNCF。 至此CRI成为了容器引擎接口的统一标准,今后如果有新的容器引擎推出,将首先支持CRI。

容器网络接口(Container Network Interface)

因为Kubernetes没有内置容器网络组件,所以每一个Kubernetes用户都需要进行容器网络的选型,给新用户带来了不小的挑战。 从现状来看,不内置网络组件的策略虽然增加了部署的复杂度,但给众多SDN厂商留下了足够的公平竞争空间,从中长期来讲是有利于容器网络领域的良性发展的。

1.0版本的Kubernetes没有设计专门的网络接口,依赖Docker来实现每个Pod拥有独立IP、Pod之间可以不经过NAT互访的网络需要。 随着与Docker的竞争加剧以及Docker主导的CNM接口的推出,Kubernetes也推出了自己的容器网络接口CNI

随着CNI的推出,各家SDN解决方案厂商纷纷表示支持。目前FlannelCalicoWeaveContiv这几款热门项目均已支持CNI, 用户可以根据需要为自己的Kubernetes集群选择适合的网络方案。面对CNI和CNM,主流厂商目前的选择是同时支持,但从中长期来看, 厂商一定会根据各个生态的发展进度来动态配置资源,这时Docker内置的原生网络组件有可能反而会影响和其他网络厂商的协作。

kubernetes网络通信

容器存储接口(Container Storage Interface)

在统一了容器引擎和容器网络之后,Kubernetes又将触角伸到了存储领域。目前还在制定过程当中的容器存储接口CSI有望复制CRI和CNI的成功, 为Kubernetes集群提供可替换的存储解决方案。不论是硬件存储厂商或是软件定义存储解决方案厂商,预计都将积极拥抱CSI。 因为不支持CSI就意味着放弃整个Kubernetes生态圈。

软件打包与分发(Packaging and Distribution)

在使用CRI,CNI,CSI解决底层运行环境的抽象以外,Kubernetes还在试图通过Helm项目以及Helm Charts来统一软件打包与分发的环节。 由于Kubernetes提供了底层的抽象,应用开发者可以利用Kubernetes内置的基础元素将上层应用打包为Chart,用户这时就能使用Helm完成一键安装以及一键升级的操作。

在系统架构越来越复杂的今天,能够方便的将复杂的分布式系统运行起来,无疑为Kubernetes的推广增加了不少亮点。 目前一些常见的开源系统,比如Redis,ElasticSearch等已经可以通过使用官方的Charts进行部署。相信未来会有更多的开源项目加入这个清单。

看到这一块商机的公司,比如CoreOS,已经推出了自己的软件仓库服务。由于这块离最终用户最近,相信未来在这一领域的竞争将会非常激烈。

云原生计算基金会(Cloud Native Computing Foundation)

前面列举的案例主要偏重技术解决方案,Kubernetes最有潜力的其实是在幕后团结容器生态中各方力量的CNCF组织。 与同期建立的Docker主导的OCI组织相比,当前CNCF不论是在项目数量,会员数量,会员质量等多个方面都明显领先。 可以说CNCF是事实上在推动整个容器生态向前发展的核心力量。

人的力量是最根本的也是最强大的,只有团结到尽可能多的玩家,才能制定出各方都能接受的标准。面对这么多的会员企业,要平衡各方的诉求实在不是容易的事情。 目前CNCF做的还不错,中立的基金会形式似乎更加容易被各方所接受。最近正在进行决策小组选举的讨论,有兴趣的朋友可以自行围观。

总结

有两句经常听到的话在Kubernetes身上得到了很好的体现,一是没有什么是不能通过增加一个抽象层解决的,二是一流的企业做标准,二流的企业做品牌,三流的企业做产品。 Kubernetes通过在具体实现上增加抽象层,试图为整个容器生态圈建立统一的标准。当标准逐步建立,用户开始依照标准选择解决方案, 将进一步强化Kubernetes位于整个容器生态核心的地位。这时容器生态的上下游将不得不面对,要么选择In拥抱Kubernetes所提出的标准, 要么选择Out被整个生态圈孤立的情况。面对这种选择,想必大部分厂商都将选择In,而更多的厂商加入将进一步强化标准的力量。

可以预见Kubernetes构建的组织、标准、开源项目三层体系,将有望统一容器生态圈的各方力量,而这种统一对最终用户是有益的。 在容器生态中的各个领域,开源的解决方案将与商业解决方案直接竞争,甚至开源解决方案之间也将展开竞争。这种竞争将促进整个容器生态的发展, 由于大家都遵守相同的标准,不论你在最初建设时选择的是哪一套解决方案,将来也可以用更新更好的方案来替换, 规避了商家绑定的风险。希望捐献给CNCF的项目将会越来越多,因为进入CNCF就意味着比其他相同功能的开源项目更加容易获得Kubernetes生态圈的认可。

 

CNI

Kubernetes CNI:Flannel、Calico、Canal和Weave

SDNSoftware-defined networking的缩写。

在大多数的Kubernetes集群中,都不需要使用SDN技术,Kubernetes的容器网络要求可以使用更加简单易懂的技术来实现, 只有当企业有特定的安全或者配置要求时,才需要使用SDN技术。SDN应当作为一个附加选项,用以解决特定的技术问题。

Kubernetes容器网络的示意图

可以看到在图中,每台服务器上的容器有自己独立的IP段,各个服务器之间的容器可以根据目标容器的IP地址进行访问。

为了实现这一目标,重点解决以下这两点:

总结起来,实现Kubernetes的容器网络重点需要关注两方面,分配和路由。

 

简化的网络配置

Flannel的工作方式有2点是需要注意的。

  1. 所有服务器上运行的Flannel均需要etcd的读写权限,不利于权限的隔离和安全防护。
  2. 许多教程中所使用的默认backend类型为vxlan,虽然它使用了内核中的vxlan模块,造成的性能损失并不大, 但是在常见的二层网络的环境中,其实并不需要使用Tunnel技术,直接利用路由就可以实现流量的转发, 这时使用hostgw模式就可以达成目标。

大部分的Kubernetes集群服务器数量并不会超过100台,不论是在物理机房当中或是利用IaaS提供的VPC技术,我们会把这些服务器均放在同一个网段, 这时我们可以去掉Flannel这一层,直接使用Kubernetes内置的kubenet功能,配合上我们为Kubernetes定制的hostroutes工具, 即可实现容器网络的要求。

kubenetkubelet内置的网络插件中的一个,它非常的简单,会根据当前服务器对应的Node资源上的PodCIDR字段所设的IP段,配置一个本地的网络接口cbr0, 在新的Pod启动时,从IP段中分配一个空闲的IP,用它创建容器的网络接口,再将控制权交还给kubelet,完成后续的Pod创建流程。

由于kubenet会自己管理容器网络接口,所以使用kubenet时,不需要修改任何的Docker配置,仅需要在启动kubelet时,传入--network-plugin=kubenet 参数即可。

allocate-node-cidrscontroller-manager的一个参数,当它和cluster-cidr参数共同使用的时候,controller-manager会为所有的Node资源分配容器IP段, 并将结果写入到PodCIDR字段。

任何的技术方案都离不开场景,在这里我们根据不同的场景给大家推荐几种技术方案:

 

Flannel

github

由CoreOS开发的项目Flannel,可能是最直接和最受欢迎的CNI插件。它是容器编排系统中最成熟的网络结构示例之一,旨在实现更好的容器间和主机间网络。随着CNI概念的兴起,Flannel CNI插件算是早期的入门。

与其他方案相比,Flannel相对容易安装和配置。它被打包为单个二进制文件FlannelD,许多常见的Kubernetes集群部署工具和许多Kubernetes发行版都可以默认安装Flannel。Flannel可以使用Kubernetes集群的现有etcd集群来使用API存储其状态信息,因此不需要专用的数据存储。

Flannel配置第3层IPv4 Overlay网络。它会创建一个大型内部网络,跨越集群中每个节点。在此Overlay网络中,每个节点都有一个子网,用于在内部分配IP地址。在配置Pod时,每个节点上的Docker桥接口都会为每个新容器分配一个地址。同一主机中的Pod可以使用Docker桥接进行通信,而不同主机上的pod会使用flanneld将其流量封装在UDP数据包中,以便路由到适当的目标。

Flannel有几种不同类型的后端可用于封装和路由。目前已经支持UDP、VXLAN、AWS VPC和GCE路由等数据转发方式。默认和推荐的方法是使用VXLAN,因为VXLAN性能更良好并且需要的手动干预更少。

总的来说,Flannel是大多数用户的不错选择。从管理角度来看,它提供了一个简单的网络模型,用户只需要一些基础知识,就可以设置适合大多数用例的环境。一般来说,在初期使用Flannel是一个稳妥安全的选择,直到你开始需要一些它无法提供的东西。

Flannel的架构示意图

Flannel依赖etcd实现了统一的配置管理机制。当一台服务器上的Flannel启动时,它会连接所配置的etcd集群, 从中取到当前的网络配置以及其他已有服务器已经分配的IP段,并从未分配的IP段中选取其中之一作为自己的IP段。 当它将自己的分配记录写入etcd之后,其他的服务器会收到这条新记录,并更新本地的IP段映射表。

Flannel的IP段分配发生在各台服务器上,由flannel进程将结果写入到etcd中。路由也由Flannel完成,网络流量先进入Flannel控制的Tunnel中, 由Flannel根据当前的IP段映射表转发到对应的服务器上。

需要指出的是Flannel有多种backend,另外新增的kube-subnet-mgr参数会导致Flannel的工作方式有所不同,

 

将源数据包封装到UDP中,并使用基础网络的IP/MAC作为外层报文头进行封装,然后在以太网上传输,到达目的地后由隧道端点解封装并将数据发送给目标地址。

 

Calico

github

Calico是Kubernetes生态系统中另一种流行的网络选择。虽然Flannel被公认为是最简单的选择,但Calico以其性能、灵活性而闻名。Calico的功能更为全面,不仅提供主机和pod之间的网络连接,还涉及网络安全和管理。Calico CNI插件在CNI框架内封装了Calico的功能。

在满足系统要求的新配置的Kubernetes集群上,用户可以通过应用单个manifest文件快速部署Calico。如果您对Calico的可选网络策略功能感兴趣,可以向集群应用其他manifest,来启用这些功能。

尽管部署Calico所需的操作看起来相当简单,但它创建的网络环境同时具有简单和复杂的属性。与Flannel不同,Calico不使用overlay网络。相反,Calico配置第3层网络,该网络使用BGP路由协议在主机之间路由数据包。这意味着在主机之间移动时,不需要将数据包包装在额外的封装层中。BGP路由机制可以本地引导数据包,而无需额外在流量层中打包流量。

除了性能优势之外,在出现网络问题时,用户还可以用更常规的方法进行故障排除。虽然使用VXLAN等技术进行封装也是一个不错的解决方案,但该过程处理数据包的方式同场难以追踪。使用Calico,标准调试工具可以访问与简单环境中相同的信息,从而使更多开发人员和管理员更容易理解行为。

除了网络连接外,Calico还以其先进的网络功能而闻名。 网络策略是其最受追捧的功能之一。此外,Calico还可以与服务网格Istio集成,以便在服务网格层和网络基础架构层中解释和实施集群内工作负载的策略。这意味着用户可以配置强大的规则,描述Pod应如何发送和接受流量,提高安全性并控制网络环境。

如果对你的环境而言,支持网络策略是非常重要的一点,而且你对其他性能和功能也有需求,那么Calico会是一个理想的选择。此外,如果您现在或未来有可能希望得到技术支持,那么Calico是提供商业支持的。一般来说,当您希望能够长期控制网络,而不是仅仅配置一次并忘记它时,Calico是一个很好的选择。

 

Canal

github

 

Weave

github

 

 

 

 

 

搭建第一个应用程序

 

传统Kubernetes应用搭建

创建Namespace

在一个Kubernetes集群中可以创建多个Namespace进行“环境隔离”,当项目和人员众多的时候,可以考虑根据项目的实际情况(例如生产、测试、开发)划分不同的Namespace。

创建一个名称为“nginx”的Namespace:

查看集群中已创建出来的Namespace:

创建Deployment

Deployment为Pod 和Replica Set(下一代Replication Controller)提供声明式更新。只需要在 Deployment 中描述想要的目标状态是什么,Deployment Controller 就会帮开发者将 Pod 和 ReplicaSet 的实际状态改变成目标状态。开发者可以定义一个全新的 Deployment 来创建 ReplicaSet 或者删除已有的 Deployment 并创建一个新的来替换。使用Deployment能够更加方便地管理Pod,包括扩容、缩容、暂停、滚动更新、回滚等。在Choerodon中用实例的方式来展现Deployment,同时支持在线升级,停止,删除等多元化功能。

典型的应用场景包括:

编写名为nginx-deployment文件,内容如下:

保存后使用kubectl命令部署:

可执行下面命令查看部署出来的Deployment:

可执行下面命令查看Deployment创建出来的Pod:

Pod状态为Running,说明已经正常工作了就可以在集群中通过Pod IP进行访问了:

更多关于Deployment的介绍请参考这里:

https://kubernetes.io/docs/con ... ment/

创建Service

Kubernetes Pod 是有生命周期的,它们可以被创建,也可以被销毁,然而一旦被销毁生命就永远结束。 通过 Deployment 能够动态地创建和销毁 Pod。 每个 Pod 都会获取它自己的 IP 地址,然而这些IP地址并不是稳定固定的,在销毁Pod时这些IP也会进行回收。 这会导致一个问题:在 Kubernetes 集群中,如果一组 Pod(称为 Backend)为其它Pod (称为 Frontend)提供服务,那么那些 Frontend 该如何发现,并连接到这组 Pod 中的哪些 Backend 呢?

这里要隆重的请出Service来解决这个问题。

编写名为svc.yaml文件,内容如下:

使用kubectl命令部署:

可执行下面命令查看部署出来的Service:

可以看到Pod对应的Service已经建好了,而这个“对应”就是依靠Service里面的Selector与Pod的Labels建立映射的(即Selector内容与Pod的Labels内容需一致)。现在集群内部可以通过该Service访问到Nginx,Choerodon中提供了Service的可视化创建操作,可以更加方便便捷的创建网络:

更多关于Service的介绍请参考这里:

https://kubernetes.io/docs/con ... vice/

创建Ingress

此时,只有集群内部和所在主机能访问Nginx,要让节点外的其他主机能够访问,还得需要创建Ingress。Ingress 可以给 Service 提供集群外部访问的 URL、负载均衡、SSL 终止、HTTP 路由等功能。Ingress对应了Choerodon中的域名,Choerodon中除了对域名的管理外还添加了域名证书的管理,支持在线申请和导入。

编写名为ing.yaml文件,内容如下:

使用kubectl命令部署:

可执行下面命令查看部署出来的Ingress:

node1

 

此时,就可以在浏览器中使用定义的URL访问Nginx了:

1.png

更多关于Ingress的介绍请参考这里:

https://kubernetes.io/docs/con ... ress/

看完传统Kubernetes的应用搭建后,来看看Choerodon中如何进行应用搭建吧。