介绍Kubernetes架构
Kubernetes 架构
从高层看,kubernetes 是由如下东西组成的:
一个或多个 master node
一个或多个 worker node
一个分布式的 key-value 存储,比如etcd
Master Node
Master node 是集群管理者,我们发出的所有请求都是到 master node 的 api server 上。
一个集群可以有多个 master node 做 HA,当有多个 master node 的时候,只有一个会提供服务,剩下的都是 follower。
集群的状态一般存储在etcd里面,所有的 master node 都会连接到 etcd。etcd 是一个分布式 k-v 存储。etcd 可以是 master 内部的,也可以是外部的。
Master node 的组件
master node 一般都有如下组件:
API Server
所有的操作都是通过 API Server 去完成的。每个用户 / 操作者通过发送 REST 请求到 api server,然后 api server 先验证然后执行这些操作。在执行完之后把集群的状态存到 etcd 里面。
Scheduler
顾名思义,Scheduler 的作用是调度,Scheduler 拥有所有 worker node 的资源使用情况,同时也知道用户设置的资源需求,比如说一个 disk=ssd的 label。在调度之前,scheduler 还会考虑到 service requirements,data locality,affinity,anti-affinity 等。scheduler 负责的是 service 和 pod 的调度。
Controller Manager
简单来说,Controller Manager 是负责启动和关闭 pod 的。Controller Manager 的任务是让集群维持在期望的状态上。Controller Manager 知道每个 Pod 的状态应该是什么样,然后会不断检测是否有不达标的 pod。
Worker Node
Worker Node 就是一个被 master node 控制的机器,Pod 一般都是调度到 worker node 里面的。Worker node 会有一些可以运行以及连接容器的工具。Pod 是 kubernetes 里面的调度单元,是一个或多个容器组成的通常一起调度的逻辑上的集合。
Worker Node 组件
一个 worker node 一般会有以下组件:
Contrainer Runtime
不用多说了,运行容器必备的,默认用的是 Docker
kubelet
kubelet 是在每个 worker node 上都会运行的,用来和 master node 通信的。kubelet 从 master 接收 pod 的定义,然后启动里面的容器,并监控容器是否一直正常运行。
kube-proxy
kube-proxy 简单来说,就是对外提供代理服务的。换句话说,没有 kube-proxy,我们要访问其中的 application,就得直接访问到 worker node 上,这显然是不合理的。我们可以通过 kube-proxy 来做 load balancer 等。以前版本的 Service 也借助了 kube-proxy。
用 etcd 来管理状态
在 kubernetes 里面,都是用的 etcd 来管理所有的状态。除了集群的状态之外,还会用来存放一些信息,比如 configmap,secret。
网络需求
为了启动一个全功能的 kubernetes 集群,我们需要先确认以下信息:
- 每个 Pod 有唯一一个独立的 IP
- 每个 Pod 里面的容器可以互相沟通
- Pod 之间可以互相沟通
- 通过设置,在 Pod 里面的 application 可以被外部访问到
- 这些问题都是需要在部署之前被解决的。
我们一个个看:
给每个 Pod 分配一个独立的 IP
在 kubernetes 里面,每个 Pod 都要有一个独立的 IP。一般容器网络有两种规格:
- Container Network Model (CNM)
- Container Network Interface (CNI)
Kubernetes 用 CNI 来给 Pod 分配 IP
简单来说,容器运行时向 CNI 申请 IP,然后 CNI 通过其下面指定的 plugin 来获取到 IP,并且返回给容器运行时。
容器之间交流
一般基于底层操作系统的帮助,所有的容器运行时都会给每个容器创建一个独立的隔离的网络整体。在 Linux 上,这个整体被称为 Network Namespace,这些 Network Namespace 可以在容器之间共享。
在一个 Pod 里面,容器共享 Network Namespace,所以所有在同一个 Pod 里面的容器可以通过 localhost 来互相访问。
跨 Node 的 Pod 之间访问
在一个集群的环境下,每个 Pod 可以被调度到任何一个 Node 上,我们需要让在不同机器上的 Pod 也可以相互通信,并且任何 Node 都可以访问到任何 Pod。Kubernetes 设定了一个条件:不能有任何的 NAT 转换,我们可以通过以下方式来达成:
- 可路由(Routable)的 Pod 和 Node,通过底层的服务,比如 GCE。
- 通过一些软件定义的网络(Software Defined Networking),比如 flannel,weave,calico 等
更多的信息可以看看 kubernetes 的官方文档。
外网和集群之间的访问
我们可以通过kube-proxy来暴露我们的 service,然后就能从外面访问到我们集群里面的应用了。
如何实现节点的扩缩容
在node节点上安装docker、kubelet和kube-proxy服务,然后将kubelet和kube-proxy的启动参数中的master url指定为当前kubernetes集群master的地址,然后启动服务即可。基于kubelet的自动注册机制,新的node会自动加入现有的kubernetes集群中
删除node节点kubectl delete node k8s-node1
如何实现pod的扩缩容
手动:kubectl scale rc redis-slave --replicas=3
自动:HPA控制器,可以实现基本CPU使用率进行自动Pod扩容和缩容的功能。
(原理:HAP控制器基于Master的Kube-controller-manager服务启动参数--horizontal-pod-autoscaler-sync-period定义的时长(默认值为30s),周期性地检测目标Pod的CPU使用率,并在满足条件时对ReplicationController或Deployment中的Pod副本数量进行调整,以符合用户定义的平均Pod CPU使用率。Pod CPU使用率来源于Heapster组件,所有需要预先安装好Heapster.)
kubernetes相关组件原理
kubernetes API Server原理分析
- 核心功能:
提供了Kubernetes各类资源对象(Pod、RC、Service等)的增删改查及Watch等HTTP Rest接口;
是集群内各个功能模块之间交互和通信的中心枢纽,整个系统的数据总线和数据中心。
- 功能特性:
1、集群管理的API入口
2、资源配额控制的入口
3、提供了完备的集群安全机制
- 连接:
默认: --insecure-port=8080
启动HTTPS安全端口:--secure-port=6443
- 交互方式:
命令行工具kubectl(实际上就是REST调用)
curl验证接口:curl localhost:8080/api/v1/pods
暴露部分REST,启动内部代理:kubectl proxy --reject-paths="^/api/v1/replicationcontrollers" --port=8001 --v=2
编程的方式:Pod内用户进程调用Kubernetes API,通常用来实现分布式集群搭建的目标。Kubernetes API Server本身也是一个Service,名字是Kubernetes。
开发基于Kubernetes的管理平台。使用Client-go。
- 扩展接口:kubernetes Prox API
kubernetes API Server会把收到的REST转发到某个Node上的kubelet的REST端口上,由该kubelete负责响应,不通过etcd获取。
/api/v1/proxy/nodes/{name}/pods/
/api/v1/proxy/nodes/{name}/run(需要kubelet启动时运行--enable-debugging-handlers=true)
通常用于kubernetes集群之外访问某个Pod容器的服务,多用于管理目的,比如检查Pod副本异常。
- 集群功能模块之间的通信
各个组件通过API Server将信息存入etcd,
通过API Server的REST接口(GET、LIST、WATCH)获取和操作数据。
例:
kubelet每隔一个时间周期,调用API Server的REST接口报告自身状态,api server将节点状态信息更新到etcd。
kubelet通过API Server的Watch接口监听Pod信息。
kube-controller-manage中的Node Controller通过API Sever提供的Watch接口实时监控Node信息,并作出相应处理。
Scheduler通过API server的watch接口监听到新建Pod副本的信息后,执行调度逻辑,将Pod绑定到目标节点。
为了缓解访问压力,各个组件采用缓存机制缓存数据。定时(LIST WATCH)指定资源对象,保存到本地。
Controller Manager原理分析
- 功能:集群内部的管理控制中心,负责将Node、Pod副本、服务端点(Endpoint),命名空间(namespace)、服务账号(ServiceAccount)、资源定额(ResourceQuota)等的管理,当某个Node意外宕机时,Controller Manage会发现故障并执行自动化修复流程,确保集群始终处于预期的工作状态。
- Replication Controller
- Node Controller
- ResourceQuota Controller
- Namespace Controller
- Service Controller & Endpoint Controller
Scheduler原理分析
- 功能:承上,接口COntroller Manager创建的新Pod,调度到合适节点。启下,调度之后交给kubelet执行
- 详细:将待调度的Pod(API新建Pod、Controller Manage维护调度的Pod)按照特定的算法绑定到Node,并写入到etcd。涉及对象:待调度Pod列表、可用Node列表、调度算法和策略。随后,目标节点Kubelet通过API Server将听到Kubernetes Scheduler产生的额Pod绑定事件,然后获取响应Pod清单,下载Image镜像,并启动容器。
- 调度流程:1)预选调度(xxx Predicates
):筛选可用Node节点。
2)优选策略(xxx Priority):确定最优节点。
插件方式:“算法提供者”(AlgorithmProvider),包含一组预选策略与一组优选策略的结构体。
注册AlorithmProvider函数:func RegisterAlgorithmProvider(name string, predicateKeys, priorityKeys util.StringSet)
name string为算法名,predicateKeys为预选策略集合,PriorityKeys为优选策略集合。- 预选策略:
1 NoDiskConflict 是否存在磁盘冲突
2 PodFitsResouces 是否满足在资源需求
3 PodSelectorMatches pod的label selector是否满足
4 PodFitsHost pod指定spec.nodeName
5 PodFitsPorts Pod端口是否可用
*6 CheckNodeLabelPresence 标签集
*7 CheckServiceAffinity service和Namespace下Pod标签是否存在- 优选策略:
1 LeastRequestedPriority:
资源消耗最小节点
score = int(((nodeCpuCapacity - totalMilliCPU)*10)/ nodeCpuCapacity+((nodeMemoryCapacity-totalMemory)*10)/nodeCpuMemory)/2)
totalMilliCPU为所有备选节点上运行的Pod和备选Pod的CPU占用量
totalMemory为所有备选节点上运行的Pod和备选Pod的内存占用量
nodeCpuCapacity为节点cpu计算能力
nodeMemoryCapacity为节点内存大小
2 CalculateNodeLabelPriority:
判断标签是否需要判断同时是否存在
3 BalancedResoruceAllocation
选出各项资源使用率最均衡的节点
Score = int(10-math.Abs(totalMilliCPU/nodeCpuCapacity-totalMemory/nodeMemoryCapacity)*10)
kubelet运行机制分析
描述:每个Node节点都会启动一个kubelet服务。
功能:
1 向API Server注册节点
2 定期向Master汇报节点资源使用情况
3 通过cAdvisor监控容器和节点资源
节点管理:
Pod管理:
容器健康检查:
cAdvisor资源监控:是一个开源的Fenix容器资源使用率和性能特性的代理工具。自动查找所有在其节点上的容器,自动采集CPU、内存、文件系统和网络使用的统计信息。
同时kubelet通过REST API暴露这些聚合后的Pod资源使用的统计信息。Heapster提供集群级别的监控和事件数据集成器(Aggregator)。
kube-proxy运行机制分析
描述:Service的透明代理兼负载均衡器。
对每个service都会在本地Node上建立已给SocketServer负责接收请求,Round Robin发送到后端Pod上。
Service的Cluster IP、NodePort等概念也是kube-proxy服务通过Iptables的NAT转换实现。
Kube-proxy通过查询和监听API Server中的Service与Endpoints的变化,为每个Service都建立了一个“服务代理对象”包括SocketServer。此外还建立了一个负载均衡器。具体路由选择取决于Round Robin算法及Service的Session会话保持(SessionAffinity)特性。
网络原理
Kubernetes网络模型
IP-per-Pod:
Docker0以Pod为单位分配IP,一个Pod内部的所有容器共享一个网络命名空间(ip、网络设备、配置)。Pod内外IP一致。
好处:Pod内共享端口,通信简单高效。
坏处:共享端口降低了容器的隔离性。
Docker网络基础
NetworkNamespace
独立的路由表、独立的Iptables/Netfilter、NAT及IP包过滤等功能
Veth设备对
NETIF_F_ETNS_LOCAL=on,属于可以转移到其他网络命名空间的网络设备
docker创建veth对通信步骤:
1 创建veth对
2 转移到另一个ns
3 改名eth0
4 分配IP
5 重启
Iptables/Netfilter
网桥
二层虚拟网络设备,连接若干网络接口,使网口之间的报文能够互相转发。
内核Netfilter,用户Iptables。
路由
Docker网络实现
- host模式
- container模式
- none模式
- bridge模式
默认桥接网络模型
1 创建Docker0网桥(docker deamon启动时)
2 给网桥分配子网
3 创建veth对(任一Docker容器启动)
4 转移并给Veth对分配IP
kubernetes网络实现
1 容器到容器通信
2 Pod到Pod之间的通信
3 Pod到Service之间的通信
4 集群外部与内部组件之间的通信。
容器到容器的通信
同一个Pod内容器共享同一个网络命名空间。直接通过localhost:port端口可以直接通信
Pod之间的网络通信
同一个Node之间的Pod通信
直接访问Pod的全局ip因为,同一个Docker0网桥分配的ip、进行路由。
1 创建Docker网桥、分配子网ip
2 创建veth对
3 转移并分配IP
不同Node之间的Pod通信
Kubernetes会记录所有正在运行的Pod的IP分配信息,并将这些信息保存在etcd中(作为Service的Endpoint)
通信的条件
1:k8s集群上的IP不冲突
2:PodIP与NodeIP关联使Pod可以相互访问
需要使用开源网络组件,如Flannel能管理资源池的分配。
开源网络组件
Flannel
作用:实现Node间pod通信
1 给每个Node上的Docker容器分配互相不冲突的IP地址
2 能在这些IP地址之间建立一个覆盖网络(Overlay Network)
流程:
首先创建flannel0网桥,
网桥的一端连接docker0网桥,
另一端连接一个flanneld服务进程。
flanneld进程:
1 利用etcd管理可分配IP池
2 监控etcd中Pod地址
3 内存中建立Pod节点路由表
4 包装docker0发送的数据
5 投递至目标flanneld上,完成Node间Pod通信
缺点:
引入了多个网络组件,导致网络的时延损耗。
Calico
简介:基于BGP的三层网络。
1 在每个计算节点利用Linux Kernel实现了高效的vRouter来负责数据转发。
2 每个vRouter通过BGP1协议广播本节点上运行容器的路由信息。
3 容器间数据流量通过IP路由方式互联。
组件:
Felix:设置容器网络资源
etcd:后端存储
BIGP Client(BIRD):BGP广播Felix路由信息
BIRD(BGP Route Reflector):大规模集群分析路由分发
calicoctl:calico命令行管理工具
共享存储原理
- 目的:
容器重建后,仍可使用之前的数据- 目标:
有状态容器应用、数据持久化应用- 类别:
宿主机目录
emptyDir临时存储卷
共享存储
PersistentVolume(PV)
是对底层网络共享存储的抽象,将共享存储定义为一种“资源”
PersistentVolumeClaim(PVC)
是对用户对于存储资源的一个“申请”。StorageClass,标记存储资源的特性和性能
PV详解
包括:
存储能力(5Gi)、
访问模式(RWO\ROX\RWX)、
存储类型(快\慢\有冗余\无冗余\slow)、
回收策略(Retain保留\Recycle回收空间\Delete删除)、
后端存储类型(HostPath\AWS\GCE)
生命周期:
Available:可用,还未与pvc绑定
Bound:已经和pvc绑定
Released:绑定的pvc已经删除,资源释放但未回收
Failed:自动资源回收失败
pvc详解
包括:
存储空间请求、
访问模式、
PV选择条件、
存储类别
KUbernetes集群高可用部署
原生应用层高可用:
Kubernetes作为容器应用的管理平台,通过对Pod的运行状态进行监控,并且根据主机或容器是小的状态将新的Pod调度到其他Node上,实现了应用层的高可用。
etcd数据存储的高可用
防止单点故障
1 集群方式部署etcd
2 etcd本身的数据本身考虑使用可靠的存储设备(RAID磁盘阵列、高性能存储设备、共享存储文件系统,云服务商提供的存储系统。)
访问集群参数设置:
--etcd-servers=http://10.0.0.1:2379,http://10.0.0.2:2379,http://10.0.0.3:2379
kubernetes Master组件的高可用
Master节点工作:
总控中心,主要的三个服务kube-apiserver、kube-controller0mansger和kube-scheduler通过不断与工作节点上的kubelet和kube-proxy进行通信来维护整个集群的健康工作状态。
高可用概述:
1 至少三台Master实现高可用。
2 容器启动。
3 kubelet以StaticPod形式启动并由kubelet进行监控和自动重启。kubelet本身的高可用通过系统的systemd管理。
kube-apiserver的高可用部署
- 首先创建CA证书、鉴权文件、每台服务器创建其日志文件
- 其次kubelet启动参数指定--config=/etc/kubernetes/manifests(Static Pod定义文件所在的目录)
- 创建kube-apiserver.yaml用于启动kube-apiserver
1 hostNetwork网络模式
2 k8s发布包的镜像tag
3 --etcd-servers指定etcd服务的URL地址
4 CA证书等
5 hostPort端口号
6 kube-apiserver.yaml文件复制到kubelet监控的/etc/kubernetes/manifests,kubelet将自动创建yaml文件中定义的kube-apiserver的Pod。
- 配置kube-apiserver的负载均衡器
GCE,阿里云都是现成的
本地使用haproxy和keepalived实现:
haproxy负责负载均衡,keepalived负责对haproxy监控和进行高可用。
- 注意:1、Master开启安全认证机制要确保证书中包含负载均衡服务的节点。
2、对于外部的访问,比如通过kubectl访问,需要配置为访问API Server对应的负载均衡器的IP地址。
kube-controller-manager和kube-scheduler的高可用配置
这两个组件会修改集群状态信息,因此不仅需要启动多个实例,还要有选举机制选举出leader,保证同一时间只有一个实例对集群状态信息进行读写,避免出现同步和一致性问题。
选举机制通过租赁锁(lease-locak)实现,在每个实例的启动参数中设置--leader-elect=true。
步骤:
1 每个Master节点上创建相应的日志文件。
2 创建kube-controller-manager和kube-scheduler的Pod定义文件。
- 最后的关键:确认集群中所有访问API Server的地方都已经将访问地址修改为负载均衡的地址。
Master高可用架构的演进
支持多个Master配置,实现不需要负载均衡器的Master高可用架构。
集群监控
cAdvisor
cAdvisor已被默认集成到kubelet组件内,会实时采集所在节点的性能指标及在节点上运行的容器的性能指标。kubelet启动采纳数--cadvisor-port可自定义cAvisor对外提供服务的端口号,默认为4194。
REST API返回JSON数据格式,采用如下URL访问:http://: /api/ /
缺点:只能采集本机的性能指标数据。
Heapster+Influxdb+Grafana集群性能监控平台搭建
大规模集群需要对所有Node和全部容器进行性能监控,使用一套工具来实现集群性能数据化肚饿采集、存储和展示:Heapster、InfuluxDB和Grafana。
Heapster:对集群中各Node上cAdvisor的 数据采集汇聚的系统。
通过kubelet的API,再通过kubelet调用cAdvisor的API来采集该节点上所有容器的性能数据。Heapster对性能进行聚合,结果保存到后端存储系统中。可以是memory(内存)、InfluxDB等
InfluxDB:分布式时序数据库(每条记录都带有时间戳属性),用于实施数据次啊及、时间跟踪记录、存储时间图表、原始数据等。
Grafana:通过Dashboard将InfluxDB中的时序数据展现成图表或曲线等形式。
Helm:kubernetes应用包管理工具
用于对Kubernetes上部署的复杂因公应进行定义、安装和更新。Helm以Chart的方式对应用软件进行描述,可以方便的创建、版本化、共享和发布复杂的应用软件。
主要概念:
Chart:一个Helm包,包含了运行一个应用所需要的工具和资源定义,还可能包含service定义。
Release:在Kubernetes集群上运行一个Chart实例。在同一个集群上,一个Chart可以安装多次。
Repository:用于存放Chart的仓库。
主要任务:
在Repository中查找需要的Chart然后将Chart以Release的形式安装到Kubernetes集群。
组件:
- HelmClient:对Repository、Chart、Release等对象的管理能力
- TillerServer:负责客户端指令和Kubernetes集群之间的交互,根据Chart定义,生成和管理各种Kubernetes的资源对象。
文件夹:
wordpress/
Chart.yaml #应用定义yaml文件
values.yaml #默认配置信息
charts/ #包含依赖chart,推荐使用requirement.yaml仅需要注明以来的Chart仓库信息,不需要定义整个Chart文件
templates/ #结合values.yaml能生成Kubernetes的manifest文件
问题定位
- 查看kubernetes对象当前运行时信息
- 深入容器内部进行故障诊断,查看容器运行日志
- Kubernetes服务日志。如kube-apiserver等的。
kubectl get pods
kubectl describe pod
Pod失败原因:无可用Node、目标节点无可用资源、正在下载镜像
kubectl logs
kubectl logs-c <container_name>
存储卷保存日志
systemd系统管理Kubernetes服务,systemd的journal系统会接管服务程序的输出日志。
systemctl status kube-controller-manager -l
journalctl -u kube-controller-manager