Kubernetes 核心原理及实战中使用方法

认识 kubernetes 架构及应用场景

kubernetes(k8s) 在企业中的应用场景

构建自动化运维平台

(1) 中小型企业,使用 k8s 构建一套自动化运维平台(降本增效)
(2) 大型互联网公司更要使用,实现更高效的运作方式

充分利用服务器资源

怎么理解充分利用服务器资源这一条呢,我们举个例子:假设并发量200请求,服务器是两核心CPU,4G内存,其中静态请求150个,比如访问CDN、nginx、缓存等,动态请求50个,主要是访问数据库,把数据读入内存,我们来估算服务器资源(只考虑内存,不考虑程序员RT与CPU切换时间):

静态+动态 = 150*2M + 50 *10M = 800M
也就是说200个请求占用了800M内存

我们可以估算这台服务器的并发能力QPS为 200*4 = 8000,但实际上 800 QPS 是无法达到的,我们需要考虑 response time,cpu切换时间,内存等等,因此实际上我们会给它安排 300 QPS,此时先然无法充分利用服务器资源,有很多资源被浪费掉了。而 k8s 使用类似 Docker 的容器化方式,也就是我们在其中部署多个容器,将服务器资源做隔离,容器中部署的就是 web 服务。

服务无缝衔接

那么服务的无缝迁移又该怎么理解呢?首先我们开发时应该有三种环境,分别是是开发环境、测试环境和生产环境。在开发 web 项目时有许多配套服务,在测试环境中这些环境也必须存在,测试完之后产品就可以上线,但这时会出现一个问题:项目在测试时没有毛病,但一旦上市生产就出现了很大的问题,这经常是环境的不一致性造成的,这时候往往就会花费大量精力去调试环境,非常麻烦,而容器化方式可以做到服务无缝迁移。也就是说我们可以把 JDK、MQ、ES、MySQL 等做成一个个镜像,这些镜像可以脱离我们的依赖环境,因此这些镜像可以做到无缝迁移。

服务部署模式变迁&服务部署模式变化的思考

我们考虑下面几个问题:

服务部署模式是怎么变迁的。

  1. 物理机部署:就是直接把服务部署到物理机上(不能充分利用物理机资源)
  2. 虚拟化(虚拟机)方式,也就是通过虚拟机将物理资源进行隔离部署服务,将服务部署到虚拟机上,但虚拟机本身就非常占用资源,因此我们寻求一种更好的方式
  3. 使用容器化方式进行部署(容器更轻量级,运行更快)

服务部署模式变化,带来哪些问题?

  1. 前提条件:SOA架构,微服务架构的模式下,项目拆分越来越多,服务越来越多,这么多服务我们是怎么管理?

    • 虚拟机服务部署方式(openstack)

    • 容器化部署模式(k8s)

    容器我们可以认为是一个更轻量级的虚拟机,使用了与虚拟机不同的技术,因此与openstack用于管理虚拟机类似, k8s 就是用来管理容器的。

  2. 面临问题:

    • 如何对服务进行横向扩展(不能 简单地加机器,会影响服务)

    • 容器宕机如何解决,数据怎么恢复

    • 重新发布新的版本如何在线上快速更新,更新后不影响业务(k8s可以做滚动更新)

    • 如何监控容器(容器出现问题怎么办)

    • 容器如何调度创建

    • 数据安全性如何保证

云架构 & 云原生

云和 k8s 是什么关系

  • 云就是使用容器构建的一套服务集群网络,云由大量容器构成,不同容器有不同功能
  • k8s 就是用来管理云中的容器

云架构

iaas 基础设施即服务

用户:可以租用(购买|分配权限)云主机,用户就不需要考虑网络,DNS,硬件环境方面的问题。
运营商:(私有云或公有云平台)提供网络,存储,DNS(基础设施服务)

paas 平台即服务

MYSQL\ES\R等服务都由平台提供了

saas 软件即服务(目前很多系统都是该系统)

钉钉:给每个公司提供一个系统,每个公司使用独立一套功能
财务管理软件:维护交给运营商维护,用户只需要使用其中的功能即可

serverless 无服务

 站在用户角度:不需要服务器,用户只需要使用云服务器即可,在云服务器所有基础环境 ,软件环境都不需要 用户自己安装
 未来:服务开发都是 serverless,企业都构建了自己的私有云环境,或者使用公有云环境(阿里云)
 	阿里将所有服务部署到云端之后,效率提升了60%

云原生

就是为了让应用程序(项目、服务软件)都 运行在云上的解决方案,这样的方案叫做云原生。
特点
(1)容器化 —— 所有服务部署都必须部署在容器中
(2)微服务 —— web 服务架构、微服务架构
(3)CI、CD —— 可持续交互与可持续部署
(4)DevOps —— 开发与运维密不可分

