为了防止pod在删除后不让数据的丢失,需要对数据做持久化操作

EmptyDir

EmptyDir是一个空目录,他的生命周期和所属的 Pod 是完全一致的,EmptyDir主要作用可以在同一 Pod 内的不同容器之间共享工作过程中产生的文件。如果Pod配置了emptyDir类型Volume, Pod 被分配到Node上时候,会创建emptyDir,只要Pod运行在Node上,emptyDir都会存在(容器挂掉不会导致emptyDir丢失数据),但是如果Pod从Node上被删除(Pod被删除,或者Pod发生迁移),emptyDir也会被删除,并且永久丢失

  1. #emptyDir模板
  2. vim nginx_busybox_emptyDir.yaml
  3. apiVersion: v1
  4. kind: Pod
  5. metadata:
  6. name: nginx-emptydir
  7. namespace: default
  8. labels:
  9. app: nginx
  10. release: web
  11. spec:
  12. containers:
  13. - name: web
  14. image: ikubernetes/myapp:v1
  15. imagePullPolicy: IfNotPresent
  16. ports:
  17. - name: http
  18. containerPort: 80
  19. volumeMounts:
  20. - name: webpage
  21. mountPath: /usr/share/nginx/html/
  22. - name: busybox
  23. image: busybox:latest
  24. imagePullPolicy: IfNotPresent
  25. volumeMounts:
  26. - name: webpage
  27. mountPath: /data/
  28. command: ["/bin/sh","-c","while true;do echo $(date) >> /data/index.html;sleep 3;done"]
  29. volumes:
  30. - name: webpage
  31. emptyDir: {}

HostPath

Hostpath会把宿主机上的指定卷加载到容器之中,如果 Pod 发生跨主机的重建,其内容就难保证了。这种卷一般和DaemonSet搭配使用。hostPath允许挂载Node上的文件系统到Pod里面去。如果Pod有需要使用Node上的东西,可以使用hostPath,不过不过建议使用,因为理论上Pod不应该感知Node的。

#hostpath共享模板
apiVersion: v1
kind: Pod
metadata:
   name: nginx-hostpath-vol
   namespace: default
spec:
  containers:
  - name: nginx-hostpath-vol
    image: ikubernetes/myapp:v1
    volumeMounts:
    - name: hostpath
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: hostpath
    hostPath:
      path: /data/hostpath/
      type: DirectoryOrCreate
----------------------------------------------
#type类型有以下几种
#DirectoryOrCreate 目录不存在就创建
#Directory 目录必须存在
#FileOrCreate 文件不存在不创建
#File 文件必须存在
#Socket socket类型的文件
#CharDevice 字符类型的文件
#BlockDevice 块类型的文件

emptyDir和hostPat很多场景是无法满足持久化需求,因为在Pod发生迁移的时候,数据都无法进行转移的,这就需要分布式文件系统的支持。

Nfs存储方案

NFS 是Network File System的缩写,即网络文件系统。Kubernetes中通过简单地配置就可以挂载NFS到Pod中,而NFS中的数据是可以永久保存的,同时NFS支持同时写操作。

# yum -y install nfs-utilsvol{0...03
#mkdir /data/wd/vol{01..03} -p
#vim /etc/exports/
/data/wd 10.0.0.0/16(rw,no_root_squash)
cat > /data/wd/index.html << EOF
<h1>NFS server!</h1>
EOF

使用pod直接挂载nfs

要保证集群内所有的node节点都可以挂载nfs

#nfs共享模板
apiVersion: v1
kind: Pod
metadata:
   name: nginx-nfs-vol
   namespace: default
spec:
  containers:
  - name: nginx-nfs-vol
    image: ikubernetes/myapp:v1
    volumeMounts:
    - name: nfs
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: nfs
    nfs:
      path: /data/wd/
      server: nfs     #服务器的名称或ip地址

使用PV和PVC

在实际的使用中,我们通常会将各存储划分成PV,然后和PVC绑定给pod使用。
PV:PersistentVolume
PVC:PersistentVolumeClaim

PV和PVC的生命周期:
供应准备:通过集群外的存储系统或者公有云存储方案来提供存储持久化支持。
静态提供:管理员手动创建多个PV,供PVC使用。
动态提供:动态创建PVC特定的PV,并绑定。

