Kubenets 存儲的分類+數(shù)據(jù)的持久化+PVC/PV+StorageClass
1. ConfigMap
以注入的方式存儲非機密的配置信息(例如配置文件、環(huán)境變量、命令行參數(shù)等)。Pod 可以通過環(huán)境變量或掛載為文件的方式讀取 ConfigMap。
# 文件方式創(chuàng)建
$ kubectl create configmap xxx --from-file=xxx.file
# 命令參數(shù)方式創(chuàng)建
$ kubectl create configmap xxx --from-literal=name=xxx --from-literal=password=xx
# --dry-run只編寫不運行, -o yaml > xxx.yaml 導出到xx.yaml保存為yaml格式
--dry-run=client
-o yaml > xxx.yaml
# 完整命令
$ kubectl create configmap xxx --from-literal=name=xxx --from-literal=password=xxx --dry-run=client -o yaml > xxx.yaml
使用方式:
- 作為環(huán)境變量注入 Pod
apiVersion: v1
kind: ConfigMap
metadata:
name: app-env-bulk
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: envfrom-demo
spec:
replicas: 1
selector:
matchLabels:
app: envfrom-demo
template:
metadata:
labels:
app: envfrom-demo
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c", "env | grep DB_"]
envFrom:
- configMapRef:
name: app-env-bulk
2.作為環(huán)境變量單個鍵值注入
apiVersion: v1
kind: ConfigMap
metadata:
name: app-env
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: env-demo
spec:
replicas: 1
selector:
matchLabels:
app: env-demo
template:
metadata:
labels:
app: env-demo
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c", "env | grep LOG_LEVEL"]
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-env
key: LOG_LEVEL
- name: FEATURE_FLAG
valueFrom:
configMapKeyRef:
name: app-env
key: FEATURE_FLAG
-
以卷 (configMap volume) 的方式掛載為文件/目錄
apiVersion: v1 kind: ConfigMap metadata: name: app-config-files --- apiVersion: apps/v1 kind: Deployment metadata: name: volume-demo spec: replicas: 1 selector: matchLabels: app: volume-demo template: metadata: labels: app: volume-demo spec: containers: - name: app image: busybox command: ["sh", "-c", "ls /config && cat /config/application.properties"] volumeMounts: - name: config-vol mountPath: /config readOnly: true volumes: - name: config-vol configMap: name: app-config-files
2. Secret
存儲敏感數(shù)據(jù)(如密碼、證書、密鑰),內容會以 Base64 編碼保存。與 ConfigMap 類似,可通過環(huán)境變量或卷掛載到 Pod,并在 API Server/ETCD 中進行額外的訪問控制。
# base64編碼
$ echo -n "Hello World" | base64
SGVsbG8gV29ybGQ=
# base64解碼
$ echo -n "SGVsbG8gV29ybGQ=" | base64 -d
常見類型如下:
-
Opaque:默認類型,存放任意 key/value,需要自行決定編碼內容。
apiVersion: v1 kind: Secret metadata: name: app-secret type: Opaque stringData: username: admin password: s3cr3t or apiVersion: v1 kind: Secret metadata: name: app-secret type: Opaque data: username: base64(admin) password: base64(s3cr3t) -
kubernetes.io/service-account-token:ServiceAccount 自動掛載的令牌,附帶 CA、namespace 等字段。
apiVersion: v1 kind: Secret metadata: name: default-token annotations: kubernetes.io/service-account.name: default type: kubernetes.io/service-account-token -
kubernetes.io/dockercfg 與 kubernetes.io/dockerconfigjson:Docker Registry 憑據(jù),分別對應舊版 .dockercfg 和新版 .dockerconfigjson。
apiVersion: v1 kind: Secret metadata: name: regcred type: kubernetes.io/dockerconfigjson data: .dockerconfigjson: <base64-encoded-config> -
kubernetes.io/basic-auth:基于用戶認證,保存用戶名/密碼對。
apiVersion: v1 kind: Secret metadata: name: basic-auth type: kubernetes.io/basic-auth stringData: username: user1 password: passw0rd -
kubernetes.io/ssh-auth:存放 SSH 私鑰數(shù)據(jù)。
apiVersion: v1 kind: Secret metadata: name: git-ssh type: kubernetes.io/ssh-auth stringData: ssh-privatekey: | -----BEGIN OPENSSH PRIVATE KEY----- ... -----END OPENSSH PRIVATE KEY----- -
kubernetes.io/tls:TLS 證書與私鑰(字段固定為 tls.crt、tls.key)。
apiVersion: v1 kind: Secret metadata: name: tls-cert type: kubernetes.io/tls stringData: tls.crt: | -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- tls.key: | -----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY----- -
bootstrap.kubernetes.io/token:集群 bootstrap 令牌,用于 kubeadm 加入節(jié)點。
apiVersion: v1 kind: Secret metadata: name: bootstrap-token-abcdef namespace: kube-system type: bootstrap.kubernetes.io/token stringData: description: "kubeadm bootstrap token" token-id: abcdef token-secret: 0123456789abcdef
3. Downward API
把 Pods 自身的元數(shù)據(jù)(例如 Pod 名稱、命名空間、標簽、注解、資源請求與限制等)暴露給容器,方式包括環(huán)境變量和掛載為文件。Downward API 不需要事先創(chuàng)建對象,由 kubelet 在 Pod 生命周期內自動提供。
-
環(huán)境變量注入 Pod 元數(shù)據(jù)(fieldRef)
apiVersion: v1 kind: Pod metadata: name: env-fieldref-demo spec: containers: - name: app image: busybox command: ["sh", "-c", "env && sleep 3600"] env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: POD_IP valueFrom: fieldRef: fieldPath: status.podIP -
環(huán)境變量注入資源請求/限制(resourceFieldRef)
apiVersion: v1 kind: Pod metadata: name: env-resource-demo spec: containers: - name: app image: busybox resources: requests: cpu: "250m" memory: "128Mi" limits: cpu: "500m" memory: "256Mi" env: - name: CPU_LIMIT valueFrom: resourceFieldRef: containerName: app resource: limits.cpu - name: MEM_REQUEST valueFrom: resourceFieldRef: containerName: app resource: requests.memory command: ["sh", "-c", "echo $CPU_LIMIT $MEM_REQUEST && sleep 3600"] -
DownwardAPI 卷(以文件形式暴露元數(shù)據(jù)或資源值,可熱更新)
apiVersion: v1 kind: Pod metadata: name: volume-downward-demo labels: app: demo spec: containers: - name: app image: busybox command: ["sh", "-c", "cat /etc/podinfo/* && sleep 3600"] volumeMounts: - name: podinfo mountPath: /etc/podinfo readOnly: true volumes: - name: podinfo downwardAPI: items: - path: "labels" fieldRef: fieldPath: metadata.labels - path: "annotations" fieldRef: fieldPath: metadata.annotations - path: "requests_cpu" resourceFieldRef: containerName: app resource: requests.cpu - path: "limits_memory" resourceFieldRef: containerName: app resource: limits.memory -
投射卷(Projected Volume)結合 DownwardAPI 與其他來源
apiVersion: v1 kind: Pod metadata: name: projected-downward-demo spec: containers: - name: app image: busybox command: ["sh", "-c", "ls /projected && sleep 3600"] volumeMounts: - name: projected-vol mountPath: /projected readOnly: true volumes: - name: projected-vol projected: sources: - downwardAPI: items: - path: pod_name fieldRef: fieldPath: metadata.name - path: cpu_limit resourceFieldRef: containerName: app resource: limits.cpu - configMap: name: app-config - secret: name: app-secret
4. Volume
解決 Pod 容器「文件系統(tǒng)不持久、彼此隔離」的問題,讓數(shù)據(jù)可以:在同一個 Pod 內共享、在容器重啟后保留,甚至在不同 Pod / 節(jié)點之間持久存儲。
-
Pod 使用 emptyDir 卷(生命周期隨 Pod)
apiVersion: v1 kind: Pod metadata: name: emptydir-pod spec: containers: - name: app image: nginx:1.27 volumeMounts: - name: cache mountPath: /cache volumes: - name: cache emptyDir: {} -
Pod 使用 hostPath 卷(掛宿主機目錄)
Kubernetes 中 hostPath 的 type 主要有以下幾種(不區(qū)分大小寫時寫法類似,但推薦用官方寫法):
-
DirectoryOrCreate
如果路徑存在:必須是目錄,否則報錯。
如果路徑不存在:在宿主機上創(chuàng)建一個空目錄(權限 0755,屬主為 kubelet 運行用戶)。
-
Directory
路徑必須已經(jīng)存在并且是一個目錄。
如果不存在或不是目錄:Pod 啟動失敗。
-
FileOrCreate
如果路徑存在:必須是文件,否則報錯。
如果路徑不存在:在宿主機上創(chuàng)建一個空文件(權限 0644,屬主為 kubelet 運行用戶)。
-
File
路徑必須已經(jīng)存在并且是一個普通文件。
如果不存在或不是文件:Pod 啟動失敗。
-
Socket
路徑必須存在且是 Unix Domain Socket(如一些本地通信場景)。
否則 Pod 啟動失敗。
-
CharDevice
路徑必須存在且是字符設備(如 /dev/null、串口設備等)。
否則 Pod 啟動失敗。
-
BlockDevice
路徑必須存在且是塊設備(如磁盤 /dev/sdb 等)。
否則 Pod 啟動失敗。
-
apiVersion: v1
kind: Pod
metadata:
name: hostpath-pod
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: host-data
mountPath: /data # 掛載容器內部的路徑
volumes:
- name: host-data
hostPath:
path: /var/data # 宿主機路徑
type: DirectoryOrCreate
-
使用 PV + PVC 持久卷
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-example
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath: # 演示用,生產一般用云盤/NFS/CSI
path: /mnt/data/pv-example
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-example
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: v1
kind: Pod
metadata:
name: pvc-pod
spec:
containers:
- name: app
image: nginx:1.27
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumes:
- name: data
persistentVolumeClaim:
claimName: pvc-example
5. PV/PVC+StatefulSet有狀態(tài)服務
Kubernetes 的 PersistentVolume (PV) 和 PersistentVolumeClaim (PVC) 負責為 Pod 提供持久化存儲:
PV:管理員預先配置的存儲資源,抽象了底層存儲實現(xiàn)(如 NFS、iSCSI、CSI 驅動等),帶有容量、訪問模式、回收策略等屬性。
PVC:應用側對存儲的請求,指定所需容量、訪問模式、StorageClass 等;控制面會嘗試把 PVC 綁定到滿足條件的 PV,或通過 StorageClass 動態(tài)創(chuàng)建新的 PV。
Pod 使用 PVC:在 Pod 的 spec.volumes 中引用 PVC,容器通過 volumeMounts 掛載后即可讀寫。
生命周期:刪除 PVC 時,PV 根據(jù)回收策略(Retain、Delete、Recycle)決定是否保留或清除實際存儲;未被綁定的 PV 處于 Available 狀態(tài),可供其它 PVC 使用。
常見注意事項:確保訪問模式匹配(例如 ReadWriteOnce vs ReadOnlyMany)、容量需要滿足或高于 PVC 請求、StorageClass 的 allowVolumeExpansion 決定是否可擴容等。
要讓 Kubernetes 的 PVC/PV 能夠正常使用,需要在集群里部署與 PVC 兼容的存儲插件(通常稱為 CSI 驅動或傳統(tǒng)的外部存儲插件)。思路如下:
確認需求:確定應用需要的訪問模式(RWO/RWX/ROX)、性能和容量要求,然后挑選合適的后端存儲(NFS、iSCSI、Ceph RBD/CephFS、各云廠商塊存儲、分布式文件系統(tǒng)等)。
-
安裝對應存儲插件:
現(xiàn)代集群最常用的是 CSI(Container Storage Interface)驅動。通常可通過 Helm Chart、Operator 或云廠商提供的安裝腳本部署。
-
例如:
NFS:可以部署 nfs-subdir-external-provisioner(Provisioner + NFS 服務已準備好)。
iSCSI:需要在節(jié)點上配置 iSCSI initiator,并部署提供 iSCSI Target 的 CSI(如 OpenEBS iSCSI)。
Ceph:常見方案是 Rook-Ceph Operator 或 ceph-csi(支持 RBD、CephFS)。
云廠商塊存儲:AWS EBS CSI、Azure Disk CSI、GKE PD CSI 等。
PV 訪問模式(Access Modes)
PV 的訪問模式定義了存儲卷如何被掛載和訪問:
1. ReadWriteOnce (RWO)
說明:卷可以被單個節(jié)點以讀寫方式掛載
特點:同一時間只能被一個節(jié)點掛載
適用場景:數(shù)據(jù)庫、單實例應用
限制:不支持多節(jié)點同時讀寫
2. ReadOnlyMany (ROX)
說明:卷可以被多個節(jié)點以只讀方式掛載
特點:多個節(jié)點可同時讀取,但不能寫入
適用場景:配置文件、靜態(tài)資源分發(fā)
限制:所有掛載都是只讀的
3. ReadWriteMany (RWX)
說明:卷可以被多個節(jié)點以讀寫方式掛載
特點:支持多節(jié)點同時讀寫
適用場景:共享存儲、多實例應用
限制:需要底層存儲系統(tǒng)支持(如 NFS、GlusterFS)
4. ReadWriteOncePod (RWOP) ?
說明:卷可以被單個 Pod 以讀寫方式掛載(Kubernetes v1.22+)
特點:確保整個集群中只有一個 Pod 可以讀寫掛載
適用場景:需要嚴格單寫入者的應用
優(yōu)勢:比 RWO 更嚴格,提供更好的數(shù)據(jù)一致性保證
注: 需在每個node節(jié)點安裝NFS服務器.
# 更新軟件軟
$ apt update && apt upgrade -y
# 安裝NFS服務器
$ apt install -y nfs-kernel-server
$ mkdir /nfs-share
$ chmod 666 /nfs-share
$ chown nobody /nfs-share
$ cat /etc/exports
/nfs-share *(rw,sync,no_subtree_check,no_root_squash)
# Kubernetes NFS 共享配置
# 格式:共享目錄 允許訪問的網(wǎng)段(權限選項)
# 方式1:允許所有節(jié)點訪問(開發(fā)環(huán)境)
/nfs-share/k8s-pv *(rw,sync,no_subtree_check,no_root_squash)
# 方式2:限制特定網(wǎng)段(生產環(huán)境推薦)
# /nfs-share/k8s-pv 10.0.0.0/8(rw,sync,no_subtree_check,no_root_squash)
# /nfs-share/k8s-pv 192.168.0.0/16(rw,sync,no_subtree_check,no_root_squash)
# 重啟服務
$ systemctl restart nfs-server.service
# 檢查
$ dpkg -l | grep nfs
$ showmount -e xxx (主機ip: Ex:192.168.61.141)
--------------------------------
node01 || node01
$ mkdir nfs-share && mkdir nfs-share/k8s-pv
# 掛載
$ mount -t nfs 192.168.61.141:/nfs-share/k8s-pv /nfs-share/k8s-pv/
# 解除掛載
$ umount /nfs-share/k8s-pv/
對于 StatefulSet,通常不直接創(chuàng)建 PVC,而是使用 volumeClaimTemplates,真正應用時在 StatefulSet 中定義模板即可。
PV清單文件
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-demo-retain
spec:
capacity:
storage: 1Gi
accessModes: [ReadWriteMany]
storageClassName: manual # 存儲類名
persistentVolumeReclaimPolicy: Retain
nfs:
path: /nfs-share/k8s-pv
server: 192.168.61.141
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-demo-recycle
spec:
capacity:
storage: 1Gi
accessModes: [ReadWriteMany]
storageClassName: manual # 存儲類名
persistentVolumeReclaimPolicy: Recycle
nfs:
path: /nfs-share/data
server: 192.168.61.141
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-demo-delete
spec:
capacity:
storage: 1Gi
accessModes: [ReadWriteMany]
storageClassName: manual # 存儲類名
persistentVolumeReclaimPolicy: Delete
nfs:
path: /nfs-share/tmp
server: 192.168.61.141
svc-headless清單文件
apiVersion: v1
kind: Service
metadata:
name: web-headless
labels:
app: web
spec:
clusterIP: None # statefulSet 無頭服務
selector:
app: web
ports:
- port: 80
targetPort: http
statefulSet清單文件
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web-stateful
spec:
serviceName: web-headless
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx
ports:
- containerPort: 80
name: http
volumeMounts:
- name: www # 綁定的卷名稱
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www # 綁定的卷名稱
spec:
accessModes: [ReadWriteMany]
storageClassName: manual # 存儲類名
resources:
requests:
storage: 1Gi
總結:
無狀態(tài)服務:使用 ConfigMap/Secret 提供配置,數(shù)據(jù)寫入外部存儲(數(shù)據(jù)庫、對象存儲、消息隊列等)。
有狀態(tài)服務:使用 StatefulSet + PV/PVC,或使用 Operator 管理。
PVC 需手動刪除
6. StorageClass
StorageClass 基于云供應商提供的服務, 是 Kubernetes 中用于定義存儲類型的資源對象.
主要作用
動態(tài)存儲供應:自動創(chuàng)建 PersistentVolume(PV)
存儲分類:區(qū)分不同性能和特性的存儲
簡化管理:無需手動創(chuàng)建 PV
創(chuàng)建StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard # 指定 StorageClass
provisioner: kubernetes.io/aws-ebs # 存儲供應者
parameters:
type: gp3
fsType: ext4
reclaimPolicy: Delete # 回收策略:Retain 或 Delete
volumeBindingMode: Immediate # 綁定模式:Immediate 或 WaitForFirstConsumer
allowVolumeExpansion: true # 是否允許卷擴容
- 在 PVC 中引用 StorageClass
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: standard # 指定 StorageClass
resources:
requests:
storage: 10Gi