DevOps的支撑服务:K8s容器管理与应用部署

DevOps的支撑服务:K8s容器管理与应用部署_第1张图片

大家好,本期微课堂介绍在新一代数字化企业云平台中对于Kubernetes的学习以及使用的总结。

DevOps的支撑服务:K8s容器管理与应用部署_第2张图片

本次分享分为两部分:

1.介绍Kubernetes是什么以及一些基本概念

2.介绍在新一代数字化企业云平台里如何使用Kubernetes,以及遇到的一些问题。

首先开始第一部分:

DevOps的支撑服务:K8s容器管理与应用部署_第3张图片

Kubernetes项目是2014年由Google公司启动的,是Google公司在15年生产环境经验基础上 ,结合了社区的一些优秀点子和实践而构建的。

Kubernetes是一个以容器为中心的基础架构,可以实现在物理集群或虚拟机集群上调度和运行容器,提供容器自动部署、扩展和管理的开源平台。满足了应用程序在生产环境中的一些通用需求:应用实例副本、水平自动扩展、命名与发现、负载均衡、滚动升级、资源监控等。

使用Kubernetes可以:

1.自动化容器的部署和复制

2.随时扩展或收缩容器规模

3.将容器组织成组,并且提供容器间的负载均衡

4.很容易地升级应用程序容器的新版本

5.提供容器弹性,如果容器失效就替换它,等等

Kubernetes不提供:

1.中间件(例如消息总线)、数据处理框架(如Spark)、数据库(如mysql),也不提供集群存储系统(如Ceph)。

2.源代码到镜像的处理,即不部署源代码也不会构建的应用,持续集成(Continuous Integration: CI)的工作也需要由用户按自己项目决定。

3.不提供应用配置系统。

4.不提供机器配置、维护、管理。

DevOps的支撑服务:K8s容器管理与应用部署_第4张图片

Kubernetes集群由2类节点组成:Master和Node。

在Master上运行etcd、kube-apiserver、kube-scheduler、kube-controller-magager四个组件,其中后3个组件构成了Kubernetes的总控中心,负责对集群中所有资源进行管控和调度。

在Node上运行kubelet、kube-proxy、dockerdaemon三个组件,其中前2个组件负责对本节点上的Pod的生命周期进行管理,以及实现服务代理的功能。

另外在所有结点上都可以运行kubectl命令行工具,它提供了Kubernetes的集群管理工具集。

etcd:是一个高可用的key/value存储系统,用于持久化K8s集群内中的所有资源对象,例如集群中的Node、Service、Pod、RC、Namespace等。

kube-apiserver:封装了操作etcd的接口,以REST的方式对外提供服务,这些接口基本上都是集群资源对象的增删改查以及监听资源变化的接口,如创建Pod、创建RC,监听Pod变化的接口。kube-apiserver是连接其它服务组件的枢纽。

kube-scheduler:集群中的调度器,负责Pod在集群节点中的调度分配。

kube-controller-manager:集群内部的管理控制中心,主要实现Kubernetes集群的故障检查和恢复自动化的工作。比如endpoints控制器负责Endpoints对象的创建,更新。node控制器负责节点的发现,管理和监控。复制控制器负责pod的数量符合预期定义。

kubelet:负责本Node上的Pod创建、修改、监控、删除等全生命周期管理,以及Pod对应的容器、镜像、卷的管理,同时定时上报本Node的状态信息给kube-apiserver。

kube-proxy:实现了Service的代理以及软件模式的负载均衡器。

DevOps的支撑服务:K8s容器管理与应用部署_第5张图片

下面主要介绍K8s的一些基本概念,使大家对K8s有个了解。

Pod:Pod是Kubernetes的里可部署的和管理的最小单元。

LabelandSelector:Label以key/value键值对的形式附加到各种对象上,Selector可以根据Label来选择对象。

ReplicationController:Pod的副本控制器。

Service:一组提供相同服务的pod的对外访问接口。

Namespace:将对象逻辑分组。

其余如Volume、PV、 PVC、HPA、Deployment、RS、DaemonSet等就不介绍了。

