k8s数据持久化

发布时间 2023-12-13 15:42:14作者: Mrterrific

前面的学习,我们已经基本完成了在k8s中部署一个web服务,运行pod、创建service、创建ingress对外提供域名的七层代理。

下一个环境就得去关注应用部署后的数据存储问题,容器化如何管理,k8s化如何管理。

1.什么是Volume

1.容器内部的存储数据,再容器生命周期中是很短暂的,伴随容器的销毁而删除,很不稳定。
2.并且在一个pod下同时运行多个容器,经常需要再多个容器之间共享文件。
3.因此k8s抽象了一个Volume存储卷来解决这些问题。
4.volume属于是pod的一部分,不能单独创建,只能在pod中定义(谨记)。
5.pod中的所有容器都可以访问Volume,且是挂载后使用,可以挂载到容器内任何目录。
6.k8s的volume不仅支持集群内部的资源类型,还支持第三方的存储类型。

 

2.Volume类型

Kubernetes的Volume有非常多的类型,在实际使用中使用最多的类型如下。

  • emptyDir:一种简单的空目录,主要用于临时存储。
  • hostPath:将主机某个目录挂载到容器中。
  • ConfigMap、Secret:特殊类型,将Kubernetes特定的对象类型挂载到Pod,在ConfigMapSecret章节介绍过如何将ConfigMap和Secret挂载到Volume中。
  • persistentVolumeClaim:Kubernetes的持久化存储类型,详细介绍请参考PV、PVC和StorageClass中会详细介绍。

2.1 EmptyDir类型

EmptyDir是最简单的一种Volume类型,根据名字就能看出,这个Volume挂载后就是一个空目录,应用程序可以在里面读写文件,emptyDir Volume的生命周期与Pod相同,Pod删除后Volume的数据也同时删除掉。

emptyDir配置示例如下。

  • Pod内的容器共享卷的数据
  • 存在于Pod的生命周期,Pod销毁,数据丢失
  • Pod内的容器自动重建后,数据不会丢失
[root@k8s-master-10 ~/test-volumes]#cat busybox-volume.yml 
apiVersion: v1
kind: Pod
metadata:
  name: busybox-empty
  namespace: yuchaoit
spec:
  containers:
  - image: busybox
    name: test-busybox
    volumeMounts:
    - mountPath: /data/busybox/
      name: cache-busybox
    command: ["/bin/sh","-c","while true;do echo $(date) >> /data/busybox/www.yuchaoit.cn.log;sleep 2;done"]
  volumes:
  - name: cache-busybox
    emptyDir: {}

emptyDir实际是将Volume的内容写在Pod所在节点的磁盘上

创建资源

[root@k8s-master-10 ~/test-volumes]#kubectl create -f busybox-volume.yml 

[root@k8s-master-10 ~/test-volumes]#kubectl -n yuchaoit get po busybox-empty -owide
NAME            READY   STATUS    RESTARTS   AGE     IP          NODE          NOMINATED NODE   READINESS GATES
busybox-empty   1/1     Running   0          2m18s   10.2.1.48   k8s-node-11   <none>           <none>

查看目标机器的Volume情况

# 1. docker inspect查看容器挂载信息

# 2. 查看宿主机挂载目录
[root@k8s-node-11 ~]#tail -f   /var/lib/kubelet/pods/e631e809-d3e7-4bcf-8d13-3364a4e4add2/volumes/kubernetes.io~empty-dir/cache-busybox/*
Mon Sep 12 08:44:03 UTC 2022
Mon Sep 12 08:44:05 UTC 2022
Mon Sep 12 08:44:07 UTC 2022
Mon Sep 12 08:44:09 UTC 2022
Mon Sep 12 08:44:11 UTC 2022
Mon Sep 12 08:44:13 UTC 2022
Mon Sep 12 08:44:15 UTC 2022
Mon Sep 12 08:44:17 UTC 2022
Mon Sep 12 08:44:19 UTC 2022

干掉pod

[root@k8s-master-10 ~/test-volumes]#kubectl -n yuchaoit delete po busybox-empty 
pod "busybox-empty" deleted

查看Volume状态
随之也被清空了

2.2 HostPath类型

https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/

Container 中的文件在磁盘上是临时存放的,这给 Container 中运行的较重要的应用程序带来一些问题。

问题之一是当容器崩溃时文件丢失。 kubelet 会重新启动容器,但容器会以干净的状态重启。

第二个问题会在同一 Pod 中运行多个容器并共享文件时出现。 Kubernetes 卷(Volume) 这一抽象概念能够解决这两个问题。

阅读本文前建议你熟悉一下 Pod

1.HostPath是一种持久化存储,emptyDir里面的内容会随着Pod的删除而消失,但HostPath不会
2.如果对应的Pod删除,HostPath Volume里面的内容依然存在于节点的目录中,如果后续重新创建Pod并调度到同一个节点,挂载后依然可以读取到之前Pod写的内容。

