【本文内容】文章主要分三章:
第一章简单的介绍了Kubernetes的特点。
第二章介绍了Kubernetes的核心组件,包括:
-
Abstraction of containers
:Pod:部署的最小单位,Container的抽象。 -
Communication
:Service,便于更好的通信。 -
Route traffic into cluster
:Ingress,基于名称的虚拟托管。 -
External Configuration
:ConfigMap,Secret,管理配置。 -
Data persistance
:Volumes,存储数据。 -
Pod blueprint
:Deployment,StatefulSet,用来定义Pod和ReplicaSet。
第三章介绍了Kubernetes的架构,包括:
- Worker Node上的3个组件:
container runtime
,kubelet
,kebe-proxy
。 - Master Node上的4个组件:
Api Server
,Scheduler
,Controller manager
,etcd
。
1. Kubernetes的特点:
-
高可用(high availibility)
,意味着需要对外提供可持续访问的服务(比如我们24小时都可以访问淘宝网首页一样)。 -
高性能(high performance)
,当用户访问服务的时候,响应速度很快。 -
灾难恢复(disaster recover)
:提供有效的备份和恢复功能。
2. Kubernetes Components(重要的组件介绍)
比如我们想在部署以下服务:
- Java project: my-app
- DB: mongo-db
2.1 Pod
官网:https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/
-
Smallest unit of k8s
:k8s上最小的可部署的单位。 -
Abstraction over container
:pod是容器(Container)的抽象,个人理解是在k8s上,我们对底层容器是透明的(不管实现是docker还是其它的容器技术),我们只会和pod打交道。 -
Usually 1 application per Pod
:虽然pod可以运行多个container,但在实现应用中,通常一个pod只会运行一个container。 -
Each Pod gets its own IP address
:每个Pod都会拥有自己的ip地址(内部地址,Pod相互之前可通过这个内部IP进行访问),所以上述的my-app这个项目可以通过内部IP访问到另一个Pod,即db。 -
New IP address on recreation
:在kubernetes中,Pod 被设计成了相对临时性的、用后即抛的一次性实体,比如运行db的Pod挂了,新的db Pod启动来代替之前不能work的Pod的工作,那么这时候启动的Pod不再是原来的IP了。这也导致一个棘手的问题,就是我们的my-app项目,不能像传统项目那样直接配置IP地址的db连接。
2.2 Service and Ingress
Service:
官网:https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/
针对上述Pod的地址不是固定的问题,Service组件可以帮助解决这个问题:
-
Permanent IP address
:Service的IP是固定的。比如my-app有自己的service,db Pod也有自己的service,于是在my-app中可以通过固定的IP访问db Pod了。 -
Lifecycle of Pod and Service NOT connected
:Pod的生命周期和Service的生命周期互不干扰,这意味着就算Pod挂了,Service还是在的,IP也不会变。
我们想要把my-app服务暴露给外部以便可以通过浏览器被访问到,例如:http://my-app-service-ip:port,这种Service叫External Service
,表示可以被外部访问到。
另一种像db的Service,我们并不希望暴露给外部,只要my-app服务能找到即可,这种Service叫Internal Service
。
Service解决了Pod的网络问题,但它本身还是有缺陷的,比如我们的my-app项目,最终的地址是:http://123.1.1.1:8080
,这样的访问方式可能适合测试,但对于最终的网站,我们希望用的是https://my-app.com
,这时候就需要用另外一个组件了,叫Ingress
。
Ingress
官网:https://kubernetes.io/zh-cn/docs/concepts/services-networking/ingress/
外部的请求会先发送给Ingress,然后通过Ingress再转发给相应的Service。
2.3 ConfigMap and Secret
官网:https://kubernetes.io/zh-cn/docs/concepts/configuration/configmap/
Pod间相互交流依赖于Service(原因上述讲过了,在Kubernetes中,Pod被设计成相对临时的实体,一个Pod down后,因为高可用的前提下,Kubernetes会保证再新起一个Pod,那么IP就会变了,Serivce中的IP是固定的)。
正因为此,我们上述的例子Java项目my-app如果想要用mongo-db,那么它会在自己的配置文件中配置db connection url:mongo-db-service。
这个配置可能会在my-app项目中的application.properies中,或是某种外部环境变量之类的。但通常情况下,Database URL的改动,可能会引起项目的镜像重新生成,再上传到repository,在Kubernetes中再pull到Pod中。一个DB的URL的小小改动,需要重新做CI/CD,好像有点太过复杂,基于此,Kubernetes引入了新的组件,叫ConfigMap
。
-
External configuration of your application
:ConfigMap 将你的环境配置信息和容器镜像解耦,便于应用配置的修改。比如我们可以把Database URL放到ConfigMap中,这样如果URL要从mongo-db-service改到abc-mongo,就可以不用重新布署项目了。 -
Don't put credentials into ConfigMap
:ConfigMap并不提供加密功能,想要有加密功能,要用另外一个组件,叫Secret
。
Secret
官网:https://kubernetes.io/zh-cn/docs/concepts/configuration/secret/
-
Used to store secret data
:Secret 类似于ConfigMap,但专门用于保存机密数据。 -
based64 encoded
:data 字段中所有键值都必须是base64编码的字符串。 -
The build-in security mechanism is not enabled by default!
:
怎么使用ConfigMap和Secret,可以在项目中当作环境变量来使用,或者在properties文件中引用。
2.4 Volumes
官网:https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/
Kubernetes是如何存储数据(data storage)的呢?
基于上述的例子,我们有一个mongo-db的Pod,假设我们的项目my-app,有一个add的功能,只要submit了,就会往mongo-db里存放数据。如果这时候db Pod重启了,那么之前存放的表单数据就没了(Container 中的文件在磁盘上是临时存放的)。这显然是不能接受的。我们希望存放在mongo-db中的数据是可靠的,并不会随意丢失的。Kubernetes通过组件Volumes
来解决数据存储的问题。
卷的核心是一个目录,其中可能存有数据,Pod 中的容器可以访问该目录中的数据。 目录可以是:
-
Storage on local machine
:和Pod一起在同一个机器上。 -
Remote
:远程,即不在Kubernetes集群中(如另一个云存储或是个人私有的存储)。
以上这些Storage,并不是Kubernetes自己管理的存储,因为k8s doesn't manage data persistance!
,可以把上述这些Storage想象成:Kubernetes集群中的外部硬件设备插件。(External hard drive plugin into the Kubernetes cluster)。这意味着用户需要自己保证数据的备份以及管理,以及存放在正确的地方。
到目前为止,上述的Kubernetes组件,可以很好让我的项目my-app运行起来,也能够读取并安全的存储数据到mondo db,并且用户可以在外部通过https://my-app.com来访问项目。
2.5 Deployment And StatefulSet
上述的架构有个问题,如果my-app项目down了呢?一般来说可以人为重启Pod即可,但这样会造成一个问题,那就是在down掉的这段时间里,my-app网页会显示404,对客户来说很不友好。
如何解决呢?Kubernetes中的设计是Replicate everything
,即一切都是可复制的,所以我们会再部署一个Node(之前的是Node1的话,那么这个Node2),然后在Node2上布署和Node1一模一样的Pod,Node2上的Pod和Node2连接的是同一个Service1。
Service的主要特点就是:IP固定,并且有Load Balance的功能。所以当Node1中的my-app Pod挂了后,外部请求就会通过Service1转发到Node2上的my-app Pod,即实现了网站的高可用。
**这里引入了另一个概念,即我们经常定义并启动Pod,应该要为Pod提供一个设计蓝图(define blueprint of Pods
),即定义Pod并声明有几份ReplicaSet,由此引出Kubernetes里另一个重要的组件,叫Deployment
。
Deployment
官网:https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/deployment/
-
Blueprint for my-app Pod
:Deployment组件可以理解为我们的项目My-app的设计蓝图。 -
You create Deployments
:在实践过程中,我们很少直接创建Pod,通常都是创建Deployment,通过它来创建Pod,好处是Deployment可以声明ReplicaSet
(副本数),比如定义了ReplicaSet=1,那么就算当前的my-app Pod挂了,Deployment也会立马重新创建并启动新的Pod。除此之前,也可以动态的增加或减少副本数。 -
Abstraction of Pods
:Deployment为Pod提供声明式的更新能力。
至此,我们解决了my-app Pod挂了后,网站处于404的问题(即创建Deployment,定义Pod和ReplicaSet,Pod down后,Kubernetes会跟据副本数立马启动新的Pod)。
但是,既然my-app Pod可能会down,毫无疑问,mongo-db Pod也可能会down。但是我们不能像my-app一样,用Deployment来定义Pod,原因是因为它有数据,比如使用同一份Storage,那么同时读写可能会造成数据的不一致。针对Stateful(有状态的)Pod,我们需要使用另一个组件来定义,叫StatefulSet
。
Stateful Set
官网:https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/statefulset/
-
For STATEFUL apps
:像elastic, mongoDB, MySQL都属于Stateful。 -
Deployment for stateLESS Apps, StatefulSet for stateFUL Apps or Databases
:使用Deployment来定义无状态的App,StatefulSet定义有状态的App或是DB。 -
Deploying StatefulSet not easy
:定义StatefulSet并没有像Deployment那样方便,所以我们也可以把这些Stateful的服务放到Kubernetes集群外。
3. Kubernetes架构
3.1 Worker Node
Node
,即节点,可以是一个虚拟机或者物理机器,取决于所在的集群配置。 每个节点包含运行Pod所需的服务。
-
Each Node has multiple Pods on it
:每个Node可以运行多个Pod,比如上述的例子,Node1上运行了两个Pod:my-app和mondo-db。 -
3 processes must be installed on every Node
:节点上必须要安装的3个组件。 -
Worker Nodes do the actual work
:所以有时候会把节点叫做Worker节点。
节点的组件:
-
container runtime
:用来提供容器运行时的环境,只有安装了这件组件,Pod才可以运行在节点上。 -
kubelet
:interacts with both - the container and node
,Kubelet starts the pod with a container inside
,kubelet用来帮助Pod中的容器和节点交互的,用它来创建Pod中的容器。 -
kube-proxy
:Kube Proxy forwards the requests
,节点上的网络代理。另外kube-proxy也提供了类似的功能:比如Node1和Node2都有my-app和mongo-db,一个请求进入了Node1的my-app,通过Service的转发,kube-proxy会优先转回到Node1的mondo-db(即同一台节点上的),而不是Node2。
介绍完单个节点的组件,那么接下来的问题就是作为管理员如何和这个节点进行交互呢?比如:schedule pod? monitor? re-schedule/re-start pod? join a new Node?
答案是:以上这些都为由Master Node
进行管理。
3.2 Master Node
4 processes run on every master node!
:不同于Worker Node需要安装3个组件,Master Node需要安装4个组件。
-
1.
Api Server
:如果你作为管理员,想要部署一个新的app到Kubernetes集群中,打交道的就是Api Server(比如通过Kubernetes Dashboard,或是命令行工具如kubelet,或是Kubernetes API)。Api Server就像是cluster gateway
, 是操作节点的请求最先到达的地方。另外,Api Server acts as a gatekeeper for authentication!
,也就是它还提供安全校验的功能,只有拥有合法权限的请求才能通过。- 整个过程:
Some request
-->Api Server
-->validates request
-->forward to other processes(组件)
-->schedule pod or create service
。 - 或者想要知道Worker Node的健康状态,也需要通过Api Server来查询。
-
Only 1 entrypoint into the cluster
,即Kubernetes的集群只有Api Service这一个方式对外,安全得到了保证。
- 整个过程:
2.
Scheduler
:比如需要创建一个Pod,那么请求首先发送到上述的Api Server,然后再转发到Scheduler组件上,再通过这个组件在具体的某台Node上创建Pod。这个过程中,Scheduler需要做决定:这个Pod要在哪个节点上创建(会权衡每台Worker Node的资源情况)。比如Node1的资源(如CPU使用情况)已经使用了30%,Node2的资源已经使用了60%,那么新的Pod就可以被Scheduler组件分到了Node1上。
这里需要注意的是,Scheduler只会做决定——Pod将在哪个Worker节点上被创建,具体的创建工作,还是要交给Worker Node上的组件:kubelet
。3.
Controller manager
:当某个Pod挂了,Master需要知道这个消息以便及时的对这个Pod进行re-schedule,这时候就要用到Controller manager
组件了。即:detects cluster state change
。
整个过程:Controller manager捕获到了Pod down了
-->通知Scheduler组件
-->Scheduler决定在哪台Worker Node上重新创建Pod
-->目标Worker Node上的kubelet组件执行创建Pod的请求
。4.
etcd
:key-value的存储结构,用来存储集群的基本信息。etcd is the cluster brain!
——可以想象成etcd是Kubernetes集群的大脑。集群里的每一次改动(比如上述的例子,Pod挂了,新的Pod被Scheduled),都会以key-value的形式存到etcd中。
正因为有了这些信息,Scheduler组件才能决定需要把新的Pod放在哪台Worker Node上,Controller manager组件才会知道某个Worker Node的Pod挂了。或者Api Server想要返回Worker Node的健康状况时,也需要用到etcd。
在实际的Kubernetes集群中,可能会不止一台Master节点,比如会有Master1,Master2,当然组件Api Server会是Load Balance,etcd存储会是分布式的。
3.3 例子
假设我们设计的集群中,有:
- 2个Master Nodes
- 3个Worker Nodes
因为Master Node上没有Pod运行在上面,所以一般来说,它所需要的资源,可以比Worker Node少——less resources
。这里的资源包括CPU、内存以及存储空间。
想要加入更多的Master Node或是Worker Node,也比较容易,比如想要创建新的Master Node:
- 我们只需要准备一台Server
- 再安装好上述的4个Master所需的组件(Api Service,Scheduler,Controller manager,etcd)。
- 最后把它加到Kubernetes集群中。
Worker Node同理,需要安装的是上述的3个组件:container runtime,kubelet,kube-proxy。
参考:https://kubernetes.io/zh-cn/docs/home/
参考:https://www.youtube.com/watch?v=X48VuDVv0do