kubernetes高级应用(PVC存储)

一、介绍

好的!我用一个简单的比喻来解释 Kubernetes 中的 **PV(Persistent Volume)** 和 **PVC(Persistent Volume Claim)**,帮你轻松理解它们的作用和关系。

---

### ️ **打个比方:PV 和 PVC 就像“仓库”和“租客”**
1. **PV(Persistent Volume)**:好比是 **一个真实的仓库**  
   - 它是集群中的一块**实际存储空间**(比如云硬盘、NFS、本地磁盘等)。  
   - 就像仓库有大小、位置、类型(冷库/常温库)一样,PV 也有容量、访问模式(读写权限)、存储类型等属性。  
   - *例子:* 你有一个 100GB 的云硬盘,这就是一个 PV。

2. **PVC(Persistent Volume Claim)**:好比是 **租户的申请单**  
   - 它是用户(或 Pod)**对存储需求的声明**,比如“我需要 10GB 的存储,能读写”。  
   - Kubernetes 会根据 PVC 的要求,**自动找到匹配的 PV** 并绑定(就像仓库管理员分配符合条件的仓库给租客)。  
   - *例子:* 你的应用需要 10GB 空间,提交一个 PVC,K8s 就会从现有的 PV 中分配一个合适的给它。

---

### **核心特点**
- **PV 是资源,PVC 是请求**:  
  PV 像硬盘,是实物;PVC 像申请单,是需求。
- **动态分配**:  
  如果现有 PV 不满足 PVC,K8s 可以动态创建新的 PV(需要配置 `StorageClass`,类似“仓库供应商”)。
- **解耦设计**:  
  用户只需关心 PVC(要多大存储),无需手动管理 PV(不用管硬盘具体在哪)。

---

### **举个实际流程**
1. **管理员创建 PV**:  
   ```yaml
   apiVersion: v1
   kind: PersistentVolume
   metadata:
     name: my-pv
   spec:
     capacity: { storage: 100Gi }
     accessModes: [ ReadWriteOnce ]
     storageClassName: ssd
   ```
   (定义了一个 100GB 的 SSD 存储卷)

2. **用户提交 PVC**:  
   ```yaml
   apiVersion: v1
   kind: PersistentVolumeClaim
   metadata:
     name: my-pvc
   spec:
     resources:
       requests: { storage: 10Gi }
     storageClassName: ssd
   ```
   (申请 10GB 的 SSD 存储)

3. **K8s 自动绑定**:  
   系统将 `my-pvc` 和 `my-pv` 绑定,Pod 通过 PVC 使用存储。

---

### **总结**
- **PV**:实际的存储资源(像硬盘)。  
- **PVC**:用户对存储的需求(像申请单)。  
- **好处**:**用户不用关心存储细节**,K8s 自动匹配和管理,就像租仓库只需提交需求,不用自己盖房子。

这样是不是清楚多了?

二、实战应用

[root@master nfs-pv]# exportfs -arv
exporting *:/root/nfs-pv/v10
exporting *:/root/nfs-pv/v9
exporting *:/root/nfs-pv/v8
exporting *:/root/nfs-pv/v7
exporting *:/root/nfs-pv/v6
exporting *:/root/nfs-pv/v5
exporting *:/root/nfs-pv/v4
exporting *:/root/nfs-pv/v3
exporting *:/root/nfs-pv/v2
exporting *:/root/nfs-pv/v1
[root@master nfs-pv]# pwd
/root/nfs-pv
[root@master nfs-pv]# ls
v1  v10  v2  v3  v4  v5  v6  v7  v8  v9

[root@master nfs-pv]# kubectl apply -f pv.yaml
persistentvolume/v1 unchanged
persistentvolume/v2 unchanged
persistentvolume/v3 created
[root@master nfs-pv]# kubectl get pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
v1     1Gi        RWX            Retain           Available                                                    66s
v2     1Gi        RWO            Retain           Available                                                    66s
v3     1Gi        ROX            Retain           Available                                                    5s
[root@master nfs-pv]# cat pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v1
  labels:
    app: v1
spec:
  nfs:
    server: 192.168.40.180
    path: /root/nfs-pv/v1
  accessModes:
  - ReadWriteMany
  capacity:
    storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v2
  labels:
    app: v2
