全栈工程师开发手册 (作者:栾鹏)
架构系列文章
##1. Volumes
###1.1. volume概述
- 容器上的文件生命周期同容器的生命周期一致,即容器挂掉之后,容器将会以最初镜像中的文件系统内容启动,之前容器运行时产生的文件将会丢失。
- Pod的volume的生命周期同Pod的生命周期一致,当Pod被删除的时候,对应的volume才会被删除。即Pod中的容器重启时,之前的文件仍可以保存。
容器中的进程看到的是由其 Docker 镜像和卷
组成的文件系统视图。
Pod volume的使用方式
Pod 中的每个容器都必须独立指定每个卷的挂载位置,需要给Pod配置volume相关参数。
Pod的volume关键字段如下:
- spec.volumes:提供怎样的数据卷
- spec.containers.volumeMounts:挂载到容器的什么路径
###1.2. volume类型
####1.2.1. emptyDir
1、特点
- 会创建
emptyDir
对应的目录,默认为空(如果该目录原来有文件也会被重置为空) - Pod中的不同容器可以在目录中读写相同文件(即Pod中的不同容器可以通过该方式来共享文件)
- 当Pod被删除,
emptyDir
中的数据将被永久删除,如果只是Pod挂掉该数据还会保留
2、使用场景
- 不同容器之间共享文件(例如日志采集等)
- 暂存空间,例如用于基于磁盘的合并排序
- 用作长时间计算崩溃恢复时的检查点
3、示例
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
####1.2.2. hostPath
1、特点
- 会将宿主机的目录或文件挂载到Pod中
2、使用场景
-
运行需要访问 Docker 内部的容器;使用
/var/lib/docker
的hostPath
-
在容器中运行 cAdvisor;使用
/dev/cgroups
的hostPath
-
其他使用到宿主机文件的场景
hostPath
的type
字段
值 | 行为 |
---|---|
空字符串(默认)用于向后兼容,这意味着在挂载 hostPath 卷之前不会执行任何检查。 | |
DirectoryOrCreate |
如果在给定的路径上没有任何东西存在,那么将根据需要在那里创建一个空目录,权限设置为 0755,与 Kubelet 具有相同的组和所有权。 |
Directory |
给定的路径下必须存在目录 |
FileOrCreate |
如果在给定的路径上没有任何东西存在,那么会根据需要创建一个空文件,权限设置为 0644,与 Kubelet 具有相同的组和所有权。 |
File |
给定的路径下必须存在文件 |
Socket |
给定的路径下必须存在 UNIX 套接字 |
CharDevice |
给定的路径下必须存在字符设备 |
BlockDevice |
给定的路径下必须存在块设备 |
注意事项
- 由于每个节点上的文件都不同,具有相同配置的 pod 在不同节点上的行为可能会有所不同
- 当 Kubernetes 按照计划添加资源感知调度时,将无法考虑
hostPath
使用的资源 - 在底层主机上创建的文件或目录只能由 root 写入。您需要在特权容器中以 root 身份运行进程,或修改主机上的文件权限以便写入
hostPath
卷
3、示例
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
# directory location on host
path: /data
# this field is optional
type: Directory
####1.2.3. configMap
configMap
提供了一种给Pod注入配置文件的方式,配置文件内容存储在configMap对象中,如果Pod使用configMap作为volume的类型,需要先创建configMap的对象。
示例
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod
spec:
containers:
- name: test image: busybox
volumeMounts:
- name: config-vol mountPath: /etc/config
volumes:
- name: config-vol configMap:
name: log-config
items:
- key: log_level path: log_level
####1.2.4. cephfs
cephfs
的方式将Pod的存储挂载到ceph
集群中,通过外部存储的方式持久化Pod的数据(即当Pod被删除数据仍可以存储在ceph集群中),前提是先部署和维护好一个ceph集群。
示例
apiVersion: v1
kind: Pod
metadata:
name: cephfs
spec:
containers:
- name: cephfs-rw image: kubernetes/pause
volumeMounts:
- mountPath: "/mnt/cephfs" name: cephfs
volumes:
- name: cephfs cephfs:
monitors:
- 10.16.154.78:6789 - 10.16.154.82:6789 - 10.16.154.83:6789 # by default the path is /, but you can override and mount a specific path of the filesystem by using the path attribute
# path: /some/path/in/side/cephfs
user: admin
secretFile: "/etc/ceph/admin.secret"
readOnly: true
更多可参考 CephFS 示例。
####1.2.5. nfs
nfs
的方式类似cephfs,即将Pod数据存储到NFS集群中,具体可参考NFS示例。
####1.2.6. persistentVolumeClaim
persistentVolumeClaim
卷用于将PersistentVolume
挂载到容器中。PersistentVolumes 是在用户不知道特定云环境的细节的情况下“声明”持久化存储(例如 GCE PersistentDisk 或 iSCSI 卷)的一种方式。
##2. PersistentVolume
###2.1. PV概述
PersistentVolume
(简称PV) 是 Volume 之类的卷插件,也是集群中的资源,但独立于Pod的生命周期(即不会因Pod删除而被删除),不归属于某个Namespace。
###2.2. PV和PVC的生命周期
####2.2.1. 配置(Provision)
有两种方式来配置 PV:静态或动态。
1、静态
手动创建PV,可供k8s集群中的对象消费。
2、动态
可以通过StorageClass
和具体的Provisioner
(例如nfs-client-provisioner
)来动态地创建和删除PV。
####2.2.2. 绑定
在动态配置的情况下,用户创建了特定的PVC,k8s会监听新的PVC,并寻找匹配的PV绑定。一旦绑定后,这种绑定是排他性的,PVC和PV的绑定是一对一的映射。
####2.2.3. 使用
Pod 使用PVC作为卷。集群检查PVC以查找绑定的卷并为集群挂载该卷。用户通过在 Pod 的 volume 配置中包含 persistentVolumeClaim
来调度 Pod 并访问用户声明的 PV。
####2.2.4. 回收
PV的回收策略可以设定PVC在释放后如何处理对应的Volume,目前有 Retained
, Recycled
和Deleted
三种策略。
1、保留(Retain)
保留策略允许手动回收资源,当删除PVC的时候,PV仍然存在,可以通过以下步骤回收卷:
- 删除PV
- 手动清理外部存储的数据资源
- 手动删除或重新使用关联的存储资产
2、回收(Resycle)
该策略已废弃,推荐使用dynamic provisioning
回收策略会在 volume上执行基本擦除(rm -rf / thevolume / *
),可被再次声明使用。
3、删除(Delete)
删除策略,当发生删除操作的时候,会从k8s集群中删除PV对象,并执行外部存储资源的删除操作(根据不同的provisioner定义的删除逻辑不同,有的是重命名)。
动态配置的卷继承其StorageClass
的回收策略,默认为Delete,即当用户删除PVC的时候,会自动执行PV的删除策略。
如果要修改PV的回收策略,可执行以下命令:
# Get pv
kubectl get pv
# Change policy to Retaion
kubectl patch pv <pv_name> -p ‘{“spec”:{“persistentVolumeReclaimPolicy”:“Retain”}}’
###2.3. PV的类型
PersistentVolume
类型以插件形式实现。以下仅列部分常用类型:
-
GCEPersistentDisk
-
AWSElasticBlockStore
-
NFS
-
RBD (Ceph Block Device)
-
CephFS
-
Glusterfs
###2.4. PV的属性
每个PV
配置中都包含一个 sepc
规格字段和一个 status
卷状态字段。
apiVersion: v1
kind: PersistentVolume
metadata:
annotations:
pv.kubernetes.io/provisioned-by: fuseim.pri/ifs
creationTimestamp: 2018-07-12T06:46:48Z
name: default-test-web-0-pvc-58cf5ec1-859f-11e8-bb61-005056b83985
resourceVersion: "100163256"
selfLink: /api/v1/persistentvolumes/default-test-web-0-pvc-58cf5ec1-859f-11e8-bb61-005056b83985
uid: 59796ba3-859f-11e8-9c50-c81f66bcff65
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 2Gi
volumeMode: Filesystem
claimRef:
apiVersion: v1
kind: PersistentVolumeClaim
name: test-web-0
namespace: default
resourceVersion: "100163248"
uid: 58cf5ec1-859f-11e8-bb61-005056b83985
nfs:
path: /data/nfs-storage/default-test-web-0-pvc-58cf5ec1-859f-11e8-bb61-005056b83985
server: 172.16.201.54
persistentVolumeReclaimPolicy: Delete
storageClassName: managed-nfs-storage
mountOptions:
- hard
- nfsvers=4.1
status:
phase: Bound
####2.4.1. Capacity
给PV设置特定的存储容量
,更多 capacity
可参考Kubernetes 资源模型 。
####2.4.2. Volume Mode
volumeMode
的有效值可以是Filesystem
或Block
。如果未指定,volumeMode 将默认为Filesystem
。
####2.4.3. Access Modes
访问模式包括:
ReadWriteOnce
——该卷可以被单个节点以读/写模式挂载ReadOnlyMany
——该卷可以被多个节点以只读模式挂载ReadWriteMany
——该卷可以被多个节点以读/写模式挂载
在命令行中,访问模式缩写为:
- RWO - ReadWriteOnce
- ROX - ReadOnlyMany
- RWX - ReadWriteMany
一个卷一次只能使用一种访问模式挂载,即使它支持很多访问模式。
以下只列举部分常用插件:
Volume 插件 | ReadWriteOnce | ReadOnlyMany | ReadWriteMany |
---|---|---|---|
AWSElasticBlockStore | ✓ | - | - |
CephFS | ✓ | ✓ | ✓ |
GCEPersistentDisk | ✓ | ✓ | - |
Glusterfs | ✓ | ✓ | ✓ |
HostPath | ✓ | - | - |
NFS | ✓ | ✓ | ✓ |
RBD | ✓ | ✓ | - |
… |
####2.4.4. Class
PV
可以指定一个StorageClass
来动态绑定PV和PVC,其中通过 storageClassName
属性来指定具体的StorageClass
,如果没有指定该属性的PV,它只能绑定到不需要特定类的 PVC。
####2.4.5. Reclaim Policy
回收策略包括:
Retain
(保留)——手动回收Recycle
(回收)——基本擦除(rm -rf /thevolume/*
)Delete
(删除)——关联的存储资产(例如 AWS EBS、GCE PD、Azure Disk 和 OpenStack Cinder 卷)将被删除
当前,只有 NFS 和 HostPath 支持回收策略。AWS EBS、GCE PD、Azure Disk 和 Cinder 卷支持删除策略。
####2.4.6. Mount Options
Kubernetes 管理员可以指定在节点上为挂载持久卷指定挂载选项。
注意:不是所有的持久化卷类型都支持挂载选项。
支持挂载选项常用的类型有:
- GCEPersistentDisk
- AWSElasticBlockStore
- AzureFile
- AzureDisk
- NFS
- RBD (Ceph Block Device)
- CephFS
- Cinder (OpenStack 卷存储)
- Glusterfs
####2.4.7. Phase
PV可以处于以下的某种状态:
Available
(可用)——一块空闲资源还没有被任何声明绑定Bound
(已绑定)——卷已经被声明绑定Released
(已释放)——声明被删除,但是资源还未被集群重新声明Failed
(失败)——该卷的自动回收失败
命令行会显示绑定到 PV 的 PVC 的名称。
##3. PersistentVolumeClaim
###3.1. PVC概述
PersistentVolumeClaim
(简称PVC)是用户存储的请求,PVC消耗PV的资源,可以请求特定的大小和访问模式,需要指定归属于某个Namespace,在同一个Namespace的Pod才可以指定对应的PVC。
当需要不同性质的PV来满足存储需求时,可以使用StorageClass
来实现。
每个 PVC 中都包含一个 spec 规格字段和一个 status 声明状态字段。
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 8Gi
storageClassName: slow
selector:
matchLabels:
release: "stable"
matchExpressions:
- {key: environment, operator: In, values: [dev]}
###3.1. PVC的属性
####3.1.1. accessModes
对应存储的访问模式,例如:ReadWriteOnce
。
####3.1.2. volumeMode
对应存储的数据卷模式,例如:Filesystem
。
####3.1.3. resources
声明可以请求特定数量的资源。相同的资源模型适用于Volume和PVC。
####3.1.4. selector
声明label selector
,只有标签与选择器匹配的卷可以绑定到声明。
- matchLabels:volume 必须有具有该值的标签
- matchExpressions:条件列表,通过条件表达式筛选匹配的卷。有效的运算符包括 In、NotIn、Exists 和 DoesNotExist。
####3.1.5. storageClassName
通过storageClassName
参数来指定使用对应名字的StorageClass
,只有所请求的类与 PVC 具有相同 storageClassName
的 PV 才能绑定到 PVC。
PVC可以不指定storageClassName,或者将该值设置为空,如果打开了准入控制插件,并且指定一个默认的 StorageClass
,则PVC会使用默认的StorageClass
,否则就绑定到没有StorageClass
的 PV上。
之前使用注解
volume.beta.kubernetes.io/storage-class
而不是storageClassName
属性。这个注解仍然有效,但是在未来的 Kubernetes 版本中不会支持。
###3.2. 将PVC作为Volume
将PVC作为Pod的Volume,PVC与Pod需要在同一个命名空间下,其实Pod的声明如下:
kind: Pod
apiVersion: v1
metadata:
name: mypod
spec:
containers:
- name: myfrontend image: dockerfile/nginx
volumeMounts:
- mountPath: "/var/www/html" name: mypd
volumes:
- name: mypd persistentVolumeClaim: # 使用PVC
claimName: myclaim
PersistentVolumes
绑定是唯一的,并且由于 PersistentVolumeClaims
是命名空间对象,因此只能在一个命名空间内挂载具有“多个”模式(ROX
、RWX
)的PVC。
##4. StorageClass
###4.1. StorageClass概述
StorageClass
提供了一种描述存储类
(class)的方法,不同的class可能会映射到不同的服务质量等级和备份策略或其他策略等。
StorageClass
对象中包含 provisioner
、parameters
和 reclaimPolicy
字段,当需要动态分配 PersistentVolume
时会使用到。当创建 StorageClass
对象时,设置名称和其他参数,一旦创建了对象就不能再对其更新。也可以为没有申请绑定到特定 class 的 PVC 指定一个默认的 StorageClass
。
StorageClass对象文件
kind: StorageClass
apiVersion: storage.k8s.io/v3
metadata:
name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
reclaimPolicy: Retain
mountOptions:
- debug
###4.2. StorageClass的属性
####4.2.1. Provisioner(存储分配器)
Storage class 有一个分配器(provisioner)
,用来决定使用哪个卷插件分配 PV,该字段必须指定。可以指定内部分配器,也可以指定外部分配器。外部分配器的代码地址为: kubernetes-incubator/external-storage,其中包括NFS
和Ceph
等。
####4.2.2. Reclaim Policy(回收策略)
可以通过reclaimPolicy
字段指定创建的Persistent Volume
的回收策略,回收策略包括:Delete
或者 Retain
,没有指定默认为Delete
。
####4.2.3. Mount Options(挂载选项)
由 storage class 动态创建的 Persistent Volume 将使用 class 中 mountOptions
字段指定的挂载选项。
####4.2.4. 参数
Storage class 具有描述属于 storage class 卷的参数。取决于分配器
,可以接受不同的参数。 当参数被省略时,会使用默认值。
例如以下使用Ceph RBD
kind: StorageClass
apiVersion: storage.k8s.io/v3
metadata:
name: fast
provisioner: kubernetes.io/rbd
parameters:
monitors: 30.36.353.305:6789
adminId: kube
adminSecretName: ceph-secret
adminSecretNamespace: kube-system
pool: kube
userId: kube
userSecretName: ceph-secret-user
fsType: ext4
imageFormat: "2"
imageFeatures: "layering"
对应的参数说明
-
monitors
:Ceph monitor,逗号分隔。该参数是必需的。 -
adminId
:Ceph 客户端 ID,用于在池(ceph pool)中创建映像。 默认是 “admin”。 -
adminSecretNamespace
:adminSecret 的 namespace。默认是 “default”。 -
adminSecret
:adminId 的 Secret 名称。该参数是必需的。 提供的 secret 必须有值为 “kubernetes.io/rbd” 的 type 参数。 -
pool
: Ceph RBD 池. 默认是 “rbd”。 -
userId
:Ceph 客户端 ID,用于映射 RBD 镜像(RBD image)。默认与 adminId 相同。 -
userSecretName
:用于映射 RBD 镜像的 userId 的 Ceph Secret 的名字。 它必须与 PVC 存在于相同的 namespace 中。该参数是必需的。 提供的 secret 必须具有值为 “kubernetes.io/rbd” 的 type 参数,例如以这样的方式创建:
kubectl create secret generic ceph-secret --type="kubernetes.io/rbd" \
--from-literal=key='QVFEQ1pMdFhPUnQrSmhBQUFYaERWNHJsZ3BsMmNjcDR6RFZST0E9PQ==' \
--namespace=kube-system
-
fsType
:Kubernetes 支持的 fsType。默认:”ext4”。 -
imageFormat
:Ceph RBD 镜像格式,”1” 或者 “2”。默认值是 “1”。 -
imageFeatures
:这个参数是可选的,只能在你将 imageFormat 设置为 “2” 才使用。 目前支持的功能只是layering
。 默认是 ““,没有功能打开。
##5. Dynamic Volume Provisioning
Dynamic volume provisioning允许用户按需自动创建存储卷,这种方式可以让用户不需要关心存储的复杂性和差别,又可以选择不同的存储类型。
###5.1. 开启Dynamic Provisioning
需要先提前创建StorageClass
对象,StorageClass
中定义了使用哪个provisioner
,并且在provisioner
被调用时传入哪些参数,具体可参考StorageClass
介绍。
例如:
- 磁盘类存储
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: slow
provisioner: kubernetes.io/gce-pd
parameters:
type: pd-standard
- SSD类存储
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast
provisioner: kubernetes.io/gce-pd
parameters:
type: pd-ssd
###5.2. 使用Dynamic Provisioning
创建一个PVC对象,并且在其中storageClassName
字段指明需要用到的StorageClass
的名称,例如:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: claim1
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast
resources:
requests:
storage: 30Gi
当使用到PVC的时候会自动创建对应的外部存储,当PVC被删除的时候,会自动销毁(或备份)外部存储。
###5.3. 默认的StorageClass
当没有对应的StorageClass
配置时,可以设定默认的StorageClass
,需要执行以下操作:
- 在API Server开启 。
- 设置默认的
StorageClass
对象。
可以通过添加storageclass.kubernetes.io/is-default-class
注解的方式设置某个StorageClass
为默认的StorageClass
。当用户创建了一个PersistentVolumeClaim
,但没有指定storageClassName
的时候,会自动将该PVC的storageClassName
指向默认的StorageClass
。
参考文章:
- https://kubernetes.io/docs/concepts/storage/volumes/
- https://kubernetes.io/docs/concepts/storage/persistent-volumes/
- https://kubernetes.io/docs/concepts/storage/storage-classes/
- https://kubernetes.io/docs/concepts/storage/dynamic-provisioning/
- https://kubernetes.io/docs/tasks/administer-cluster/change-pv-reclaim-policy/