kubernetes架构原理和核心概念
k8s是kubernetes的外号,后面文中大多以k8s来简称kubernetes!k8s官方文档地址:https://kubernetes.io/docs/home/官方对k8s...
k8s是kubernetes的外号,后面文中大多以k8s来简称kubernetes!
k8s官方文档地址:
https://kubernetes.io/docs/home/
官方对k8s的描述:
Kubernetes is an open source container orchestration engine for automating deployment, scaling, and management of containerized applications. The open source project is hosted by the Cloud Native Computing Foundation (CNCF).
译:
Kubernetes是一个开源容器编排引擎,用于支持应用程序容器自动化部署、扩展和管理,kubernetes是开源的,项目由Cloud Native Computing Foundation(CNCF)托管。
读完之后第一感就是:好抽象的一段话!详细点去理解k8s可以先从下面这张图开始:
这个图从左往右看,它阐述了软件工程部署架构的一个演变过程:从传统部署(第一图)到虚拟机部署(第二图)到容器化部署(第三图),k8s诞生在第容器化部署阶段,容器化部署的特点就是:将软件工程各种依赖(例如jdk、tomcat)打包成一个镜像,然后就可以将这个镜像拿到任何安装了相应的容器环境下运行,并且可以将该镜像推送到某个私服仓库上,其它节点直接从该仓库拉取镜像运行进行集群部署实现高可用,同一个主机上不同的容器实例之间通过命名空间实现资源(pid\net\ipc\mnt\uts)互相隔离,这就是容器化部署的核心特点:可移植性强、copy实例成本低、资源互相隔离,这在当下微服务盛行的时代非常有用,其中docker是目前市面上典型的容器代表。
容器化技术解决了当下微服务时代部署成本高的问题,而k8s是使容器支持在集群环境下更智能、更稳定运行、更方便管理的一个框架。
k8s架构
了解k8s的架构对我们后续部署和使用都至关重要,下面是k8s架构图:
k8s有点类似主从的架构,左边虚线矩形组件称为控制面板(kubernetes Control Plane)组件,这部分组件运行在master节点上,右边虚线矩形组件称为节点组件(kubenetes Nodes),这部分组件运行在work节点上。在k8s集群部署后默认情况下不会在master节点上调度Pod(后续学习过程会逐步理解Pod概念),Pod统一调度到work节点上,这样做目的是保证master节点的稳定性,因为master太重要了,一旦挂掉,整个集群的应用服务将不可用。下面我们先简单了解上图中几个核心概念。
控制面板组件:
kube-api-server:k8s集群控制面板的前端,将控制面板的所有需要对外的能力以rest api的方式对外提供,外部可以通过http协议直接编写代码来访问,也可以使用kubectl命令行工具来访问。
etcd:k8s集群KV键值对存储组件,存储整个k8s集群的数据。
kube-scheduler:k8s集群调度器,为新创建的Pod根据需要的资源分配到相应的节点上,调度算法包括个体和整体的资源情况分析、硬件或软件策略分析、工作负载等因素。
kube-controller-manager:k8s集群控制器,内部逻辑划分为:节点控制器、副本控制器、端点控制器、账户和令牌控制器。
cloud-controller-manager:k8s集群云控制器,嵌入特定与云的控制逻辑的组件,使你可以访问特定云提供商的API(例如验证亚马逊云虚拟服务器健康状况)。云控制器也包括节点控制器、路由控制器、服务控制器。
节点组件:
kubelet:每个work节点上运行的k8s代理,为节点提供k8s环境支持,管理work节点的Pod中的容器正常运行,该组件与控制面板进行通信。
kube-proxy:每个work节点上运行的k8s网络代理,通过维护网络规则来允许其它会话与当前节点的Pod通信,类似防火墙。
集群节点信息
当k8s集群部署成功后,可以通过下面命令查看每个节点的信息:
kubectl describe node <nodename>
每一个节点都包括以下状态:
地址(Address):
HostName:节点内核设置的hostname。
ExternalIP:集群外部可以访问的节点IP。
InternalIP:集群内部可访问节点IP。
条件(Condition):
Node Conditions | Desc |
OutOfDisk | True 表示节点的空闲空间不足以用于添加新 pods, 否则为 False |
Ready | 表示节点是健康的并已经准备好接受 pods;False 表示节点不健康而且不能接受 pods;Unknown 表示节点控制器在最近 40 秒内没有收到节点的消息 |
MemoryPressure | True 表示节点存在内存压力 – 即节点内存用量低,否则为 False |
PIDPressure | True 表示节点存在进程压力 – 即进程过多;否则为 False |
DiskPressure | True 表示节点存在磁盘压力 – 即磁盘可用量低,否则为 False |
NetworkUnavailable | True 表示节点网络配置不正确;否则为 False |
总容量和可分配容量(Capacity and Allocatable):
描述节点上的可用资源,capacity表示节点总资源,allocatable表示Pod可使用的资源。
信息(Info):
描述节点的各种信息:内核版本、kubenetes版本、Docker版本、操作系统名称。
集群节点注册
当节点kubelte标志--register-node为true时(默认为true),它会尝试向API Server服务注册当前节点,在注册时同时报告自己的容量信息。当节点注册到API Server时k8s内部通过创建一个节点对象表示该节点以及节点的信息,节点加入k8s集群后控制面板会维护集群节点列表。节点上的kubelet进程会定时发送心跳信息给API Server保存更新到etcd上,然后kube-controller-manager的节点控制器会定时(可以通过--node-monitor-period配置)分析etcd存储的节点信息变化,如果节点控制器发现某个节点在指定时间内(默认40s)没有更新过状态,则会将节点的NodeReady状态更新为ConditionUnknown,如果超过5m后仍然收不到节点的心跳,则开始驱逐节点上的pods。
集群安全
k8s集群所有功能都是通过Restful API Server的方式对外提供,所以集群的安全主要的也就是API Server访问的安全问题。在数据传输层面支持通过配置为https方式将传输的数据包进行加密,在准入机制层面通过token的方式实现身份认证,在访问API层面基于RABC基于角色的方式进行API权限控制。默认情况下,master访问API Server时,内部是通过HTTP,但是访问的是运行在master节点localhost接口上暴露的端口,而API Server访问节点上kubelte时,使用的也是HTTPS,但是注意,默认情况下,API Server访问nodes、pods、和services时则为纯HTTP,这类连接目前还不能安全地运行在不安全的公网上。
k8s解决什么问题
前面架构图我们了解了k8s和主从划分以及运行在主从各个组件的大致作用和Pod默认调度策略,下面我们继续讲解k8s的原理,理解原理可以帮助我们更好地使用k8s。
因为k8s的诞生目的主要是管理容器为容器服务的,所以要理解k8s的原理可以先从没有k8s时容器化部署开始,就拿docker容器技术使用来说,首先需要编写一个镜像配置文件,通过配置文件定义将该应用需要的各种基础组件:例如unix类操作系统、jdk、tomcat、业务应用lib、业务应用Jar等一起打包配置到一个镜像包中,然后就可以直接在docker环境下运行该镜像,运行起来后的镜像称为容器实例,不同的容器实例之间的资源是隔离的,比如同一个主机运行两个容器实例可以有相同的端口号,这种使用在单机部署时并没什么太大的问题,但是当下的任何业务应用基本都是集群进行负载,当业务应用集群部署时容器化部署的问题就凸显出来了,主要问题如下:
DNS和负载均衡问题
几百台机器大型机器快速部署问题
根据集群节点资源情况自动调度容器实例问题
自动恢复宕机节点的容器实例问题
自动扩容和缩减集群负载副本问题
支持灰度发布问题
安全问题
K8s对象
k8s是怎么解决这些问题的呢?
k8s在前面讲解的架构基础上,将这些问题抽象为对象的方式去实现,总体上分为基本对象和控制对象:
基本对象包括:
Pod
Service
Volume
Namespace
控制对象包括:
Deployment
DaemonSet
StatefulSet
ReplicaSet
Job
可以通过yaml或json配置文件的方式去定义这些对象,然后通过kubectl命令行或restful api的方式调用kube-apiserver,由kube-apiserver进程将该请求转发给k8s控制面板,最后由控制面板将对象信息持久化或更新到etcd,最后由控制面板来完成对象的创建或状态更新。
几乎每个对象内部维护两个属性字段来表示对象的当前状态(object status)和期望状态(object spec),k8s控制面板持续主动地观察每个对象的实际状态是否匹配期望状态,一旦发现某个对象的实际状态不匹配期望状态,控制面板将主动修正实际当前状态和期望状态的差异。例如某个Deployment对象通过yaml配置文件定义的方式告诉k8s为该应用程序部署期望副本数量是3,由于某个节点宕机导致Deployment对象的副本数量变为2,此时控制面板将发现这个问题并从其它节点启动新的副本来修正这个问题。
下面是通过配置文件deployment.yaml定义Deployment对象的一个例子:
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # tells deployment to run 2 pods matching the template
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
几乎任何对象yaml配置文件中必须要定义如下几个字段:
apiVersion:使用哪个版本的kubernetes api创建该对象。
kind:指定要创建的对象类型。
metadata:对象元数据信息,例如name、namespace。
spec:对象的期望状态。
将deployment.yaml配置文件翻译为文字如下:
1、使用v1.10.x版本的Kubenertes API来创建对象。
2、创建一个name为 nginx-deployment的Deployment控制对象。
3、该Deployment对象期望状态是:
3.1、通过选择器(selector部分定义)的定义来匹配带有标签app=nginx的Pod对象。
3.2、控制匹配的Pod对象副本实例数量为2。
4、template部分描述的是Pod基本对象的定义,描述的定义如下:
4.1、为Pod打个标签app=nginx(这个标签刚好可以匹配到Deployment对象的选择器)。
4.2、该Pod期望状态为拉取名称为nginx的镜像,运行端口为80。
最后可以通过下面命令来创建和运行这些对象定义:
kubectl apply -f deployment.yaml --record
k8s对象管理
k8s支持以下3种方式来创建或管理对象:
完全命令式:完全通过命令行参数的方式来指定创建或更新对象信息。
命令+配置文件:首先编写一个yaml或json配置文件,然后通过kubectl命令-f参数来指定执行的配置文件。
声明式配置:由k8s监听某个目录下的配置文件,根据监听到的目录文件的创建、修改、删除来执行相应对象配置的创建、修改、删除。
官方建议统一只选择其中一种方式来管理对象,如果使用3种方式混合管理的话可能产生意想不到的问题,这里本人比较习惯使用第二种方式。
k8s对象名称和IDs
集群中每一个对象拥有一个名称和UID,名称在同一类型的对象是唯一的,UID在集群中全局唯一。
k8s对象标签
标签是附加到k8s对象上的键值对,目的是标识对象属性。标签可以在创建时设置,也可以在未来修改,同一个对象标签键是唯一的,不同对象标签键可以相同,下面是一个例子:
metadata:
labels: {key1: value1, key2: value2}
匹配规则示例如下:
env=prod
env!=prod
app=nginx
env in (dev, test)
env notin (dev, test)
env
!env
标签的作用其一是方便某些对象(Service、Deployment)通过选择器来查询匹配,例如:
selector:
matchLabels:
component: redis
matchExpressions:
- {key: tier, operator: In, values: [cache]}
- {key: environment, operator: NotIn, values: [dev]}
标签的作用其二是为API查询时作为条件使用,例如:
?labelSelector=environment%3Dproduction,tier%3Dfrontend
?labelSelector=environment+in+%28production%2Cqa%29%2Ctier+in+%28frontend%29
kubectl get pods -l environment=production,tier=frontend
kubectl get pods -l 'environment in (production),tier in (frontend)'
对象标签只是对象的标记,并不会对k8s管理对象过程产生影响,下面要讲解的注解则会改变k8s管理对象过程时产生一些影响。
官方推荐为每个对象都标记下面这些标签:
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app.kubernetes.io/name: mysql #应用程序的名称
app.kubernetes.io/instance: wordpress-abcxzy #用于唯一确定应用实例的名称
app.kubernetes.io/version: "5.7.21" #应用程序的当前版本
app.kubernetes.io/component: database #架构中的组件
app.kubernetes.io/part-of: wordpress #此级别的更高级别应用程序的名称
app.kubernetes.io/managed-by: helm #用于管理应用程序的工具
k8s对象注解
对象标签只是对象的标记,并不会对k8s管理对象过程产生影响,而注解则会改变k8s管理对象过程时产生一些影响。下面是一个通过注解设置拉取镜像仓库地址的例子:
apiVersion: v1
kind: Pod
metadata:
name: annotations-demo
annotations:
imageregistry: "https://hub.docker.com/"
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
k8s字段选择器
下面是在命令行使用字段选择器的例子:
kubectl get pods --field-selector status.phase=Running
kubectl get services --all-namespaces --field-selector metadata.namespace!=default
k8s命名空间
k8s集群可以通过命名空间来划分多个虚拟集群,通过命名空间可以为不同的团队或项目实现隔离的效果,k8s初始化集群会创建3个默认的命名空间:
default:没有指明使用其它命名空间的对象所使用的默认命名空间。
kube-system:Kubernetes 系统创建对象所使用的命名空间
kube-public:这个命名空间是自动创建的,所有用户(包括未经过身份验证的用户)都可以读取它。
可以通过下面命令查看命名空间情况:
kubectl get namespace
创建对象时可以通过--namespace选项参数设置命名空间。
---------------------- 正文结束 ------------------------
长按扫码关注微信公众号
Java软件编程之家
更多推荐
所有评论(0)