kubernetes 是什么?
- kubernetes又称k8s,他是一个基于容器技术的分布式架构方案。他是谷歌
Borg
的一个开源版本,基于容器技术用于大规模集群管理。
它能做那些事?
- 资源管理自动化
- 跨多个数据中心的资源利用率的最大化
- 降低开发成本(负载均衡器、服务治理、服务监控、故障处理模块等都不用开发了)
- 降低运维难度和运维成本(基于配置文件的UI运维)
- 开放的开发平台,可使用任意语言通过TCP协议进行交互
- 分布式系统支撑平台,具有完备的集群管理能力,包括多层次的安全防火和准入机制、多租户应用支撑能力、透明的服务注册和服务发现机制、内建智能负载均衡器、强大的故障发现和自我修复能力、服务滚动升级和在线扩容能力、可扩展的资源调度机制、多粒度的资源配额管理功能
为什么要使用它?
- 降低复杂系统的开发难度
- 全面拥抱微服务架构
- 具备搬迁至公有云的能力
- 超强的横向扩容能力
kubernetes的基本概念和术语
kubernetes集群管理角色有两种:Master和Node,包含“资源对象”如Node Pod Replication Controller Services
等
管理角色
Master 集群控制节点,每个集群中都需要有一个Master节点负责整个集群的管理和控制(高可用部署建议部署3台),Master节点上有以下进程:
- kube-apiserver:提供了http rest接口的关键服务进程,是集群控制的入口进程
- kube-controller-manager:所有资源对象的自动化控制中心
- kube-scheduler:Pod调度的进程
- etcd:用于存储资源对象的数据
Node 除了Master之外的机器为Node节点,主要是集群工作中的负载节点,当一个node宕机时,其上的工作会被master转移到其他节点上去,Node之上运行着以下进程:
- kubelet:负责Pod对应容器的创建、启停等任务,同时与master节点密切协作,实现集群管理的基本功能
- kube-proxy:实现kubernetes services 的通信与负载均衡机制的重要组件
- Docker Engine
资源对象
kubernetes里的资源对象都可以使用yaml
或者json
文件进行描述定义
Pod
Pod:由一个根容器(Pause)和一组用户容器组成。Pause容器的状态代表了整个容器组的状态,多个业务容器共享Pause容器的IP,共享Pause容器挂接的Volume。 K8s为每个Pod都分配了唯一的IP地址,称为
Pod IP
,所以在集群中一个Pod里的容器与另外主机的Pod容器能够直接通信;Pod有两种类型:普通的Pod以及静态的Pod,后者不存在于Etcd里,而是在具体Node上的一个具体文件中举例
$ cat > k8s-tomcat-pod.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
name: k8s-tomcat
labels:
name: demo
spec:
containers:
- name: k8s-tomcat
image: alleyz.com:5000/k8s-tomcat-demo:1211
ports:
- containerPort: 8080
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
EOF
$ kubectl apply -f k8s-tomcat-pod.yaml
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
k8s-tomcat 1/1 Running 0 20s
Label
Label:一个label就是一个
key=value
的键值对,key和value均可自己指定。Label可以附加到各种资源对象上,一个资源对象可以定义任意数量的Label。通途
通过给指定的资源对象捆绑一个或者多个不同的Label来实现多维度的资源分组管理功能,以便于灵活、方便地进行资源分配、调度、配置、部署等管理工作,例如:部署不同的版本到不同的环境中Label Selector:当给资源对象打上标签以后,就可以通过label selector查询和筛选这些资源对象。一般有两种label selector表达式,如
基于等式:
- name=demo 匹配所有具有标签name=demo的资源对象
- name!=demo 匹配所有不具有name=demo的对象
- 基于集合:
- name in (dev, test) 匹配所有具有name=dev或者name=test的资源对象
- name not in (dev, test) 匹配所有不具备name=dev或者name=test的资源对象
Label Selector的使用场景:
- kube-controller进程通过资源对象RC上定义的Label Selector来筛选要监控的Pod副本数量,从而实现Pod副本数量始终符合预期设定的全自动控制流程
- kube-proxy 进程通过service的label selector来选择对应的pod,自动建立起每个service到pod的请求转发路由表,从而实现service的智能均衡负载机制
- 通过对某些Node定义特定的label,并且在pod定义文件中使用NodeSelector进行定向调度
Replication Controller
简称RC,用于声明某个Pod的副本数量在任意时刻的预期值,它主要包括下边几个部分:
- pod期待的副本数
- 用于筛选目标pod的label selector
- 当pod数量小于预期数量时,用于创建新pod的模板(template)
Replica Set: 新版本的RC,与Replication Controller的唯一区别是:ReplicaSet支持集合labelselector,而RC只支持等式的labelSelector,当然在后续的版本里,deployment已经取代了RC(后文详述)
特性:
- 通过定义RC实现Pod的创建过程以及副本数量的自动控制
- RC里包括完整的Pod定义模板
- RC通过Label Selector机制实现对Pod副本的自动控制
- 通过改变RC里的Pod副本数量,可以实现Pod的扩容或者缩容功能
- 通过改变RC里Pod模板中的镜像版本可以实现Pod的滚动升级功能
举例:
$ cat > k8s-tomcat-demo-rc.yaml <<EOF
apiVersion: v1
kind: ReplicationController
metadata:
name: k8s-tomcat-rc
spec:
replicas: 3
selector:
demo: k8s-tomcat
template:
metadata:
labels:
demo: k8s-tomcat
name: demo
spec:
containers:
- name: tomcat-demo
image: alleyz.com:5000/k8s-tomcat-demo:1211
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
EOF
$ kubectl apply -f k8s-tomcat-demo-rc.yaml
$ kubectl get rc
NAME DESIRED CURRENT READY AGE
k8s-tomcat-rc 3 3 3 12m
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
k8s-tomcat 1/1 Running 0 15m
k8s-tomcat-rc-klnvv 1/1 Running 0 12m
k8s-tomcat-rc-zb1r0 1/1 Running 0 12m
Deployment
Deployment可以认为是RC的升级版,最大的区别是我们可以随时知道POD容器的部署进度,典型的使用场景有:
- 创建一个Deployment对象来生成RC并完成Pod副本的创建过程
- 检查Deployment的状态看部署动作是否完成
- 更新deployment以创建新的Pod(升级)
- 如果当前Deployment不稳定则回滚到早先版本
- 暂停Deployment以便于一次修改多个PodTemplateSpec的配置项,之后再进行发布
- 扩展Deployment以应对高负载
- 查看Deployment的状态,以此作为发布是否成功的指标
- 清理不在需要的旧版本RC
例子
$ cat > k8s-tomcat-demo-deploy.yaml <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: k8s-tomcat-dep
spec:
replicas: 4
selector:
matchLabels:
demo: k8s-tomcat
template:
metadata:
labels:
demo: k8s-tomcat
name: demo
spec:
containers:
- name: tomcat-demo
image: alleyz.com:5000/k8s-tomcat-demo:1211
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
EOF
$ kubectl apply -f k8s-tomcat-demo-deploy.yaml
$ kubectl get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
k8s-tomcat-dep 4 4 4 4 21s
HPA(横向自动扩容)
Horizontal Pod Autoscaler 即HPA也是一种资源对象,通过追踪分析RC控制的pod的负载变化情况来确定是否需要针对性地调整目标pod的副本数(增加或者减少),当前主要有以下两种方式作为Pod负载的度量指标:
- CpuUtilizationPercentage(CPU利用率),取所有副本自身CPU利用率的平均值(需要定义Pod Request值)
- 应用程序自定义的度量指标,比如TPS或者QPS
StatefulSet
用于实现有状态的集群管理,可以将它看做Deployment/RC的一个变种,它有以下特性
- StatefulSet里的每个Pod都有稳定、唯一的网络标识,可以用来发现集群的其他成员
- StatefulSet控制的Pod副本的启停顺序是受控的,如StatefulSet名叫zk,则第一个叫做zk-0,第二个叫做zk-2,依次类推
- Stateful里的Pod采用稳定的持久化存储卷,通过PV/PVC实现
详细使用待了解过PV/PVC之后进行zookeeper集群部署时进行说明
Service
service定义了一个服务的访问入库地址,前端应用(Pod)通过这个入口地址访问其背后的一组由Pod副本组成的集群实例,Service与其后端Pod副本集群之间则是通过Label Selector来实现无缝对接的。RC的作用实际上是保证service服务能力和服务质量始终处于预期的标准。
一组Pod组成的服,客户端如何访问?每个Node上的kube-proxy进程负责把对service的请求转发的后端某个Pod的实例上,并在内部实现了服务的负载均衡与会话保持机制。但需要注意的是:service不是共用一个IP,而是每个Service分配了一个全局唯一的虚拟IP地址(ClusterIP),服务调用就变成一个TCP网络通信。
kubernetes的服务发现机制,Service对象都有一个唯一的ClusterIP以及唯一的名字,在老版本中通过自动注入环境变量将service的name与ClusterIP绑定,新版本中采用插件的方式引入了DNS系统,把service的name作为DNS域名,然后程序就可以通过service的name来建立通信连接了
外部系统访问service的关键在于3种IP,即:
Node IP node节点的IP地址
,集群之外的节点访问集群内的服务时,必须要通过NodeIP进行访问Pod IP pod的IP地址
,Docker Engine根据dicker0网桥的IP地址段进行分类的一个虚拟的二层网络的IP地址Cluster IP service的IP地址
,虚拟的IP,它的特点:- 仅作用域service对象,由k8s管理和分配IP地址
- 无法被
ping
- 只能结合service port组成一个具体的通信端口,单独的Cluster IP不具备通信基础
- 集群之内 Node/pod/cluster之间的通信与通常的IP路由与很大的不同
service的cluster IP无法供外部直接使用,但通过指定服务的port绑定在节点的port上,即可进行访问;当pod位于多个node时,通过nodeip:port访问到的是nodeip所在node上的pod,如需负载可以考虑使用硬件负载均衡器或者Nginx
例子:只在集群内进行访问的service
$ cat > k8s-tomcat-demo-svc.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
name: k8s-tomcat-svc
spec:
ports:
- port: 8080
selector:
demo: k8s-tomcat
EOF
$ kubectl apply -f k8s-tomcat-demo-svc.yaml
$ kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
k8s-tomcat-svc 10.108.64.29 <none> 8080/TCP 14h
$ kubectl get endpoints
NAME ENDPOINTS AGE
k8s-tomcat-svc 10.36.0.3:8080,10.36.0.4:8080,10.36.0.5:8080 + 4 more... 14h
- 例子:集群之外可以进行访问的service
$ cat > k8s-tomcat-demo-svc.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
name: k8s-tomcat-svc
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30001
selector:
demo: k8s-tomcat
EOF
$ kubectl apply -f k8s-tomcat-demo-svc.yaml
$ kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
k8s-tomcat-svc 10.108.64.29 <nodes> 8080:30001/TCP 15h
Volume
volume是pod中能够别多个容器访问的共享目录;k8s中volume定义在pod上,然后被pod中的多个容器挂载到具体的目录下;volume与pod的生命周期相同
volume具有丰富的类型:
emptyDir:Pod分配到node时创建的,它的初始内容为空,并且无需指定宿主机上对应的目录文件,pod从node上移除时,则emptyDir中的数据永久删除;emptyDir的用途有:
- 临时空间
- 长时间任务的checkpoint点
- 一个容器需要从另一个容器获取数据的目录
hostPath,在pod上挂载宿主机的文件或目录,
主要用途:
- 容器应用生成的文件(如日志)需要永久保存时
- 需要访问宿主机的文件时
注意事项:
- 不同的node上具有相同配置的pod可能因为宿主机上的目录和文件不同而导致对Volume上目录和文件的访问结果不一致
- hostPath无法纳入资源配额管理
NFS,使用NFS网络文件系统共享存储数据
其他类型:
ceph
、glusterfs
等
PV (Persistent Volume,持久卷)
PV是k8s集群中某个网络存储中对应的一块存储,它和Volume的区别:
- PV只能是网络存储,不属于任何Node,但可以在每个Node上访问
- PV独立于Pod定义
- PV目前支持的类型涵盖了很多公有云平台存储(gce、aws)以及一些网络文件系统(NFS)
Pod想申请PV时,需要先定义一个PVC(Persistent Volume Claim),然后在Pod的Volume中引用定义好的PVC
Namespace 命名空间
Namespace通过将集群中的资源对象分配(逻辑上的)到不同的Namespace中,形成逻辑上的分组不同的项目、用户组等,便于实现多租户资源管理。 默认的namespace是
default
声明资源对象时,在metadata一项中可以指定,如
namespace: dev
Annotation
- 注解与
Label
类似,但具有严格的命名规则
参考资料:《kubernetes权威指南》