3.HostPath存储的内容与节点相关,所以它不适合像数据库这类的应用,想象下如果数据库的Pod被调度到别的节点了,那读取的内容就完全不一样了。

4.记住永远不要使用HostPath存储跨Pod的数据,一定要把HostPath的使用范围限制在读取节点文件上,这是因为Pod被重建后不确定会调度哪个节点上,写文件可能会导致前后不一致。

yaml

[root@k8s-master-10 ~/test-volumes]#cat busybox-volume.yml 
apiVersion: v1
kind: Pod
metadata:
  name: busybox-hostpath
  namespace: yuchaoit
spec:
  volumes:
  - name: hostpath-busybox
    hostPath:
      path: /data/hostpath-busybox # 宿主机映射点
      type: DirectoryOrCreate # 目录不存在自动创建


  containers:
  - image: busybox
    name: test-busybox
    volumeMounts:  # 容器数据挂到Volume里
    - mountPath: /data/busybox/ # 容器内挂载点
      name: hostpath-busybox    # 容器内挂载点,挂到哪个卷
    command: ["/bin/sh","-c","while true;do echo $(date) 超哥带你学k8s >> /data/busybox/www.yuchaoit.cn.log;sleep 2;done"]

创建结果

[root@k8s-master-10 ~/test-volumes]#kubectl -n yuchaoit get po busybox-hostpath -owide
NAME               READY   STATUS    RESTARTS   AGE   IP          NODE          NOMINATED NODE   READINESS GATES
busybox-hostpath   1/1     Running   0          42s   10.2.1.49   k8s-node-11   <none>           <none>

查看宿主机日志挂载

 

删除pod,查看hostPath数据

 

2.3 NFS 类型

https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/#nfs

很明显,这种不一致的数据持久化,必然是不可取的,我们可以采用共享式存储文件系统,NFS就是个代表。

nfs 卷能将 NFS (网络文件系统) 挂载到你的 Pod 中。

不像 emptyDir 那样会在删除 Pod 的同时也会被删除,nfs 卷的内容在删除 Pod 时会被保存,卷只是被卸载。 这意味着 nfs 卷可以被预先填充数据,并且这些数据可以在 Pod 之间共享。

注意: 在使用 NFS 卷之前,你必须运行自己的 NFS 服务器并将目标 share 导出备用。

# 变化的只有关于Volume设置参数
# 查看应该用什么字段
# [root@k8s-master-10 ~/test-volumes]#kubectl explain pod.spec.volumes.nfs
# 提前准备好一个NFS服务器即可。
 # yum install nfs-utils rpcbind -y
 # /nfsShare *(insecure,rw,sync,root_squash)

具体yaml

[root@k8s-master-10 ~/test-volumes]#cat busybox-volume.yml 
apiVersion: v1
kind: Pod
metadata:
  name: nginx-volume-nfs
  namespace: yuchaoit
spec:
  volumes:
  - name: nfs-data
    nfs:
      server: 10.0.0.11
      path: /nfsShare


  containers:
  - image: nginx:1.14.1
    name: nginx-volume-nfs
    ports:
      - name: http
        containerPort: 80
    volumeMounts:  # 容器数据挂到Volume里
    - mountPath: /usr/share/nginx/html/ # 容器内挂载点
      name: nfs-data    # 容器内挂载点,挂到哪个卷

创建pod查看nfs共享数据

[root@k8s-master-10 ~/test-volumes]#kubectl create -f nfs-volume.yml 
pod/nginx-volume-nfs created
[root@k8s-master-10 ~/test-volumes]#
[root@k8s-master-10 ~/test-volumes]#kubectl -n yuchaoit get po -owide
NAME                                READY   STATUS    RESTARTS   AGE   IP          NODE          NOMINATED NODE   READINESS GATES
nginx-deployment-6f7886b6db-pvjd5   1/1     Running   0          6h    10.2.2.60   k8s-node-12   <none>           <none>
nginx-deployment-6f7886b6db-xsj8n   1/1     Running   0          6h    10.2.1.47   k8s-node-11   <none>           <none>
nginx-volume-nfs                    1/1     Running   0          6s    10.2.1.50   k8s-node-11   <none>           <none>
[root@k8s-master-10 ~/test-volumes]#
[root@k8s-master-10 ~/test-volumes]#curl 10.2.1.50
<meta charset=utf-8>超哥带你学k8s www.yuchaoit.cn

思考

这只是给pod单个的添加Volume字段,如果一组pod控制器需要使用nfs,该如何配置?

volume支持的种类众多(参考 https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes )
每种对应不同的存储后端实现,因此为了屏蔽后端存储的细节,同时使得Pod在使用存储的时候更加简洁和规范,k8s引入了两个新的资源类型,PV和PVC。


