【K8s 实战】Volume 存储、PV/PVC、ConfigMap 与 Secret 完整实验

文章目录

    • 前言
    • 复习实验
      • [实验 1:Namespace and Contexts 综合实验](#实验 1:Namespace and Contexts 综合实验)
      • [实验 2:多容器 Pod 基础管理](#实验 2:多容器 Pod 基础管理)
  • [一、Kubernetes Volume 存储卷](#一、Kubernetes Volume 存储卷)
    • [1. emptyDir 临时空目录卷](#1. emptyDir 临时空目录卷)
    • [2. hostPath 主机路径卷](#2. hostPath 主机路径卷)
    • [3. NFS 网络存储卷](#3. NFS 网络存储卷)
    • [4. PV & PVC 持久存储架构](#4. PV & PVC 持久存储架构)
      • [访问模式 accessModes](#访问模式 accessModes)
      • [volumeMode 卷模式](#volumeMode 卷模式)
      • [回收策略 PersistentVolumeReclaimPolicy](#回收策略 PersistentVolumeReclaimPolicy)
      • [NFS 静态 PV 实验](#NFS 静态 PV 实验)
  • [二、Kubernetes 配置管理 ConfigMap & Secret](#二、Kubernetes 配置管理 ConfigMap & Secret)
    • [1. ConfigMap](#1. ConfigMap)
      • [创建 ConfigMap 三种方式](#创建 ConfigMap 三种方式)
      • [Pod 引用 ConfigMap 两种方式](#Pod 引用 ConfigMap 两种方式)
      • [综合实验:haproxy + webapp 负载均衡案例](#综合实验:haproxy + webapp 负载均衡案例)
        • [步骤 1 创建 webapp‑1](#步骤 1 创建 webapp‑1)
        • [步骤 2 创建 webapp‑2](#步骤 2 创建 webapp‑2)
        • [步骤 3 haproxy 配置与 pod](#步骤 3 haproxy 配置与 pod)
    • [2. Secret](#2. Secret)
      • [创建 secret](#创建 secret)
      • [Pod 引用 Secret](#Pod 引用 Secret)
    • 综合实验
    • 环境清理
    • 小结

前言

本篇记录 Kubernetes 存储卷与配置管理相关实验,包含临时卷emptyDir、节点卷hostPath、NFS 网络存储、PV/PVC 持久存储架构,以及 ConfigMap、Secret 配置管理对象。所有案例均为可直接复制运行的实操命令与 yaml。

复习实验

实验 1:Namespace and Contexts 综合实验

  1. yaml 方式创建命名空间dev‑ns
  2. 在dev‑ns创建 nginx pod,镜像nginx:alpine
  3. 使用kubectl config修改当前上下文默认命名空间为dev‑ns,不使用‑n查看 pod
  4. 安装kubens切换回default命名空间,查看 dev‑ns 资源必须带‑n参数
  5. 编写 shell 脚本实现命名空间切换
  6. 删除dev‑ns,ns 删除后内部 pod 会自动清除

验证点

  • kubectl get ns 看到 dev‑ns
  • 不指定‑n 可以看到 nginx pod
  • 切到 default 后直接get pod看不到 dev‑ns 的 pod
  • 删除 ns,内部资源自动回收

实验 2:多容器 Pod 基础管理

  1. 创建命名空间pod‑lab,设置上下文默认 ns 为pod‑lab

  2. yaml 创建多容器 pod

    复制代码
    two‑container‑pod
    • 容器 web:nginx:alpine
    • 容器 client:busybox:1.36,command 执行sleep 3600保活
  3. kubectl get pod ‑o wide确认状态2/2 Running,查看 PodIP

  4. 在 client 容器内部 wget 127.0.0.1 访问同 Pod 内 nginx

  5. 将 master 节点/etc/hosts复制到 pod web 容器/tmp/hosts

  6. 查看 nginx 日志;进入 client 执行 hostname

  7. 删除 pod,观察 Terminating 状态


一、Kubernetes Volume 存储卷

参考官方文档:卷 | Kubernetes

环境准备

复制代码
kubectl create ns storage
kubectl config set‑context --current --namespace storage

K8s 支持众多 Volume 类型: emptyDir、hostPath、nfs、iscsi、fc、glusterfs、rbd、gitRepo、secret、persistentVolumeClaim、downwardAPI 等。

1. emptyDir 临时空目录卷

特点:Pod 调度到节点时创建;Pod 从节点删除,emptyDir 数据永久丢失;同一 Pod 多个容器之间可以共享该卷。

pod‑with‑emptyDir.yaml

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  volumes:
  - name: datavolume
    emptyDir: {}
  containers:
  - name: busybox1
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
    volumeMounts:
    - mountPath: /data
      name: datavolume
  - name: busybox2
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
    volumeMounts:
    - mountPath: /data
      name: datavolume

实操命令

复制代码
kubectl apply -f pod-with-emptyDir.yaml
# 在busybox1写文件
kubectl exec busybox -c busybox1 -- touch /data/b1-f1
# busybox2读取共享目录
kubectl exec busybox -c busybox2 -- ls /data

# 登录对应node查看宿主机实际路径
# /var/lib/kubelet/pods/<pod‑uid>/volumes/kubernetes.io~empty‑dir/datavolume

# 删除pod验证数据销毁
kubectl delete pod busybox --force
# node上目录直接消失

用途:Pod 内部多容器临时数据共享、缓存;Pod 销毁数据就没,不能做持久存储。

2. hostPath 主机路径卷

特点:把Node 节点本地文件 / 目录直接挂载进 Pod ;Pod 删除,节点上数据依然保留。 ⚠️ 注意:多节点集群,pod 漂移到其他节点,就读不到旧节点数据;生产尽量少用。

pod‑with‑hostPath.yaml

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  volumes:
  - name: datavolume
    hostPath:
      path: /busyboxdir
  containers:
  - name: busybox1
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
    volumeMounts:
    - mountPath: /data
      name: datavolume
  - name: busybox2
    image: hub.laoma.cloud/library/busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
    volumeMounts:
    - mountPath: /data
      name: datavolume
      readOnly: false
kubectl apply -f pod-with-hostPath.yaml
# pod写文件,node节点查看;删除pod,node上文件依旧保留
kubectl exec busybox -c busybox1 -- touch /data/b1-f1
kubectl delete pod busybox --force
# node节点 /busyboxdir 数据还在

3. NFS 网络存储卷

NFS 属于网络共享存储,Pod 删除数据仍然保留,可以多 Pod 共享读写。

环境准备

master 安装 nfs 服务端

复制代码
apt install -y nfs-kernel-server
mkdir -m 777 /nfsshares
echo hello laoma > /nfsshares/index.html

cat << EOF > /etc/exports
/nfsshares *(rw)
EOF
systemctl restart nfs-server.service

所有 worker 节点安装 nfs 客户端

复制代码
apt install -y nfs-common

pod‑with‑nfs.yaml

复制代码
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: nginx
  name: nginx
spec:
  volumes:
  - name: nfs
    nfs:
      server: 10.1.8.30
      path: "/nfsshares"
  containers:
  - image: hub.laoma.cloud/library/nginx
    name: nginx
    volumeMounts:
    - name: nfs
      mountPath: "/usr/share/nginx/html"
kubectl apply -f pod-with-nfs.yaml
kubectl get pod -o wide
curl <pod‑ip>
# 在pod内新建文件,master的/nfsshares可以看到;删除pod,nfs服务器数据不会丢失
kubectl delete pod nginx --force

4. PV & PVC 持久存储架构

PV(PersistentVolume):集群级别资源 ,代表后端真实存储,由集群管理员创建。 PVC(PersistentVolumeClaim):命名空间级别资源,用户存储申请;K8s 自动寻找匹配 PV 完成绑定。

访问模式 accessModes

模式 说明 缩写
ReadWriteOnce 卷可以被一个节点读写挂载,同节点多 pod 可以共用 RWO
ReadOnlyMany 多节点只读挂载 ROX
ReadWriteMany 多节点同时读写挂载 RWX
ReadWriteOncePod 仅单个 Pod 读写(1.22+) RWOP

NFS 同时支持 RWO/ROX/RWX;hostPath 仅支持 RWO。

volumeMode 卷模式

  • Filesystem 默认,作为文件系统挂载到目录
  • Block 原始块设备,不做文件系统格式化,给应用直接使用块设备

回收策略 PersistentVolumeReclaimPolicy

  1. Retain(默认)保留 :删除 PVC 后,PV 状态变为 Released,保留数据;需要手动清理claimRef才能重新绑定新 PVC。
  2. Recycle:已经废弃。
  3. Delete:删除 PVC 同时删除后端存储资产;NFS 不支持 Delete,会报错。

关键点:当 PV 为 Released 状态,里面还残留上一个 PVC 的 claimRef 引用,直接新建 PVC 无法绑定,需要 kubectl edit pv 删除 claimRef 字段。

NFS 静态 PV 实验

pv.yaml

复制代码
apiVersion: v1
kind: PersistentVolume
metadata:
  name: web
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /nfsshares
    server: 10.1.8.30

pvc.yaml

复制代码
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: webclaim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

pod‑with‑pvc.yaml

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    name: web
spec:
  containers:
    - image: hub.laoma.cloud/library/nginx
      name: web
      ports:
        - containerPort: 80
          name: web‑port
      volumeMounts:
        - name: web‑persistent‑storage
          mountPath: /usr/share/nginx/html
  volumes:
    - name: web‑persistent‑storage
      persistentVolumeClaim:
        claimName: webclaim

操作命令

复制代码
kubectl apply -f pv.yaml
kubectl apply -f pvc.yaml
# 查看状态,PVC状态Bound代表绑定成功
kubectl get pv,pvc
kubectl apply -f pod-with-pvc.yaml
kubectl get pod -o wide
curl <pod‑ip>
kubectl delete pod web --force
# 删除pod,NFS后端数据依旧保留

PV‑PVC 匹配规则:

  1. accessModes 要满足 PVC 最低要求
  2. 存储容量大于等于 PVC 申请大小
  3. StorageClassName 必须一致(如果设置)

环境清理

复制代码
kubectl delete ns storage

二、Kubernetes 配置管理 ConfigMap & Secret

ConfigMap:存放普通非敏感配置,明文;上限 1MiB。 Secret:存放密码、密钥等敏感数据,内部 base64 编码,不是加密,只是简单编码。

环境准备

复制代码
kubectl create ns configure
kubectl config set‑context --current --namespace configure

1. ConfigMap

创建 ConfigMap 三种方式

  1. ‑‑from‑literal 键值对

  2. ‑‑from‑file 文件

  3. ‑‑from‑file 整个目录

    字面量键值对

    kubectl create configmap mysql --from‑literal=password=redhat

    文件方式

    echo Hello World > index.html
    kubectl create configmap web1 --from‑file=./index.html

    目录方式

    mkdir web2
    mv index.html error.html web2
    kubectl create configmap web2 --from‑file=./web2

Pod 引用 ConfigMap 两种方式

  1. 环境变量 configMapKeyRef pod‑with‑env‑from‑configmap.yaml

    apiVersion: v1
    kind: Pod
    metadata:
    name: mysql
    labels:
    name: mysql
    spec:
    containers:

    • image: hub.laoma.cloud/library/mysql:latest
      imagePullPolicy: IfNotPresent
      name: mysql
      ports:
      • containerPort: 3306
        name: mysql
        env:
      • name: MYSQL_ROOT_PASSWORD
        valueFrom:
        configMapKeyRef:
        name: mysql
        key: password
  2. Volume 挂载方式(最常用)

configMap 作为卷挂载:key = 文件名,value = 文件内容。支持整体挂载,也支持指定单个 key 挂载;configMap 更新,挂载卷内容会自动同步更新。

pod‑with‑volume‑from‑configmap.yaml

复制代码
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: web
  name: web
spec:
  containers:
  - image: hub.laoma.cloud/library/nginx:latest
    imagePullPolicy: IfNotPresent
    name: web
    volumeMounts:
    - name: webcontent
      mountPath: "/usr/share/nginx/html"
  volumes:
  - name: webcontent
    configMap:
      name: web2

单个 key 挂载两种写法:items 方式 /subPath 方式。注意:subPath 挂载的文件不会自动热更新 configmap。

综合实验:haproxy + webapp 负载均衡案例

需求

  1. haproxy pod,配置文件存放在 configmap,volume 挂载到/usr/local/etc/haproxy/haproxy.cfg,转发流量到 webapp‑1、webapp‑2。
  2. webapp‑1、webapp‑2 为 nginx pod,使用 configmap 提供 index.html、error.html 页面内容。
步骤 1 创建 webapp‑1
复制代码
kubectl create cm webapp‑1 --from‑literal=index.html="hello webapp‑1" --from‑literal=error.html="sorry, error."

pod‑webapp‑1.yaml

复制代码
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: webapp‑1
  name: webapp‑1
spec:
  containers:
  - name: nginx
    image: hub.laoma.cloud/library/nginx:latest
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: config
      mountPath: "/usr/share/nginx/html"
      readOnly: true
  volumes:
  - name: config
    configMap:
      name: webapp‑1
kubectl apply -f pod-webapp-1.yaml
步骤 2 创建 webapp‑2
复制代码
kubectl create cm webapp‑2 --from‑literal=index.html="hello webapp‑2" --from‑literal=error.html="sorry, error."

pod‑webapp‑2.yaml

复制代码
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: webapp‑2
  name: webapp‑2
spec:
  containers:
  - name: nginx
    image: hub.laoma.cloud/library/nginx:latest
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: config
      mountPath: "/usr/share/nginx/html"
      readOnly: true
  volumes:
  - name: config
    configMap:
      name: webapp‑2
kubectl apply -f pod-webapp-2.yaml
步骤 3 haproxy 配置与 pod

获取 webapp‑1、webapp‑2 的 PodIP 填入 haproxy.cfg backend server 地址。

haproxy.cfg

复制代码
global
    daemon
    maxconn 256
defaults
    mode http
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms
frontend http‑in
    bind *:8080
    default_backend servers
backend servers
    server  app1 10.224.xx.xx:80 check
    server  app2 10.224.xx.xx:80 check
kubectl create cm haproxy.cfg --from‑file=haproxy.cfg=./haproxy.cfg

pod‑haproxy.yaml

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: haproxy
spec:
  containers:
  - name: haproxy
    image: hub.laoma.cloud/library/haproxy
    imagePullPolicy: IfNotPresent
    securityContext:
      allowPrivilegeEscalation: true
    volumeMounts:
    - name: config
      mountPath: "/usr/local/etc/haproxy"
      readOnly: true
  volumes:
  - name: config
    configMap:
      name: haproxy.cfg
kubectl apply -f pod-haproxy.yaml
# 访问haproxy podIP:8080,轮询返回webapp‑1与webapp‑2页面
curl http://<haproxy‑pod‑ip>:8080

2. Secret

Secret 存储敏感信息,数据内部是 base64 编码,不是加密,仅简单编码,不能当做加密使用。

Secret 类型:

  1. generic (Opaque):通用键值、文件。
  2. docker‑registry:镜像仓库登录凭据。
  3. tls:存放证书私钥。

创建 secret

复制代码
# 字面量generic
kubectl create secret generic mysecret1 --from‑literal=user=tom --from‑literal=password1=redhat

# 文件方式
kubectl create secret generic mysecret2 --from‑file=./user --from‑file=./password1

# docker‑registry镜像仓库凭据
kubectl create secret docker‑registry registry --docker‑username=laoma --docker‑password=redhat --docker‑email=admin@laoma.cloud --docker‑server=registry.laoma.cloud

# tls证书密钥secret
openssl genrsa -out www.key 2048
openssl req -new -key www.key -out www.csr -subj "/C=CN/ST=JS/L=NJ/O=LM/OU=DEVOPS/CN=www.laoma.cloud"
openssl x509 -req -days 3650 -in www.csr -signkey www.key -out www.crt
kubectl create secret tls www‑tls --cert=./www.crt --key=./www.key

Pod 引用 Secret

  1. 环境变量 secretKeyRef

    env:
    ‑ name: MYSQL_ROOT_PASSWORD
    valueFrom:
    secretKeyRef:
    name: mysecret1
    key: password1

  2. Volume 挂载 secret 卷

    volumes:
    ‑ name: webcontent
    secret:
    secretName: web
    volumeMounts:
    ‑ name: webcontent
    mountPath: "/usr/share/nginx/html"

secret 卷默认文件权限 644,可以通过defaultMode设置全局权限;items 可以单独设置每个 key 文件 mode 权限。secret 卷挂载同样支持配置热更新。

综合实验

使用 mysql+wordpress 部署 blog:

  1. mysql 密码、站点证书存放在 secret;
  2. nginx 虚拟主机 vhost 配置文件由 configmap 提供。

环境清理

复制代码
kubectl delete ns configure

小结

  1. 临时存储:emptyDir,Pod 删除数据丢失,用于 Pod 内多容器共享临时数据。
  2. 节点本地存储:hostPath,绑定节点目录,多节点环境 pod 漂移会出现数据不一致。
  3. 网络存储 NFS,实现跨节点持久共享。
  4. PV‑PVC 实现存储与业务解耦,管理员维护 PV,业务开发只申请 PVC。
  5. ConfigMap 管理普通配置,Secret 管理敏感信息(仅 base64 编码,不是加密)。
  6. ConfigMap/Secret 两种注入方式:环境变量、volume 挂载;subPath 挂载不支持热更新,直接 volume 整体挂载支持热更新。
相关推荐
逐流人1 小时前
ELK企业级日志分析系统:从零搭建集中化日志平台
运维·elk·云原生·云计算·日志分析
Z21-X1 小时前
云原生运维学习笔记:存储、网络与操作系统——云计算的底层基石
运维·笔记·学习·云原生
qianyuqiye11 小时前
K8s 命名空间与 Pod 入门:从概念到实战
java·docker·kubernetes
SelectDB15 小时前
开源替代怎么选:能力对照、三条部署路径与四类边界速查
数据库·云原生·开源
SelectDB15 小时前
自建与托管怎么选:开源自建、私有化与云上托管三条路径速查
数据库·云原生·开源
fengkai454515 小时前
3、Kubernetes的Namespace&Contexts&Pod&YAML格式
运维·容器·kubernetes·k8s·namespace·yaml·pod
SatanII16 小时前
K8s 存储与配置管理|Volume、ConfigMap、Secret 核心笔记
笔记·rpc·kubernetes
容器魔方16 小时前
Volcano v1.16 发布:新增 NamespaceQueue 与 fairshare,拓展 HyperNode 生态
人工智能·云原生·容器·华为云·云计算
秦jh_17 小时前
【Docker】镜像、卷原理
运维·docker·容器