Kubernetes基础
一、Kubernetes基础1. 什么是Kubernetes(k8s)?2. 为什么要用k8s?2.1 k8s的好处3. k8s的架构1. Master2. Node4. Kubernetes对象5. 一些核心概念5.1 Pod5.2 Replica Set5.3 Service5.4 Deployment5.5 Label5.6 Replication Controller (RC)5.7 Vo
一、 Kubernetes基础
1. 什么是Kubernetes(k8s)?
-
k8s是Google的一个开源容器编排引擎,用于自动部署、扩展和管理容器化应用程序。Kubernetes集群可以跨本地和公共云基础设施跨越主机,使Kubernetes成为托管云本地应用程序的理想平台。
-
Kubernetes 的一般概念相当简单:
-
从一个或多个工作节点开始运行容器工作负载。
-
从一个或多个控制平面节点管理这些工作负载的部署。
-
将容器包装在称为 Pod 的部署单元中。使用 Pod 为容器提供额外的元数据,并提供将多个容器分组到单个部署实体中的能力。
-
创建特殊类型的资产。例如,服务由一组 Pod 和定义如何访问它们的策略表示。此策略允许容器连接到它们需要的服务,即使它们没有服务的特定 IP 地址。复制控制器是另一种特殊资产,它指示一次运行需要多少个 Pod 副本。您可以使用此功能自动扩展您的应用程序以适应其当前需求。
-
https://kubernetes.io/ #k8s官网
https://github.com/kubernetes/kubernetes/ #大量 example案例
https://www.kubernetes.org.cn/ #kubernetes中文社区
http://docs.kubernetes.org.cn/ #大量中文文档
2. 为什么要用k8s?
IT是一个由新技术驱动的行业,Docker这个容器技术当前已经被很多公司所采用,其从单机走向集群已成为必然,k8s作为当前唯一被业界广泛看好的Docker分布式系统解决方案,未来会有大量的新系统选择它。
2.1 k8s的好处
-
跨多个主机编排容器
-
更好地利用硬件来最大化运行您的企业应用程序所需要的资源
-
控制和自动化应用程序部署和更新
-
挂载并添加存储空间以运行具有有状态的应用程序
-
声明式地管理服务,以保证已部署的服务应用程序总是以您预期的运行方式运行。
-
使用autoplacement进行健康检查和自我修复应用程序,自动重新启动、自动重新应用和自动缩放
-
客户在其环境中使用Kubernetes的优势在于能够在物理系统或虚拟机(VM)的集群上调度和运行容器。并且客户的系统可以随时随地整体“搬迁”到公有云上。
-
超强的横向扩容能力。不用修改代码,一个k8s集群即可从只包含几个node的小集群平滑扩展到拥有上百个node的大规模集群,只要微服务设计的好,结合硬件或公有云资源的线性增加,系统就能承受大量用户的并发访问所带来的巨大压力。
-
k8s可以在以下环境中运行:
- 裸金属服务器
- 虚拟机
- 公有云供应商
- 私有云
- 混合云环境
3. k8s的架构
1. Master
- Master节点上面主要由四个模块组成:kube-APIServer、kube-scheduler、kube-controller-manager、etcd
- kube-APIServer负责对外提供RESTful的Kubernetes API服务,他是系统管理指令的统一入口,任何对资源进行增删改查的操作都要交给APIServer处理后再提交给etcd。如架构图所示,kubectl(k8s提供的客户端工具,该工具内部就是对Kubernetes API的调用)是直接和APIServer交互的。
- kube-scheduler负责调度Pod到合适的Node上。如果把scheduler看成一个黑匣子,那么它输入的是Pod和由多个Node组成的列表,输出的是Pod和一个Node的绑定,即将这个Pod部署到这个Node上。k8s目前提供了调度算法,但是同样也保留了接口,用户可以根据自己的需求定义自己的调度算法。
- kube-controller-manager负责管理资源的控制器(一般每个资源都对应一个控制器)。比如我们通过APIServer创建一个Pod,当这个Pod创建成功后,APIServer的任务就算完成了。而后面保证Pod的状态始终和我们预期的一样的重任就由kube-controller-manager去完成。
- 这些控制器包括:
- 节点(Node)控制器
- 副本(Replication)控制器:负责维护系统中每个副本中的Pod
- k8s集群中的服务扩容和系统升级,只需要为扩容的Service关联的Pod创建一个Replication Controller(简称RC),则该Service的扩容及升级都可以解决。在一个RC定义文件中包括以下3各关键信息
- 目标Pod的定义
- 目标Pod需要运行的副本数量(replicas)
- 要监控的目标Pod标签
- 在创建好RC(系统会自动创建好Pod)后,k8s会通过RC定义的Label筛选出对应的Pod实例并实时监控其状态和数量,如果实例数量少于定义的副本数量(ralicas),则会根据RC中定义的Pod模板来创建一个新的Pod,然后将此Pod调度到合适的node上启动运行,直到Pod实例的数量达到预定目标。
- k8s集群中的服务扩容和系统升级,只需要为扩容的Service关联的Pod创建一个Replication Controller(简称RC),则该Service的扩容及升级都可以解决。在一个RC定义文件中包括以下3各关键信息
- 端点(endpoint)控制器:填充Endpoints对象(即连接services&Pods)
- Service Account和Token控制器:为新的Namespace创建默认账户访问API Token
- 这些控制器包括:
- etcd是一个高可用的键值存储系统,k8s使用它来存储各个资源的状态,从而实现了Restful的API。
2.Node
- Node节点可以是物理机,也可以是私有云火或公有云中的一个虚拟机。每个Node主要由三个模块组成:kubelet、kube-proxy、runtime
- kubelet是Master在每个Node节点上面的agent,是Node节点上面最重要的模块,负责维护和管理该Node上面的所有容器,但是如果容器不是通过k8s创建的,它并不会管理。本质上它负责使Pod的运行状态与期望的状态一致。负责Pod对应的容器的创建、启动等任务,同时与Master节点密切合作,实现集群管理的基本功能。
- 具体功能:
- 安装Pod所需的volume
- 下载Pod的secrets
- Pod中运行的docker(或rkt)容器
- 定期执行容器健康检查
- 具体功能:
- kube-proxy模块实现了k8s中的服务发现和反向代理功能。
- 反向代理方面:kube-proxy支持TCP和UDP连接转发,默认基于Round Robin算法将客户端流量转发到与service对应的一组后端Pod。
- 服务发现发现方面,kube-proxy使用etcd的watch机制,监控集群中service和endpoint对象数据的动态变化,并且维护一个service到endpoint的映射关系,从而保证了后端Pod的IP变化不会对访问者造成影响,另外kube-proxy还支持session affinity。
- runtime指的是容器运行环境,目前k8s支持docker和rkt两种容器。
- kubelet是Master在每个Node节点上面的agent,是Node节点上面最重要的模块,负责维护和管理该Node上面的所有容器,但是如果容器不是通过k8s创建的,它并不会管理。本质上它负责使Pod的运行状态与期望的状态一致。负责Pod对应的容器的创建、启动等任务,同时与Master节点密切合作,实现集群管理的基本功能。
4.Kubernetes对象
-
Kubernetes对象是Kubernetes系统中的持久实体。Kubernetes使用这些实体来表示集群的状态。具体来说,他们可以描述:
- 容器化应用正在运行(以及在哪些节点上)
- 这些应用可用的资源
- 关于这些应用如何运行的策略,如重新策略,升级和容错
-
k8s里的所有资源对象都可以采用yaml或者JSON格式的文件来定义或描述
-
k8s对象包括:
- Pod
- Service
- …
-
要创建/删除/修改k8s对象,需要使用Kubernetes API
- 例如,当使用kubectl命令管理工具时,CLI会为提供Kubernetes API调用。
- 你也可以直接在自己的程序中使用Kubernetes API
-
对象(object)规范和状态
- 每个对象包含两个嵌套对象字段,用于管理object的配置
- object spec
- 描述对象所需的状态,希望object具有的特性
- object status
- 描述了对象的实际状态,并由k8s系统提供和更新
- object spec
- 每个对象包含两个嵌套对象字段,用于管理object的配置
5. 一些核心概念
5.1 Pod
-
Pod运行在Node中,通常一个节点上运行几百个Pod;Pod是Kubernetes创建或部署的最小/最简单的基本单位,一个Pod代表集群上正在运行的一个进程。
-
用户可以通过kubernetes的Pod API生产一个Pod,让k8s对这Pod进行调度,也就是把它放在某一个k8s管理的节点上运行起来。一个Pod简单来说是对一组容器的抽象,他里面会包含一个或多个容器。一个Pod封装一个应用容器(也可以有多个容器),存储资源、一个独立的网络IP以及管理控制容器运行方式的策略选项。Pod代表部署的一个单位:Kubernetes中单个应用的实例,它可能由单个容器或多个容器共享组成的资源。
-
每个Pod里运行这一个特殊的被称之为Pause的容器,Pause容器对应的镜像属于k8s平台的一部分。其他容器称之为业务容器,这些业务容器共享Pause容器的网络栈和Volume挂载卷。下图展示Pod组成与容器的关系。
-
注意:并不是每个Pod和它里面运行的容器都能被“映射”到一个Service上,只有那些提供服务(无论对内或对外)的一组Pod才会被“映射”成一个服务。
-
在k8s里,一个Pod里的容器与另外主机上的Pod容器能够直接通信。
-
根据状态分,Pod有两种类型
-
普通的Pod
- 一旦创建就会被放入到etcd中存储,随后会被k8s Master调度到某个具体的Node上进行绑定(Binding),随后该Pod被对应的Node上的kubelet进程实例化成一组相关的Docker容器启动起来。
-
静态Pod(Static Pod)
- 存放在某个具体的Node上的一个具体文件中,并且只在此Node上启动运行。
-
-
默认情况下,当Pod里的某个容器停止时,k8s会自动检测到这个问题并且重新启动这个Pod(重启Pod里的所有容器),如果Pod所在的Node宕机,则会将这个Node上的所有Pod重新调度到其他节点上。Pod、容器与Node的关系如图
-
根据运行的容器数量分类,k8s的Pod分为两种:
- Pod中运行一个容器
- Pod中运行多个容器,这些容器之间能够共享资源,可以形成一个单一的内部service单位 - 一个容器共享文件。
-
如果需要水平扩展应用(比如运行多个实例),应该使用多个Pods,每个实例一个Pod
-
Pods如何管理多个容器
- Pods的设计可用于支持多进程的协同工作(作为容器),形成一个cohesive的Service单位。Pod中的容器在集群中Node上被自动分配,容器之间可以共享资源、网络和相互依赖关系,并同时被调度使用。
- Pods提供两种共享资源:网络和存储
- 网络:每个Pod被分配一个独立的IP地址,Pod中的每个容器共享网络命名空间,包括IP和端口。Pod内的容器可以使用localhost相互通信。当Pod中的容器与Pod 外部通信时,他们必须协调如何使用共享网络资源(如端口)
- 存储:Pod可以指定一组共享存储volumes。Pod中的所有容器都可以访问共享volumes,允许这些容器共享数据。volumes 还用于Pod中的数据持久化,以防其中一个容器需要重新启动而丢失数据。
-
使用Pod:不会单独使用Pod,Kubernetes使用更高级的称为Controller的抽象层,来管理Pod实例。
- controller可以创建和管理多个Pod,提供副本管理、滚动升级和集群级别的自愈能力。
- 例如,如果一个Node故障,Controller就能自动将该节点上的Pod调度到其他健康的Node上。
- 包含一个或多个Pod的controller实列:
- Deployment
- StatefulSet
- DaemonSet
- 通常,controller会用你提供的Pod template来创建相应的Pod
- controller可以创建和管理多个Pod,提供副本管理、滚动升级和集群级别的自愈能力。
-
Pod模板
- Deployment
- Replication Controller
- Replicaset
- Daemonset
- Statefulset
5.2 Replica Set
-
Replica Set目的是为了定义一个期望的场景,比如定义某种Pod的副本数量在任意时刻都处于 Replica Set期望的值,假设 Replica Set定义Pod的副本数目为: replicas=2,当该 Replica Set提交给 Master后, Master会定期巡检该Pod在集群中的数目,如果发现该Pod挂掉了ー个, Master就会芸试依据 Replica Set设置的Pod模版创建Pod,以维持Pod的数量与 Replica Set预期的Pod数量相同。
-
很少单独使用Replica Set,它主要被Deployment这个更高层的资源对象所使用,从而形成一套Pod创建、删除、更新的编排机制。
-
通过 Replica Set,k8s集群实现了用户应用的高可用性,而且大大减少了运维工作量。因此生产环境一般用Deployment?或者 Replica Set去控制Pod的生命周期和期望信,而不是直接单独创建Pod。
-
Replica Set与 Deployment这两个重要资源对象逐步替换了之前的RC的作用
5.3 Service
-
Service是分布式集群架构的核心,k8s的 Service就是我们平时所提及的微服务架构中的"微服务”,本文上面提及的Pod、 Replica Set等都是为 Service服务的资源,如下图表示Service、Pod、 Replica Set的关系:
-
一个Service对象拥有如下关键特征:
- 一个唯一指定的名字(比如mysql-server)
- 一个虚拟IP(cluster IP、service IP或VIP)和端口号
- 在Service的整个生命周期内,它的Cluster IP不会发生改变
- 能够提供某种远程服务能力
- 被映射到了这种服务能力的一组容器应用上。
-
Service的服务进程目前都基于socket通信方式对外提供服务,比如Redis、Memcache、MySQL、Web Server,或者是实现了某个具体业务的一个特定的TCP Server进程。
-
Service定义了一个服务的访问入口地址,前端的应用通过这个入口地址访问其背后的一组由Pod副本组成的集群实例,Service与后端Pod副本集群之间则是通过Label Selector来实现1对接的,而RC的作用实际上是保证Service的服务能力和服务质量始终处于预期的标准。
-
一个Service通常由多个相关的服务进程来提供服务,每个服务进程都有独立的Endpoint(IP+Port)访问点,但k8s能够让我们通过Service(虚拟Cluster IP+Service Port)连接到指定的Service上。
-
Service与Pod的关联关系:
- Pod中运行的容器就是为Service提供服务的进程,首先给Pod贴上一个标签(Label),给运行MySQL的Pod贴上name=mysql标签,给运行PHP的Pod贴上name=php标签,然后给对应的Service定义标签选择器(Label Selector),比如MySQL的Service的标签选择器的选择条件为name=mysql,意味该Service要作用于所有包含name=mysql标签的Pod上。
-
用户是如何访问一个集群的服务的呢?
- 一般的做法是部署一个负载均衡器(软件或硬件),为这组Pod开启一个对外的服务端口如8000端口,将这些Pod的Endponit列表加入8000端口的转发列表中,客户端就可以通过负载均衡器的对外IP地址+服务端口来访问此服务,而客户端最后会被转发到哪个Pod,则由负载均衡器的算法决定。
-
很多服务都存在多端口的问题,通常一个端口提供业务服务,另外一个端口提供管理服务,比如Mycat、Codis等常见中间件。Service支持多个Endpoint,在存在多个Endpoint的情况下,要求每个Endpoint定义一个名字来区分,例如
-
为什么要给每个端口命名呢?
- 涉及k8s的服务发现机制(1.4.5小节)
5.4 Deployment
-
Deployment,为Pod和 Replica Set提供声明式更新,Dployment在内部使用了Replica Set来实现目的。
-
你只需要在 Deployments中描述你想要的目标状态是什么, Deployment controller就会帮你将Pod和 Replica Set的实际状态改变到你的目标状态。你可以定义一个全新的 Deployment,也可以创建一个新的替换旧的Deployment.
-
典型使用场景
-
使用 Deployment来创建 Replicaset. Replicaset,在后台创建Pod。检查启动状态,看它是成功还是失败。
-
然后,通过更新 Deployment的 Podtemplatespec字段来声明Pod的新状态。这会创建一个新的Replicaset, Deployment会按照控制的速率将Pod从日的 Replicaset移动到新的Replicasete中,如果当前状态不稳定,回滚到之前的 Deployment revision。每次回滚都会更新 Deployment的 Revision.
-
扩容 Deployment以满足更高的负载
-
暂停 Deployments来应用 Pod Templatespecl的多个修复,然后恢复上线。
-
根据 Deployment的状态判断上线是否hang住了。
-
清除旧的不必要的ReplicaSet
-
5.5 Label
-
一个Label是一个key=value地键值对,其中key与value由用户自己指定资源对象与Label的关系是:n:n,Label通常在资源对象定义时确定,也可以在对象创建后动态添加或删除。
-
给某个资源对象定义一个Label,随后通过Label Selector(标签选择器)查询和筛选某些Label的资源对象。
-
Label Selector类似于SQL的where查询条件
-
基于等式的表达式(Equality-based)
name=redis-slave:匹配所有具有标签name=redis-slave的资源对象。 env!=production:匹配所有不具有标签env=production的资源对象,比如env=test就是满足此条件的标签之一。
-
基于集合的表达式(Set-based)
name in( redis-master,redis-slave):匹配所有具有标签name=redis-master或者name=redis-slave的资源对象。 name not in(php-frontend):匹配所有不具有标签name=php-frontend的资源对象。
-
-
Label Selector的重要使用场景:
- kube- controller进程通过资源对象RC上定义的 Label Selector来筛选要监控的Pod副本的数量,从而实现Pod副本的数量始终符合预期设定的全自动控制流程。
- kube-proxy进程通过 Service的 Label Selector来选择对应的Pod,自动建立起每个 Service到对应Pod的请求转发路由表,从而实现 Service的智能负载均衡机制。
- 通过对某些Node定义特定的 Label,并且在Pod定义文件中使用 NodeSelector这种标签调度策略,kube- scheduler进程可以实现Pod“定向调度”的特性。
-
-
总结:使用 Label可以给对象创建多组标签, Label和 Label Selector共同构成了 Kubernetes系统中最核心的应用模型,使得被管理对象能够被精细地分组管理,同时实现了整个集群的高用性。
5.6 Replication Controller (RC)
-
RC是定义了一个期望的场景,即声明某种Pod的副本数量在任意时刻都符合某个预期值,所以RC的定义包括如下几个部分:
- Pod期待的副本数(replicas)
- 用于筛选目标Pod的Label Selector
- 当Pod的副本数量小于预期数量的时候,用于创建新Pod的Pod模板(template)
-
删除RC并不会影响通过该RC已创建好的Pod。为了删除所有Pod,可以设置replicas的值为0,然后更新该RC。
- stop和delete命令一次性删除RC和RC控制的全部Pod
-
通过RC,K8S可以实现系统的平滑升级,称为“滚动升级”
5.7 Volume(存储卷)
- Volume是Pod中能够被多个容器访问的共享目录。
- Volume与Pod的生命周期相同,与容器的生命周期不相关。
- k8s支持多种类型的Volume,例如GLUSTERfs、Ceph等分布式文件系统。
- Volume的使用:
- 先在Pod上声明一个Volume,然后在该容器里引用该Volume并Mount到容器的某个目录上。
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 1
selector:
matchLabels:
tier: frontend
matchExpressions:
- {key: tier, operator: In, values: [frontend]}
template:
metadata:
labels:
app: app-demo
tier: frontend
spec:
volume: ###
- name: datavol ###
emptyDir: {} ###
containers:
- name: tomcat-demo
image: tomcat
volumeMounts: ###
- mountPath: /mydata-data ###
name: datavol ###
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
k8s提供了很多的Volume类型
1. emptyDir
- 在Pod分配到Node时创建的,它的初始化内容为空,并且无须指定宿主机上对应的目录文件,因为这是Kubernetes自动分配的一个目录,当Pod从Node上移除时,emptyDir中的数据也会被永久删除。emptyDir的一些用途如下:
- 临时空间,例如用于某些应用程序运行时所需要的临时目录,且无须永久保留。
- 长时间任务的中间过程CheckPoint的临时保存目录。
- 一个容器需要从另一个容器中获取数据的目录。
2. hostPath
- 为Pod上挂载宿主机上的文件或目录,它通常可以用于以下几个方面。
- 容器应用程序生成的日志文件需要永久保存时,可以使用宿主机的高速文件系统进行存储
- 需要访问宿主机上Docker引擎内部数据结构的容器应用时,可以通过定义hostPath为宿主机/var/lib/docker目录,使用容器内部应用可以直接访问Docker的文件系统。
- 使用时需要注意:
- 不同Node上具有相同配置的Pod可能会因为宿主机上的目录和文件不同而导致对Volume上目录和文件的访问结果不一致。
3. gcePersistentDisk
- 使用谷歌公有云提供的永久磁盘存放Volume的数据
- 需要创建一个永久磁盘(PD),才能使用gcePersistentDisk。
- 使用 gcePersistent Disk有以下一些限制条件。
- Node(运行 kubelet I的节点)需要是GCE虚拟机。
- 这些虚拟机需要与PD存在于相同的GCE项目和Zone中。
4. awsElasticBlockStore
- 亚马逊公有云提供的EBS Volume存储数据,需要创建一个EBS Volume才能使用awsElasticBlockStore。
- 使用 awsElasticBlockStore的一些限制条件如下。
- Node(运行 kubelet I的节点)需要是 AWS E2实例。
- 这些 AWS EC2实例需要与 EBS volume存在于相同的 region和 availability-zone中。
- EBS只支持单个EC2实例 mountー个 volume.
5. NFS
- 网络文件系统提供的共享目录存储数据,需要在系统中部署一个NFS Server。
6.其他类型
- iscsi
- flocker
- glusterfs
- rbd
- gitRepo
- secret
5.8 Persistent Volume
- Persistent Volume(简称PV),可以理解成网络存储中的一块存储。
- 只能是网络存储,不属于任何Node,但可以在每个Node上访问。
- 独立于Pod之外定义。
- 类型:GCE Persistent Disks、NFS、RBD、 ISCSI、AWS Elastic Block Store、 Glusterfs等。
- PV的accessModes属性的类型
- ReadWriteNnce:读写权限、并且只能被单个Node挂载。
- ReadOnlyMany:只读权限、允许被多个Node挂载。
- ReadWriteMany:读写权限、允许被多个Node挂载。
- 如果某个Pod想申请某种条件的PV,则首先需要定义一个PersistentVolumeClaim(PVC)对象。
- PV是有状态的对象,它的状态如下
- Available:空闲状态。
- Bound:已经绑定到某个PVC上。
- Released:对应的PVC已经删除,但资源还没有被集群收回。
- Failed:PV自动回收失败。
5.9 Namespace
- 用于实现多租户的资源隔离。
- 通过将集群内部的资源对象“分配”到不同的Namespace中,形成逻辑上分组的不同项目、小组或用户组,便于不同的分组在共享使用整个集群的资源的同时还能被分别管理。
- k8s集群在启动后,会创建一个名为“default”的Namespace,通过kubectl可以查看到
[root@master ~]# kubectl get namespaces
NAME STATUS AGE
default Active 6d21h
- 如果没有特别指明Namespace,则用户创建的Pod、RC、Service都将被系统创建到default的Namespace中。
5.10 Annotation(注解)
- key/value键值对形式进行定义,定义的是k8s对象的元数据(Metadata),并且用于Label Selector。
- 用户任意定义的“附加”信息,以便于外部工具进行查找,很多时候k8s的模块自身会通过Annotation的方式标记资源对象的一些特殊信息。
- 通常来说,用Annotation来记录的信息如下
- build信息、 release信息、 Docker镜像信息等,例如时间戳、 release id号、PR号、镜像hash值、 docker registry地址等
- 日志库、监控库、分析库等资源库的地址信息。
- 程序调试工具信息,例如工具名称、版本号等。
- 团队的联系信息,例如电话号码、负责人名称、网址等。
更多推荐
所有评论(0)