PersistentVolume(持久化卷),是对底层的存储的一种抽象,它和具体的底层的共享存储技术的实现方式有关,比如 Ceph、GlusterFS、NFS 等,都是通过插件机制完成与共享存储的对接。
如使用PV对接NFS存储。

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity: 
    storage: 1Gi
  accessModes:
  - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /nfsShare
    server: 10.0.0.11

2.4 实践持久化mysql数据

学习点

1.基于节点选择器指定运行mysql的Node
2.使用Deployment管理mysql
3.使用hostPath持久化mysql数据

yaml

apiVersion: apps/v1      # 注意这里与Pod的区别,Deployment是apps/v1而不是v1
kind: Deployment         # 资源类型为Deployment
metadata:
  name: mysql-deploy         # Deployment的名称
  namespace: yuchaoit
spec:
  selector:      # 要和pod的label对应上
    matchLabels:
      app: mysql  
  replicas: 1             # Pod的数量,Deployment会确保一直有1个Pod运行         

  template:               # Pod的定义,用于创建Pod,也称为Pod template
    metadata:             # pod的信息
      labels:             # pod打上标签
        app: mysql 
    spec:                 # pod具体字段属性,如容器信息,存储卷,pod部署节点等
      volumes:
        - name: mysql-volume # 卷名
          hostPath: # 卷类型
            path: /www.yuchaoit.cn/mysql # 宿主机目录
            type: DirectoryOrCreate
      nodeSelector: # pod部署节点选择器
        diskType: ssd # label的key-value
      containers: # pod内容器信息
      - image: mysql:5.7 # 镜像下载地址
        name: mysql-pod # 容器名
        imagePullPolicy: IfNotPresent # 镜像下载策略
        ports: # 容器内暴露端口
          - name: mysql-port 
            containerPort: 3306 # 指明容器内要暴露的端口
        env: # 给容器设置运行环境变量
          - name: MYSQL_ROOT_PASSWORD
            value: "www.yuchaoit.cn"
        volumeMounts:
          - mountPath: /var/lib/mysql # 容器内挂载点
            name: mysql-volume # 挂载的设备,卷的名字

创建mysql-pod

[root@k8s-master-10 ~/test-volumes]#kubectl create -f mysql-deploy.yml 
deployment.apps/mysql-deploy created


[root@k8s-master-10 ~/test-volumes]#kubectl -n yuchaoit get po
NAME                                READY   STATUS    RESTARTS   AGE
mysql-deploy-569f9d64fc-86mpq       0/1     Pending   0          10s

# 查看事件,为什么pending
[root@k8s-master-10 ~/test-volumes]#kubectl -n yuchaoit describe pod mysql-deploy-569f9d64fc-86mpq 


# 经典的事件报错
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  41s   default-scheduler  0/3 nodes are available: 3 node(s) didn't match node selector.
  Warning  FailedScheduling  41s   default-scheduler  0/3 nodes are available: 3 node(s) didn't match node selector.


# 给Node打上标签
[root@k8s-master-10 ~/test-volumes]#kubectl label nodes k8s-node-12 diskType=ssd
node/k8s-node-12 labeled


# 此时会发现pod动态已自动更新了
[root@k8s-master-10 ~/test-volumes]#kubectl -n yuchaoit get po mysql-deploy-569f9d64fc-86mpq  -o wide
NAME                            READY   STATUS    RESTARTS   AGE     IP          NODE          NOMINATED NODE   READINESS GATES
mysql-deploy-569f9d64fc-86mpq   1/1     Running   0          2m47s   10.2.2.61   k8s-node-12   <none>           <none>

图解mysql-pod数据持久化

1.检查mysql节点的持久化数据
[root@k8s-node-12 /www.yuchaoit.cn/mysql]#ls
auto.cnf  ca-key.pem  ca.pem  chaoge666  client-cert.pem  client-key.pem  ib_buffer_pool  ibdata1  ib_logfile0  ib_logfile1  ibtmp1  mysql  performance_schema  private_key.pem  public_key.pem  server-cert.pem  server-key.pem  sys
[root@k8s-node-12 /www.yuchaoit.cn/mysql]#

2.尝试连接集群内pod的mysql
# 这里临时运行一个新pod,去登录mysql-pod。

 

创建pod远程连接mysql-pod

[root@k8s-master-10 ~/test-volumes]#kubectl run client-mysql -it --image=mysql:5.7 --  bash -c 'mysql -uroot -pwww.yuchaoit.cn -h10.2.2.61 -P3306'
If you don't see a command prompt, try pressing enter.

mysql> status
--------------
mysql  Ver 14.14 Distrib 5.7.36, for Linux (x86_64) using  EditLine wrapper