spec:
  nfs:
    server: 192.168.40.180
    path: /root/nfs-pv/v2
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v3
  labels:
    app: v3
spec:
  nfs:
    server: 192.168.40.180
    path: /root/nfs-pv/v3
  accessModes:
  - ReadOnlyMany
  capacity:
    storage: 1Gi

[root@master nfs-pv]# kubectl get pvc
NAME     STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
pvc-v1   Bound    v1       1Gi        RWX                                            101s
pvc-v2   Bound    v2       2Gi        RWO                                            76s
pvc-v3   Bound    v3       3Gi        ROX                                            101s
[root@master nfs-pv]# cat pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-v1
spec:
  accessModes:
  - ReadWriteMany
  selector:
    matchLabels:
      app: v1
  resources:
    requests:
      storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-v2
spec:
  selector:
    matchLabels:
      app: v2
  resources:
    requests:
      storage: 2Gi
  accessModes:
  - ReadWriteOnce
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-v3
spec:
  selector:
    matchLabels:
      app: v3
  resources:
    requests:
      storage: 3Gi
  accessModes:
  - ReadOnlyMany

[root@master nfs-pv]# kubectl apply -f pod-pvc.yaml
deployment.apps/nginx created
[root@master nfs-pv]# cat pod-pvc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-3
  template:
    metadata:
      name: nginx-3
      labels:
        app: nginx-3
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - name: pvc-v1
          mountPath: /usr/share/nginx/html
      volumes:
      - name: pvc-v1
        persistentVolumeClaim:
          claimName: pvc-v1

[root@master nfs-pv]# kubectl get pods
NAME                     READY   STATUS    RESTARTS   AGE
nginx-54854d6776-6p4fq   1/1     Running   0          4s
nginx-54854d6776-kmsz8   1/1     Running   0          4s
nginx-54854d6776-rjp2g   1/1     Running   0          4s

[root@master nfs-pv]# kubectl get pods -owide
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
nginx-54854d6776-6p4fq   1/1     Running   0          28s   10.244.166.163   node1             
nginx-54854d6776-kmsz8   1/1     Running   0          28s   10.244.104.21    node2             
nginx-54854d6776-rjp2g   1/1     Running   0          28s   10.244.166.162   node1             
[root@master nfs-pv]# kubectl exec -it nginx-54854d6776-6p4fq -- bash
root@nginx-54854d6776-6p4fq:/# cd /usr/share/nginx/html/
root@nginx-54854d6776-6p4fq:/usr/share/nginx/html# ls
root@nginx-54854d6776-6p4fq:/usr/share/nginx/html# touch cjr
root@nginx-54854d6776-6p4fq:/usr/share/nginx/html# exit
exit
[root@master nfs-pv]# kubectl exec -it nginx-54854d6776-kmsz8 -- bash
root@nginx-54854d6776-kmsz8:/# cd /usr/share/nginx/html/
root@nginx-54854d6776-kmsz8:/usr/share/nginx/html# ls
cjr
root@nginx-54854d6776-kmsz8:/usr/share/nginx/html# touch cjr2
root@nginx-54854d6776-kmsz8:/usr/share/nginx/html# ls
cjr  cjr2
root@nginx-54854d6776-kmsz8:/usr/share/nginx/html# exit
exit
[root@master nfs-pv]# cd v1
[root@master v1]# ls
cjr  cjr2
[root@master v1]# touch cjr3
[root@master v1]# cd ../
[root@master nfs-pv]# kubectl exec -it nginx-54854d6776-kmsz8 -- bash
root@nginx-54854d6776-kmsz8:/# cd /usr/share/nginx/html/
root@nginx-54854d6776-kmsz8:/usr/share/nginx/html# ls
cjr  cjr2  cjr3
root@nginx-54854d6776-kmsz8:/usr/share/nginx/html# exit
exit

[root@master nfs-pv]# cat pod-pvc.yaml && cat pvc.yaml && cat pv.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-3
  template:
    metadata:
      name: nginx-3
      labels:
        app: nginx-3
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - name: pvc-v1
          mountPath: /usr/share/nginx/html
      volumes:
      - name: pvc-v1
        persistentVolumeClaim:
          claimName: pvc-v1

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-v1
spec:
  accessModes:
  - ReadWriteMany
  selector:
    matchLabels:
      app: v1
  resources:
    requests:
      storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-v2