kubernetes 架构原理

1)kubernetes 是 Google 使用 go 语言开发,原来的系统是 borg 系统(也是云平台管理工具),Docker后来自己开发了容器管理平台 Docker Swarm,Google 表示不服,因此参照 borg 架构开发了 k8s 架构

2)k8s 架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1FX9K7FA-1591151340036)(./Pic/k8s/arch1.jpg)]

关系:一个 master 对应多个 node 节点

master 节点

  1. api server:k8s 网关,所有指令请求都必须经过 api server
  2. scheduler:调度器,使用调度算法,将请求资源调度给某一个 node 节点
  3. controller 控制器:维护 k8s 资源对象(添加、删除、更新、修改)
  4. etcd:存储资源对象,服务的注册与发现

node 节点

  1. docker:运行容器的基础环境,容器引擎
  2. kuberlet:在每个 node 节点都存在一份,在 node 节点上的资源操作指令由其执行
  3. kube-proxy:代理服务,负载均衡
  4. fluentd:日志收集服务
  5. pod:是 k8s 管理的基本单位,内部是容器,也即是 k8s 不直接管理容器,而是管理 pod

深入认识 kubernetes 核心组件原理

pod的核心原理

k8s的作用:k8s是用来管理容器的,但不直接操作容器,最小操作单元是pod(间接地管理容器)
k8s的特点

  1. 一个master有一群node节点与之对应
  2. master节点不存储容器,只负责调度、网关、控制器、资源对象存储
  3. 容器是存储在node节点(容器是存储在pod内部)
  4. pod内部都可以有一个容器,或者是多个容器
  5. kubelet负责本地的pod维护
  6. kube-proxy负责在多个pod之间做负载均衡

pod是什么呢:pod也是一个容器,但这个容器中装的是docker创建的容器,也就是pod是用来封装容器的容器,pod是一个虚拟化分组(pod有自己的地址,主机名),相当于一台独立的沙箱环境(主机),可以封装一个容器或多个容器

pod用来干什么:通常情况下,在服务部署时使用pod来管理一组相关服务(一个pod要么部署一个服务,要么部署一组相关的服务),所谓的一组相关的服务,即为链式调用的调用链路上的服务。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cieWbksy-1591151340037)(./Pic/k8s/pod1.png)]

web服务集群如何实现:只需要复制多方pod的副本即可,这也是k8s管理的先进之处,k8s如果继续扩容、缩容,只需要控制pod的数量即可

pod底层网络,数据存储是如何进行的:pod内部容器创建之前必须先创建pause容器,服务容器之间的访问使用localhost访问,性能非常高,实际就像访问本地服务一样

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tIbIoE1Q-1591151340039)(./Pic/k8s/pod2.png)]

ReplicaSet副本控制器

什么叫做副本控制器用于控制pod副本的数量,使副本数量与预期数量保持一致。例如,我们提前设置replicas=3(有三个副本),因此创建三个pod。当有一个pod宕机之后,k8s会立刻创建一个新的,保证副本数量等于三个,这就是副本控制器的作用——永远保证副本数量为设定值。

副本控制器能通过标签选择器选择维护一组相关的服务(它自己的服务),那么它要怎么判断是自己的服务呢?这里就通过标签选择,比如

selector:
	app = web
    release = stable

ReplicationController和ReplicaSet两个副本控制器有什么区别

  1. ReplicaSet
    • 单选
    • 复合选择
  2. ReplicationController
    • 单选

在新版的k8s中,推荐使用Replicaset作为副本控制器(功能更强大),ReplicationController不再使用

Deployment资源部署对象

  • 服务部署结构模型
  • 滚动更新

虽然在企业中我们采用ReplicaSet作为副本控制器,但在实际中项目不断更新,项目的版本将会不停的发版,版本的变化如何做到服务的更新呢?我们做的是滚动更新,如下图,每当发布一个新的版本,每更新一个POD,就要干掉原有的POD。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AYqWfw7n-1591151340040)(./Pic/k8s/Deployment.png)]

那么滚动更新是由谁实现的呢?这就涉及到部署模型:因为事实上ReplicaSet是不支持滚动更新的,滚动更新是由Deployment支持的,通常两者一起使用,因此部署模型为如下结构:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DinzZ2cM-1591151340043)(./Pic/k8s/dep2.png)]

如果后一个版本出现问题,k8s也可以支持向前滚动。

StatefulSet部署有状态服务

StatefulSet和Deployment类似,区别就是StatefulSet是为了解决有状态服务容器化部署问题而产生的。

思考:MySQL使用容器化部署,存在怎样的问题?

  • 容器是有生命周期的,一旦宕机,数据丢失
  • pod部署:pod有生命周期,但重启pod集群副本时数据可能丢失

