K8s企业实践使用storageclass实现动态存储
一、原理简介
因为要搭建,很多人还不太懂原理,我这里只是简单说明
使用StatefulSet的前提:
Kubernetes集群的版本 >=1.5 安装好DNS集群插件,版本 >=15 )
StatefulSet
注意: 官方提示StatefulSets在1.9中是稳定的
StatefulSet由Service和volumeClaimTemplates组成。Service中的多个Pod将会被分别编号,并挂载volumeClaimTemplates中声明的PV。
1.每个节点都有固定的身份ID,通过这个ID,集群中的成员可以互相发现并且通信 2.集群的规模是比较固定的,集群规模不能随意变动。 3.集群里的每个节点都是有状态的,通常会持久化数据到永久存储中 4.如果磁盘损坏,则集群里的某个节点无法正常运行,集群功能受损。
官方文档对Statefulet解释
StorageClass
通过StorageClass的定义,管理员可以将存储资源定义为某种类别(Class),正如存储设备对于自身的配置描述(Profile),例如 "快速存储" "慢速存储" "有数据冗余" "无数据冗余"等。用户根据StorageClass的描述就能够直观得知各种存储资源的特性,就可以根据应用对存储资源的需求去申请存储资源了。
Deployment
Deployment相对于RC的一个最大升级是我们可以随时知道当前Pod"部署"的进度,实际上由于一个Pod的创建、调度、绑定节点及在Node上启动对应的容器这一完整过程需要一定的时间,所以我们期待系统启动N个Pod副本的目标状态,实际上是一个连续变化的"部署过程"导致的最终状态
二、服务搭建
IP | 服务 | 备注 |
---|---|---|
192.168.60.24 | K8S环境-master | 在master节点需要安装ceph-common,否则会出现image错误 |
192.168.60.25 | K8S环境-node节点 | master和slave节点需要安装ceph命令,用于调用 |
192.168.60.28 | ceph-master | |
192.168.60.29 | ceph1 | |
192.168.60.31 | Ceph2 | |
Centos7.4系统,其他不变 | Ceph 安装文章 | Ceph 工作原理详解 |
创建StorageClass之后有两种方式引用,第一种:StatefulSet 第二种使用:Deployment
StatefulSet相比Deployment有以下特点 1.稳定的,唯一的网络表示,可以用来发现集群内部的其他成员。比如StatefulSet的名字叫abc,那么第一个起来的叫abc-1第二个abc-2依此类推 2.稳定的持久化存储:通过K8S的PV/PVC或者外部存储(预先提供的)来实现启动或关闭保证有序:优雅的部署和伸缩:操作第n个pod时,前n-1Pod已经是运行并且是准备好的状态。
RDB类型的pv只能被一个Pod可以读写,一个rbd image挂载到Pod后,image会加锁。如果使用支持多个Pod同时读写挂载的PV类型,就需要用到StorageClass,每个Pod各自挂载一个PV
注! 比如mysql、redis我们可以使用StatefulSet,nginx,tomcat可以使用deployment
一、使用StatefulSet创建StorageClass、pv和pvc
使用ceph存储前需要先创建pool池和密钥,便于服务调用
==(1).创建pool池,本例环境均在namespace abc_pool
下==
通常在创建pool,需要覆盖默认的pg_num,官方推荐
- 若小于5个OSD,设置pg_num为128
- 5~10个OSD,设置pg_num为512
- 10~50个OSD,设置pg_num为4096
- 超过50个OSD,可以参考pgcalc计算
- 更多pool配置参考
温馨提示:K8s中master节点及node节点都需要安装ceph命令!!!! Ceph install 仅仅需要安装ceph并不需要其他的认证了
#创建pool池
ceph osd pool create abc_pool 512
#####################命令格式##################
#创建Pool
ceph osd pool create [pool池名称] 512
#删除pool
ceph osd pool delete [pool池名称]
#调整副本数量
ceph osd pool set [pool池名称] size 2
查看pool 池
ceph osd lspools
rados lspools
查看pool池密钥,记录下pool池的密钥,创建用户密钥信息的时候会使用到
查看并创建test用户
ceph auth get-or-create client.test mon 'allow r' osd 'allow rwx pool=abc_pool'
记录admin用户key
ceph auth get-key client.admin
##如果需要修改test用户权限,可执行下命令
ceph auth caps client.test mon 'allow r' osd 'allow rwx pool=rbd'
ceph用户管理,官方文档 我们还需要查看admin用户的key,并进行记录. admin用户默认就存在
查看用户权限及密钥
查看用户秘钥
ceph auth get-key client.admin
查询用户权限
ceph auth get client.admin
ceph auth list
查看全部用户
==(2). 创建用户的空间创建用户的密钥信息== 创建用户的空间创建用户的密钥信息
创建 命名空间,也可以使用default
kubectl create namespace abcdocker
##不同的命名空间不可以互通
创建k8s admin用户
kubectl create secret generic ceph-secret-admin --from-literal=key='AQAhjnZb8iCgOBAAhp/nQrkivY+d660jk6FL6A==' --type=kubernetes.io/rbd -n kube-system
###这里的key是我们上面查看admin用户的key
创建k8s use用户
kubectl create secret generic ceph-secret-user --from-literal=key='AQAhjnZb8iCgOBAAhp/nQrkivY+d660jk6FL6A==' --type=kubernetes.io/rbd -n abcdocker
## 这里的key是上面创建用户的key
查询admin & user secret
Admin
kubectl get secret ceph-secret-admin -o yaml --namespace=kube-system
User
kubectl get secrets --namespace=abcdocker ceph-secret-user
创建k8s用户参数解释:kubectl create secret generic [USERSecretName] --from-literal=key='[pool池密钥]' --type=kubernetes.io/rbd -n [命名空间]
==(3).创建StorageClass== 需要修改的地方
请不要执行,这里是参数说明@@@@@#######
cat >./storageclass.yaml <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: [StorageClass名称]
provisioner: kubernetes.io/rbd
parameters:
monitors: mon节点:6789,172.16.20.3:6789,#多节点mon请使用逗号分隔
adminId: admin ##admin用户是我们刚刚k8s上创建的用户
adminSecretName: ceph-secret-admin #secret用户
adminSecretNamespace: "kube-system" #命secret名空间
pool: [pool池名称]
userId: [USER-ID] ##ceph上创建的用户
userSecretName: [USERSecretName] ##普通用户的secret
EOF
创建StorageClass
cat > storageclass.yaml <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: abc-storageclass
provisioner: kubernetes.io/rbd
parameters:
monitors: 192.168.60.28:6789
adminId: admin
adminSecretName: ceph-secret-admin
adminSecretNamespace: "kube-system"
pool: abc_pool
userId: test
userSecretName: ceph-secret-user
EOF
kubectl create -f storageclass.yaml --namespace=abcdocker
#需要我们指定命名空间,也可以写在配置文件中,不同的命名空不可以互相通信
==(4)StatefulSet服务调用storageclass,自动创建pv和pvc==
下面的创建StatefulSet使用企业真实案例进行创建 (这只是个例子,下面我们进行创建,启动redis 3个pod实例)
cat >./statefulset-template.yaml <<EOF
apiVersion: apps/v1beta1 #指定api版本,此值必须在kubectl apiversion种
kind: StatefulSet #指定创建资源的角色/类型
metadata: #资源的元数据/属性
name: statefulset-template #资源(Pod)的名称
namespace: qiqi-china-zxbk-prod #命名空间
labels: #设置资源标签
k8s-app: statefulset-template
spec:
serviceName: statefulset-template #service名称
replicas: 3
template:
metadata:
labels:
name: statefulset-template
spec:
containers: #容器配置
- name: statefulset-template #容器名称
image: harbor.zxbike.cn/public/redis:3.2.11 #容器镜像
imagePullPolicy: IfNotPresent #三个选择Always、Never、IfNotPresent,每次启动时检查和更新(从registry)images的策略
# Always,每次都检查
# Never,每次都不检查 (不管本地是否有)
# IfNotPresent,如果本地有就不检查,如果没有就拉取
command:
- redis-server #启动容器的运行命令,将覆盖容器中的Entrypoint,对应Dockerfile中的ENTRYOINT
args:
- /config/master.conf #启动容器的命令参数,对应Dockerfile中CND参数
volumeMounts: #volume挂载参数
- name: data #volume名称
mountPath: /data #volume容器内部挂载路径
subPath: nodejs-mallh5 #一个pod中,将同一个卷共享,使其有多个用处。volumeMounts.subPath特性可以用来指定卷中的一个子目录,而不是直接使用卷的根目录。
volumeClaimTemplates:
- metadata:
name: data #statefulSet名称
annotations:
volume.beta.kubernetes.io/storage-class: "[StorageClass名称]" #这里定义StorageClass名称
gcp-auto-backup: "yes"
spec:
accessModes: [ "ReadWriteOnce" ] #访问模式
resources:
requests:
storage: 2Gi #2G的动态共享资源供应模式
EOF
################################################################
StatefulSet服务调用storageclass,自动创建pv和pvc
redis例子
因为StatefulSet会自动帮我们创建pv和pvc
cat >./statefulset-template.yaml <<EOF
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: statefulset-template
namespace: abcdocker
labels:
k8s-app: statefulset-template
spec:
serviceName: statefulset-template
replicas: 3
template:
metadata:
labels:
name: statefulset-template
spec:
containers:
- name: statefulset-template
image: daocloud.io/library/redis:3.2.9
imagePullPolicy: IfNotPresent
volumeMounts:
- name: data
mountPath: /data
subPath: nodejs-mallh5
volumeClaimTemplates:
- metadata:
name: data
annotations:
volume.beta.kubernetes.io/storage-class: "abc-storageclass"
gcp-auto-backup: "yes"
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 2Gi
EOF
kubectl create -f statefulet-template.yaml
storageclass会自动帮我们创建pv和pvc
==(5) 验证检查redis实例==
- 首先我们需要检查PVC和PV是否被创建
- 当检查PVC和PV都属于绑定状态我们在查看Pod是否正常
这里我们可以pvc已经属于绑定状态,绑定到我们创建的sc上
如果创建了pvc并没有创建pv或者是pvc报错,可以通过kubectl describe pvc进行查看
查看Pod启动是否正常
如果无法正常运行可以使用kubectl describe查看详细信息,或者使用journalctl -fu kube-controller-manager.servicec查看报错
查看secret用户
[root@master ceph]# kubectl get --namespace=abcdocker secrets
NAME TYPE DATA AGE
ceph-secret-user kubernetes.io/rbd 1 56m
default-token-krlgb kubernetes.io/service-account-token 3 56m
如果使用我们本地emptyDir卷当删除pod时,同时数据也会被删除
rdb类型的pv只能被一个pod可以挂载,一个rbd image挂在到pod后,image会加锁。 也就是pv只能这一个访问,如果想多个pod访问就使用StatefulSet。Deployment 只可以一个pod访问一个image
二、StorageClass 手动指定pvc
刚刚我们演示了使用storageclass直接创建Pod,期间不需要创建pv和pvc,接下来我们演示手动指定pvc
缺点:手动指定pvc可以自己定义
创建nginx例子
上面我们已经介绍了如何获取ceph用户的key这里就直接执行了 创建pool池
ceph osd pool create nginx_pool 128
创建ceph用户,用于sc连接
ceph auth get-or-create client.nginx mon 'allow r' osd 'allow rwx pool=nginx_pool'
#用户名称nginx
pool是nginx_pool
创建命名空间
kubectl create namespace nginx
在K8s中创建ceph用户的密钥信息(下面pvc和pv会用到)
如果你上面已经创建过sc模式了,已经在k8s中生成了admin的key,那么你这里不需要在创建admin用户的key了
#########################################
#查看ceph admin的用户密钥
cat /etc/ceph/ceph.client.admin.keyring |grep key |awk '{print $3}'
#将密钥输入到以下地方,创建ceph在k8s上的密钥
kubectl create secret generic ceph-secret-admin --from-literal=key='AQBfxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=' --namespace=kube-system --type=kubernetes.io/rbd
如果使用文件创建就需要使用base64加密
######################################
& 我们这里直接创建普通用户的key
查看ceph 普通用户(nginx)密钥
ceph auth get-key client.nginx
kubectl create secret generic ceph-secret-user-nginx --from-literal=key='AQBQyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy==' --namespace=nginx --type=kubernetes.io/rbd
##指定我们创建好的命名空间
###### 如果不使用文件创建的,不需要使用base64加密
查看名称为ceph-secret-user-nginx普通用户
创建storageClass (创建动态卷组)
### sc文件解释 ###
cat >rbd-storage-class.yaml <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nginx-deployment-sc ## sc名称
namespace: nginx ##命名空间
provisioner: kubernetes.io/rbd #该字段指定使用存储卷类型为kubernetes.io/rbd,注意kubernetes.io开头为K8s内部支持的存储提供者,不同的存储卷提供类型这里要修改对应的值
parameters:
monitors: 172.16.30.5:6789 #mon节点地址,多节点以逗号分隔
adminId: admin #ceph角色admin,默认admin用户已经创建。userID如果没有也可以使用admin
adminSecretName: ceph-secret-admin #k8s中创建ceph的用户,为上边创建的Ceph管理员admin使用的。secret种必须要有"kubernetes.io/rbd"这个type
adminSecretNamespace: "kube-system" #管理员secret使用的命名空间,默认是default
pool: nginx_pool #pool池地址
userId: nginx #secret用户,连接sc
userSecretName: ceph-secret-user-nginx #K8s中创建的ceph用户,连接ceph
EOF
创建storageClass
需要注意的是执行的时候pvc和sc要在一个命名空间哦
cat >rbd-storage-class.yaml <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nginx-deployment-sc
provisioner: kubernetes.io/rbd
parameters:
monitors: 192.168.60.28:6789
adminId: admin
adminSecretName: ceph-secret-admin
adminSecretNamespace: "kube-system"
pool: nginx_pool
userId: nginx
userSecretName: ceph-secret-user-nginx
EOF
kubectl create -f rbd-storage-class.yaml --namespace=nginx
查看创建好的storageClass
[root@master deployment]# kubectl get storageclasses.storage.k8s.io --namespace=nginx
NAME PROVISIONER AGE
abc-storageclass kubernetes.io/rbd 1d
nginx-deployment-sc kubernetes.io/rbd 16s
创建pvc
pvc文件解释
cat >nginx-pvc.yaml <<EOF
{
"kind": "PersistentVolumeClaim",
"apiVersion": "v1",
"metadata": {
"name": "nginx-deployment-pvc" ##pvc名称
},
"spec": {
"accessModes": [ #访问模式,此处不多说了
"ReadWriteOnce"
],
"resources": {
"requests": {
"storage": "3Gi" #设置数据大小
}
},
"storageClassName": "nginx-deployment-sc" #sc名称
}
}
EOF
查看创建好的pvc
[root@master deployment]# kubectl get pvc --namespace=nginx
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nginx-deployment-sc Pending nginx-deployment-sc 12m
查看pvc,现在pvc创建好是属于等待的一个状态,这里需要等待几分钟,一会就会变成绑定状态
正常效果如下
我们手动创建pvc,一个pod只可以绑定一个pvc,否则会报错。如果想多个pod连接可以不创建pvc
解决办法:删除pvc,这个是由于master和node节点没有安装ceph造成的,在master和node安装ceph命令
创建nginx pod
cat > nginx_pod.yaml < EOF
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: nginx-deployment-sc
namespace: abcdocker
spec:
replicas: 1
template:
metadata:
labels:
app: nginx-sc
spec:
containers:
- name: nginx-sc
image: daocloud.io/library/nginx:1.13.0-alpin
ports:
- containerPort: 80
volumeMounts:
- mountPath: "/data"
name: nginx-volume
volumes:
- name: nginx-volume
persistentVolumeClaim:
claimName: nginx-deployment-pvc
EOF
## claimName pvc名称
Deployment或者set删除的时候需要注意
- 删除rc
- 删除pvc 和pvc
参考: https://www.cnblogs.com/iiiiher/p/7159810.html