控制器资源对象StatefulSet和PV/PVC动态供应项目
首先了解一个新的控制器对象StatefulSet
StatefulSet 是 Kubernetes 中的一个控制器对象,用于管理有状态应用的部署和运行。与 Deployment 控制器不同,StatefulSet 具有以下特点:
稳定的网络标识符:每个 StatefulSet 中的 Pod 都自动生成一个唯一的网络标识符,通常采用序号的方式(例如,pod-0、pod-1)。这样可以确保每个 Pod 在重启或重新部署时都能保持相同的标识符。
稳定的持久化存储:StatefulSet 可以与持久化存储卷(如 AWS EBS 或 GCE PD)结合使用,确保每个 Pod 在重启或重新部署时都能保持相同的持久化存储。在删除 Pod 时,持久化存储不会被自动删除,以便数据的持久性。
顺序部署和伸缩:StatefulSet 中的 Pod 是按照序号的顺序依次部署和伸缩的。例如,如果需要扩展副本数量,会先创建 pod-2,然后是 pod-3,以此类推。这确保了有状态应用的有序启动和关闭。
有序终止和删除:与 Deployment 控制器不同,StatefulSet 中的 Pod 是按照相反的顺序进行终止和删除的。例如,如果需要缩减副本数量,会先删除 pod-3,然后是 pod-2,以此类推。这确保了有状态应用的有序关闭和删除。
稳定的 DNS 名称:每个 StatefulSet 中的 Pod 都有一个稳定的 DNS 名称,可以通过该名称进行访问。DNS 名称的格式为
<pod-name>.<service-name>.<namespace>.svc.cluster.local
。
StatefulSet 对象是通过定义一个包含 Pod 模板的模板化 Deployment 来实现的。这个 Pod 模板中的每个 Pod 都有一个唯一的标识符,并且可以与持久化存储卷关联。StatefulSet 还可以与 Headless Service 结合使用,以提供稳定的网络标识符和 DNS 名称。
创建一个实例
apiVersion: apps/v1 #版本号
kind: StatefulSet #控制器
metadata:
name: nginx-statefulset #自定义名称
spec:
selector: #指定了将用于选择Pod的标签
matchLabels:
app: nginx #会对含有该标签的pod控制
serviceName: nginx-service #引用一个service,需要自己创建
replicas: 3 #创建3个Pod实例
template:
metadata:
labels: #设置标签键值对
app: nginx #app是键,nginx是值,加在一起是标签
spec:
containers:
- name: nginx #容器名字
image: daocloud.io/library/nginx:1.12.0-alpine #镜像
ports:
- containerPort: 80 #开放端口
volumeMounts:
- name: nginx-persistent-storage #指定挂载这个卷到mountPath内,没有需要自己创建
mountPath: /usr/share/nginx/html #挂载到容器内的这个目录
volumeClaimTemplates:
- metadata:
name: nginx-persistent-storage #选择该名称的pvc对象
spec:
accessModes: [ "ReadWriteOnce" ] #定义了访问模式
resources: #定义了PVC请求的资源
requests:
storage: 10Gi #请求了大小为10Gi的存储空间
接下来开始创建动态供应项目,这种项目可以在创建pvc的同时自动创建对应的pv,不需要手动匹配
定义一个storage
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-storage #自定义storage名称,后面需要引用
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner #k8s1.27.4需要指定external存储类型,常用的NFS外部存储扩展插件
因为storage自动创建pv需要经过kube-apiserver,所以要进行授权
创建1个sa(serviceaccount)
创建1个clusterrole,并赋予应该具有的权限,比如对于一些基本api资源的增删改查;
创建1个clusterrolebinding,将sa和clusterrole绑定到一起;这样sa就有权限了;
然后pod中再使用这个sa,那么pod再创建的时候,会用到sa,sa具有创建pv的权限,便可以自动创建pv;
apiVersion: v1 #版本号
kind: ServiceAccount #创建一个对象获得权限,需要绑定到pod内给予pod权限
metadata:
name: nfs-client-provisioner #创建一个serviceaccount对象,绑定在默认命名空间内
namespace: default
---
kind: ClusterRole #集群角色
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner #对该角色提供以下权限
rules:
# 对 nodes 资源进行 get、list、watch 操作的权限
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
# 对 persistentvolumes 资源进行 CRUD 操作的权限
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
# 对 persistentvolumeclaims 资源进行更新操作的权限
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
# 对 storageclasses 资源进行 get、list、watch 操作的权限
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding #关联权限的资源对象
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner #自定义名称,下面会引用
subjects: #指定了要绑定角色的对象
- kind: ServiceAccount #表示对象的类型,这里是服务账号
name: nfs-client-provisioner #是服务账号的名称,引用上面的对象
namespace: default #绑定到默认空间
roleRef: #定义了要绑定的角色及其所属的角色类型和 API 组
kind: ClusterRole #表示角色的类型,这里是集群角色
name: nfs-client-provisioner-runner #角色的名称,引用了上面创建的角色对象
apiGroup: rbac.authorization.k8s.io #角色所属的API组,用于管理 RBAC(基于角色的访问控制)
---
kind: Role #定义一个命名空间级别的角色
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner #角色名称,下面会引用
namespace: default #绑定到默认空间
rules: #定义了角色的权限规则
- apiGroups: [""] #空字符串 "" 表示核心 API 组
resources: ["endpoints"] #指定了该角色要操作的资源类型
verbs: ["get", "list", "watch", "create", "update", "patch"] #权限
---
kind: RoleBinding #命名空间级别的角色绑定
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner #是角色绑定的名称
namespace: default #绑定在默认空间
subjects: #定义了被绑定的对象
- kind: ServiceAccount #指定了对象的类型
name: nfs-client-provisioner #指定了服务账号的名称,引用了上创建的角色
namespace: default #指定了服务账号所在的命名空间
roleRef: #指定了要绑定的角色
kind: Role #指定了角色的类型
name: leader-locking-nfs-client-provisioner #指定了角色的名称
apiGroup: rbac.authorization.k8s.io #角色所属的API组,用于管理 RBAC(基于角色的访问控制)
创建一个名为
nfs-client-provisioner
的服务账号,并将其限定在默认命名空间中。创建一个名为
nfs-client-provisioner-runner
的集群角色,赋予对 Nodes、PersistentVolumes、PersistentVolumeClaims、StorageClasses 和 Events 等资源进行操作的权限。使用上述集群角色,将
nfs-client-provisioner
服务账号与之绑定,以便运行 NFS 客户端提供程序。创建一个名为
leader-locking-nfs-client-provisioner
的角色,授权 NFS 客户端提供程序锁定堆栈所需的权限。使用上述角色,将
nfs-client-provisioner
服务账号与之绑定,以便在 Kubernetes 中进行信息锁定。
部署一个自动创建pv的pod服务
这个pod具有serviceaccount关联的权限,可以自动创建pv
这里自动创建pv的服务由nfs-client-provisioner完成
kind: Deployment
apiVersion: apps/v1
metadata:
name: nfs-client-provisioner #指定Deployment的名称
spec:
selector:
matchLabels: #指定了要匹配的标签
app: nfs-client-provisioner
replicas: 1
strategy:
type: Recreate #表示采用重新创建的方式更新Pod,不滚动更新
template:
metadata:
labels: #指定了 Pod 的标签
app: nfs-client-provisioner
spec:
serviceAccount: nfs-client-provisioner #指定了要使用的ServiceAccount的名称
containers:
- name: nfs-client-provisioner #指定容器的名称
image: registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
#运行 NFS 客户端供应器的镜像,是常用的NFS外部存储扩展插件
volumeMounts:
- name: nfs-client-root #指定了卷的名称
mountPath: /persistentvolumes #指定了将卷挂载到容器内的路径
env: #定义了容器的环境变量
- name: PROVISIONER_NAME #指定容器内环境变量的名称
value: k8s-sigs.io/nfs-subdir-external-provisioner #为环境变量指定了值
- name: NFS_SERVER #指定变量和值
value: 192.168.48.139 #NFS服务器的ip
- name: NFS_PATH #指定变量和值
value: /opt/container_data #共享挂载的目录
volumes: #定义了要使用的卷列表
- name: nfs-client-root #指定了卷的名称
nfs: #定义了 NFS 卷的配置
server: 192.168.48.139 #指定 NFS 服务器的地址
path: /opt/container_data #指定 NFS 服务器上共享目录的路径
查看一下创建好的storageclasses,缩写sc
kubectl get sc -n default
默认策略是delete,删除pvc后自动删除pv
测试自动创建pv,部署有状态服务
我们部署一个nginx服务,让其html下面自动挂载数据卷
apiVersion: v1
kind: Service #暴露端口
metadata:
name: nginx #自定义名称
labels: #设置标签
app: nginx
spec:
ports: #定义了 Service 的端口映射
- port: 80
name: web #为端口映射定义了一个名称
clusterIP: None #表示不分配 Cluster IP,即将 Service 提供为 Headless Service
selector: #会将包含该标签的pod加入管理
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet #创建statefulset控制器
metadata:
name: web #指定 StatefulSet 的名称为 web
spec:
serviceName: "nginx" #指定调用名字为nginx的service
replicas: 2
selector:
matchLabels: #运行两个包含该标签的pod
app: nginx
template: #定义了要创建的 Pod 模板
metadata:
labels: #对创建的pod打上该标签
app: nginx
spec:
containers:
- name: nginx #指定容器的名称
image: daocloud.io/library/nginx:1.12.0-alpine
ports:
- containerPort: 80
name: web #为端口映射定义了一个名称
volumeMounts:
- name: www #指定了引用的卷的名称
mountPath: /usr/share/nginx/html #卷挂载到容器内的路径
volumeClaimTemplates: #要使用的 PVC 模板列表
- metadata:
name: www #指定了pvc的名称,被上面引用
spec:
accessModes: [ "ReadWriteOnce" ] #访问模式为一次读写
storageClassName: "nfs-storage" #指定PVC使用的StorageClass名称,第一个文件创建的
resources:
requests:
storage: 1Gi #指定需要的存储容量为 1GB
创建完成后查看pv,自动生成了两个查看pvc,因为statefulset的特性,自动给pvc分配端口映射的名字+卷的名字组合
查看pod的挂载目录,并且创建一个文件
然后删除该pod,然后手动删除pv和pvc,在查看挂载目录,数据还保存在目录内,有高可用的作用,达到了效果,(有时候删除pvc和pod后目录会改名)
过程:当创建新的pod需要pv时,只需要创建pvc,然后引用storageclass对象,starageclass会通过插件通知具有该插件的pod,该pod通过设置的预定义变量将pv自动创建到指定的ip和nfs目录,提供给pvc绑定,启动动态储存的效果