kubernetes的数据管理
kubernetes管理储存资源-------volume
我们经常说:容器和pod是短暂的,其含义是他们的生命周期可能很短,会被频繁的销毁和创建。容器销毁时,保存在容器内部文件中的数据都会被清除。
为了持久化保存容器的数据,可以使用kubernetes volume。
volume的生命期独立于容器,pod中的容器可能被销毁和重建,但volume会被保留。
本质上, Kubernetes Volume是一个目录,这一点与Docker Volume类似。当Volume被mount到Pod, Pod中的所有容器都可以访问这个Volume, Kubernetes Volume也支持多种backend类型,包括emptyDirhostPath, GCE Persistent Disk, AWS Elastic Block Store, NFS, Ceph等,完整列表可参考https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes
Volume提供了对各种backend的抽象,容器在使用Volume读写数据的时候不需要关心数据到底是存放在本地节点的文件系统中呢还是云硬盘上。对它来说,所有类型的Volume都只是一个目录。
emptydir
emptydir
emptydir是最基础的volume类型。一个emptydir volume是host上的一个空目录。
emptydir volume对于容器来说都是持久的,对于pod则不是,当pod从节点删除时,volume的内容也会被删除。但如果只是容器被销毁而pod还在,则volume不受影响。也就是说: emptydir volume的生命周期与pod一致。
案例:
[root@master de]# cat producer-consumer.yml apiVersion: v1 kind: Pod metadata: name: producer-consumer spec: containers: - image: busybox name: producer volumeMounts: - mountPath: /producer_dir name: shared-volume args: - /bin/sh - -c - echo "hello world" > /producer_dir/hello; sleep 30000 - image: busybox name: consumer volumeMounts: - mountPath: /consumer_dir name: shared-volume args: - /bin/sh - -c - cat /consumer_dir/hello ; sleep 3000 volumes: - name: shared-volume emptyDir: {}
这里我们模拟了一个producer-consumer场景。Pod有两个容器producer和consumer ,它们共享一个Volume, producer负责往Volume中写数据, consumer则是从Volume读取数据。
1:文件最底部volumes定义了一个emptyDir类型的Volume shared-volume
2 :producer容器将shared-volume mount到/producer_dir目录。
3 producer通过echo将数据写到文件hello里。
4: consumer容器将shared-volume mount到/consumer_dir目录。
5 consumer通过cat从文件hello读数据。
验证结果:
[root@master de]# kubectl logs producer-consumer producer [root@master de]# kubectl get pod NAME READY STATUS RESTARTS AGE producer-consumer 2/2 Running 0 7m59s
[root@master de]# kubectl logs producer-consumer consumer
hello world
kubectl logs 显示容器consumer 成功读到了 producer 写入的数据,验证两个容器共享emptydir volume
因为emptydir是docker host 文件系统里的目录,其效果相当于执行了 docker run -v /producer_dir和 docker run -v /consumer_dir 。通过docker_inspect 查看容器的详细配置信息,我们发现两个容器都mount到一个目录:
[root@node1 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5a766d5d38b1 busybox "/bin/sh -c 'cat /co…" 27 minutes ago Up 27 minutes k8s_consumer_producer-consumer_default_cec3012a-5ecf-450f-afa6-33e0a797bd5f_0 d6ed136d6ae8 busybox "/bin/sh -c 'echo "h…" 27 minutes ago Up 27 minutes k8s_producer_producer-consumer_default_cec3012a-5ecf-450f-afa6-33e0a797bd5f_0
[root@node1 ~]# docker inspect d6ed136 "Mounts": [ { "Type": "bind", "Source": "/var/lib/kubelet/pods/cec3012a-5ecf-450f-afa6-33e0a797bd5f/volumes/kubernetes.io~empty-dir/shared-volume", "Destination": "/producer_dir", "Mode": "", "RW": true, "Propagation": "rprivate" }, { ------------------------------------------------------------------------- "Mounts": [ { "Type": "bind", "Source": "/var/lib/kubelet/pods/cec3012a-5ecf-450f-afa6-33e0a797bd5f/volumes/kubernetes.io~empty-dir/shared-volume", "Destination": "/consumer_dir", "Mode": "", "RW": true, "Propagation": "rprivate" }, {
emptydir是host上创建的临时目录,其优点是能够方便地为pod中的容器提供共享存储,不需要额外的配置,但他不具备持久性,如果pod不存在了,emptydir也没有了。
hostPath volume
hostpath volume的作用是将docker host文件系统中已经存在的目录mount给pod的容器。大部分应用都不会使用hostPath volume,因为这实际上增加了pod与节点的耦合,限制了pod的使用。不过那些需要访问kubernetes或docker内部数据。
比如kube-apiserver和kube-controller-manager就是这样应用,通过:
[root@master de]# kubectl edit pod --namespace=kube-system kube-apiserver-master volumeMounts: - mountPath: /etc/ssl/certs name: ca-certs readOnly: true - mountPath: /etc/pki name: etc-pki readOnly: true - mountPath: /etc/kubernetes/pki name: k8s-certs readOnly: true dnsPolicy: ClusterFirst enableServiceLinks: true hostNetwork: true nodeName: master priority: 2000000000 priorityClassName: system-cluster-critical restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 tolerations: - effect: NoExecute operator: Exists volumes: - hostPath: path: /etc/ssl/certs type: DirectoryOrCreate name: ca-certs - hostPath: path: /etc/pki type: DirectoryOrCreate name: etc-pki - hostPath: path: /etc/kubernetes/pki type: DirectoryOrCreate name: k8s-certs
外部storageprovider
如cephglusterfs独立于kubernetes集群的就算集群瘫痪了数据也不会丢失
PV(persistentVolume)和PVC(persistentVolumeClaim):
Pv是外部存储系统的一块存储空间,具有持久性,生命周期独立于pod
Pvc是对pv的申请,用户创建pvc时,指明存储资源的大小和访问模式等信息,
kubernetes会查找符合条件的pv
Kubernetes支持多中persistentVolume:NFSCephEBS等
在创建pv和pvc之前,先搭建一个NFS。
Nfs192.168.172.137
所有节点都安装:
yum -y install rpcbindnfs-utils
在nfs节点上:
[root@localhost~]#vim /etc/exports /volume*(rw,sync,no_root_squash)
创键这个目录:
[root@localhost~]#mkdir/volume
启动服务:所有节点
systemctlstartrpcbind&&systemctlenablerpcbind
在nfs节点:
[root@localhost~]#systemctl start nfs-server.service && systemctl enable
nfs-server.service
关闭防火墙和selinux:
[root@localhost~]#setenforce0
[root@localhost~]#systemctl stop firewalld
除了nfs节点随便找一个节点测试一下可以访问nfs节点的目录:
[root@masteremptydir]#showmount-e 192.168.172.137 Exportlistfor192.168.172.137: /volume*
创键pv:
[root@masteremptydir]#cd.. [root@master]#mkdirpv-pvs [root@master]#cdpv-pvs/ [root@masterpv-pvs]#vimmypv.yml apiVersion:v1 kind:PersistentVolume metadata: name:mypv spec: capacity: storage:1Gi accessModes: -ReadWriteOnce persistentVolumeReclaimPolicy:Recycle storageClassName:nfs nfs: path:/volume/mypv server:192.168.172.137
kind:PersistentVolume 类型是pv
capacity:
storage:1Gi 指定pv的容量
accessModes:
-ReadWriteOnce 指定访问的模式读写模式mount到单个节点
ReadWriteMany 读写模式mount到多个节点
ReadOnlyMany 只读的模式mount到多个节点
persistentVolumeReclaimPolicy:Recycle 指定pv的回收策略
Recycle 删除pv中的数据Retain需要手动清除数据
Delete 删除storageprovider上对应的存储资源
storageClassName:nfs 指定pv的classpvc可以指定class中的pv
path:/volume/mypv 需要手动在nfs节点上创建不然会报错
运行文件:
[root@masterpv-pvs]#kubectl apply-fmypv.yml
persistent volume/mypv created
查看:
[root@masterpv-pvs]#kubectl get pv
NAMECAPACITYACCESSMODESRECLAIMPOLICYSTATUSCLAIM
STORAGECLASSREASONAGE
mypv1GiRWORecycleAvailable
nfs14s
创建pvc:
apiVersion:v1 kind:PersistentVolumeClaim metadata: name:mypvc spec: accessModes: -ReadWriteOnce resources: requests: storage:1Gi
storageClassName:nfs
指定资源类型,访问模式,容量大小,指定class
运行文件:
[root@masterpv-pvs]#kubectl apply-fmypvc.yml
persistentvolumeclaim/mypvccreated
查看:
[root@masterpv-pvs]#kubectlgetpvc
NAMESTATUSVOLUMECAPACITYACCESSMODESSTORAGECLASS
AGE
mypvcBoundmypv1GiRWOnfs
14s
在查看一下pv:
[root@masterpv-pvs]#kubectlgetpv
NAMECAPACITYACCESSMODESRECLAIMPOLICYSTATUSCLAIM
STORAGECLASSREASONAGE
mypv1GiRWORecycleBound
default/mypvcnfs4m22s
可以看到pvc已经成功bound到pv上了之前没创建pvc时pv的状态为
Available
创建一个pod,使用这个存储:
[root@masterpv-pvs]#vimpod.yml
apiVersion:v1
kind:Pod
metadata:
name:mypod
spec:
containers:
-image:busybox
name:test
args:
-/bin/sh
--c
-sleep300000000000
volumeMounts:
-mountPath:/aaaa
name:myvolu
volumes:
-name:myvolu
persistentVolumeClaim:
claimName:mypvc
运行文件:
[root@masterpv-pvs]#kubectlapply-fpod.yml
pod/mypodcreated
查看:
[root@masterpv-pvs]#kubectlgetpod
NAMEREADYSTATUSRESTARTSAGE
mypod1/1Running038s
测试创建一个文件试一下:
[root@masterpv-pvs]#kubectlexecmypodtouch/aaaa/hello
在nfs节点的目录查看:
[root@localhost~]#cd/volume/mypv/
[root@localhostmypv]#ls
hello
可以看到已经保存到nfs节点的/volume/mypv/下了
回收pv(删除pvc):
先删除pod:
[root@masterpv-pvs]#kubectldeletepodmypod
pod"mypod"deleted
删除pvc:
[root@masterpv-pvs]#kubectldeletepvcmypvc
persistentvolumeclaim"mypvc"deleted
查看一下pv的状态:
[root@masterpv-pvs]#kubectlgetpv
NAMECAPACITYACCESSMODESRECLAIMPOLICYSTATUSCLAIM
STORAGECLASSREASONAGE
mypv1GiRWORecycleAvailable
nfs16m
可以看到状态又变为Available了
到nfs节点查看还有数据么:
[root@localhostmypv]#ls可以看到数据已经没了
数据被清除是因为pv的回收策略是recycle所以数据被删除了
要想不被删除需要改成retain
[root@masterpv-pvs]#vimmypv.yml
执行文件
查看一下更新后的pv:
[root@masterpv-pvs]#kubectlgetpv
NAMECAPACITYACCESSMODESRECLAIMPOLICYSTATUSCLAIM
STORAGECLASSREASONAGE
mypv1GiRWORetainAvailable
nfs20m
再次创建pvc和pod:
[root@masterpv-pvs]#kubectlapply-fmypvc.yml
[root@masterpv-pvs]#kubectlapply-fpod.yml
查看一下这两个的状态确保开启了
创建一个文件:
[root@masterpv-pvs]#kubectlexecmypodtouch/aaaa/hello
再次删除pod和pvc:
[root@masterpv-pvs]#kubectldeletepodmypod
pod"mypod"deleted
[root@masterpv-pvs]#kubectldeletepvcmypvc
persistentvolumeclaim"mypvc"deleted
查看一下pv的状态:
[root@masterpv-pvs]#kubectlgetpv
NAMECAPACITYACCESSMODESRECLAIMPOLICYSTATUSCLAIM
STORAGECLASSREASONAGE
mypv1GiRWORetainReleased
default/mypvcnfs25m
状态变为了Released会一直保持这个状态,不能被其他pvc申请,可以删除pv,
存储空间中的数据不会被删除
删除pv:
[root@masterpv-pvs]#kubectldeletepvmypv
persistentvolume"mypv"deleted
在nfs节点查看数据是否保存下来了:
[root@localhostmypv]#ls
hello
Pv的动态供给:
没有满足pvc的条件会自动创建pv,是通过storageclass实现的
MYSQL使用pv,pvc:
创建pv,pvc:
[root@master]#mkdirmysql
[root@master]#cdmysql/
[root@mastermysql]#vimmysql-pv.yml
apiVersion:v1
kind:PersistentVolume
metadata:
name:mysql-pv
spec:
accessModes:
-ReadWriteOnce
capacity:
storage:1Gi
persistentVolumeReclaimPolicy:Retain
storageClassName:nfs
nfs:
path:/volume/mysql-pv
server:192.168.172.137
path:/volume/mysql-pv需要提前在nfs节点创建出来
Pvc:
[root@mastermysql]#vimmysql-pvc.yml
apiVersion:v1
kind:PersistentVolumeClaim
metadata:
name:mysql-pvc
spec:
accessModes:
-ReadWriteOnce
resources:
requests:
storage:1Gi
storageClassName:nfs
运行文件并查看:
[root@mastermysql]#kubectlapply-fmysql-pv.yml
[root@mastermysql]#kubectlgetpv
NAMECAPACITYACCESSMODESRECLAIMPOLICYSTATUS
CLAIMSTORAGECLASSREASONAGE
mysql-pv1GiRWORetainAvailable
nfs45s
[root@mastermysql]#kubectlapply-fmysql-pvc.yml
[root@mastermysql]#kubectlgetpvc
NAMESTATUSVOLUMECAPACITYACCESSMODES
STORAGECLASSAGE
mysql-pvcBoundmysql-pv1GiRWOnfs
5s
创建MYSQL:
[root@mastermysql]#vimmysql.yml
apiVersion:apps/v1
kind:Deployment
metadata:
name:mysql
labels:
app:mysql
spec:
selector:
matchLabels:
app:mysql
template:
metadata:
labels:
app:mysql
spec:
containers:
-image:mysql:5.7
name:mysql
env:
-name:MYSQL_ROOT_PASSWORD
value:password
ports:
-containerPort:3306
name:mysql
volumeMounts:
-name:mysql-volume
mountPath:/var/lib/mysql
volumes:
-name:mysql-volume
persistentVolumeClaim:
claimName:mysql-pvc
---
apiVersion:v1
kind:Service
metadata:
labels:
app:mysql
name:mysql
spec:
ports:
-protocol:TCP
port:3306
targetPort:3306
selector:
app:mysql
执行文件
进入mysql:
[root@mastermysql]#kubectlrun-it--rm--image=mysql:5.7
--restart=Nevermysql-client--mysql-hmysql-ppassword
回车一下
进入数据库创建库,表,插入数据
mysql>createdatabaseaaa;
QueryOK,1rowaffected(0.00sec)
mysql>useaaa;
Databasechanged
mysql>createtabletest(idint,namevarchar(20));
QueryOK,0rowsaffected(0.03sec)
mysql>insertintotestvalues(1,"aa");
QueryOK,1rowaffected(0.03sec)
mysql>insertintotestvalues(2,"bb");
QueryOK,1rowaffected(0.00sec)
mysql>insertintotestvalues(3,"cc"),(4,"dd");
mysql>select*fromtest;
+------+------+
|id|name|
+------+------+
|1|aa|
|2|bb|
|3|cc|
|4|dd|
+------+------+
退出
查看pod:
[root@mastermysql]#kubectlgetpod-owide
NAMEREADYSTATUSRESTARTSAGEIP
NODENOMINATEDNODEREADINESSGATES
mysql-7774bd7c76-5sk2l1/1Running06m33s
10.244.1.90k8snode2<none><none>
可以看到pod在node2上关闭node2模拟故障
等待一段时间会发现mysql服务转移到node1上了
[root@mastermysql]#kubectlgetpod-owide
NAMEREADYSTATUSRESTARTSAGEIP
NODENOMINATEDNODEREADINESSGATES
mysql-7774bd7c76-5sk2l1/1Terminating014m
10.244.1.90k8snode2<none><none>
mysql-7774bd7c76-6w49h1/1Running073s
10.244.2.83k8snode1<none><none>
登陆mysql,验证数据:
[root@mastermysql]#kubectlrun-it--rm--image=mysql:5.7
--restart=Nevermysql-client--mysql-hmysql-ppassword
mysql>showdatabases;
+--------------------+
|Database|
+--------------------+
|information_schema|
|aaa|
|mysql|
|performance_schema|
|sys|
+--------------------+
5rowsinset(0.01sec)
mysql>useaaa;
mysql>showtables;
+---------------+
|Tables_in_aaa|
+---------------+
|test|
+---------------+
1rowinset(0.00sec)
mysql>select*fromtest;
+------+------+
|id|name|
+------+------+
|1|aa|
|2|bb|
|3|cc|
|4|dd|
+------+------+
4rowsinset(0.00sec)
可以看到数据没有丢失