K8s核心概念
本文是CNCF × Alibaba 云原生技术公开课的第三章Kubernetes 核心概念学习笔记。
关键词:k8s
k8s的架构
k8s的架构是比较典型的二层架构和server-client架构。Master作为中央的管控节点,会与Node进行一个链接。
所有用户侧的组件,只会和Master进行连接,把希望的状态或者想执行的命令发给Master,Master会把这些命令发给相应的节点。

Master
Master节点主要包含四个主要的组件:API Server、Controller、Scheduler以及etcd:

- API Server:用来处理API操作,k8s的所有组件都会和API Server进行连接,组件和组件之间一般不进行独立链接,都要依赖API Server进行消息的传送。
- Controller:控制器。用来完成对集群状态的一些管理。例如自动对容器进行修复,或者自动进行水平扩张。
- Scheduler:调度器。顾名思义就是完成调度的操作。例如把一个用户提交的Container,依赖于它对CPU、对memory请求大小,找一台合适的节点,进行放置。
- etcd:分布式存储系统。API Server中所需要的原信息存在etcd中,etcd本身是一个高可用系统,通过etcd保证整个k8s Master节点的高可用性。
Node
Node是真正运行业务负载的,每个业务负载以Pod的形式运行。一个Pod中运行一个或者多个容器,真正运行这些Pod组件的是kubelet,也就是Node上面最关键的组件,它通过API Server接收到需要Pod运行的状态,然后提交到Container Runtime组件中,在OS上创建容器所需要的环境,最终把容器或者Pod运行起来。Node需要对存储和网络进行管理。K8s不直接管理存储和网络,K8s通过Storage Plugin或者Network Plugin进行管理,完成存储和网络操作。

在K8s自己的环境里,也会有k8s的Network,他是为了提供Service Network来进行组网。真正完成组网的组件是Kube-proxy。Kube-proxy利用iptable的能力来组建k8s集群的网络。以上就是Node上面的四个组件(Container Runtime、Storage Plugin、Network Plugin、Kube-proxy)。
注意:K8s上的Node不会直接和用户进行交互,Node和用户之间的交互只会通过Master节点。用户通过Master节点下发这些信息。K8s上的每个Node,都会运行上面的这几个组件。
例子
通过一个例子看K8s架构中的这些组件是如何进行交互的。

用户通过UI或者CLI提交一个Pod到K8s进行部署,这个Pod请求会首先通过UI或者CLI提交给K8s API Server,下一步API Server会把这个信息写入到存储系统etcd,之后Scheduler会通过API Server的watch机制得到这个信息:有一个Pod需要被调度。
此时Scheduler会根据这个内存状态进行一次调度决策,在完成这次调度以后,Scheduler向API Server报告。此时API Server接收到消息以后,把这次结果写入etcd,然后API Server会通知相应的节点。相应节点的Kubelet会得到这个通知,Kubelet调用Container Runtime来启动配置这个容器和这个容器的运行环境,去调度Storage Plugin来配置存储,Network Plugin去配置网络。
核心概念
Pod
Pod是K8s的一个最小调度和属性单元,用户可以通过K8s的Pod API来生产一个Pod,让K8s对这个Pod进行调度,也就是把他放到另一个K8s管理的节点上运行起来。
一个Pod简单来说是一组容器的抽象,它包含一个或者多个容器。
Pod包含一些其他所需要的资源,比如卷。

Pod的共享上下文包括一组Linux命名空间,控制组和可能一些其他的隔离方面,这些都是用来隔离Docker容器的技术。在Pod的上下文中,每个独立的应用可能会进一步实施隔离。
就Docker使用的概念术语来说,Pod类似于共享名字空间和文件系统卷的一组Docker容器。
Pod给这些容器提供了一个共享的运行环境,他们会共享同一个网络环境,这些容器可以用localhost来进行直接的连接。
使用Pod
1 | apiVersion: v1 |
要创建上面的Pod,请运行以下命令
1 | kubectl apply -f simple-pod.yaml |
注意:Pod一般不是直接创建的,而是使用工作负载资源创建的,
Volume
Volume用来管理K8s存储,Volume声明容器中的容器可以访问文件的目录。
一个卷可以被挂载Pod中一个或者多个容器指定的路径下面。
Volume本身是一个抽象的概念,一个Volume可以支持多种后端存储。K8s的Volume就支持了很多存储插件,可以支持本地的存储,也可以支持分布式存储。它也可以支持云存储,例如阿里云上的云盘、AWS上的云盘、Google上的云盘等。