DevOps的支撑服务:K8s容器管理与应用部署_第6张图片

Pod是Kubernetes的里可部署的和管理的最小单元,一个或多个容器构成一个Pod,通常Pod里的容器运行相同的应用。Pod包含的容器都运行在同一个宿主机上,看作一个统一管理单元。

每个Pod中都有一个pause容器,pause容器做为Pod的网络接入点,Pod中其他的容器会使用容器映射模式启动并接入到这个pause容器。属于同一个Pod的所有容器共享网络的namespace。

一个Pod可以被一个容器化的环境看做是应用层的逻辑宿主机(Logical Host),每个Pod中有多个容器,同一个Pod中的多个容器通常是紧密耦合的。同一个pod中的容器共享如下资源:

PID 名字空间:Pod中不同应用程序可以看到其它应用程序的进程ID。

网络名字空间:Pod中的多个容器访问同一个IP和端口空间。

IPC名字空间:Pod中的应用能够使用SystemV IPC和POSIX消息队列进行通信。

UTS名字空间:Pod中的应用共享一个主机名。

Volumes:Pod中的各个容器应用还可以访问Pod级别定义的共享卷。

Pod的生命周期,通过模板定义Pod,然后分配到一个Node上运行,在Pod所包含的容器运行结束后Pod也结束。

在整个过程中,Pod的状态:

挂起 ︰ Pod已被提交到Master,但一个或多个容器镜像尚未创建。包括调度和下载镜像,可能需要一段时间。

运行 ︰ Pod已绑定到的节点,和所有容器镜像已创建完成。至少一个容器是仍在运行,或正在启动或重新启动。

成功 ︰ Pod的所有容器已经成功的终止,并不会重新启动。

失败 ︰ Pod的所有容器已经都终止,至少一个容器已都终止失败 (以非零退出状态退出)。

未知 ︰ 出于某种原因的Pod状态无法获得,通常由于在与主机的Pod通信错误。

容器探测的诊断方式:

ExecAction :在container中执行指定的命令。当其执行成功时,将其退出码设置为0;

TCPSocketAction :执行一个TCP检查使用container的IP地址和指定的端口作为socket。如果端口处于打开状态视为成功;

HTTPGetAcction :执行一个HTTP默认请求使用container的IP地址和指定的端口以及请求的路径作为url,用户可以通过host参数设置请求的地址,通过scheme参数设置协议类型(HTTP、HTTPS)如果其响应代码在200~400之间,设为成功。

探测的结果有:

Success :表示通过检测

Failure :表示没有通过检测

Unknown :表示检测没有正常进行

探测的种类:

LivenessProbe :表示container是否处于live状态。如果LivenessProbe失败,LivenessProbe将会通知kubelet对应的container不健康了。随后kubelet将kill掉container,并根据RestarPolicy进行进一步的操作。默认情况下LivenessProbe在第一次检测之前初始化值为Success,如果container没有提供LivenessProbe,则也认为是Success;

ReadinessProbe :表示container是否以及处于可接受service请求的状态了。如果ReadinessProbe失败,endpointscontroller将会从service所匹配到的endpoint列表中移除关于这个container的IP地址。因此对于Service匹配到的endpoint的维护其核心是ReadinessProbe。默认Readiness的初始值是Failure,如果一个container没有提供Readiness则被认为是Success。

对容器实施配额,只要在Pod的定义文件中设定resources的属性就可以为容器指定配额,目前容器支持的CPU和Memory两种资源的配额。requests指定必须保证的最小资源,limits限制最大资源。

DevOps的支撑服务:K8s容器管理与应用部署_第7张图片

Label以key/value键值对的形式附加到各种对象上,如Pod、Node等。Label定义了这些对象的可识别属性,用来对它们进行管理和选择。Label可以在创建对象时指定也可以在对象创建后通过api进行添加。

在为对象定义好了Label后,其它对象就可以使用Label Selector来选择还有指定Label的对象。