spec:
  selector:
    matchLabels:
      app: v2
  resources:
    requests:
      storage: 2Gi
  accessModes:
  - ReadWriteOnce
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-v3
spec:
  selector:
    matchLabels:
      app: v3
  resources:
    requests:
      storage: 3Gi
  accessModes:
  - ReadOnlyMany

apiVersion: v1
kind: PersistentVolume
metadata:
  name: v1
  labels:
    app: v1
spec:
  nfs:
    server: 192.168.40.180
    path: /root/nfs-pv/v1
  accessModes:
  - ReadWriteMany
  capacity:
    storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v2
  labels:
    app: v2
spec:
  nfs:
    server: 192.168.40.180
    path: /root/nfs-pv/v2
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v3
  labels:
    app: v3
spec:
  nfs:
    server: 192.168.40.180
    path: /root/nfs-pv/v3
  accessModes:
  - ReadOnlyMany
  capacity:
    storage: 3Gi

# 解释 Kubernetes NFS Persistent Volume 配置

这段代码演示了如何在 Kubernetes 中使用 NFS 作为持久化存储的配置。下面我将分部分解释:

## 1. NFS 服务器设置

首先,你在 NFS 服务器上设置了共享目录:
```bash
exportfs -arv
exporting *:/root/nfs-pv/v1
...
exporting *:/root/nfs-pv/v10
```
这表示你将 `/root/nfs-pv/` 下的 v1-v10 目录通过 NFS 共享出去,允许所有客户端(*)访问。

## 2. PersistentVolume (PV) 定义

`pv.yaml` 文件定义了三个 PersistentVolume 资源:

1. **v1**:
   - 使用 NFS 存储,路径为 `/root/nfs-pv/v1`
   - 访问模式为 ReadWriteMany (RWX) - 可被多个节点同时读写
   - 容量为 1Gi

2. **v2**:
   - 路径为 `/root/nfs-pv/v2`
   - 访问模式为 ReadWriteOnce (RWO) - 只能被单个节点读写
   - 容量为 2Gi

3. **v3**:
   - 路径为 `/root/nfs-pv/v3`
   - 访问模式为 ReadOnlyMany (ROX) - 可被多个节点同时只读
   - 容量为 3Gi

## 3. PersistentVolumeClaim (PVC) 定义

`pvc.yaml` 文件定义了三个 PVC,它们会绑定到对应的 PV:

1. **pvc-v1**:
   - 请求 1Gi 存储
   - 需要 RWX 访问模式
   - 通过标签选择器匹配 app=v1 的 PV

2. **pvc-v2**:
   - 请求 2Gi 存储
   - 需要 RWO 访问模式
   - 匹配 app=v2 的 PV

3. **pvc-v3**:
   - 请求 3Gi 存储
   - 需要 ROX 访问模式
   - 匹配 app=v3 的 PV

## 4. Deployment 使用 PVC

`pod-pvc.yaml` 定义了一个 Deployment,它创建了 3 个 Nginx 副本,所有副本都使用 pvc-v1:

- 每个 Pod 将 pvc-v1 挂载到 `/usr/share/nginx/html` 目录
- 由于 pvc-v1 使用 RWX 模式,所有 Pod 可以同时读写同一个 NFS 目录

## 5. 验证测试

你通过以下操作验证了存储功能:
1. 在一个 Pod 中创建文件 `cjr`,在其他 Pod 中可以看到
2. 在另一个 Pod 中创建文件 `cjr2`,其他 Pod 也能看到
3. 直接在 NFS 服务器上创建文件 `cjr3`,所有 Pod 也能立即看到

这证明了多个 Pod 可以共享同一个 NFS 存储,并且读写是同步的。

## 总结

这个配置展示了 Kubernetes 如何通过 PV/PVC 机制使用 NFS 作为共享存储:
- PV 定义了实际的存储资源
- PVC 是 Pod 对存储的请求
- Deployment 中的 Pod 通过 PVC 使用存储
- 使用 RWX 模式时,多个 Pod 可以共享同一个存储卷

你可能感兴趣的:(kubernetes,容器,云原生)