绑定:用户创建pvc并指定需要的资源和访问模式。在找到可用pv之前,pvc会保持未绑定状态。

使用:用户可在pod中像使用volume一样使用pvc。

释放:用户删除pvc来回收存储资源,pv将变成“released”状态。由于还保留着之前的数据,这些数据需要根据不
同的策略来处理,否则这些存储资源无法被其他pvc使用。

回收(Reclaiming):pv可以设置三种回收策略:保留(Retain),回收(Recycle)和删除(Delete)
保留策略:允许人工处理保留的数据。(默认)
删除策略:将删除pv和外部关联的存储资源,需要插件支持。
回收策略:将执行清除操作,之后可以被新的pvc使用,需要插件支持。

PV卷阶段状态:
Available – 资源尚未被PVC使用
Bound – 卷已经被绑定到PVC了
Released – PVC被删除,PV卷处于释放状态,但未被集群回收。
Failed – PV卷自动回收失败

创建pv资源,在定义pv时不需要指定名称空间,它属于集群级别的资源,也k8s标准的资源

selector字段

pvc可以使用标签来选择要绑定那种类型的pv(pv也有标签),如果不指定标签,就会找所有的pv然后匹配最适合自己的pv。
pvc和pv是一一对应的,一旦绑定就不会被其它pvc再选重,状态是binding,多个pod可以访问一个pvc(一对多的关系由accessmode来决定)

创建pv资源代码

vim pv.yml
apiVersion: v1
kind: PersistentVolume
metadata:
    name: pv001
    labels:
      name: pv001
spec:
  nfs:
   path: /data/wd/vol1
   server: 10.0.0.70
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 2Gi

accessModes 访问类型

#ReadWriteOnce  单路读写
#ReadOnlyMany   多路只读
#ReadWriteMany  多路读写
#resources  资源的限制,比如至少5G

创建pvc资源代码

#pvc模板
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
    name: pvc-demo
    namespace: default  #一定要和pod在同一个名称空间
spec:
  accessModes: ["ReadWriteMany"]  #这个访问模式一定是pv的子集
  resources:
    requests:
      storage: 6Gi
---
apiVersion: v1
kind: Pod
metadata:
   name: nginx-pvc-vol
   namespace: default
   labels:
     app: nginx-pvc
     release: canary
spec:
  containers:
  - name: nginx-pvc-vol
    image: nginx:1.15-alpine
    volumeMounts:
    - name: pvc
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: pvc
    persistentVolumeClaim:
      claimName: pvc-demo

volumeName 精确匹配

#capacity 限制存储空间大小
#reclaim policy pv的回收策略
#retain  pv被解绑后上面的数据仍保留
#recycle pv上的数据被释放,这个pv这空的
#delete  pvc和pv解绑后pv就被删除
备注:用户在创建pod所需要的存储空间时,前提是必须要有pv存在才可以,这样就不符合自动满足用户的需求,而且之前在k8s 9.0版本还可删除pv,这样造成数据不安全性

创建一个service资源测试

cat > svc.yml <<EOF
apiVersion: v1
kind: Service
metadata:
  name: nginx-pod
spec:
  selector:
    app: nginx-pvc
    release: canary
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
    nodePort: 80
EOF

访问测试

cat > /data/wd/vol03/index.html << EOF
<h1>NFS server!</h1>
EOF
curl 10.0.0.70
#PV的回收策略默认设置为Retain.
虽然pv中的数据得到了保留,但其PV状态会一直处于Released,不能被其他PVC申请。
为了重新使用存储资源,可以删除并重新创建mypv1.删除操作只是删除了PV对象,存储空间中的数据并不会被删除。
kubectl delete pod nginx-pvc-vol
kubectl delete pvc pvc-demo
kubectl apply -f pv.yml
重新加载的pv,状态为Available,已经可以被PVC申请

ConfigMap

configMap也是一种标准的资源,用于动态更新文件信息.

创建一个configmap资源

命令创建:

#创建一个www.conf文件
cat > /data/www.conf <<EOF 
server {
           server_name yy.edu.com;
       listen 80;
       root /data/web/html/;
 }