Docker 也有 卷(Volume) 的概念,但对它只有少量且松散的管理。 Docker 卷是磁盘上或者另外一个容器内的一个目录。 Docker 提供卷驱动程序,但是其功能非常有限。
Kubernetes 支持很多类型的卷。 Pod 可以同时使用任意数目的卷类型。 临时卷类型的生命周期与 Pod 相同,但持久卷可以比 Pod 的存活期长。 当 Pod 不再存在时,Kubernetes 也会销毁临时卷;不过 Kubernetes 不会销毁持久卷。 对于给定 Pod 中任何类型的卷,在容器重启期间数据都不会丢失。
挂载本地卷
1 | apiVersion: v1 |
挂载网络卷NFS
待补充
Deployment
Deployment为Pod和ReplicaSet(副本)提供声明式的更新能力。
Deployment是在Pod上层的抽象,用Deployment这个抽象来做应用的真正管理,而Pod是组成Deployment的最小单元。
K8s通过Controller也就是控制器去维护Deployment中Pod的数目,帮助Deployment自动恢复失败的Pod。

例如可以定义一个Deployment,这个Deployment需要两个Pod,当一个Pod失败后,控制器会检测到,他会重新把Deployment中的Pod数据从一个恢复到两个,然后再去重新生成一个Pod。
通过控制器,还可以完成发布的策略,例如进行滚动升级,或者版本回滚等。
创建Deployment
下面是一个 Deployment 示例。其中创建了一个 ReplicaSet,负责启动三个
nginx Pods:
1 | apiVersion: apps/v1 |
在该例中:
- 创建名为
nginx-deployment的Deployment - 该Deployment创建
3个(由replicas字段标明)Pod副本 selector字段定义了Deployment如何查找要管理的Pods。在这里选择Pod模板中定义的标签(app:nginx)。
spec.selector.matchLabels字段是key-Value键值对映射,在matchLabels映射的每个Key-Value映射等效于matchExpressions中的一个元素,即key字段是key,操作符是In,values数组仅包含value。在matchLabels和matchExpressions中给出的所有条件都满足才能匹配。
- template包含以下子字段:
- Pod被使用
.metadata.labels字段打上app:nginx标签 - Pod模板规约即
.template.spec字段指示Pods运行一个nginx容器,该容器运行nginx:1.14.2的Docker Hub 镜像 - 创建一个容器并使用
.spec.template.spec.containers[0].name字段并将其命名为nginx
- Pod被使用
Service
Service提供了一个或者多个Pod实例的稳定访问地址。
从上文中可以看到,一个Deployment可以有两个甚至更多个完全相同的Pod,对于一个外部的用户来说,访问哪一个Pod其实都属于一样的,所以他希望做一次负载均衡,在做负载均衡的同时,只想访问某一个固定的VIP,VirtualIP地址,而不希望得到一个具体的Pod的IP地址。
由于Pod本身可能会终止,如果一个Pod失败了,可能会换成另外一个新的。
对于外部用户来说,提供了多个具体的Pod地址,这个用户需要不停的去更新Pod地址。K8s的Service把所有Pod的访问能力抽象成一个第三方的IP地址。
实现Service有多种方式,K8s支持Cluster IP,上面讲过的kuber-proxy组网,也支持nodePort,LoadBalancer等其他的一些访问能力。

使用Service
例如,假定有一组Pod,他们对外暴露了9376端口,同时还被打上了app=Myapp标签
1 | apiVersion: v1 |
上述配置创建了一个名为my-service的对象,它会将请求代理到TCP端口9376,并且具有标签app=MyApp的Pod上。