有效的Label key有两个部分︰可选前缀和名称,以一个正斜杠(/)分隔。名称部分是必须的并且长度为 63 个字符或更少,开始和结束以字母数字字符 ([a-z0-9A-Z]) 中间可以有破折号(-),下划线 (_),圆点(.)和字母数字。前缀是可选的。如果指定,前缀必须是 DNS 子域︰一系列的 DNS 标签分隔用点(.),不长于 253 个字符总数,其次是斜杠(/)。如果省略前缀,则标签键是须推定为私人用户。kubernetes.io/ 前缀为 Kubernetes 核心组件保留。

有效的Label value必须是 63 个字符或更少,必须为空或开始和结束以字母数字字符 ([a-z0-9A-Z])中间可以有破折号(-),下划线 (_),圆点(.)和字母数字。

有2种Label Selector:基于等式的(Equality-based requirement)和基于集合的(Set-based requirement),在使用时可以将多个Label进行组合来选择。

基于等式的Label Selector使用等式的表达式来进行选择。

· name=redis:选择所有包含Label中key=“name”且value=“redis”的对象。

· tier!=frontend:选择所有包含Label中key=“tier”且value!=“frontend”的对象。

基于集合的Label Selector使用集合操作的表达式来进行选择。

· name in(redis-master, redis-slave):选择所有包含Label中key=“name”且value=“redis-master”或”redis-slave”的对象。

· tier notin(frontend):选择所有包含Label中key=“tier”且value不等于”frontend”的对象。

可以将多个Label Selector进行组合,使用”,”进行分割。基于等于的Label Selector和基于集合的Label Selector可以任意组合。例如:

name=redis,tier!=frontend

name in(redis-master, redis-slave), tier=backend

使用Label可以给对象创建多组标签,Service,RC组件通过Label Selector来选择对象范围,Label 和 Label Selector共同构成了Kubernetes系统中最核心的应用模型,使得对象能够被精细的分组管理,同时实现了高可用性。

DevOps的支撑服务:K8s容器管理与应用部署_第8张图片

Replication Controller核心作用是确保在任何时候集群中一个RC所关联的Pod都保持一定数量的副本处于正常运行状态。如果该Pod的副本数量太多,则Replication Controller会销毁一些Pod副本;反之Replication Controller会添加副本,直到Pod的副本数量达到预设的副本数量。

最好不要越过RC直接创建Pod,因为Replication Controller会通过RC管理Pod副本,实现自动创建、补足、替换、删除Pod副本,这样就能提高应用的容灾能力,减少由于节点崩溃等意外状况造成的损失。即使应用程序只有一个Pod副本,也强烈建议使用RC来定义Pod。

当Pod通过RC创建后,即使修改RC的模板定义,也不会影响到已经创建的Pod。此外Pod可以通过修改标签来实现脱离RC的管控,该方法可以用于将Pod从集群中迁移、数据修复等调试。对于被迁移的Pod副本,RC会自动创建一个新副本替换被迁移的副本。需要注意的是,通过kubectl删除RC时会一起删掉RC所创建的Pod副本,但是通过REST API删除时,需要将replicas设置为0,等到Pod删除后再删除RC。

重新调度:如前面所说,不论是想运行1个副本还是1000个副本,Replication Controller都能确保指定数量的副本存在于集群中,即使发生节点故障或Pod副本被终止运行等意外情况。

伸缩:修改Replication Controller的replicas的属性值,可以非常容易的实现扩大或缩小副本的数量。例如,通过下列命令可以实现手工修改名为foo的RC副本数量为3:kubectl scale –replicas=3 rc/foo