EOF
kubectl create configmap nginx-configmap --from-file=www.conf=/data/www.conf
#www.conf#是一个键的名称,后面的www.conf是键值

资源清单创建:

cat > configmap.yml <<EOF
apiVersion: v1
data:
  www.conf: |
    server {
           server_name yy.edu.com;
           listen 80;
           root /data/web/html/;
     }
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: nginx-configmap
EOF

创建一个pod和对应的svc资源

cat > configmap-pod-nginx.yaml <<EOF 
apiVersion: v1
kind: Pod
metadata:
    name: configmap-pod
    namespace: default
    labels:
      app: configmap-pod
spec:
   containers:
   - name: configmap-pod
     image: 10.0.0.70:5000/nginx:1.15-alpine 
     imagePullPolicy: IfNotPresent
     ports:
     - name: http
       containerPort: 80
       protocol: TCP
     volumeMounts:
       - name: nginx-configmap
         mountPath: /etc/nginx/conf.d/
         readOnly: true 
   volumes:
   - name: nginx-configmap
     configMap:
        name: nginx-configmap
---
apiVersion: v1
kind: Service
metadata:
    name: configmap-pod-svc
    namespace: default
spec:
  selector:
    app: configmap-pod
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 88
    protocol: TCP
  type: NodePort
EOF

修改configmap的配置文件,检查www.conf中的内容是否是发生变化

kubectl edit cm nginx-configmap
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
  www.conf: "server {\n           server_name yy.edu.com;\n\t   listen 80;\n\t
    \  root /data/web/html/;\n }\n"
kind: ConfigMap
metadata:
  creationTimestamp: "2019-11-25T02:17:09Z"
  name: nginx-configmap
  namespace: default
  resourceVersion: "1140123"
  selfLink: /api/v1/namespaces/default/configmaps/nginx-configmap
  uid: 318aada8-d529-4f6b-a5dd-c70ca9d9ebd3
#修改server_name的值 yy.edu.com为 server_name oldboywd.edu.com
#检查是否修改成功

工作案例:实现mysql数据持久化

创建一个pv资源

cat > mysql_pv.yml << EOF
apiVersion: v1
kind: PersistentVolume
metadata:
    name: pv001
    labels:
      name: pv001
spec:
  nfs:
   path: /data/wd/vol01
   server: 10.0.0.70
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 2Gi
EOF

创建一个mysql_pvc资源

cat > mysql_pvc << EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
    name: pvc-mysql
    namespace: default
spec:
  accessModes: ["ReadWriteMany"]
  resources:
    requests:
      storage: 2Gi
EOF

创建一个mysql_deploy资源

cat > mysql-deployment.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: 10.0.0.70:5000/mysql:5.7
        ports:
        - containerPort: 3306
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "123456"
        volumeMounts:
        - name: mysql-volume
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-volume
        persistentVolumeClaim:
          claimName: pvc-mysql

创建mysql_service资源

cat > mysql-svc.yaml << EOF
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
    - port: 3306
  selector:
    app: mysql
EOF

创建一个tomcat的deploy资源和service资源

cat > tomcat_peploy_svc.yml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat
spec:
  replicas: 2
  selector:
    matchLabels:
      app: tomcat
  template:
    metadata:
      labels:
        app: tomcat
    spec:
      containers:
      - name: tomcat
        image: 10.0.0.70:5000/tomcat-app:v2
        ports:
        - containerPort: 8080
        env:
        - name: MYSQL_SERVICE_HOST
          value: 'mysql'
        - name: MYSQL_SERVICE_PORT
          value: '3306'
      imagePullSecrets:
      - name: harbor-secret
---
apiVersion: v1
kind: Service
metadata:
  name: tomcat-svc
spec:
  type: NodePort
  ports:
    - port: 8080
      nodePort: 8080
  selector:
    app: tomcat

测试:

浏览器访问10.0.0.70:8080/demo添加数据
把以前的资源删除重新创建,浏览器查看数据是否还在

storageClass存储类

  • pod创建时所指定的卷的大小不确定,当pvc和下面的pv绑定时,会根据pod的需要动态的创建一个符合pod的一个pv.而这种动态的实现的方法是存储类(storageClass)
  • 后端的存储设备必须支持resfull封装的api接口(glusterfs),当有用户请求时,会动态的生成一个pv