配置 Pod 以使用 PersistentVolume 存储

本页面介绍如何将 Pod 配置为使用PersistentVolumeClaim 作为存储。过程总结如下:

  1. 作为集群管理员,你创建一个由物理存储支持的 PersistentVolume。你不会将此卷与任何 Pod 相关联。

  2. 现在你扮演开发者/集群用户的角色,创建一个 PersistentVolumeClaim,它将自动绑定到一个合适的 PersistentVolume。

  3. 你创建一个使用上述 PersistentVolumeClaim 作为存储的 Pod。

开始之前

  • 你需要拥有一个只有一个节点的 Kubernetes 集群,并且必须配置 kubectl 命令行工具与你的集群通信。如果你还没有单节点集群,可以使用 Minikube 创建一个。

  • 熟悉 Persistent Volumes 中的内容。

在你的节点上创建一个 index.html 文件

打开你的集群中的单个节点的 Shell。打开 Shell 的方式取决于你设置集群的方式。例如,如果你正在使用 Minikube,可以通过输入 minikube ssh 打开节点的 Shell。

在该节点的 Shell 中,创建一个 /mnt/data 目录

# This assumes that your Node uses "sudo" to run commands
# as the superuser
sudo mkdir /mnt/data

/mnt/data 目录中,创建一个 index.html 文件

# This again assumes that your Node uses "sudo" to run commands
# as the superuser
sudo sh -c "echo 'Hello from Kubernetes storage' > /mnt/data/index.html"

测试 index.html 文件是否存在

cat /mnt/data/index.html

输出应为

Hello from Kubernetes storage

现在你可以关闭到你的节点的 Shell。

创建 PersistentVolume

在本练习中,你将创建一个 hostPath PersistentVolume。Kubernetes 支持在单节点集群上使用 hostPath 进行开发和测试。hostPath PersistentVolume 使用节点上的文件或目录来模拟网络连接存储。

在生产集群中,你不会使用 hostPath。集群管理员将配置网络资源,例如 Google Compute Engine 持久盘、NFS 共享或 Amazon Elastic Block Store 卷。集群管理员还可以使用 StorageClasses 设置动态配置

以下是 hostPath PersistentVolume 的配置文件

apiVersion: v1
kind: PersistentVolume
metadata:
  name: task-pv-volume
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"

配置文件指定卷位于集群节点的 /mnt/data 处。配置还指定了 10 GiB 的大小和 ReadWriteOnce 的访问模式,这意味着该卷可以由单个节点以读写方式挂载。它为 PersistentVolume 定义了 StorageClass 名称 manual,这将用于将 PersistentVolumeClaim 请求绑定到此 PersistentVolume。

创建 PersistentVolume

kubectl apply -f https://k8s.io/examples/pods/storage/pv-volume.yaml

查看 PersistentVolume 的信息

kubectl get pv task-pv-volume

输出显示 PersistentVolume 的 STATUSAvailable。这意味着它尚未绑定到 PersistentVolumeClaim。

NAME             CAPACITY   ACCESSMODES   RECLAIMPOLICY   STATUS      CLAIM     STORAGECLASS   REASON    AGE
task-pv-volume   10Gi       RWO           Retain          Available             manual                   4s

创建 PersistentVolumeClaim

下一步是创建一个 PersistentVolumeClaim。Pod 使用 PersistentVolumeClaims 请求物理存储。在本练习中,你将创建一个 PersistentVolumeClaim,它请求一个至少 3 GiB 的卷,该卷可以同时为至多一个节点提供读写访问。

以下是 PersistentVolumeClaim 的配置文件

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: task-pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 3Gi

创建 PersistentVolumeClaim

kubectl apply -f https://k8s.io/examples/pods/storage/pv-claim.yaml

创建 PersistentVolumeClaim 后,Kubernetes 控制面会查找满足该声明要求的 PersistentVolume。如果控制面找到一个具有相同 StorageClass 的合适 PersistentVolume,则将该声明绑定到该卷。