滚动更新:副本控制器被设计成通过逐个替换Pod的方式来辅助服务的滚动更新。推荐的方法是创建一个新的只有一个副本的RC,若新的RC副本数量加1,则旧的RC副本数量减1,直到这个旧的RC副本数量为0,然后删除旧的RC。这样即使在滚动更新的过程中发生了不可预测的错误,Pod集合的更新也都在可控范围之内。在理想情况下,滚动更新控制器需要将准备就绪的应用考虑在内,保证在集群中任何时刻都有足够数量的可用的Pod(https://github.com/kubernetes/kubernetes/issues/1353)

DevOps的支撑服务:K8s容器管理与应用部署_第9张图片

虽然每个Pod都会被分配一个单独的IP地址,但这个IP地址会随着Pod的销毁而消失。引出的一个问题是:如果有一组Pod组成一个应用集群来提供服务,那么该如何访问它们呢?

Service就是用来解决这个问题的,一个Service可以看作一组提供相同服务的Pod的对外接口,Service是通过LabelSelector选择一组Pod作用后端服务提供者。

举个例子:redis运行了2个副本,这两个Pod对于前端程序来说没有区别,所以前端程序并不关心是哪个后端副本在提供服务。并且后端Pod在发生变化时,前端也无须跟踪这些变化。Service就是用来实现这种解耦的抽象概念。

Pod的IP地址是由Docker Daemon根据docker0网桥的IP地址段进行分配的,但Service的Cluster IP地址是Kubernetes系统中的虚拟IP地址,由系统动态分配。

Service的Cluster IP相对于Pod的IP地址来说相对稳定,Service被创建时即被分配一个IP地址,在销毁该Service之前,这个IP地址都不会再变化了。而Pod在Kubernetes集群中生命周期较短,可能被Replication Controller销毁、再次创建,新创建的Pod就会被分配一个新的IP地址。

如何通过Service Cluster IP访问到后端的Pod呢?Kubernetes群集中的每个节点运行kube-proxy。该程序负责对Service实现虚拟IP的实现。在 Kubernetes v1.0,代理即是纯粹在用户空间。在Kubernetes v1.1添加了iptables代理,但是并不是默认的操作模式。在Kubernetes v1.2默认用iptables代理模式。在iptables代理模式下kube-proxy会观察Kubernetes Master节点添加和删除Service对象和Endpoint对象的行为,对于每个服务,kube-proxy会在本机的iptables中安装相应的规则,iptables通过这些规则将会捕获到该Service的流量并将他们重定向到一个后端的Pod。默认情况下后, 后端的选择是随机的。

但是也可以选择基于客户端IP的sessionaffinity,可以通过设置service.spec.sessionAffinity=ClientIP(默认值为“None”)来选择该方式。与用户空间的代理一样,客户端不知道Kubernetes或Service或Pod,任何对于Service的IP:Port的访问都会被代理到后端。但是iptables的代理比用户空间代理是更快、 更可靠。

Kubernetes支持两种主要的模式来找到Service:一个是容器的Service环境变量,另一个是DNS。在创建一个Pod时,kubelet在该Pod的所有容器中为当前所有Service添加一系列环境变量。

Kubernetes支持形如“{SVCNAME}SERVICE_HOST”和“{SVCNAME}_SERVICE_PORT”的变量。其中“{SVCNAME}”是大写的ServiceName,同时Service Name包含的“-”符号会转化为“”符号。例如,已存在名称为“redis-master”的Service,它对外暴露6379的TCP端口,且集群IP为10.0.0.11。kubelet会为新建的容器添加以下环境变量:

REDIS_MASTER_SERVICE_HOST=10.0.0.11

REDIS_MASTER_SERVICE_PORT=6379

REDIS_MASTER_PORT=tcp://10.0.0.11:6379

REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379

REDIS_MASTER_PORT_6379_TCP_PROTO=tcp

REDIS_MASTER_PORT_6379_TCP_PORT=6379

REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11

通过环境变量来创建Service会带来一个不好的结果,即任何被某个Pod所访问的Service,必须先于该Pod创建,否则和这个后创建的Service相关的环境变量,将不会被加入该Pod的容器中。

另一个通过名字找到服务的方式是DNS。DNS服务器通过Kubernetes API Server监控与Service相关的活动。当监控到添加Service的时,DNS服务器为每个Service创建一系列DNS记录。例如:有个叫做”my-service“的service,他对应的kubernetesnamespace为”my-ns“,那么会有他对应的dns记录,叫做”my-service.my-ns“。那么在my-ns的namespace中的pod都可以对my-service做name解析来轻松找到这个service。在其他namespace中的pod解析”my-service.my-ns“来找到他。解析出来的结果是这个service对应的cluster ip。

Service的ClusterIP地址只能在集群内部访问,如果集群外部的用户希望Service能够提供一个供集群外用户访问的IP地址。Kubernetes通过两种方式来实现上述需求,一个是“NodePort”,另一个是“LoadBalancer”。

每个service都有个type字段,值可以有以下几种:

· ClusterIP:使用集群内的私有ip —— 这是默认值。

· NodePort:除了使用cluster ip外,也将service的port映射到每个node的一个指定内部port上,映射的每个node的内部port都一样。

· LoadBalancer:使用一个ClusterIP & NodePort,但是会向cloud provider申请映射到service本身的负载均衡。

如果将type字段设置为NodePort,kubernetesmaster将会为service的每个对外映射的port分配一个”本地port“,这个本地port作用在每个node上,且必须符合定义在配置文件中的port范围(为–service-node-port-range)。这个被分配的”本地port“定义在service配置中的spec.ports[*].nodePort字段,如果为这个字段设定了一个值,系统将会使用这个值作为分配的本地port 或者 提示你port不符合规范。

DevOps的支撑服务:K8s容器管理与应用部署_第10张图片

Kubernetes 支持在一个物理集群上创建多个虚拟群集。这些虚拟群集被称为命名空间。大多数Kubernetes资源(例如: pods, services, replication controllers, and others) 在名称空间中。但是namespace资源本身不在名称空间中。还有一些底层资源如Node, PersistentVolumes不在名称空间中。

Kubernetes集群启动后,会创建一个名为“default”的Namespace,如果不特别指明Namespace,则创建的Pod、RC、Service都将被创建到“default”的Namespace中。

当你创建一个服务时,它将创建相应的 DNS 条目。此条目是窗体..svc.cluster.local,这意味着如果一个容器只是使用 它将解析为命名空间的本地的服务。这是用于跨多个命名空间,比如开发、分期和生产使用相同的配置。如果你想要达到整个命名空间,您需要使用完全限定的域名称(FQDN)。

使用Namespace来组织Kubernetes的各种对象,可以实现对用户的分组,即“多租户”的管理。对不同的租户还可以进行单独的资源配额设置和管理,使得整个集群的资源配置非常灵活、方便。一个集群中的资源总是有限的,当这个集群被多个租户的应用同时使用时,为了更好地使用这种有限的共享资源,需要将资源配额的管理单元提升到租户级别,通过在不同租户对应的Namespace上设置对应的ResourceQuota即可达到目的。

DevOps的支撑服务:K8s容器管理与应用部署_第11张图片

介绍完K8s后,下面我们开始第二部分,K8s在新一代数字化企业云平台的使用。

经过前几节微课堂的介绍,大家应该知道我们的DevOps是由一个个领域系统组成,各领域系统负责提供不同的能力。SEM领域系统主要是用于租户和微服务的资源管理以及容器的调度管理。可以看到这些能力基本和K8s提供的能力匹配,因此在新一代数字化企业云平台里就是使用K8s作为一个底层的容器调度平台来支撑上层微服务的部署运行。

DevOps的支撑服务:K8s容器管理与应用部署_第12张图片

DevOps的支撑服务:K8s容器管理与应用部署_第13张图片

SEM与DevOps其他领域系统中的TM、SRM、DPR会有依赖和交互。

TM会在创建租户时与SEM有交互。TM在创建租户时候会默认给该租户同时创建开发、测试、预发、上线4套环境,这时TM就需要调用SEM的接口,创建相应的环境。这些环境在K8s中我们使用Namespace来表示。因此可以在创建这些环境的时候同时指定配额。

SRM会在部署组件时与SEM有交互。SRM在部署组件时,会调用SEM的部署接口,指定部署介质、部署环境、内存、cpu等。

SEM在具体执行部署的过程中会依赖DPR,下载部署包。

DevOps的支撑服务:K8s容器管理与应用部署_第14张图片

一个“租户”可以有多个“环境”,“环境”是表示的一个从“集群”中按照指定的“资源配额”而划分出来的虚拟集群。“容器组”会运行在“环境”里。

“集群”表示的是由多个“结点”组成的物理环境。“结点”可以是物理机或虚拟机。

“部署包”会被按照“部署规格”部署到 “容器组”,“容器组”包含一组“容器”和多个“卷”,“容器”就是一个Docker的Container。“卷”可以是一个“本地目录”或者是一个“RBD”。

“容器组”通过“服务”对外暴露可访问的接口。

“容器组”通过“复制控制器”来保证高可用。

DevOps的支撑服务:K8s容器管理与应用部署_第15张图片

以MySQL举例,SEM会根据部署规格:

1.选择指定的环境(开发、测试、预上、发布)

2.从私库下载指定的镜像名称、版本

3.设置容器的CPU、内存的限额

4.设置MySQL的服务端口、用户名/密码,数据库名

5.设置MySQL的数据卷

这里部署时会遇到的问题:

1.服务部署后如何访问

可以根据服务部署后的IP去访问服务,但是限制就是被依赖的服务需要先部署(如A依赖B),就要先等B部署完后,需要根据返回的服务ip和端口修改A的配置再打包A,再部署A。当然这个修改A的配置也可以通过配置中心在A启动时再注入,而不需要提前在打包注入。

使用SkyDNS,服务直接的依赖掉用采用域名的方式掉用,这样就可以做到A和B同时打包,并且如果A支持重连功能,A和B还可以一起部署。

2.容器的漂移造成数据丢失

我们一开始使用的是把宿主机目录作为卷,但是遇到了一个问题,就是在多个容器一起部署时,如果容器的limit资源设置过大,会触发宿主机资源过载,造成容器漂移,容器漂移后的结果就是MySQL的数据只存在第一次被调度到的宿主机上。发现后我们采用了NFS的方式,将所有K8s的结点的本地持久化目录都从NFS mount。

DevOps的支撑服务:K8s容器管理与应用部署_第16张图片

产品组件的部署,即应用部署,和三方产品部署有些差别,差别是会存在一个基础镜像,首先会在下载这个基础镜像并创建启动容器,在容器启动时又会再次从DPR下载部署包,然后解压部署包并执行部署包里的start.sh。

为什么不用sidecar模式?

DevOps的支撑服务:K8s容器管理与应用部署_第17张图片

这就是sidecar模式的流程,通过CI从GitHub上下载代码并编译成war,再通过image builder把war包编译成镜像,最后在一个Pod里运行2个容器,一个是基础容器(Tomcat),另一个是应用镜像。2个容器共用一个Pod的emptyDir,tomcat把emptyDir作为自身的webapps目录,应用镜像会把应用解压到empty目录,这样tomcat就能加载应用。

需要注意的是,同一个Pod里的容器创建和启动是没有先后顺序的,因为tomcat支持动态加载应用,所以即使tomcat先启动,而后应用镜像再解压应用也不会有问题。而我们是SpringBoot的应用,可以简单认为是一个java的应用,需要通过java -jar的方式运行,这时再使用sidecar模式就会有可能再执行java -jar时应用还没有被解压,当然这可以通过在启动脚本里轮询判断jar包是否存在来解决。

DevOps的支撑服务:K8s容器管理与应用部署_第18张图片

SEM、DockerRegistry、K8sMaster、K8sNodeX都在一个物理网段里(10.15.15.0/24),然后在所有的K8s Node上又创建一个OverlayNetwork(10.16.16.0/24)。

基于上面的部署结构,有4个通信问题要解决:

1.Container to Container

基于第一部分的介绍,在K8s里同一个Pod里的所有容器拥有同样的网络空间,所以同一个Pod的容器和容器之间可以通过127.0.0.1来互相访问(每个Pod中都有一个pause容器,pause容器做为Pod的网络接入点,Pod中其他的容器会使用容器映射模式启动并接入到这个pause容器。属于同一个Pod的所有容器共享网络的namespace。)

2.Pod to Pod (Overlay network)

每个Pod都有一个IP,这个IP不是宿主机的IP,这个IP是通过docker0分配的,Pod和Pod之间可以直接通过IP访问。Pod和Pod的互通是依靠Flannel。

3.Pod to Service (–service-ip-range)

每个Service有自己的IP,这个IP是K8s自动分配的虚IP,虚IP的范围可以通过在启动kube-apiserver时指定“–service-ip-range”来确定。对于每一个Service,kube-proxy都会修改iptables的rules。Iptables会将对Service IP、Port请求重定向到后端的Pod IP、Port。

4.External to internal(–service-node-port-range)

对于从外部访问K8s集群内的Service,需要在宿主机上做端口映射,K8s将会为service的port分配一个”本地port“,这个本地port作用在每个node上,且必须符合定义在配置文件中的port范围(为–service-node-port-range)。当有外部访问node的”本地port“时,iptables会将请求重定向到后端Pod的IP、端口。

DevOps的支撑服务:K8s容器管理与应用部署_第19张图片

Flannel是CoreOS团队针对Kubernetes设计的一个网络规划服务;简单来说,它的功能是让集群中的不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址,并使Docker容器可以互连。

Flannel实质上是一种“覆盖网络(overlay network)”,也就是将TCP数据包装在另一种网络包里面进行路由转发和通信,目前已经支持UDP、VxLAN、AWS VPC和GCE路由等数据转发方式。 默认的节点间数据通信方式是UDP转发。

数据从源容器中发出后,经由所在主机的docker0虚拟网卡转发到flannel0虚拟网卡,这是个P2P的虚拟网卡,flanneld服务监听在网卡的另外一端。

Flannel通过Etcd服务维护了一张节点间的路由表。源主机的flanneld服务将原本的数据内容UDP封装后根据自己的路由表投递给目的节点的flanneld服务,数据到达以后被解包,然后直 接进入目的节点的flannel0虚拟网卡,然后被转发到目的主机的docker0虚拟网卡,最后就像本机容器通信一下的有docker0路由到达目标容器。

DevOps的支撑服务:K8s容器管理与应用部署_第20张图片

这是一张我们4月底在aliyun上的devops基础架构图,ECS - K8s Master和 ECS - K8sNode 组成了一个K8s集群,左面中间方块的是新一代数字化企业云平台的各个领域系统的微服务。现在各领域系统的微服务是直接作为在docker的contianer运行。没有做高可用的事情,在后续的计划里我们会对领域系统作一些高可用的设计。

DevOps的支撑服务:K8s容器管理与应用部署_第21张图片

后续我们打算将领域系统都搬上K8s集群,这样就会存在2个集群一个是新一代数字化企业云平台领域系统的K8s集群,一个是用户微应用的K8s集群。

以SEM为例,在新一代数字化企业云平台领域系统的K8s集群中,会创建一个多Pod的RC来保证SEM应用本身的高可用,而后通过部署多主的MySQL实现数据库服务的高可用。

MySQL 多主多活 Galera

DevOps的支撑服务:K8s容器管理与应用部署_第22张图片

对于K8s的高可用,主要就是对Master结点上的进程做高可用,大概思路就是:

1.etcd做集群,并采用分布式存储

2.单个apiserver通过systemd服务化保证失败后自重启,多个apiserver通过

3.loadbalance对外暴露

4.单个scheduler通过systemd服务化保证失败后自重启,多个scheduler通过选举,保证只有一个scheduler可以使用

5.单个controllermanager通过systemd服务化保证失败后自重启,多个controllermanager通过选举,保证只有一个controllermanager可以使用

这个K8s的高可用方案参考的是官方的方案,不太一样的地方就是K8s的本身组件是通过systemd来保证可用性。

普元云计算专区:http://primeton.csdn.net/m/zone/primeton/index#

普元公众号:
DevOps的支撑服务:K8s容器管理与应用部署_第23张图片

你可能感兴趣的:(DevOps的支撑服务:K8s容器管理与应用部署)