Connection id:        6
Current database:    
Current user:        root@10.2.2.63
SSL:            Cipher in use is ECDHE-RSA-AES128-GCM-SHA256
Current pager:        stdout
Using outfile:        ''
Using delimiter:    ;
Server version:        5.7.36 MySQL Community Server (GPL)
Protocol version:    10
Connection:        10.2.2.61 via TCP/IP
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    latin1
Conn.  characterset:    latin1
TCP port:        3306
Uptime:            8 min 39 sec

Threads: 1  Questions: 15  Slow queries: 0  Opens: 105  Flush tables: 1  Open tables: 98  Queries per second avg: 0.028
--------------

mysql>

2.5 综合练习 k8s运行wordpress

以目前所有所学知识点,完成wordpress在k8s下的运行,并且可以通过域名

1. wordpress.yuchaoit.cn 访问博客集群入口
2. 用deployment控制器单独管理mysql(副本数1)、单独管理wordpress(副本数2)
3. 创建Service代理mysql,以及wordpress
4. 创建wordpress访问集群入口

实践

nfs共享存储

选用随便一个机器,如11机器。

yum install nfs-utils -y 
cat >/etc/exports <<'EOF'
/nfs-volume/blog/ *(rw,sync,no_root_squash)
EOF

mkdir -p /nfs-volume/blog/

systemctl restart nfs

1. mydel-deployment.yml

yaml所有字段,不要求你去记住,会看、会修改、确保业务运行即可。

面试官问你,k8s中遇见不认识的字段,你是怎么处理的?

答。基于kubectl explain查阅资料,以及官网。

apiVersion: apps/v1      # 注意这里与Pod的区别,Deployment是apps/v1而不是v1
kind: Deployment         # 资源类型为Deployment
metadata:
  name: mysql-deploy            # Deployment的名称
  namespace: yuchaoit
  labels:
    app: mysql
spec:
  selector:       # RS控制器基于label匹配pod,确保副本数
    matchLabels:
      app: mysql

  template:              # Pod的定义,用于创建Pod,也称为Pod template
    metadata:
      labels:           # pod打上标签
        app: mysql  # 必须和selector一样
    spec:
      volumes:
        - name: db
          hostPath:
            path: /data/mysql
      nodeSelector:
        diskType: ssd

      containers:
      - image: mysql:5.7
        name: mysql-blog
        imagePullPolicy: IfNotPresent
        args:                               # 容器运行参数
        - --default_authentication_plugin=mysql_native_password
        - --character-set-server=utf8mb4
        - --collation-server=utf8mb4_unicode_ci

        ports:            
          - name: dbport   
            containerPort: 3306 # 指明容器内要暴露的端口
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: www.yuchaoit.cn
        - name: MYSQL_DATABASE
          value: wordpress
        - name: MYSQL_USER
          value: wordpress
        - name: MYSQL_PASSWORD
          value: www.yuchaoit.cn
        volumeMounts:
          - name: db
            mountPath: /var/lib/mysql/

创建结果

[root@k8s-master-10 ~]#kubectl -n yuchaoit get po -owide
NAME                           READY   STATUS    RESTARTS   AGE   IP          NODE          NOMINATED NODE   READINESS GATES
mysql-deploy-75f47f87c-l7t8f   1/1     Running   0          6s    10.2.2.64   k8s-node-12   <none>           <none>

2. mysql-svc.yml

给mysql服务,进行服务发现(选择pod 带有app: mysql)

apiVersion: v1
kind: Service
metadata:
  name: mysql        # Service的名称,服务发现名称
  namespace: yuchaoit
spec:
  selector:          # Label Selector,选择包含app=nginx标签的Pod
    app: mysql
  ports:
  - name: mysql-port
    targetPort: dbport   # 直接基于mysql-pod暴露的端口名即可对应
    port: 3306         # Service对外暴露的端口,也就是ClusterIP的port
    protocol: TCP    # 转发协议类型,支持TCP和UDP

查看svc

[root@k8s-master-10 ~]#kubectl -n yuchaoit get svc mysql -owide
NAME    TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE    SELECTOR
mysql   ClusterIP   10.1.225.170   <none>        3306/TCP   103s   app=mysql


# 确认svc可用
[root@k8s-master-10 ~]#docker run mysql:5.7.25 bash -c 'mysql -uroot -pwww.yuchaoit.cn -h10.1.225.170 -P3306 -e "status;"'
mysql: [Warning] Using a password on the command line interface can be insecure.
--------------
mysql  Ver 14.14 Distrib 5.7.25, for Linux (x86_64) using  EditLine wrapper

Connection id:        3
Current database:    
Current user:        root@10.2.0.0
SSL:            Cipher in use is DHE-RSA-AES256-SHA
Current pager:        stdout
Using outfile:        ''
Using delimiter:    ;
Server version:        5.7.36 MySQL Community Server (GPL)
Protocol version:    10
Connection:        10.1.225.170 via TCP/IP
Server characterset:    utf8mb4
Db     characterset:    utf8mb4
Client characterset:    latin1
Conn.  characterset:    latin1
TCP port:        3306
Uptime:            9 min 46 sec

