总览
k8s 由谷歌开发
k8s是一个基于容器技术的分布式架构方案,是一个强大的分布式系统支撑平台
使用好处:
降低运维难度和运维成本
便于迁移(不局限于任何语言,任何接口)
完备的集群管理能力。
便于扩容
service概念
- 拥有唯一指定名称
- 拥有一个虚拟ip和端口
- 能够提供某种远程能力并且被映射到提供这种服务能力的一组容器上
- 一旦创建,其本身就不在变化。通过k8s内置的负载均衡、故障恢复等,保证了其稳定使用。
Pod:k8s把为service提供服务的这组进程放入容器中进行隔离,每个服务进程作为在pod中运行的一个容器。每个pod都会有一个标签,例如(name=mysql)service可以根据标签来选择pod
Node(节点):节点可以使物理机,也可以是虚拟机,一个节点上可以运行上百个pod,这些业务容器共享pause容器的网络栈和挂载卷。
k8s将机器划分成master和一些node,master集群管理,k8s的最小管理单元是pod。
基本概念和术语
总览:k8s通过跟踪对比etcd库里保存的“资源期望状态”与当前环境中的“实际资源状态”的差异来实现自动控制和自动纠错的高级功能
Master
master是集群控制节点,执行的所有命令都交给master,通常master独占一台机器或多台机器。
- master上运行着
- k8s API server(提供http rest 接口,是k8s所有资源增删查改的唯一入口),
- k8s controller manager(资源对象自动化控制中心),
- k8s scheduler(资源调度/pod调度)
Node
k8s集群中除了 Master的所有机器都叫做Node。Node可以是一台物理机,也可以是一台虚拟机。每个Node上会跑着Master分配的工作负载(Docker容器),一个Node宕机时,他的负载会被交给别的机器
- Node的进程
- kubelet 负责pod对应容器的创建、启停, 参与集群管理
- kube-proxy k8s service通信和负载均衡 组件
- Docker Engine 本机容器的创建管理
Node可以动态加入k8s集群,向master节点注册自己,汇报自身信息(pod运行信息,机器自身信息等)
Pod
图1.4 pod 示意图
- Pod的结构:根容器(pause容器)+ 业务容器
- Pod的pause容器的状态,代表了整个容器组的状态(可用/不可用)
- Pod里的容器组共享pause容器的ip和volume
- 任意两个Pod可以通过Tcp/Ip通信
Pod包括
普通pod,创建之后,1放入etcd存储,2会被k8s master调度到某个Node绑定3被node上的kubelet实例化成一组docker容器并启动
- pod所在的node不可用,会把这个node上的所有pod调度到另一个可用node
静态pod 不放在etcd,只定义在某个node上,纯供这个node使用。
pod中的每个容器可以定义一个容器端口(container endpoint),访问这个容器可以通过pod的ip+容器的端口(=endpoint)进行访问
Pod可以拥有Volume ,被各个容器挂载到自己的文件系统里
Node和Pod都有 k8s Event(事件记录)
Pod的container可以通过Request设置资源最小申请量和Limie设置资源最大允许量,当资源(Cpu,内存)在这两个区间时,可以运行。
Label
Label是一个标签,可以通过不同的Label实现多维度的分组管理功能。
管理对象如RC、Service可以设置Pod的Label(set apptype=app),Job等消费者可以通过标签(select apptype=app)来分组筛选对象。
- 场景
- 资源对象RC通过RC上定义的label selector标签筛选要监控的Pod副本数量,使Pod副本数量始终满足需求
- kube-proxy通过Serice上的Label Selector选择Pod,建立每个service到对应pod的请求路由表,实现负载均衡。
- k8s Scheduler通过标签实现Pod的定向调度
Replication Controller
RC定义了一个期望场景,即某种Pod副本数量在任何时候都满足某个预期值。
RC 目前逐渐被deployment和Replica Set 取代
- RC作用
- 定义一个RC实现Pod的创建和Pod副本数量自动控制
- RC里包含完整的Pod定义模板
- RC通过Label Selector实现对Pod副本的自动控制
- 改变RC Pod副本数量,实现Pod的扩容缩容
- 改变RC里Pod模板的镜像版本,实现Pod滚动升级
Deployment
一个pod的创建、调度、绑定节点以及在目标Node上启动对应的容器这一过程需要时间。”启动N个Pod副本“是一个连续变化的”部署过程“。
- 场景:
- 创建一个deployment对象生成对应的replica set ,完成pod的创建
- 检查deployment的状态查看部署是否完成(副本数量是否达到预期)
- 更新deployment来升级pod
- 扩展deployment应对高负载
- 。。。
示例代码:
1 |
|
Horizontal Pod Autoscaler
- 自动Pod扩容缩容资源
- 缩扩容触发
- 通过 CPUUtilizationPercentage(目标Pod每分钟Cpu使用量)来计算是否需要缩容扩容
- 通过程序自定义的度量指标,例如服务每秒钟的请求数
- 通过内置的metrics.k8s.io/v1beta1接口获取CPU监控指标
1
2
3
4
5
6
7
8
9
10
11
12
13#chapter 1.4.7
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
namespace: default
spec:
maxReplicas: 10
minReplicas: 1
scaleTargetRef:
kind: Deployment
name: php-apache
targetCPUUtilizationPercentage: 90 //当平均Cpu使用率达到90%,开始扩容
- 缩扩容触发
StatefulSet Todo
Service
k8s中的每个Service实际上就是微服务架构里的一个微服务
- 一个 service 对应一个负载均衡器,后端是一堆被service标签选择器选中的pod
- service 可以通过 clusterip 访问,可以通过nodeport访问
每个pod都会被分配一个IP地址,每个Pod可以提供多个Endpoint(Pod ip + containerPort)被访问。所以当多个Pod副本组成了一个集群提供服务时,k8s采用kube-proxy作为负载均衡器,为这组pod开启一个对外服务的接口。
service一旦被创建,k8s会为它非配一个可用的cluster IP,在service的整个生命周期里,他的cluster ip不会变。在服务发现时,会用service的name和service的cluster ip做一个dns映射。
service的多端口问题
- 很多服务可能存在多个端口,在此情况下每个端口会需要定义一个名称来进行区分。
k8s的服务发现机制
- k8s把服务名作为dns域名,程序可以使用服务名来建立通信连接。
外部访问service方案1
- Node IP
- node ip 是k8s集群中每个节点的物理网卡的ip地址,是一个真实存在的物理网络。 - 在k8s集群之外的节点访问k8s集群之内的节点需要通过Node IP通信
- Pod IP
- pod ip是一个虚拟的二层网络 - k8s两个pod之间的流量,实际上是走的node ip
- Cluster IP
- 仅对k8s service 对象生效,由k8s管理和分配ip地址 - cluster ip只能结合service port 组成一个具体的通信端口。单独的cluster ip不具备tcp/ip通信的基础。 - 无法集群外使用cluster ip
- 采用NodePort的方式,使service具备集群外访问的能力
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#chapter 1.4.9
apiVersion: v1
kind: Service
metadata:
name: tomcat-service
spec:
type: NodePort #定义使用NodePort,使集群外可以访问此Service
ports:
- port: 8080 #Service服务端口
name: service-port
nodePort: 31002 #指定NodePort,使集群外可以访问此Service
- port: 8005 #多端口示例
name: shutdown-port #每个端口都需要命名
selector:
tier: frontend #所有拥有“tier=frontend”这个Label的Pod都属于此Service
外部访问service方案2-负载均衡组件
NodePort不具备负载均衡能力
可以将service的type修改成LoadBalance,k8s会创建一个LoadBalance实例并返回它的IP地址供外部客户端使用。
JOB
批处理任务通常并行(或者串行)启动多个计算进程去处理一批工作项(work item),在处理完成后
Job控制一组pod容器。Job控制的Pod容器是短暂运行的,可视为一组Docker容器,每个Docker容器仅运行一次,Job控制的所有Pod副本运行结束时,对应的Job视作结束
Job控制的Pod副本能够多实例并行计算
Volume
Volume(存储卷)是Pod中能够被多个容器访问的共享目录
k8s Volume和Docker Volume的区别
Kubernetes中的Volume被定义在Pod上,然后被一个Pod里的多个容器挂载到具体的文件目录下
Kubernetes中的Volume与Pod的生命周期相同,但与容器的生命周期不相关,当容器终止或者重启时,Volume中的数据也不会丢失。
Kubernetes支持多种类型的Volume,例如GlusterFS、Ceph等先进的分布式文件系统。
Volumes支持多种类型
- emptyDir
- 初始内容为空,无需指定宿主机上的目录文件。
- Pod从Node移除时,emptyDir的内容会被清除
- 适用于作为临时空间、多容器共享目录适用
- hostPath
- 将宿主机的某个目录文件挂载到Pod
- gcePersistentDisk
- 谷歌云提供的永久磁盘(Persistent Disk,PD)
- 该Volume(PD)的内容会永久保存
- Pod被删除时,PD被unmount,不会被删除
- 同亚马逊提供的awsElasticBlockStore
- NFS
- 网络文件系统
- 需要现在系统中部署一个NFS Server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44#chapter 1.4.6, 1.4.11
apiVersion: apps/v1
#书中extensions/v1beta1的API版本不再提供Deployment,使用apps/v1
#https://kubernetes.io/blog/2019/07/18/api-deprecations-in-1-16/
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:
volumes: #为Pod增加Volume
- name: datavol
emptyDir: {} #emptyDir类型的Volume,跟随Pod生命周期
- name: "presistent-storage"
hostPath: #hostPath类型的Volume,可在Pod上挂载宿主机上的文件或目录
path: "/data" #例如挂载宿主机的/data目录
- name: test-volume
gcePersistentDisk
pdName:my-data=disk
fsType:ext4
- name : nfs
nfs:
#自己部署的NFS server地址
server:nfs-server.localhost
path:"/"
containers:
- name: tomcat-demo
image: tomcat
volumeMounts: #挂在到/mydata-data目录
- mountPath: /mydata-data
name: datavol
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
- emptyDir
PV
Volume是被定义在Pod上的,属于计算资源的一部分;网络存储是相对独立于计算资源而存在的一种实体资源;我们通常会先定义一个网络存储,然后从中划出一个“网盘”并挂接到虚拟机上。Persistent Volume(PV)和与之相关联的PersistentVolume Claim(PVC)也起到了类似的作用。
PV只能是网络存储,不属于任何Node,但可以在每个Node上访问。
PV不是在Pod上定义的,是独立于Pod定义
支持的类型:gcePersistentDisk、AWSElasticBlockStore、AzureFile。。。
1 |
|
如果某个Pod想申请某种某种类型的PV,需要定义一个PVC(PersistentVolumeClaim)对象后,在Pod的Volume定义中引用定义的PVC
1 |
|
Namespace
Namespace在很多情况下用于实现多租户的资源隔离。Namespace通过将集群内部的资源对象“分配”到不同的Namespace中,形成逻辑上分组的不同项目、小组或用户组,便于不同的分组在共享使用整个集群的资源的同时还能被分别管理
- k8s集群会默认创建一个名为default的namespace
- 如果不特别指定namespace,用户创建的Pod,RC,Service会被系统默认分配到default的Namespace
当给每个租户创建一个Namespace来实现多租户的资源隔离时,还能结合Kubernetes的资源配额管理,限定不同租户能占用的资源,例如CPU使用量、内存使用量等
Annotation
Annotation(注解)类似Label。区别是注解的命名规则并不严格,由用户定义,便于外部工具查找。
可能用注解记录build信息、release信息、docker镜像信息。。。
ConfigMap
ConfigMap 理解成 是一个key-value形式存储了配置信息(环境变量)的map,这个map存放在etcd里,可以由k8s以Volume映射的方式 变成pod里的配置文件。当configMap的数据修改时,映射到pod里的”配置文件“也会随之更新。