因此容器是不太适合部署数据这样的有状态服务的,对于k8s而言,不能使用Deployment模型来部署有状态服务,通常情况下Deployment用于部署无状态服务,对于有状态服务的部署使用StatefulSet。

什么是有状态什么是无状态呢?

  • 有状态服务
    • 有实时的的数据需要存储
    • 有状态服务集群中,把某一个服务抽离出去,一段时间后再加入机器网络,如果集群网络无法使用就被称为有状态服务
  • 无状态服务
    • 无实时的的数据需要存储
    • 有状态服务集群中,把某一个服务抽离出去,一段时间后再加入机器网络,对集群网络没有影响

底层的数据存储借助PVC文件系统,而StatefulSet会保证POD重新建立后,hostname不会发生变化,POD就可以通过hostname来关联数据

kubernetes 的服务的注册与发现(核心)

pod在生产环境中的访问流程

pod的结构:根据前面所说,pod相当于一个容器,有独立的ip地址,也有自己的hostname,利用namespace进行资源隔离,独立沙箱环境。同时pod内部封装的是容器,可以封装一个,也可以封装一组相关的容器。

pod网络:有自己独立的ip地址,pod内部容器之间访问采用localhost访问。

pod如何对外网提供服务

  • 前提思考:pod有PODID和hostname,pod是虚拟的资源对象(进程),没有对应的实体(物理机,物理网卡),单独的POD不能直接对外提供访问,对外提供访问一定要有物理机,通过端口访问
  • 解决方案:POD如果想要对外提供访问,必须绑定物理机的端口,(在物理及上开启端口,让这个端口和POD的端口建立映射),这样就可以通过物理机进行数据包的转发
  • 总结为步骤:①先通过物理机IP+port进行访问NODE节点;②数据包转发

pod如何实现负载均衡访问

一组相同的副本直接POD如何实现负载均衡访问,思考nginx能否做负载均衡:事实上pod是一个进程,是有生命周期的(宕机,版本更新),都会创建新的pod(ip地址发生变化,hostname发生变化),nginx做负载均衡不太合适,因为nginx不能识别出hostname的变化,因此在pod动态变化的前提下(且由于经常做滚动更新,变化速度比较快),nginx不能发现我们的服务。因此我们使用service VIP实现负载均衡。

利用service来实现负载均衡

  • POD IP:pod的ip地址
  • NODE IP:物理机的IP地址
  • cluster IP:虚拟化IP,是由k8s抽象出的service对象,这个service对象是一个VIP的资源对象

Kubernetes 这样定义Service :逻辑上的一组 Pod,一种可以访问Pod的策略,通常称之为微服务。 这一组 Pod 能够被 Service 访问到,通常是通过selector实现的。当我们调用某个服务时并不关心调用了哪个Pod,对外提供服务一组的 Pod 实际上可能会发生变化(是否能提供服务,或者在销毁中,或者在创建中),而Service 能够解耦这种关联。

在 Kubernetes 集群中,每个Node运行一个 kube-proxy代理进程。kube-proxy 负责为 Service实现了一种VIP(虚拟 IP)。

以下为Service资源对象:

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  labels:
    app: nginx
spec:
  type: ClusterIP
  ports:
    - port: 80
       targetPort: 80
  selector:
    app: nginx

Service如何实现负载均衡

我们知道了一组相关的port做负载均衡会使用虚拟IP来做数据包转发,但service是节点(资源对象)是怎么实现数据包的转发呢?

我们已知的

  1. service和pod都是一个进行,因此service也不能对外网提供服务
  2. service和pod之间可以直接进行通信,它们的通信属于局域网通信
  3. 把请求交给service后,service使用(ipstables,ipvs)来做数据包分发

访问步骤

  1. 在物理机上绑定端口
  2. 通过ip:port访问
  3. 访问完成之后将请求转交给service
  4. service将数据包分发给相应的pod

service对象是如何与pod建立关联的?

每一组相同的pod(副本)会有相同的标签,通过标签选择器(selector),service对一组相同的副本提供服务,如果是需要访问另一组,则需在创建一个service。因此不同的业务会有不同的service。然后service将对应的POD的IP地址存储到endpoints中,由此将service和相应的pod关联起来了。

当pod宕机或者发布了新的版本,service怎么发现pod发生了变化?

主要是依靠kube-proxy组件,k8s安装后每个节点都运行着这个组件。kube-proxy进程将监听所有的pod,一旦发现pod有变化,就会更新service中endpoint中的映射关系。

本文图片上传有些问题,若想获得更好的观看体验,欢迎访问我的个人博客主页 ~

你可能感兴趣的:(其他,网络,大数据,负载均衡,nginx,服务器)