之前《Kubernetes基本架构及集群部署》中介绍了Kubernetes的基本架构、功能组件以及部署,在本文继续介绍Kubernetes的一些基础的资源对象。
上图是整个Kubernetes集群中的资源对象,主要功能和对象分类如下:
API对象是K8S的集群中管理操作单元,采用声明式设计风格,顶层(Top Level)元素由 kind、apiVersion、metadata、spec 和 status 等几个部分组成。
以下是简单的Deployment的yaml定义:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: nginx-example
labels:
apps: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
status: {}
Label是Kubernetes中另一个重要概念,一个Label是一个key=value的键值对,其中key与value由用户自己指定。Label是资源上的标识,用来对它们进行区分和选择,具有以下特点:
实际过程中可以通过label实现资源的多维度分组,以便灵活,方便的进行资源分配,调度,配置,部署等管理工作;常用的多维度标签分类如下:
Kubernetes通过label selector查询和筛选拥有某些Label的资源对象,这种方式类似于SQL的where查询条件,比如name=redis-slave匹配所有name=redis-slave的资源对象、env!=production匹配所有不具有标签env=production的资源对象。
NameSpace为Kubernetes集群提供虚拟的隔离作用,通过将集群内部的资源对象“分配”到不同的Namespace上,形成逻辑上分组的不同项目或用户组。
Kubernetes集群初始有三个命名空间,分别是default、kube-system和kube-public,除此以外,管理员可以创建新的命名空间满足需要。一旦创建了Namespace,可以在创建资源对象的时候指定资源对象属于哪个NameSpace。
官方对于Pod的解释是:
Pod是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。
简单来说Pod就是由若干容器组成的最小管理单元,在Pod内可以共享网络、存储和计算资源。Kubernetes为每个Pod都分配了唯一的IP地址,称之为Pod IP,一个Pod内的多个容器共享Pod IP地址。在同一节点上,Pod相互可见,但是Pod不能跨节点,一定在一个节点之上,如下图所示:
Pod有两种类型普通的Pod和静态Pod,静态Pod比较特殊,它并没有存放在K8S的etcd存储中,而是存放在某个具体的Node的一个具体文件中,并且只在此Node上启动运行。普通的Pod一旦被创建,就会放入etcd存储,随后被K8S Master调度到某个具体的Node上并进行绑定,随后该Pod被Kubelet进程实例化为一组Docker容器并启动。
K8S中的所有对象都可以通过yaml来定义,以下是Pod的yaml文件:
apiVersion: v1
kind: Pod
metadata:
name: memory-demo
namespace: mem-example
spec:
containers:
- name: memory-demo-ctr
image: polinux/stress
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
volumeMounts:
- name: redis-storage
mountPath: /data/redis
volumes:
- name: redis-storage
Kubernetes集群中的Workload工作负载根据不同业务分为以下:
业务类型 | API对象 |
---|---|
无状态 | ReplicaSet、Deployment |
有状态 | StatefulSet |
后台持续服务 | DaemonSet |
批处理型 | Job |
ReplicaSet声明需要多少个复本,由调度控制器通知节点启动副本,目的是维护一组在任何时候都处于运行状态的Pod副本的稳定集合。因此,它通常用来保证给定数量的、完全相同的Pod的可用性。RS的特性与作用总结如下:
如下图所示, ReplicaSets定义了5个副本分布在三个Node上,因此需要运行5个POD,而DaemonSet每个节点上只运行一个副本。
需要注意的是一般很少单独使用ReplicaSet,主要被Deployment这个更高层的资源对象引用,从而形成一整套Pod的创建、删除和更新的编排机制。
Deployment的作用是管理和控制Pod和ReplicaSet,通过声明某种Pod的副本数量在任意时刻都符合某个预期值,并由ReplicaSet 控制。Deployment和ReplicaSet之间的关系如下:
Deployment的典型使用场景如下:
Deployment的定义如下所示,声明最终的部署结果,执行具体过程由kubernetes完成
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: kubia
spec:
replicas: 3
template:
metadata:
name: kubia
labels:
app: kubia
spec:
containers:
- image: luksa/kubia:v1
name: nodejs
运行下面命令创建Deployment
# kubectl create -f tomcat-deployment.yaml
运行下面命令查看Deployment信息:
# kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AGE
tomcat-deploy 1 1 1 4h
在Kubernetes管理的对象中,ReplicaSet、Deployment、DaemonSet和Job都是面向无状态的服务,但现实中很多服务是有状态的,比如数据库集群、Zookeeper集群等。这些有状态的集群有一些共性的特征:
为了解决这些有状态的服务,Kubernetes引入了StatefulSet资源,StatefulSet带有状态Pod,重启后依然具有原来的状态信息。具有以下特性:
适合于StatefulSet的业务包括数据库服务MySQL和PostgreSQL、集群化管理服务ZooKeeper、etcd等有状态服务。StatefulSet的另一种典型应用场景是作为一种比普通容器更稳定可靠的模拟虚拟机的机制。使用 StatefulSet,Pod仍然可以通过漂移到不同节点提供高可用,而存储也可以通过外挂的存储来提供高可靠性,StatefulSet做的只是将确定的 Pod 与确定的存储关联起来保证状态的连续性。
对于一些批处理型的业务,可能有些节点上运行多个同类业务的Pod,有些节点上又没有这类Pod运行。DaemonSet用于管理在集群中每个Node上仅运行一份Pod的副本实例。
典型的DaemonSet服务包括存储,日志和监控等在每个节点上支持Kubernetes集群运行的服务,比如每个Node上运行一个日志采集程序或者性能监控程序。
Job是Kubernetes用来控制批处理型任务的API对象,在处理完成后整个批处理任务就结束了。Job管理的Pod根据用户的设置把任务成功完成就自动退出了,成功完成的标志根据不同的spec.completions策略而不同:
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: cronjob
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: cronjob
image: busybox
command: ["/bin/sh","-c","date"]
restartPolicy: Never
按照批处理任务实现方式的不同,批处理任务可以分为几种模式:
Service服务是Kubernetes中的核心资源对象之一,它屏蔽了服务细节,统一对外暴露服务接口,真正做到了“微服务”。在Kubernetes中RS和Deployment只是保证了支撑服务的微服务Pod的数量,但是没有解决如何访问这些服务的问题。一个 Pod 只是一个运行服务的实例,随时可能在一个节点上停止,在另一个节点以一个新的IP启动一个新的Pod,因此不能以确定的IP和端口号提供服务。
如果要稳定地提供服务需要服务发现和负载均衡能力:
从图中可以看出,Kubernetes的Service定义了一个服务的访问入口地址,前端的应用通过这个入口地址访问其背后由Pod副本组成的集群实例,Service与其后端的Pod副本是通过Label Selector来实现无缝对接的。
Kubernetes提供了强大的Volume机制和丰富的插件,解决了容器数据持久化和容器间共享数据的问题。在容器部署过程中一般有以下三种数据:
以上都不希望在容器重启时就消失,存储卷由此而来,K8S中可以根据不同场景提供不同类型的存储能力。K8S中支持的存储类型如下:
#hostPath – 挂载主机磁盘到容器
#NFS/NAS –挂载共享文件系统
#emptyDir
#awsElasticBlockStore / azureFileVolume
#Glusterfs
#Ceph rbd / Cephfs
Volume的使用比较简单,现在Pod中声明一个Volume,然后在容器内引用该Volume并mount到容器的某个目录上,如下图所示:
普通的Volume是定义在Pod上的,属于计算资源的一部分,实际上网络存储是相对独立于计算资源而存在的一种实体资源。因此PersistentVolumes可以理解为Kubernetes集群中某个网络存储对应的存储。如果某个Pod想申请某种类型的PV,首先需要定义一个PersistentVolumeClaims对象。
PersistentVolume是存储系统与应用系统区分开,单独资源对象。PV是对底层共享存储的一种抽象,将共享存储定义为一种资源。PV不直接和Pod发生关系,通过资源对象PVC (PersistentVolumeClaim)来绑定关联。PV与Volume的区别如下:
PVC是用户存储的请求,在pod中定义存储卷,定义的时候直接指定大小,与对应的pv建立关系。PV的整个生命周期是:
Provisioning(配置)--->Binding(绑定)--->Using(使用)--->Releasing(释放)--->Recycling(回收)
PV的创建有两种模式:静态模式和动态模式,静态模式下除了创建PVC外,还需要手动创建PV。
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodb-nfs-pv
namespace: default
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy:Retain
storageClassName: nfs-mongodb
nfs:
path: /root/data/nfs/mongodb
server: 192.168.72.100
在Docker中,通过将程序、依赖库、数据及配置文件“打包固化”到一个不变的镜像文件中,解决了应用的部署的难题,但同时也带来了棘手的问题,即配置文件中的参数在运行期如何修改的问题。Docker提供了两种方式解决该问题:
上述两种方式在分布式系统中存在着明显的缺陷,因为修改多台服务器上的某个指定文件并确保这些文件是一致的,在一定程度上很难实现。另外,希望能够集中管理系统的配置参数,而不是一堆配置文件。在Kubernetes中通过ConfigMap实现上述功能:
以上是Kubernetes集群中涉及到的主要的资源对象包括Pod、Namespace、Workload、Volume以及Configmap,总结如下图所示:
参考资料:
转载请注明原文地址:https://blog.csdn.net/solihawk/article/details/125040123
文章会同步在公众号“牧羊人的方向”更新,感兴趣的可以关注公众号,谢谢!