Threads: 1  Questions: 10  Slow queries: 0  Opens: 105  Flush tables: 1  Open tables: 98  Queries per second avg: 0.017
--------------

3. wordpress-deploy.yml

于超老师强烈建议,纯手敲,前期别偷懒,挨个的理解字段的作用。

你可能会遇见N个错误,但是你也有了N个成长。

[root@k8s-master-10 ~]#cat deploy-wordpress.yml 
apiVersion: apps/v1      # 注意这里与Pod的区别,Deployment是apps/v1而不是v1
kind: Deployment         # 资源类型为Deployment
metadata:
  name: wordpress-deploy            # Deployment的名称
  namespace: yuchaoit
  labels:
    app: wordpress
spec:
  replicas: 2 # pod副本数
  selector:       # RS控制器基于label匹配pod,确保副本数
    matchLabels:
      app: wordpress
  minReadySeconds: 5 # 新创建的 pod 应准备就绪的最小秒数
  strategy: # 设置Deployment滚动更新pod的策略
    type: RollingUpdate # 默认就是滚动更新
    rollingUpdate:
      maxSurge: 1 # 最大调度1个pod
      maxUnavailable: 1 # 最多不可用1个
  template:              # Pod的定义,用于创建Pod,也称为Pod template
    metadata:
      labels:           # pod打上标签
        app: wordpress 
    spec:
      volumes:
        - name: nfs-data # 定义pod的数据卷,给容器使用
          nfs:
            server: 10.0.0.11
            path: /nfs-volume/blog/ # 使用nfs的什么共享目录
      initContainers:  # 初始化容器,启动wordpress前,至少确认呢mysql是连通的,否则没意义
        - name: init-db
          image: busybox
          command: ['sh','-c','until nslookup mysql;do echo waiting for mysql service done....www.yuchaoit.cn...;sleep 1;done;']


      containers:
      - image: wordpress
        name: wordpress-blog
        imagePullPolicy: IfNotPresent
        ports:
          - name: wordpressport # 容器暴露端口,对应的名字,便于其他服务调用
            containerPort: 80


        env: # 根据wordpress镜像要求的环境变量,传入参数
        - name: WORDPRESS_DB_HOST
          value: mysql:3306 # 传入的是Service名字,以及端口
        - name: WORDPRESS_DB_USER
          value: wordpress
        - name: WORDPRESS_DB_PASSWORD
          value: www.yuchaoit.cn

        readinessProbe: # 就绪探针
          tcpSocket:
            port: 80
          initialDelaySeconds: 5 #5秒后开始探测
          periodSeconds: 10 # 10S探测一次
        resources:
          requests: # 节点所需的最小资源
            memory: 256Mi
            cpu: 200m
          limits:   # 限制pod最大资源使用量
            memory: 256Mi
            cpu: 200m
        volumeMounts: # 容器使用卷
          - name: nfs-data
            mountPath: /var/www/html/wp-content # 容器内挂载点

# 这是一个经典的应用部署yaml,对于基础所需的deployment,部署应用,需要考虑到的pod字段,都用上了,作为学习pod部署样本。
#
[root@k8s-master-10 ~]#

创建wordpress应用pod,过程估计得有1分钟,有一个下载时间,可以提前先准备好镜像。

查看pod运行结果
[root@k8s-master-10 ~]#kubectl -n yuchaoit get po -owide -l app=wordpress
NAME                               READY   STATUS     RESTARTS   AGE    IP          NODE          NOMINATED NODE   READINESS GATES
wordpress-deploy-c4df856c7-4p4bt   0/1     Init:0/1   0          5m8s   <none>      k8s-node-12   <none>           <none>
wordpress-deploy-c4df856c7-qncj2   1/1     Running    0          5m8s   10.2.1.51   k8s-node-11   <none>           <none>


# 熟练用describe去看资源状态
[root@k8s-master-10 ~]#kubectl -n yuchaoit describe pod wordpress-deploy-c4df856c7-

踩坑记录,客户端主机,不支持nfs插件

       In some cases useful info is found in syslog - try
       dmesg | tail or so.
  Warning  FailedMount  88s (x4 over 7m34s)  kubelet  (combined from similar events): MountVolume.SetUp failed for volume "nfs-data" : mount failed: exit status 32
