我又来更新文章啦,k8s的东西还是非常有意思的,每个点都值得深入研究啊。
今天要说的是kubernetes storage的问题,即kubernetes支持的后端存储卷(Volume)。在容器集群时代之后,kubernetes按照时间顺序先后提供了emptyDir、hostPath、localVolume 三种本地磁盘存储卷解决方案。
emptyDir、hostPath都是kubernetes很早就实现和支持了的技术,local Volume方式则是k8s v1.7才刚刚发布的alpha版本,目前在k8s v1.10中发布了local volume的beta版本。
- 三种存储特点
存储类型 | 特点 | 使用场景 |
---|---|---|
emptyDir |
emptyDir类型的volume在Pod分配到Node上时被创建,kubernetes会在Node上自动分配一个目录,因此无需指定宿主机Node上对应的目录文件。这个目录的初始内容为空,当pod从Node上移除时,emptyDir中的数据会被永久删除。 |
临时空间,当pod从Node上移除时,emptyDir的数据h会被永久删除。 |
hostPath | hostPath类型是映射node文件系统中的文件或者目录到pod里。 配置相同的pod,可能在不同的node上表现不同,因为不同节点上映射的文件内容不同。 |
pv/pvc/StorageClass的方法实现。 这种使用的场景是: hostpath是单节点的本地存储方案,不提供任何基于node节点亲和性的pod调度管理支持。 |
localVolume | local volume 允许用户通过标准pvc接口以简单且可移植的方式访问node节点的本地存储。 PV的定义中需要包含描述节点亲和性的信息,k8s系统则使用该信息将容器调度到正确的pod节点。 |
pv/pvc/StorageClass的方法实现 适用于小规模、多节点的k8s开发或测试环境,尤其是在不具备一套安全、可靠且性能有保障的存储集群时。 |
近期在物理机上部署了一套k8s集群,简单部署了一个nfs-server想用于NFS的存储实现,但是无奈性能太差。见下图:
168MB/s VS 1.1GB/s ,性能确实下降的厉害。
另外我们也不具备分布式存储的条件,故采用localVolume的方式来解决存储的问题。
回到需求本身,我们物理机环境下,为什么还有这种storage的需求,其实就是有一些服务需要存储有状态的数据。正常情况下,k8s物理机环境跑一些无状态的服务简直再好不过,理由如下:
1、可用于快速迭代开发,一个apply 命令搞定上线;
2、集群自带的故障切换能力;
3、公司内平台级的产品,技术沉淀;
(后面会专门做一个系列,如何利用ingress快速实现无状态服务的部署)
用 localVolume 来搞定PV/PVC的问题:
- localVolume项目地址: https://github.com/kubernetes-incubator/external-storage/tree/master/local-volume
- step1:创建一个pv:
apiVersion: v1
kind: PersistentVolume
metadata:
name: example-pv
spec:
capacity:
storage: 300Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /data5
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- cnbj-y2051
字段解释:
-- nodeAffinity字段是必须配置的,k8s依赖于这个标签为你定义的Pods在正确的nodes节点上找到需要使用的local volumes。values字段需要指定node节点主机名;
-- 使用volumeMode字段时,需要启用BlockVolume 这一Alpha feature特性;
-- volumeMode字段的默认值是Filesystem,但也支持配置为Block,这样就会把node节点的local volume作为容器的一个裸块设备挂载使用。step2:创建一个 local persistent volume claim(pvc):
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: example-local-claim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi
storageClassName: local-storage
storageClassName必须是pv的字段对应上。
kubectl describe pvc [pvcname] //可以查看到pvc这个时候的状态pending.
A cluster administrator can address this issue by specifying the WaitForFirstConsumer mode which will delay the binding and provisioning of a PersistentVolume until a Pod using the PersistentVolumeClaim is created. https://kubernetes.io/docs/concepts/storage/storage-classes/
- step3:创建一个测试Pod并引用上面创建的PVC:
apiVersion: v1
kind: Pod
metadata:
name: local-pvc-pod
spec:
containers:
- image: busybox
name: test-local-pvc
command: [ "sleep", "3600" ]
volumeMounts:
- mountPath: /data
name: data-volume
volumes:
- name: data-volume
persistentVolumeClaim:
claimName: example-local-claim
apply上面的配置之后,pod创建成功,查看pod:
root@cnbj-y2051:/etc/kubernetes/test_pv/success# kubectl describe pod local-pvc-pod
Name: local-pvc-pod
Namespace: default
Priority: 0
PriorityClassName: <none>
Node: cnbj-y2051/192.168.5.11
Start Time: Thu, 24 Jan 2019 10:10:42 +0800
Labels: <none>
Annotations: cni.projectcalico.org/podIP: 192.168.0.21/32
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"local-pvc-pod","namespace":"default"},"spec":{"containers":[{"command...
Status: Running
IP: 192.168.0.21
Containers:
test-local-pvc:
Container ID: docker://7104b3c3fee83efba89fa599534cbfd491d197a12cb3f81fb6b3baf5305b8d36
Image: busybox
Image ID: docker-pullable://busybox@sha256:7964ad52e396a6e045c39b5a44438424ac52e12e4d5a25d94895f2058cb863a0
Port: <none>
Host Port: <none>
Command:
sleep
3600
State: Running
Started: Thu, 24 Jan 2019 10:10:45 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/data from data-volume (rw)
/var/run/secrets/kubernetes.io/serviceaccount from default-token-swckb (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
data-volume:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: example-local-claim
ReadOnly: false
default-token-swckb:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-swckb
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 16s default-scheduler Successfully assigned default/local-pvc-pod to cnbj-y2051
Normal Pulling 15s kubelet, cnbj-y2051 pulling image "busybox"
Normal Pulled 13s kubelet, cnbj-y2051 Successfully pulled image "busybox"
Normal Created 13s kubelet, cnbj-y2051 Created container
Normal Started 13s kubelet, cnbj-y2051 Started container
以上,完成localVolume PV/PVC的实现。