Kubernetes的缩写为:K8S, 这个缩写是因为K和S之间有八个字符的关系。
kubernetes是一个可移植的、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化,kubernetes用有一个庞大且快速增长的生态系统。
docker的翻译为:码头工人,logo为轮船。
kubernetes的翻译为:舵手、飞行员。
可以理解为:kubernetes用来管理docker的。
k8s由google的brog系统(博格系统)作为原型,后用go语言进行重新编写,捐赠到CNCF基金会开源。
k8s是资源管理器,管理的全部称作为资源,不管是pod还是什么。
目前最新版本为:1.25版本
官网:https://kubernetes.io
中文社区版:http://docs.kubernetes.org.cn/92.html
在部署应用程序的方式,主要经历了三个时代:
传统部署:互联网早期,会直接将应用程序部署在物理机上。
优点: 简单,不需要其他技术的参与
缺点: 不能为应用程序定义资源使用边界,很难合理地分配计算资源,而且程序之间容易产生影响
虚拟化部署:可以在一台物理机上运行多个虚拟机,每一个虚拟机都是独立的一个环境。
优点: 程序环境不会相互影响,提供可一定程度的安全性。
缺点: 增加了操作系统,浪费了部分资源。
容器化部署: 与虚拟化类似,共享操作系统内核。
优点:
缺点:
这些容器管理的问题统称为 容器编排 问题,为了解决这些容器编排问题,就产生了一些容器编排的软件:
①Swarm: Docker自己的容器编排工具
②Mesos: Apache的一个资源统一管控的工具,需要和Marathon(一个基础框架)结合使用。
③Kubernetes: Google开源的容器编排工具
试想下传统的后端部署办法:把程序包(包括可执行的二进制文件,配置文件)放到服务器上,接着运行启动脚本把程序跑起来,同时启动守护脚本定期检查程序运行状态,必要要的话重新拉起来程序。
设想一下,如果服务的请求量上来,已部署的服务响应不过来怎么办?传统的做法往往是:如果请求量、内存、cpu超过阈值做了告警,运维人员马上再加几台服务器,部署号服务之后,接下来负载均衡来分担已有服务的压力。
//这样问题就出现了:从监控告警到部署服务,中间需要人力介入,那么,有没有办法自动完成服务的部署,更新、卸载和扩容、缩容呢?
#而这就是k8s要做的事情:自动化运维管理容器化(docker)程序
K8S的目标是让部署容器应用简单高效。
#K8S解决了裸跑Docker的若干痛点
1、单机使用、无法有效有效集群
2、随着容器数量的上升,管理成本攀升
3、没有有效的容灾,自愈机制
4、没有预设编排模板,无法实现快速,大规模容器调度
5、没有统一的配置管理中心工具
6、没有容器生命周期的管理工具
7、没有图形化运维管理工具
kubernetes是一个容器编排工具,可以高效、批量的管理容器。
docker有自带的docker-compose(单机编排)和docker-Swarm(多机编排)。那为啥还要用k8s?
技术 | 应用场景 | 资源占用比 |
---|---|---|
docker | 单机部署简单应用 | 低 |
docker-compose | 单机/少数机器部署应用 | 低 |
kubernetes | 集群部署高可用应用 | 低 |
K8S是google开源的容器集群管理系统,在Docker等容器技术的基础上,为容器化的应用提供部署运行,资源调度,服务发现和动态伸缩等一系列完整功能,提高了大规模容器集群管理的便捷性,其主要功能如下:
使用Docker等容器技术对应用程序包装(package)、实例化(instantiate)、运行(run)
以集群的方式运行、管理跨机器的容器
解决Docker跨机器容器之间的通讯问题
K8S的自我修复机制使得容器集群总是运行在用户期望的状态。
#什么是期望的状态?
期望状态就是在k8s中设置期望值加入为4台机器,管理的pod也是4台机器,如果管理中的一个pod宕机了,会有自愈机制将会删除后重新创建一个新的pod。持续保持与期望值一样的设备数量。
**1、轻量级 **
2、开源
**3、自我修复 **
在k8s管理的节点集群中,假如有一台节点宕机了,k8s会自我修复,先重启,重启无效,就会漂移到其它主机上继续运行。假如是服务宕机了,k8s会将它自动修复,继续运行。总之要与期望值一样的数量。
**4、弹性伸缩 **
使用命令UI或基于CPU使用情况自动快速扩容和缩容应用程序实例,保证应用业务高峰并发时的高可用性,业务低峰时回收资源,以最小成本运行服务。
伸缩: 扩容和缩容
弹性: 人为只要指定规则,满足条件时,就会自动触发扩容或缩容的操作。
5、服务发现和负载均衡
K8S为多个pod提供一个统一访问入口(内部IP地址和一个DNS名称),并且负载均衡关联的所有容器,使用用户无需考虑容器IP问题。
服务发现: 服务可以通过自动发现的形式找到它所依赖的服务
负载均衡: 如果一个服务启动了多个容器,能够自动实现请求的负载均衡。
6、自动发布和回滚
K8S采用滚动策略更新应用,一次更新一个Pod,而不是同时删除所有的Pod,如果更新过程中出现问题,将回滚更新。确保升级影响业务。
**7、存储编排 **
挂载外部存储系统,无论是来自本地存储,公有云(AWS),还是网络存储(如NFS、GlusterFS、Ceph)都作为集群资源的一部使用,极大提高存储使用灵活性。
支持外挂存储并对外挂存储资源进行编排。
**8、批处理 **
提供一次性任务(job),定时任务(crontab),满足批量数据处理和分析的场景。
9、集中化配置管理和秘钥管理
管理机密数据和应用程序配置,而不需要把敏感数据暴露在镜像里,提高敏感数据安全性。并可以将一些常用的配置存储在K8S中,方便应用程序使用。
K8S是属于主从设备模型(master-slave架构),即有master节点负责集群的调度、管理和运维、salve节点时集群中的运算工作负载节点。
#在k8s中,主节点一般被称为master节点,而从节点则被称为worker node 节点,每个node都会被master分配一些工作负载。
1、master组件可以在群集中的任何计算机上运行,但是建议master节点占据一个独立的服务器。
2、因为master是整个集群的大脑,如果master所在节点宕机或不可用,那么所有的控制命令都将失效,除了master,在k8s集群中的其它机器被称为worker node节点,当某个node宕机时,其上的工作负载会被master自动转移到其它节点上去。
//master搭建集群架构时,最少不能低于3台。
master:集群的控制平面,负责集群的决策(管理)
kubernetes API,集群的统一入口,各组件协调者,以Restful API提供接口服务,所有对象资源的增删改查和监听操作都交给 API server 处理后再提交给Etcd存储。
控制器 | 功能 |
---|---|
node contrpller(节点控制器) | 负责在节点出现故障时发现和响应 |
replication controller(副本控制器) | 负责保证集群中一个RC(资源对象)所关联的pod副本数量始终保持预设值,可以理解成确保集群中有且仅有N个pod实际,N是RC中定义的pod副本数量 |
endpoints controller(端点控制器) | 填充端点对象(即连接services和pods),负责监听service和对应的pod副本的变化,可以理解短点是一个服务暴露出来的访问点 如果需要访问一个服务,则必须知道它的endpoint |
service account & token controllers(服务账户和令牌控制器) | 为新的命令空间创建默认账户和API访问令牌 |
resourcequota controller(资源配额控制器) | 确保指定的资源对象在任何时候都不会超量占用系统物理资源 |
namespace controller(命令空间控制器) | 管理namespace的生命周期 |
service controller(服务控制器) | 属于k8s集群与外部的云平台的一个接口控制器 |
根据调度算法(预选/优选的策略)为新创建的pod选择一个node节点,可以任意部署,可以部署在同一个节点上,也可以部署在不同的节点上。
k8s的存储服务,etcd是分布式键值对存储系统,存储了k8s的关键配置和用户配置,k8s中仅API server才具备读写权限,其它组件必须通过API server的接口才能读写数据。
API server 接收到请求创建一批Pod。API server 会让Controller-manager按照所预设的模板去创建Pod。Controller-manager会通过API server 去找Scherduler为新创建的Pod选择最适合的Node节点,比如运行这个Pod需要2C4G的资源,Schduler会通过预算策略在所有node节点中挑选最优的,node节点中还剩下多少资源是通过汇报给API Server 存储在etcd中,API server 会调用一个方法找到etcd里所有node节点的剩余资源,再对比新创建Pod所需要的资源,在所有node节点中查找哪些node节点符合要求,如果都符合,预算策略就交给优先策略处理,优先策略再通过CPU的负载、内存的剩余量等因素选择最适合的node节点,并把pod调度到这个node节点上运行。
Node节点的监视器,以及与master节点的通讯器 ,kubelet是master节点安插在node节点上的 “眼线” ,它会定时向APIserver 汇报自己node节点上运行的服务的状态,并接受来自master节点的只是采取吊证措施。
从master节点获取自己节点上pod的期望状态(比如运行什么容器,运行的副本数量,网络或者存储如何配置等),直接跟容器引擎交互实现容器的生命周期管理,如果自己上pod的状态与期望状态不一致,则调用对应的容器平台接口(即docker的接口)达到这个状态,管理镜像和容器的清理工作,保证节点上镜像不会占满磁盘空间,退出的容器不会占用太多资源。
在每个node节点上实现pod网络代理,是kuberbetes service资源的载体,负责维护网络规划和四层负载均衡工作。 负责写入规则至iptables、ipvs实现服务映射访问的。
kube-proxy本身不是直接给pod提供网络,pod的网络是由kubelet提供的,kube-proxy实际上维护的是虚拟的pod集群网络。
kube-apiserver 通过监控kube-proxy 进行对kubernets service 的更新和端点的维护。
kube-proxy 是k8s集群内部的负载均衡器,它是一个分布式代理服务器,在k8s的每个节点上都会运行一个kube-proxy。
容器引擎,运行容器,负责本机的容器创建和管理工作。
#master
API server:所有服务访问的统一入口
controller manager: 负责根据预设模块创建pod。维持pod等资源的副本期望数目
scheduler:负责调度pod,通过预选策略、优选策略选择最适合的node节点分配pod。
etcd:分布式键值对数据库,负责存储k8s集群的重要信息(持久化)
#worker node 节点
kubelet:跟apiserver通信汇报当前node节点上资源使用情况和状态,接收apiserver的指令跟容器引擎交互来实现容器生命周期管理。
kube-proxy:在node节点上实现pod的网络代理,维护网络规则和四层负载均衡工作,负责写入规则到iptables或ipvs实现服务的映射访问
容器运行时(容器引擎):docker运行容器,负责本机的容器创建和管理工作。
#总的流向(k8s创建Pod流程)
kubectl提交一条命令。
1、首先经过AUTH认证,然后将请求递交给API server进行处理(创建一个包含pod信息的yaml文件),然后将文件信息存储在etcd中。
2、controller-manager控制器会监听到API server,发现了创建Pod的请求后,会根据预设模板进行创建pod。(但是controller-manager无法完成调度,所以它会通过API server 向scheduler获取node节点的信息)//controller-manager的功能:控制、管理维护node节点。
3、此时API server 就会向etcd获取后端节点信息。
4、scheduler调度器也会监听API server,发现请求信息,然后进行预选调度和优选调度的调度计算,找出最闲且最符合条件的node节点。最后将结果信息给到API server。
//预选调度和优先调度
//1、预选调度: 一般根据资源对象的配置信息进行筛选,例如:nodeselector、hostselector、节点亲和性。
//2、优先调度: 根据资源对象需要的资源和node节点的资源的使用情况,为每个节点打分,然后选出最优的节点创建资源对象(pod)
5、此时controller-manage 也监听到 API server,选出了node节点,controller-manager会根据请求创建pod的配置信息。(也就是需要什么控制器),然后把控制资源给API server
------------下面开始与node节点交互------------------
6、此时API server会提交清单给对应的节点的kubelet(代理),kubelet相当于api server在node节点的监视器。
7、kubelet代理通过k8s与容器的接口(例如:containnerd)进行交互。假如是docker容器,那么此时kubelet就会通过dockershim以及runc接口与docker的守护进行docker-server进行交互,来创建对应的容器,再生成对应的pod。
8、kubelet同时会借助于 metric server收集本节点的所有状态信息,然后再提交给 API server。
9、最后 API server 会提交list清单给etcd存储。
------------------------------------------------------
10、最终用户可以通过kube-proxy实现访问不同节点的数据。(ipvs映射、iptables规则),kube-proxy为网络代理,四层负载均衡工作。
kubernetes包含多种类型的资源对象: pod、label、service、Replication、Contaroller等
Pod是Kubernetes创建或部署的最小/最简单的基本单位,一个Pod代表集群上正在运行的一个进程。
可以把Pod理解成豌豆荚,而同一个Pod内的每个容器时一颗豌豆。
一个Pod由一个或多个容器组成,Pod中容器共享网络,存储和计算资源,在同一台Docker主机上运行。
一个Pod里可以运行多个容器,又叫边车模式(sidecar),而在生产环境中一般都是单个容器或者具有强关联互补的多个容器组成一个Pod。
///边车模式
就是在一个pod里面可以运行多个容器。多个容器就是以边车模式存储在pod中。
//同一个POd中,容器之间的端口不能冲突,不然会导致无限重启。
Pod中存储的几种类型的容器
//基础容器(pause):
维护整个Pod网络和存储空间,node节点中操作,启动一个实例,k8s会自动启动一个基础容器。
//初始化容器(init):
Init容器必须在应用程序容器启动之前运行完成,而应用程序容器是并行运行的,所以Init容器能够提供了一种简单的阻塞或延迟应用容器的启动的方法。
//业务容器:
并行启动
面试题:
下图中。
// 单个Pod之间的容器可以直接通过locathost完成通信。(因为各个容器之间使用的是container网络模式)
# 相同节点不同Pod之间如何通信?
//不Pod之间不能通过localhost通信。它需要通过容器网络容器(比如docker0、bridge、host等)
# 不相同节点pod之间怎么通讯?
//借助于cni插件(container network interface:容器网络接口)通信。
//常用的接口有calico、flannel、cannel。
pod控制器是Pod启动的一种模板,用来保证在K8S里启动的Pod硬始终按照用户的预期运行(副本数,生命周期、健康状态检查等)。
K8S内提供了众多的 Pod 控制器,常用的有以下几种。
#可以理解成Deployment就是总包工头,主要负责监督底下的工人Pod干活,确保每时每刻有用户要求数量的Pod在工作。如果一旦发现某个工人Pod不行了,就赶紧拉一个Pod过来替换它。
而ReplicaSet就是总包工头手下的小包工头。从K8S使用者者角度来看,用户会直接操作Deployment而不操心Replicaset。
资源对象 Replication Controller(RC) 是ReplicaSet的前身,官方推荐用Deployment取代 RC 来部署服务。
-----------------------------------------------------------------
//RS支持标签选择器,RC不支持,所以后面大型架构都选择RS来控制Pod
//虽然RC能独立使用,但是基本还是和Deployment一起使用,因为RC不支持滚动更新和回滚,Deployment支持。但是又由于Deployment不支持容器的创建,所以两个经常放一起使用。
Daemonset: 确保所有节点运行同一类Pod,保证每个节点上都有一个此类Pod运行,通常用于实现系统级后台任务。
Statefulset: 有状态应用部署
Job : 一次性任务,根据用户的设置,Job管理的Pod把任务成功完成就自动退出了。
Cronjab: 周期性计划任务。
#无状态应用部署:
相当于http协议,我们每次访问nginx或apache页面,都是返回一样的结果
也就是无状态服务就是,我们将此服务从集群中脱离出来,再拉回集群中,它还可以继续运行。
#有状态应用部署:
相当于数据库,存储的数据不一样。
也就是说有状态服务,当服务从集群中脱离出来,再拉回集群,可能导致不可用了,服务的数据不一致了。
标签,是K8S特色的管理方式,便于分类管理资源对象。
Label可以附加到各种资源对象上,例如Node、Pod、Service、RC等,用于关联,查询和筛选。
一个Label是一个Key-value的键值对,其中key与value由用户自己指定。
一个资源对象可以定义任意数量的label,同一个label也可以被添加到任意数量的资源对象中,也可以在对象后动态添加或者删除,可以通过给指定的资源对象捆绑一个或多个不同的label,来实现多维度的资源分组管理功能。
//简单来说:标签就是用来分类管理,k8s管理的资源打上标签,进行分类。通过键值对的存储标签的格式,最后通过标签选择器去选择标签。找到对应的数据。
#与label类似的,还有Annotaion(注释)。
区别在于有效的标签值必须为63个字符或更少,并且必须为空或以字母数字字符(a-z0-9A-Z)开头和结尾,中间可以包含横杠(-),下划线(_),点(.)和字母或数字,注释值则没有字符长度限制。
给某个资源对象定义一个label,就相当于给它打了一个标签。随后可以通过标签选择器(label selector)查询和筛选拥有某些label的资源对象。
标签选择器目前有两种: 基于等值关系(等于、不等于)和基于集合关系(属于、不属于、存在)
//总结: 有了标签,就需要通过标签选择器去寻找不同的标签,然后找到对应的ip地址。
在K8S的集群里,虽然每个Pod会被分配一个单独的IP地址,但由于Pod是由生命周期的,随时可能会因为业务的变更,导致整个IP地址会随着Pod的销毁而消失。
service就是用来解决这个问题的核心概念。
//为啥ipvs推荐?
因为ipvs是效率高。它是直接通过ip转发。
iptables是经过策略进行转发,且在策略中,是一行一行执行,效率较低。
Service 是K8S服务的核心,屏蔽了服务细节,统一对外暴露服务接口,真正做到了“微服务”。比如我们的一个服务A,部署了3个副本,也就是3个Pod;
对于用户来说,只需要关注一个Service 的入口就可以,而不需要操心究竞应该请求哪一个Pod。
优势非常明显 : 一方面外部用户不需要感知因为Pod上服务的意外崩溃、K8S重新拉起Pod 而造成的IP变更,外部用户也不需要感知因升级、变更服务带来的Pod替换而造成的IP变化。
##########总结:
#serice核心概念
service可以看做是pod对外的统一访问接口,每个service都有一个固定的虚拟ip(Cluster ip ),自动并且动态的绑定后端pod。所有网络请求,通过service转发到后端。
#转发流程
//service属于4层转发。service的实现方式就是kube-proxy运行在每个节点上。
service通过匹配的标签,通过标签选择器找到对应的标签,然后找到对应ip地址,然后通过负载均衡,将请求转发到对应的pod上。
service主要负责k8s集群内部的网络拓扑,那么集群外部怎么访问集群内部呢?
这个时候就需要ingress了,ingress是整个k8s集群的接入层,负责集群内外通讯。
Ingress是K8S集群里工作在OSI网络参考模型下,第七层的应用,对外暴露的接口,典型的访问方式是http/https.
service只能进行第4层的流量调度,表现形式是ip+prot。ingress则可以调度不同的业务域,不同URL访问路径的业务流量。
比如:客户端请求http://www.ydq.com:prot ----->ingress ----->service----->pod
#总的流程
//客户端将请求发送到ingress对外暴露的接口上面,ingress通过七层转发(http/https)转发到不同的cluster ip上也就是service上面,service是每个节点上的所有pod的对外的接口,service经过四层转发,通过标签选择器,负载均衡到不同的pod上面的标签,找到对应的pod。
由于k8s内部,使用 “ 资源 ”来定义每一种逻辑概念(功能),所以每种“ 资源 ”,都应该有自己的“名称”。
“ 资源 ” : 有api版本(apiversion),类别(kind)、元素数据(metadata),定义清单(spec)、状态(status)等配置信息。
“名称 ” : 通常统一在“ 资源 ”的 “ 元数据 ”信息里,在同一个namespace空间中必须是唯一的。
//总结:在同一个命名空间里面,名称是唯一的。不同的名称只能出现不同命名空间里面。
随着项目增多,人员增加,集群规模的扩大,需要一种能够逻辑上隔离k8s内部“资源”的办法,这就是namespace。
namespace是为了把一个K8S集群划分为若干了资源不可共享的虚拟集群组而诞生的。
不同namespace内的“资源”名称可以相同,系相同的namespace内的同种“同种资源”,”名称“不能相同。
合理的使用k8s的namespace,可是的集群管理员能够更好的对交付到K8S里的服务进行分类管理和浏览。
K8S里默认存在namespace有:default、kube-system、kube-public等。
查询k8s里特定的“资源“ 要带上相应的namespace。
//总结:k8s集群中需要namespace命令空间将资源进行隔离。当我们查找资源的时候,需要根据命令空间去查找。