Mounting command: systemd-run
Mounting arguments: --description=Kubernetes transient mount for /var/lib/kubelet/pods/ae9fd074-e367-4b0b-a84a-8a2132e265ff/volumes/kubernetes.io~nfs/nfs-data --scope -- mount -t nfs 10.0.0.11:/nfs-volume/blog/ /var/lib/kubelet/pods/ae9fd074-e367-4b0b-a84a-8a2132e265ff/volumes/kubernetes.io~nfs/nfs-data
Output: Running scope as unit run-116975.scope.
mount: wrong fs type, bad option, bad superblock on 10.0.0.11:/nfs-volume/blog/,
       missing codepage or helper program, or other error
       (for several filesystems (e.g. nfs, cifs) you might
       need a /sbin/mount.<type> helper program)

       In some cases useful info is found in syslog - try
       dmesg | tail or so.
  Warning  FailedMount  49s (x4 over 7m39s)  kubelet  Unable to attach or mount volumes: unmounted volumes=[nfs-data], unattached volumes=[default-token-nkzpq nfs-data]: timed out waiting for the condition
[root@k8s-master-10 ~]#

# 给客户端机器,安装nfs套件即可。
[root@k8s-node-12 ~]#yum install nfs-utils -y

# 重建pod查看结果
[root@k8s-master-10 ~]#kubectl -n yuchaoit delete po -l app=wordpress

# 提示:可以去看目标机器的init容器运行结果


# 等待片刻后,通信没问题了
[root@k8s-master-10 ~]#kubectl -n yuchaoit get po -owide -l app=wordpress 
NAME                               READY   STATUS    RESTARTS   AGE     IP          NODE          NOMINATED NODE   READINESS GATES
wordpress-deploy-c4df856c7-qjs68   1/1     Running   0          6m51s   10.2.1.52   k8s-node-11   <none>           <none>
wordpress-deploy-c4df856c7-x8gm9   1/1     Running   0          6m51s   10.2.2.66   k8s-node-12   <none>           <none>

4.wordpress-svc.yml

apiVersion: v1
kind: Service
metadata:
  name: wordpress        # Service的名称,服务发现名称
  namespace: yuchaoit
spec:
  selector:          # Label Selector,选择包含app=nginx标签的Pod
    app: wordpress
  ports:
  - name: wordpress-port
    targetPort: wordpressport   # 直接基于wordpress-pod暴露的端口名即可对应
    port: 80         # Service对外暴露的端口,也就是ClusterIP的port
    protocol: TCP    # 转发协议类型,支持TCP和UDP

查看svc

[root@k8s-master-10 ~]#kubectl -n yuchaoit get svc wordpress -owide 
NAME        TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE   SELECTOR
wordpress   ClusterIP   10.1.49.131   <none>        80/TCP    60s   app=wordpress

5.wordpress-ingress.yml

支持集群内配置就完毕了,提供一个外部访问入口吧。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: wordpress
  namespace: yuchaoit
spec:
  rules:                                 # 转发规则
  - host: "wordpress.yuchaoit.cn"            # 填入你们的业务域名
    http:                                # 基于http协议解析
      paths:                            # 基于url路径匹配
      - pathType: Prefix                 #要设置路径类型,否则不合法,
        path: "/"                     # 以 / 分割的URL路径前缀匹配,区分大小写,这里表默认所有路径。
        backend:                      # 后端Service信息的组合
          service:                    
            name: wordpress    # 代理到名字是service1的ClusterIP
            port:                    # 代理到的Service的端口号。
              number: 80

查看结果

[root@k8s-master-10 ~]#kubectl -n yuchaoit get ingress
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
NAME           CLASS    HOSTS                   ADDRESS   PORTS   AGE
test-ingress   <none>   www.yuchaoit.cn                   80      32h
wordpress      <none>   wordpress.yuchaoit.cn             80      4s

# 可以去ingress控制器里看nginx规则

6.访问试试!!

hosts解析来一波
10.0.0.10      www.yuchaoit.cn wordpress.yuchaoit.cn


[root@k8s-master-10 ~]#kubectl --namespace=nginx-ingress  logs -f  nginx-ingress-75c88594dc-klfqc

 

3.PV(PersistentVolume) 持久化存储卷

前面介绍的是针对pod资源设置Volume的三种玩法

EmptyDir,非持久化
hostPath,属于持久化,但只限在具体Node,只适合读的场景。
nfs,属于持久化。

如果要求pod在重新被调度后,依然能保留,使用之前读写后的数据,就必须用网络存储;

网络存储有很多主流的方案,块存储、文件存储、对象存储等。

开源技术
cephFS 
GlusterFS
NFS

生产环境下的公有云厂商提供的
-对象存储
-云硬盘
-弹性文件系统

k8s为了解适配诸多的存储技术,抽象了PV、PVC两个资源,让运维不用关心具体的存储基础设施来源,只需要关心使用存储资源,声明好自己要用多少资源即可。

图解生产下的k8s存储架构

 

PV是什么

PersistentVolume

PV描述的是持久化存储卷,主要定义的是一个持久化存储在宿主机上的目录,比如一个NFS的挂载目录。