再次查看 PersistentVolume

kubectl get pv task-pv-volume

现在输出显示 STATUSBound

NAME             CAPACITY   ACCESSMODES   RECLAIMPOLICY   STATUS    CLAIM                   STORAGECLASS   REASON    AGE
task-pv-volume   10Gi       RWO           Retain          Bound     default/task-pv-claim   manual                   2m

查看 PersistentVolumeClaim

kubectl get pvc task-pv-claim

输出显示 PersistentVolumeClaim 已绑定到你的 PersistentVolume task-pv-volume

NAME            STATUS    VOLUME           CAPACITY   ACCESSMODES   STORAGECLASS   AGE
task-pv-claim   Bound     task-pv-volume   10Gi       RWO           manual         30s

创建 Pod

下一步是创建一个 Pod,该 Pod 使用你的 PersistentVolumeClaim 作为卷。

以下是 Pod 的配置文件

apiVersion: v1
kind: Pod
metadata:
  name: task-pv-pod
spec:
  volumes:
    - name: task-pv-storage
      persistentVolumeClaim:
        claimName: task-pv-claim
  containers:
    - name: task-pv-container
      image: nginx
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: task-pv-storage


注意,Pod 的配置文件指定了 PersistentVolumeClaim,但未指定 PersistentVolume。从 Pod 的角度来看,该声明就是一个卷。

创建 Pod

kubectl apply -f https://k8s.io/examples/pods/storage/pv-pod.yaml

验证 Pod 中的容器正在运行

kubectl get pod task-pv-pod

获取运行在你的 Pod 中的容器的 Shell

kubectl exec -it task-pv-pod -- /bin/bash

在你的 Shell 中,验证 nginx 正在从 hostPath 卷提供 index.html 文件

# Be sure to run these 3 commands inside the root shell that comes from
# running "kubectl exec" in the previous step
apt update
apt install curl
curl http://localhost/

输出显示了你写入 hostPath 卷上的 index.html 文件的文本

Hello from Kubernetes storage

如果你看到该消息,则表示你已成功配置 Pod 使用 PersistentVolumeClaim 中的存储。

清理

删除 Pod

kubectl delete pod task-pv-pod

在两个位置挂载同一个 PersistentVolume

你已经了解如何创建 PersistentVolume 和 PersistentVolumeClaim,以及如何将卷挂载到容器中的单个位置。接下来我们探讨如何在容器中的两个不同位置挂载同一个 PersistentVolume。示例如下:


apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
    - name: test
      image: nginx
      volumeMounts:
        # a mount for site-data
        - name: config
          mountPath: /usr/share/nginx/html
          subPath: html
        # another mount for nginx config
        - name: config
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf
  volumes:
    - name: config
      persistentVolumeClaim:
        claimName: task-pv-storage

此处

  • subPath:此字段允许将挂载的 PersistentVolume 中的特定文件或目录暴露到容器内的不同位置。在此示例中
    • subPath: html 挂载 html 目录。
    • subPath: nginx.conf 挂载特定文件 nginx.conf。

由于第一个 subPath 是 html,需要在节点的 /mnt/data/ 目录中创建一个 html 目录。

第二个 subPath nginx.conf 表示将使用 /mnt/data/ 目录中的一个文件。无需创建其他目录。

你的 nginx 容器上将进行两次卷挂载

  • /usr/share/nginx/html 用于静态网站
  • /etc/nginx/nginx.conf 用于默认配置

将节点上的 index.html 文件移动到一个新文件夹

此处提及的 index.html 文件是指在"在你的节点上创建一个 index.html 文件" 部分中创建的文件。

打开你的集群中的单个节点的 Shell。打开 Shell 的方式取决于你设置集群的方式。例如,如果你正在使用 Minikube,可以通过输入 minikube ssh 打开节点的 Shell。

创建 /mnt/data/html 目录

# This assumes that your Node uses "sudo" to run commands
# as the superuser
sudo mkdir /mnt/data/html