PVC是什么

PersistentVolumeClaim

PVC描述的是Pod所希望使用的持久化存储的属性,比如,Volume存储的大小、可读写权限等等。

PVC绑定PV

 

1. pv是对底层网络共享存储的抽象,将共享存储定义为一种"资源"
2. PV由管理员先创建和配置
3. PVC则是用户对存储资源的一种 `申请`
4.对比理解的话
Pod的运行会消耗Node的资源、PVC会消耗PV的资源。
5.PVC的申请,有特定的存储空间,以及访问方式。

PV、PVC关系、与使用流程

 

nfs与mysql数据共享持久化

1.准备NFS

yum install nfs-utils -y
mkdir /nfs-volume/mysql/ -p
cat > /etc/exports <<'EOF'
/nfs-volume/mysql/ 10.0.0.0/24(rw,async,no_root_squash,no_all_squash)
EOF


systemctl restart nfs rpcbind 
systemctl enable nfs rpcbind

showmount -e 127.0.0.1

2.node安装nfs套件

yum install nfs-utils -y

showmount -e 10.0.0.10

3.管理员准备NFS-PV

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv # pv资源名
  # namespace: yuchaoit 
spec:
  capacity: 
    storage: 10Gi  # 存储10Gi资源
  accessModes:
  - ReadWriteMany  # 多个节点可以读写PV
  persistentVolumeReclaimPolicy: Retain # PV回收策略,保留数据,需要管理员手工删除
  nfs:  # 对接存储类型
    path: /nfs-volume/mysql/
    server: 10.0.0.10

创建pv

[root@k8s-master-10 /all-k8s-yml]#kubectl create -f mysql-nfs-pv.yml 
persistentvolume/nfs-pv created


[root@k8s-master-10 /all-k8s-yml]#kubectl -n yuchaoit get pv -owide
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE   VOLUMEMODE
nfs-pv   10Gi       RWX            Retain           Available                                   9s    Filesystem


一个 PV 的生命周期中,可能会处于4中不同的阶段:

Available(可用):表示可用状态,还未被任何 PVC 绑定
Bound(已绑定):表示 PV 已经被 PVC 绑定
Released(已释放):PVC 被删除,但是资源还未被集群重新声明
Failed(失败): 表示该 PV 的自动回收失败

pv资源字段解释

capacity,存储能力, 目前只支持存储空间的设置, 就是我们这里的 storage=1Gi,不过未来可能会加入 IOPS、吞吐量等指标的配置。

accessModes,访问模式, 是用来对 PV 进行访问模式的设置,用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:
ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
ReadOnlyMany(ROX):只读权限,可以被多个节点挂载
ReadWriteMany(RWX):读写权限,可以被多个节点挂载

persistentVolumeReclaimPolicy,pv的回收策略, 目前只有 NFS 和 HostPath 两种类型支持回收策略
Retain(保留)- 保留数据,需要管理员手工清理数据
Recycle(回收)- 清除 PV 中的数据,效果相当于执行 rm -rf /volume_yuchaoit.cn/*
Delete(删除)- 与 PV 相连的后端存储完成 volume 的删除操作,当然这常见于云服务商的存储服务,比如 ASW EBS。
目前只有NFS、HostPath两个类型的PV支持Recycle,直接删除。

PV不属于集群资源

因为PV是直接对接底层存储的,就像集群中的Node可以为Pod提供计算资源(CPU和内存)一样,PV可以为Pod提供存储资源。

因此PV不是namespaced的资源,属于集群层面可用的资源。

Pod如果想使用该PV,需要通过创建PVC挂载到Pod中。

当PV进入Released状态备注

若PVC被删除,PV会进入Released状态,PVC也无法重新绑定,PVC只能和Availabel状态的PV绑定。

生产做法是
1. 备份PV数据,迁移走
2.  修改PV状态,删除对PVC的引用记录,此时k8s的PV控制器watch到PV变化,更新PV状态,恢复Availabel状态。

 

claimRef该字段记录PV、PVC的双向绑定记录

[root@k8s-master-10 /all-k8s-yml]#kubectl edit pv nfs-pv 
persistentvolume/nfs-pv edited


[root@k8s-master-10 /all-k8s-yml]#kubectl -n yuchaoit get pv -owide
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE   VOLUMEMODE
nfs-pv   10Gi       RWX            Retain           Available                                   24m   Filesystem
[root@k8s-master-10 /all-k8s-yml]#

4.用户创建mysql-pvc

PVC全写是PersistentVolumeClaim(持久化卷声明),PVC 是用户存储的一种声明,创建完成后,可以和PV实现一对一绑定。

对于真正使用存储的用户不需要关心底层的存储实现细节,只需要直接使用 PVC 即可。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
  namespace: yuchaoit # pvc属于ns下的资源
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi # 声明PVC用多少存储
  volumeName: nfs-pv # PVC绑定PV 
  # 也可以不填,
  #PersistentVolumeController会不断地循环去查看每一个 PVC,是不是已经处于 Bound(已绑定)状态。
  # 如果不是,那它就会遍历所有的、可用的 PV,并尝试将其与未绑定的 PVC 进行绑定
  # 这样,Kubernetes 就可以保证用户提交的每一个 PVC,只要有合适的 PV 出现,它就能够很快进入绑定状态。
  # 而所谓将一个 PV 与 PVC 进行“绑定”,其实就是将这个 PV 对象的名字,填在了 PVC 对象的 spec.volumeName 字段上。

创建pvc,绑定PV

[root@k8s-master-10 /all-k8s-yml]#kubectl create -f mysql-nfs-pvc.yml 
persistentvolumeclaim/nfs-pvc created



[root@k8s-master-10 /all-k8s-yml]#kubectl -n yuchaoit get pvc -owide
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE     VOLUMEMODE
nfs-pvc   Bound    nfs-pv   10Gi       RWX                           7m43s   Filesystem


[root@k8s-master-10 /all-k8s-yml]#kubectl -n yuchaoit get pv -owide
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM              STORAGECLASS   REASON   AGE   VOLUMEMODE
nfs-pv   10Gi       RWX            Retain           Bound    yuchaoit/nfs-pvc                           25m   Filesystem

5.storageClass实现动态挂载

上面于超老师讲的PV、PVC、创建pv及pvc过程是手动,且pv与pvc一一对应,手动创建很繁琐。

k8s提供了一个更简单的方法,能动态自动创建PV。

通过storageClass + provisioner的方式来实现通过PVC自动创建并绑定PV。

这里作为高阶存储玩法,以后再补充。

6.创建mysql-deployment控制器

apiVersion: apps/v1      # 注意这里与Pod的区别,Deployment是apps/v1而不是v1
kind: Deployment         # 资源类型为Deployment
metadata:
  name: mysql-deploy            # Deployment的名称
  namespace: yuchaoit
  labels:
    app: mysql
spec:
  selector:       # RS控制器基于label匹配pod,确保副本数
    matchLabels:
      app: mysql

  template:              # Pod的定义,用于创建Pod,也称为Pod template
    metadata:
      labels:           # pod打上标签
        app: mysql  # 必须和selector一样

    spec:
      volumes: # 给pod内定义2个卷
        - name: mysql-pvc
          persistentVolumeClaim: # pod引用PVC
            claimName: mysql-pvc
        - name: mysql-log 
          hostPath:
            path: /var/log/mysql

      nodeSelector: # pod部署节点选择器
        diskType: SSD

      containers:
      - image: mysql:5.7
        name: mysql
        imagePullPolicy: IfNotPresent

        ports:            
          - name: dbport   
            containerPort: 3306 # 指明容器内要暴露的端口
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "www.yuchaoit.cn"

        volumeMounts:
          - name: mysql-pvc # 容器内挂载pvc
            mountPath: /var/lib/mysql # 挂载点
          - name: mysql-log 
            mountPath: /var/log/mysql

运行

[root@k8s-master-10 /all-k8s-yml]#kubectl create -f mysql-deploy.yml 

起不来?看看问题
[root@k8s-master-10 /all-k8s-yml]#kubectl -n yuchaoit describe   pod mysql-deploy-98b786585-p9b9g 

加上label
[root@k8s-master-10 /all-k8s-yml]#kubectl label nodes k8s-node-12 diskType=SSD
error: 'diskType' already has a value (ssd), and --overwrite is false
[root@k8s-master-10 /all-k8s-yml]#kubectl label nodes k8s-node-12 diskType=SSD --overwrite 
node/k8s-node-12 labeled

查看结果
[root@k8s-master-10 /all-k8s-yml]#kubectl -n yuchaoit get po -owide 
NAME                           READY   STATUS    RESTARTS   AGE     IP          NODE          NOMINATED NODE   READINESS GATES
mysql-deploy-98b786585-p9b9g   1/1     Running   0          2m12s   10.2.2.74   k8s-node-12   <none>           <none>

7.结果测试

按如下流程测试即可
1.查看PV里的数据
[root@k8s-master-10 /nfs-volume/mysql]#ls
auto.cnf    ca.pem           client-key.pem  ibdata1      ib_logfile1  mysql               private_key.pem  server-cert.pem  sys
ca-key.pem  client-cert.pem  ib_buffer_pool  ib_logfile0  ibtmp1       performance_schema  public_key.pem   server-key.pem


2.加一个数据试试
mysql> create database yuchao_k8s;
Query OK, 1 row affected (0.01 sec)


3.删除pod,查看数据能回来吗?(deployment保障了pod的副本数)