将 index.html 移动到该目录

# Move index.html from its current location to the html sub-directory
sudo mv /mnt/data/index.html html

创建一个新的 nginx.conf 文件

user  nginx;
worker_processes  auto;

error_log /var/log/nginx/error.log notice; pid /var/run/nginx.pid;

events { worker_connections 1024; }

http { include /etc/nginx/mime.types; default_type application/octet-stream;

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for"';

access_log  /var/log/nginx/access.log  main;

sendfile        on;
#tcp_nopush     on;

keepalive_timeout  60;

#gzip  on;

include /etc/nginx/conf.d/*.conf;

}

这是默认 nginx.conf 文件的修改版本。在此,默认的 keepalive_timeout 已修改为 60

创建 nginx.conf 文件

cat <<EOF > /mnt/data/nginx.conf
user  nginx;
worker_processes  auto;
error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '\$remote_addr - \$remote_user [\$time_local] "\$request" '
                      '\$status \$body_bytes_sent "\$http_referer" '
                      '"\$http_user_agent" "\$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  60;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}
EOF

创建 Pod

在这里,我们将创建一个使用现有 persistentVolume 和 persistentVolumeClaim 的 Pod。但是,该 Pod 仅将特定文件 nginx.conf 和目录 html 挂载到容器。

创建 Pod

kubectl apply -f https://k8s.io/examples/pods/storage/pv-duplicate.yaml

验证 Pod 中的容器正在运行

kubectl get pod test

获取运行在你的 Pod 中的容器的 Shell

kubectl exec -it test -- /bin/bash

在你的 Shell 中,验证 nginx 正在从 hostPath 卷提供 index.html 文件

# Be sure to run these 3 commands inside the root shell that comes from
# running "kubectl exec" in the previous step
apt update
apt install curl
curl http://localhost/

输出显示了你写入 hostPath 卷上的 index.html 文件的文本

Hello from Kubernetes storage

在你的 Shell 中,同时验证 nginx 正在从 hostPath 卷提供 nginx.conf 文件

# Be sure to run these commands inside the root shell that comes from
# running "kubectl exec" in the previous step
cat /etc/nginx/nginx.conf | grep keepalive_timeout

输出显示了你写入 hostPath 卷上 nginx.conf 文件的修改文本

keepalive_timeout  60;

如果你看到这些消息,则表示你已成功配置 Pod 使用 PersistentVolumeClaim 中的存储中的特定文件和目录。

清理

删除 Pod

kubectl delete pod test
kubectl delete pvc task-pv-claim
kubectl delete pv task-pv-volume

如果你的集群中还没有打开到节点的 Shell,请按照之前的方式打开一个新的 Shell。

在节点上的 Shell 中,删除你创建的文件和目录

# This assumes that your Node uses "sudo" to run commands
# as the superuser
sudo rm /mnt/data/html/index.html
sudo rm /mnt/data/nginx.conf
sudo rmdir /mnt/data

现在你可以关闭到你的节点的 Shell。

访问控制

使用组 ID (GID) 配置的存储只允许使用相同 GID 的 Pod 进行写入。GID 不匹配或缺失会导致权限拒绝错误。为了减少与用户的协调需要,管理员可以在 PersistentVolume 上注解一个 GID。然后,该 GID 会自动添加到使用该 PersistentVolume 的任何 Pod 中。

按如下方式使用 pv.beta.kubernetes.io/gid 注解

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv1
  annotations:
    pv.beta.kubernetes.io/gid: "1234"

当 Pod 使用带有 GID 注解的 PersistentVolume 时,注解的 GID 将应用于 Pod 中的所有容器,就像 Pod 安全上下文中指定的 GID 一样。每个 GID,无论是来自 PersistentVolume 注解还是 Pod 规约,都将应用于每个容器中运行的第一个进程。

下一步

参考

上次修改时间:2024 年 12 月 17 日,太平洋标准时间 5:46:改进 pv 存储任务 (f31a75226e)