Kubernetes第八章--存储类型

k8s存储

 概述

在Kubernetes(K8s)中,存储系统是一个关键的组成部分,用于管理容器化应用的数据持久性和共享性。K8s的存储分类可以从多个维度进行理解,但主要分为两大类:临时存储和持久存储。关于元数据和真实数据的分类,虽然这两个概念在存储系统中普遍存在,但在K8s的存储分类中,它们并不是直接用于分类存储类型的标准。不过,可以从K8s存储类型如何管理和使用这些数据的角度来探讨。

k8s支持的卷类型

持久卷:持久卷是集群中的存储资源,就像他的名字一样,在里面存储的数据不会随着 Pod 的删除而丢失。

临时卷:有些应用程序需要额外的存储,但并不关心数据在重启后是否仍然可用。卷会遵从 Pod的生命周期,与Pod一起创建和删除。

投射卷:它允许您将多个现有卷源映射到同一个目录。通过将这些不同类型的卷源组合成一个统一的卷,可以更方便地管理和使用这些资源

  • 临时存储

EmptyDir:EmptyDir是一种在Pod中创建的空目录,用于在容器之间共享文件。它的数据存储在Pod所在节点的本地磁盘上,当Pod被删除时,数据也会被删除。这种存储方式适用于需要临时存储数据的场景,如缓存数据。在这种情况下,元数据(如目录结构、文件属性等)和真实数据(文件内容)都是临时的,与Pod的生命周期绑定。

  • 持久存储

PersistentVolume (PV) 和 PersistentVolumeClaim (PVC):

PV是由管理员配置的存储资源,而PVC是用户请求的存储资源。PVC允许用户抽象地请求存储资源,而不需要关心具体的存储后端。PV和PVC的结合使用,可以动态地分配和释放存储资源,用于持久化存储真实数据。元数据(如PV和PVC的配置信息)存储在K8s的etcd数据库中,而真实数据则存储在配置的存储后端(如NFS、Ceph等)上。

NFS:

NFS卷将网络文件系统(NFS)挂载到容器中,允许跨多个Pod和节点共享数据。元数据(如NFS文件系统的目录结构、文件权限等)和真实数据都存储在NFS服务器上,实现了数据的持久化和共享。

ConfigMap 和 Secret:

虽然ConfigMap和Secret主要用于挂载配置文件和密钥到容器中,但它们也可以视为一种存储形式。这些资源对象的元数据(如配置项的名称、值等)和真实数据(配置文件内容、密钥值等)都存储在K8s的etcd数据库中。不过,它们的主要用途是配置和安全性,而非大规模的数据存储。

StatefulSet:

StatefulSet是一种用于管理有状态应用的控制器,它确保每个Pod都有稳定的标识和顺序。StatefulSet通常会为每个Pod分配一个独特的持久卷(通过PVC实现),以存储Pod的持久化数据。在这种情况下,元数据(如StatefulSet的配置、Pod的标识等)存储在K8s的etcd数据库中,而真实数据则存储在分配的持久卷上。

总结

在K8s中,元数据和真实数据的存储和管理是通过不同的机制实现的。元数据通常存储在K8s的etcd数据库中,用于管理集群的状态和配置。而真实数据则根据所选的存储类型(如PV、PVC、NFS等)存储在相应的存储后端上。通过合理配置和使用这些存储类型,K8s能够提供灵活、可靠的数据存储解决方案,满足各种应用场景的需求。

ConfigMap介绍与使用

K8s(Kubernetes)中的ConfigMap是一种用于存储配置数据的API对象,它属于Kubernetes中的核心对象。ConfigMap的主要作用是将应用程序的配置信息与容器镜像分离,以便在不重新构建镜像的情况下进行配置的修改和更新。

用途:

ConfigMap用于存储键值对形式的配置数据,这些数据可以包括环境变量、命令行参数、配置文件等。它提供了一种集中管理和传递配置信息的机制,使得应用程序能够从ConfigMap中获取配置数据,从而在不修改容器镜像的前提下,动态地修改应用程序的配置参数。

与Secret的区别:

ConfigMap主要用于存储非敏感的配置数据,如应用程序的配置文件、环境变量等,而Secret则用于存储敏感的数据,如密码、密钥等。Secret提供了更高的安全性和访问控制机制。

通过命令行管理ConfigMap示例:

使用文字值创建,利用 --from-literal 参数传递配置信息,该参数可以使用多次

[root@k8s-master test02]# kubectl create cm literal-config --from-literal=name=lili --from-literal=passwd=123
configmap/literal-config created

# 查看指定cm的属性信息
[root@k8s-master test02]# kubectl describe cm literal-config
Name:         literal-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
name:
----
lili
passwd:
----
123

BinaryData
====

Events:  <none>

# 使用YAML格式输出
[root@k8s-master test02]# kubectl get cm literal-config -o yaml
apiVersion: v1
data:
  name: lili
  passwd: "123"
kind: ConfigMap
metadata:
  creationTimestamp: "2025-01-24T03:33:55Z"
  name: literal-config
  namespace: default
  resourceVersion: "391106"
  uid: 860618b7-3177-4f8c-ac83-62d458da7dc0

通过目录创建:

--from-file 指定在目录下的所有文件都会被用在 ConfigMap 里面创建一个键值对,键的名字就是文件名,值就是文件的内容

示例:

# 以下两个文件里分别有两个值
[root@k8s-master ~]# ls test_cm/
name  passwd

# 通过目录创建
[root@k8s-master ~]# kubectl create cm test-cmdir --from-file=./test_cm/
configmap/test-cmdir created

# 查看configmap
[root@k8s-master ~]# kubectl get cm
NAME               DATA   AGE
kube-root-ca.crt   1      9d
literal-config     2      35m
test-cmdir         2      10s

# 查看属性信息
[root@k8s-master ~]# kubectl describe cm test-cmdir 
Name:         test-cmdir
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
name:
----
haha
lili

passwd:
----
1234
6789


BinaryData
====

Events:  <none>

# 通过yaml格式输出
[root@k8s-master ~]# kubectl get cm test-cmdir -o yaml
apiVersion: v1
data:
  name: |
    haha
    lili
  passwd: |
    1234
    6789
kind: ConfigMap
metadata:
  creationTimestamp: "2025-01-24T04:09:00Z"
  name: test-cmdir
  namespace: default
  resourceVersion: "394234"
  uid: 35476d3a-3ac0-4409-b04d-06936cde7d1e

通过文件创建:

--from-file 参数只要指定为一个文件就可以从单个文件中创建 ConfigMap。--from-file 这个参数可以使用多次,你可以使用两次分别指定上个实例中的那两个配置文件,效果就跟指定整个目录是一样的

示例:

[root@k8s-master test02]# kubectl create cm test-config --from-file=test_cm.file 
configmap/test-config created

# 查看configmap
[root@k8s-master test02]# kubectl get cm
NAME               DATA   AGE
kube-root-ca.crt   1      9d
literal-config     2      108m
test-cmdir         2      73m
test-config        1      6s

# 查看cm的属性信息
[root@k8s-master test02]# kubectl describe cm test-config 
Name:         test-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
test_cm.file:
----
name=hehe
passwd=123456


BinaryData
====

Events:  <none>

# 以yaml的格式输出指定cm
[root@k8s-master test02]# kubectl get cm test-config -o yaml
apiVersion: v1
data:
  test_cm.file: |
    name=hehe
    passwd=123456
kind: ConfigMap
metadata:
  creationTimestamp: "2025-01-24T05:22:24Z"
  name: test-config
  namespace: default
  resourceVersion: "396512"
  uid: bfa82c9a-2aea-425e-8623-fe26aee5473b
  • ConfigMap使用
环境变量

环境变量:可以将ConfigMap中的数据设置为Pod中容器的环境变量。这样,容器在启动时就可以从环境变量中获取配置信息。

注意:使用该 ConfigMap 挂载的 Env 不会同步更新

示例:

[root@k8s-master test02]# vim config-env.yaml 
---
kind: ConfigMap
apiVersion: v1
metadata: 
  name: literal-config
data: 
  name: hehe     # 定义数据
  passwd: admin
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: env-config
data: 
  log_level: INFO
---
kind: Pod   # 定义Pod
apiVersion: v1
metadata: 
  name: env-pod
spec: 
  restartPolicy: Never   # 重启策略 永不
  containers: 
  - name: test
    image: myos:nginx
    command:   # 启动命令 打印容器内部env环境变量
    - sh
    - -c
    - env
    env:    # 定义env 为容器内部添加环境变量
    - name: USERNAME  # 环境变量名字
      valueFrom: # 值来源
        configMapKeyRef: # 值来源于configmap
          name: literal-config # 值来源的configmap类别的名字
          key: name  # key的名字/字段
    - name: PASSWORD
      valueFrom: 
        configMapKeyRef:
          name: literal-config
          key: passwd
    envFrom:     # 直接引入名为env-config的configmap
    - configMapRef: 
        name: env-config
#创建以上资源清单文件
[root@k8s-master test02]# kubectl apply -f config-env.yaml 
configmap/literal-config unchanged
configmap/env-config unchanged
pod/env-pod created        

[root@k8s-master test02]# kubectl get pods
NAME      READY   STATUS      RESTARTS   AGE
env-pod   0/1     Completed   0          5m10s

[root@k8s-master test02]# kubectl logs env-pod 
NGINX_PORT_8888_TCP=tcp://10.245.8.8:8888
NGINX_PORT_8888_TCP_ADDR=10.245.8.8
HOSTNAME=env-pod
USERNAME=hehe  # literal-config添加的环境变量
NGINX_PORT_8888_TCP_PORT=8888
PASSWORD=admin    # literal-config添加的环境变量
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.245.0.1
NGINX_PORT=tcp://10.245.8.8:8888
KUBERNETES_PORT=tcp://10.245.0.1:443
PWD=/usr/local/nginx/html
HOME=/root
NGINX_SERVICE_PORT=8888
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP=tcp://10.245.0.1:443
SHLVL=1
NGINX_PORT_8888_TCP_PROTO=tcp
KUBERNETES_SERVICE_PORT=443
log_level=INFO    # env-config添加的环境变量
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/nginx/sbin
KUBERNETES_SERVICE_HOST=10.245.0.1
NGINX_SERVICE_HOST=10.245.8.8
_=/usr/bin/env
命令行参数

命令行参数:将ConfigMap中的数据作为命令行参数传递给容器中的应用程序。这通常需要先将ConfigMap的数据保存在环境变量中,然后通过环境变量的方式引用。

[root@k8s-master test02]# vim cm-command.yaml 
---
kind: Pod
apiVersion: v1
metadata: 
  name: cm-command-pod
spec: 
  restartPolicy: Never
  containers: 
  - name: test
    image: myos:nginx
    command: 
    - sh
    - -c
    - |
      echo ${USERNAME} ${PASSWORD}
    env: 
    - name: USERNAME
      valueFrom: 
        configMapKeyRef: 
          name: literal-config
          key: name
    - name: PASSWORD
      valueFrom: 
        configMapKeyRef: 
          name: literal-config
          key: passwd
  
[root@k8s-master test02]# kubectl apply -f cm-command.yaml 
pod/cm-command-pod created

[root@k8s-master test02]# kubectl logs cm-command-pod 
hehe admin
卷挂载

卷挂载:ConfigMap可以作为卷挂载到Pod中,使得容器可以直接读取ConfigMap中的配置文件。每个键值对都会生成一个文件,其中键为文件名,值为文件内容。这样,应用程序就可以根据需要读取配置文件中的配置信息。

示例:

[root@k8s-master test02]# vim cm-volume.yaml 
---
apiVersion: v1
kind: Pod
metadata:
 name: cm-volume-pod
spec:
 restartPolicy: Never
 containers:
  - name: test
    image: myos:nginx
    volumeMounts: # volume挂载
    - name: config-volume # 挂载下面指定的 volume
      mountPath: /etc/config # 挂载到的目录(容器内路径,该目录下,文件名就是键名,文件内容就是键值)
      subPath: 
 volumes:
  - name: config-volume  # volume 名称
    configMap:            # 来自configmap
     name: literal-config  # 上边的示例已经定义过
     
[root@k8s-master test02]# kubectl apply -f cm-volume.yaml 
pod/cm-volume-pod created

[root@k8s-master test02]# kubectl exec -it cm-volume-pod -- bash

[root@cm-volume-pod html]# ls /etc/config
name  passwd

# 这种方式创建的是连接文件 热更新
[root@cm-volume-pod html]# cat /etc/config/name
hehe[root@cm-volume-pod html]# cat /etc/config/passwd
admin[root@cm-volume-pod html]# ls -l /etc/config
total 0
lrwxrwxrwx 1 root root 11 Jan 24 07:16 name -> ..data/name
lrwxrwxrwx 1 root root 13 Jan 24 07:16 passwd -> ..data/passwd
热更新

通过kubectl edit configmap [configmap name]命令直接修改内容就可以达到热更新

示例:

[root@k8s-master test02]# cat cm-update.yaml 
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: log-config
  namespace: default
data:
  log_level: INFO
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 1
  selector: 
    matchLabels: 
      run: my-nginx
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
        - name: nginx
          image: myos:nginx
          ports:
            - containerPort: 80
          volumeMounts:
            - name: config-volume
              mountPath: /etc/config # 容器内这个目录下会有 log_level 这个文件,内容为 INFO
      volumes:
        - name: config-volume
          configMap:
            name: log-config
# 查看容器里的文件
[root@k8s-master test02]# kubectl exec -it my-nginx-746bd4859b-qw6wp -- cat /etc/config/log_level
INFO
# 使用edit命令修改cm的键值为NOTICE
[root@k8s-master test02]# kubectl edit cm log-config 
configmap/log-config edited
# 过个10秒再次查看容器里的文件,文件的配置修改了
[root@k8s-master test02]# kubectl exec -it my-nginx-746bd4859b-qw6wp -- cat /etc/config/log_level
NOTICE

补充:添加不可改变选项

# 添加不可改变选项 immutable: true 
[root@k8s-master test02]# kubectl edit cm log-config 
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
  log_level: NOTICE
immutable: true  # 添加不可改变选项
kind: ConfigMap
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","data":{"log_level":"INFO"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"log-config","namespace":"default"}}
  creationTimestamp: "2025-01-24T08:56:32Z"
  name: log-config
  namespace: default
  resourceVersion: "429330"
  uid: 4e138ec5-861f-4205-8611-69c00035e973
# 添加之后就无法进行热更新了
# 添加之后是不可逆的 需要重新创建一个cm

Pod滚动更新

ConfigMap 更新后,并不会让相应的文件重载。例如,Nginx 在启动时,会加载一次配置文件(配置文件中有 ConfigMap 的相关参数),加载完成后,无论这个配置文件再怎么变化,Nginx 都不会再加载它。因此需要 ConfigMap 更新后滚动更新 Pod

可以通过修改 pod annotations 的方式强制触发滚动更新。这里我们在 Deployment.spec.template.metadata.annotations 中添加 version/config字段来实现pod的滚动更新

kubectl patch deployment my-nginx --patch '{"spec": {"template": {"metadata": {"annotations":{"version/config": "20250124" }}}}}'

注意:更新 ConfigMap 后:

  • 使用该 ConfigMap 挂载的 Env 不会同步更新
  • 使用该 ConfigMap 挂载的 Volume 中的数据需要一段时间(实测大概10秒)才能同步更新
CM的优势

配置解耦:将配置信息与容器镜像解耦,使得配置可以在不重新构建镜像的情况下进行修改和管理。

动态更新:ConfigMap中的配置可以在运行时动态更新,而不需要重新启动应用程序。

版本控制:ConfigMap中的配置可以使用版本控制系统进行管理,随时回滚到之前的版本。

共享和复用:ConfigMap可以被多个应用程序共享和复用,提高了配置的一致性和可维护性。

综上所述,K8s ConfigMap是Kubernetes中用于存储和管理配置数据的重要组件,它提供了灵活的配置管理方式,使得应用程序的配置更加清晰、易于管理和更新。

 Secret

概述

K8s(Kubernetes)中的Secret是一种用于保存敏感信息的资源对象,如密码、OAuth令牌、ssh密钥等。这些信息如果直接放在Pod的定义中或镜像中,可能会带来安全风险,因为Pod的定义和镜像都可能被存储在版本控制系统中,或者被不同的用户访问。通过使用Secret,可以更安全地管理这些敏感信息。

Secret特性

  1. 安全性:Secret中的信息被加密存储(实际上是Base64编码,但Kubernetes社区通常称之为加密),以减少敏感信息泄露的风险。
  2. 灵活性:Secret可以以多种方式被Pod使用,包括作为环境变量、挂载到Pod中的卷中的文件,或者在kubelet为Pod拉取镜像时使用。
  3. 可重用性:多个Pod可以引用同一个Secret,从而避免在多个地方重复存储相同的敏感信息。
  4. k8s通过仅仅将Secret分发到需要访问Secret的Pod所在的节点来保障安全性
  5. Secret只会存储在节点的内存中,永不写入物理存储,这样从节点删除secret时就不需要擦除磁盘数据

Secret的类型

  • Opaque:这是默认的Secret类型,用于存储任意格式的敏感信息。数据以Base64编码的形式存储在Secret中。
  • kubernetes.io/service-account-token:由Kubernetes自动创建,用于Pod与API Server之间的通信认证。
  • kubernetes.io/dockerconfigjson:用于存储私有Docker Registry的认证信息。
  • kubernetes.io/tls:用于存储TLS证书和私钥,以便Pod能够使用SSL/TLS协议进行安全通信。
  • kubernetes.io/basic-auth:用于存储基本认证信息,如用户名和密码

OpaqueSecret

Opaque和configMap很像, 数据是一个 map 类型,要求 value 是 base64 编码格式,可以用于环境变量和数据卷挂载

示例:

# 使用base64编码
[root@k8s-master test02]# echo -n hehe | base64
aGVoZQ==
[root@k8s-master test02]# echo -n 321 | base64
MzIx
# 解码
[root@k8s-master test02]# echo -n aGVoZQ== | base64 -d
hehe
# 使用加密后的用户名和密码创建 Secret
[root@k8s-master test02]# vim secret.yaml 
---
kind: Secret
apiVersion: v1
metadata: 
  name: mysecret
type: Opaque
data: 
  passwd: MzIx
  username: aGVoZQ==

[root@k8s-master test02]# kubectl apply -f secret.yaml 
secret/mysecret created
# 查看secret
[root@k8s-master test02]# kubectl get secret
NAME       TYPE     DATA   AGE
mysecret   Opaque   2      2m18s
# 查看secret属性信息
[root@k8s-master test02]# kubectl describe secrets mysecret 
Name:         mysecret
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
passwd:    3 bytes
username:  4 bytes
# 以yaml的格式输出指定的secret
[root@k8s-master test02]# kubectl get secrets mysecret -o yaml
apiVersion: v1
data:
  passwd: MzIx
  username: aGVoZQ==
kind: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","data":{"passwd":"MzIx","username":"aGVoZQ=="},"kind":"Secret","metadata":{"annotations":{},"name":"mysecret","namespace":"default"},"type":"Opaque"}
  creationTimestamp: "2025-01-24T15:57:16Z"
  name: mysecret
  namespace: default
  resourceVersion: "442203"
  uid: 9bff22dc-aaf2-4c1f-af1f-d4bda8accd8c
type: Opaque

在pod中使用secret

环境变量

作为环境变量(不可以热更新)

[root@k8s-master test02]# vim mysecret.yaml 
---
kind: Deployment
apiVersion: apps/v1
metadata: 
  name: deploy-secret
spec: 
  replicas: 3
  selector: 
    matchLabels: 
      app: secret
  template: 
    metadata: 
      labels: 
        app: secret
    spec: 
      containers: 
      - name: test
        image: myos:httpd
        command: 
        - sh
        - -c
        - |
          echo ${TEST_USER} ${TEST_PASS}
        env:     # 添加环境变量
        - name: TEST_USER  # 环境变量名
          valueFrom:        # 值来源
            secretKeyRef:    # 从 Secret 中获取
              name: mysecret # Secret 的名字,在以上示例已定义
              key: username  # Secret 中的键名
        - name: TEST_PASS
          valueFrom: 
            secretKeyRef: 
              name: mysecret
              key: passwd
[root@k8s-master test02]# kubectl apply -f mysecret.yaml 
deployment.apps/deploy-secret created

# secret中的键值会自动的解码
[root@k8s-master test02]# kubectl logs deploy-secret-6c848876bf-dcb2s 
hehe 321
卷挂载

secret也是支持热更新的和configmap一样,但是使用secret作为子路径卷挂载的容器不会收到secret更新

将secret挂载到volume中示例:

[root@k8s-master test02]# vim secret_volume.yaml 
---
kind: Pod
apiVersion: v1
metadata: 
  name: secret-test
spec: 
  volumes:   # 创建一个卷
  - name: secret  # 卷名
    secret:    # 卷使用的方案
      secretName: mysecret  # 来自于上面案例创建的 mysecret
  containers: 
  - name: test
    image: myos:nginx
    volumeMounts:   # 卷挂载
    - name: secret   # 挂载的是上面声明的 secrets
      mountPath: /data  # 挂载的目录(容器内目录)
      readOnly: true  # 只读 

[root@k8s-master test02]# kubectl apply -f secret_volume.yaml 
pod/secret-test created

[root@k8s-master test02]# kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
secret-test   1/1     Running   0          4s

# 进入容器
[root@k8s-master test02]# kubectl exec -it secret-test -- bash
[root@secret-test html]# cd /data
# Opaque Secret 中的用户名和密码都已经挂载进来了
[root@secret-test data]# ls
passwd  username
# 查看内容,发现内容已经自动被解码
[root@secret-test data]# cat passwd 
321[root@secret-test data]# cat username 
hehe

注意事项:

  • 当使用Secret时,应确保Pod有足够的权限来访问这些Secret。
  • Secret中的信息虽然被加密(实际上是Base64编码),但应尽量避免将过于敏感的信息存储在Kubernetes集群中,以防止潜在的泄露风险。
  • 定期检查并更新Secret中的敏感信息,以确保系统的安全性。

Downward API(将pod元数据反馈到容器内部)

在Kubernetes(k8s)中,Downward API 是一种特殊类型的 API,它允许 Pod 中的容器获取关于 Pod 本身及其所在环境的元数据信息。这些信息可以通过两种方式注入到容器内部:环境变量和卷挂载(Volume Mounts)。

  • 提供容器元数据
  • 动态配置
  • 与kubernetes环境集成

Downward API 的两种注入方式

环境变量

环境变量是 Downward API 注入信息到容器的常用方式,适用于单个变量的情况。通过 Downward API,可以将 Pod 的 IP 地址、名称、命名空间等基本信息以环境变量的形式注入到容器内部。这样,容器内的应用程序就可以通过读取这些环境变量来获取 Pod 的相关信息。

示例:

[root@k8s-master test02]# vim test_downwardapi.yaml 
kind: Pod
apiVersion: v1
metadata: 
  name: downward-api-pod
spec: 
  restartPolicy: Never
  containers: 
  - name: test
    image: myos:nginx
    env:   # 定义容器的环境变量
    - name: POD_NAME # POD_NAME 环境变量,其值来源于 Pod 的元数据字段 metadata.name
      valueFrom: 
        fieldRef: 
          fieldPath: metadata.name
    - name: NAMESPACE
      valueFrom: 
        fieldRef: 
          fieldPath: metadata.namespace
    - name: POD_IP
      valueFrom: 
        fieldRef: 
          fieldPath: status.podIP
    - name: CPU_LIMIT  # CPU_LIMIT 环境变量,其值来源于 Pod 的资源限制字段 limits.cpu
      valueFrom: 
        resourceFieldRef: 
          resource: limits.cpu
    - name: CPU_REQUEST
      valueFrom: 
        resourceFieldRef: 
          resource: requests.cpu
          
[root@k8s-master test02]# kubectl apply -f test_downwardapi.yaml 
pod/downward-api-pod created

[root@k8s-master test02]# kubectl get pods
NAME               READY   STATUS    RESTARTS   AGE
downward-api-pod   1/1     Running   0          9s
secret-test        1/1     Running   0          5h58m

# 验证效果
[root@k8s-master test02]# kubectl exec -it downward-api-pod -- env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/nginx/sbin
HOSTNAME=downward-api-pod
POD_IP=10.244.85.215        # 得到的podIP地址
CPU_LIMIT=2                   # 限制2个cpu
CPU_REQUEST=0                # 0代表没有进行配额的设置
POD_NAME=downward-api-pod  #pod的名称
NAMESPACE=default
NGINX_PORT_8888_TCP_PORT=8888
KUBERNETES_SERVICE_PORT_HTTPS=443
NGINX_PORT_8888_TCP_ADDR=10.245.8.8
NGINX_PORT=tcp://10.245.8.8:8888
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
NGINX_SERVICE_HOST=10.245.8.8
NGINX_PORT_8888_TCP=tcp://10.245.8.8:8888
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.245.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.245.0.1:443
KUBERNETES_PORT_443_TCP_ADDR=10.245.0.1
NGINX_SERVICE_PORT=8888
NGINX_PORT_8888_TCP_PROTO=tcp
KUBERNETES_SERVICE_HOST=10.245.0.1
TERM=xterm
HOME=/root
卷挂载

是将 Pod 的信息生成为文件,并通过卷挂载的方式将这些文件注入到容器内部。这种方式适用于需要批量处理或复杂查询 Pod 信息的情况。

示例:

[root@k8s-master test02]# vim test_downwardapi02.yaml 
---
kind: Pod
apiVersion: v1
metadata: 
  name: test-volume-pod
  labels: 
    app: volume
spec: 
  restartPolicy: Never
  containers:
  - name: test
    image: myos:nginx
    resources: 
      limits: 
        cpu: 1
        memory: 400Mi
      requests:
        cpu: 1
        memory: 300Mi
    volumeMounts: 
    - name: downwardapi-volume
      mountPath: /podinfo
  volumes: 
  - name: downwardapi-volume
    downwardAPI: 
      items: 
      - path: "labels"  # 挂载的文件路径
        fieldRef: 
          fieldPath: metadata.labels  # 引用的字段路径
      - path: "name"
        fieldRef: 
          fieldPath: metadata.name
      - path: "namespace"
        fieldRef:
          fieldPath: metadata.namespace
      - path: "uid"
        fieldRef:
          fieldPath: metadata.uid
      - path: "cpuRequest"
        resourceFieldRef:
          containerName: test   # 引用的容器名称
          resource: requests.cpu  # 引用的资源字段
      - path: "memoryRequest"  # 挂载的文件路径
        resourceFieldRef:
          containerName: test
          resource: requests.memory
      - path: "cpuLimit"
        resourceFieldRef:
          containerName: test
          resource: limits.cpu
      - path: "memoryLimit"
        resourceFieldRef:
          containerName: test
          resource: limits.memory
          
[root@k8s-master test02]# kubectl get pods
NAME               READY   STATUS    RESTARTS   AGE
downward-api-pod   1/1     Running   0          136m
secret-test        1/1     Running   0          8h
test-volume-pod    1/1     Running   0          8m2s
# 进入容器验证效果
[root@k8s-master test02]# kubectl exec -it test-volume-pod -- bash
[root@test-volume-pod html]# cd /podinfo $$ ls
bash: cd: too many arguments
[root@test-volume-pod html]# cd /podinfo
[root@test-volume-pod podinfo]# ls
cpuLimit    labels       memoryRequest  namespace
cpuRequest  memoryLimit  name           uid
[root@test-volume-pod podinfo]# cat name
test-volume-pod[root@test-volume-pod podinfo]# cat labels
app="volume"

Downward API 支持的字段

Downward API 支持的字段包括但不限于:

spec.nodeName:宿主机名字

status.hostIP:宿主机 IP

metadata.name:Pod 的名字

metadata.namespace:Pod 的 Namespace

status.podIP:Pod 的 IP

spec.serviceAccountName:Pod 的 Service Account 的名字

metadata.uid:Pod 的 UID

metadata.labels[‘’]:指定 的 Label 值

metadata.annotations[‘’]:指定 的 Annotation 值

metadata.labels:Pod 的所有 Label

metadata.annotations:Pod 的所有 Annotation

使用 Downward API 的步骤

1、创建包含 Downward API 信息的 Pod:

编写 Pod 的 YAML 配置文件,定义需要注入的环境变量或卷挂载。

2、使用 kubectl 创建 Pod:

使用 kubectl apply -f <pod-config-file.yaml> 命令创建 Pod。

3、在容器中读取 Downward API 注入的信息:

进入 Pod 的容器内部,通过环境变量或文件来读取注入的信息。

通过以上步骤,你可以在 Kubernetes 中使用 Downward API 来获取 Pod 的相关信息,并将其注入到容器内部,以满足应用程序的需求。

 Volume(真实数据存储方式,脱离容器生命周期以外的存储方式)

K8s(Kubernetes)中的Volume(存储卷)是一种用于在Pod中持久存储数据的机制,它为Pod中的容器提供了一个共享的存储空间

定义与用途

定义:在K8s中,Volume是一种抽象的概念,用于提供Pod中容器的持久化存储。它允许将数据存储在Pod的生命周期之外,以便在容器重启、迁移或重新调度时保留数据。

用途:

  • 数据持久化:将数据存储在Volume中,确保容器重启后数据仍然存在。
  • 数据共享:Volume可以连接到Pod中的一个或多个容器,使它们能够共享相同的数据。
  • 数据备份和恢复:使用Volume来备份和还原应用程序的数据。
  • 数据迁移和复制:将Volume从一个Pod迁移到另一个Pod,或将Volume复制到其他地方。

kubernets支持的卷的类型

官网:https://kubernetes.io/zh/docs/concepts/storage/volumes/

k8s支持的卷的类型如下:

awsElasticBlockStore 、azureDisk、azureFile、cephfs、cinder、configMap、csidownwardAPI、emptyDir、fc (fibre channel)、flexVolume、flocker、gcePersistentDisk、gitRepo (deprecated)、glusterfs、hostPath、iscsi、local、nfs、persistentVolumeClaim、projected、portworxVolume、quobyte、rbd、scaleIO、secret、storageos、vsphereVolume

emptyDir

当 Pod 被分配给节点时,首先创建 emptyDir 卷,并且只要该 Pod 在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。该卷可以挂载到 Pod 每个容器中的相同或不同路径上,并且每个容器都可以读取和写入 emptyDir 卷中的文件。当出于任何原因从节点中删除 Pod 时, emptyDir 中的数据将被永久删除。

注意:容器崩溃不会从节点中移除 pod,因此 emptyDir 卷中的数据在容器时是安全的

emptyDir 的用法有:

  • 存放临时文件,例如用于基于磁盘的归并排序;
  • 用作长时间计算崩溃恢复时的检查点,供容器崩溃后恢复使用;
  • Web 服务器容器提供数据时,保存内容管理器容器提取的文件;

示例:

[root@k8s-master test02]# vim test_emptydir.yaml 
---
kind: Pod
apiVersion: v1
metadata: 
  name: test-emptydir-pod
spec: 
  containers: 
  - name: test01
    image: myos:nginx
    volumeMounts: 
    - name: emptydir-volume     # 通过哪个 volume 挂载
      mountPath: /test01_volume  # 挂载到容器的哪个目录下
  - name: test02
    image: myos:php-fpm
    volumeMounts: 
    - name: emptydir-volume
      mountPath: /test02_volume
  volumes: 
  - name: emptydir-volume  # volume 名称
    emptyDir: {}     # volume 类型
    
[root@k8s-master test02]# kubectl apply -f test_emptydir.yaml 
pod/test-emptydir-pod created

[root@k8s-master test02]# kubectl get pods
NAME                READY   STATUS    RESTARTS   AGE
test-emptydir-pod   2/2     Running   0          4s

# 在容器1的 /test 目录下,创建一个 info.txt 文件
[root@k8s-master test02]# kubectl exec -it test-emptydir-pod -c test01 -- touch /test01_volume/info.txt
# 查看容器2的 /test02_volume 目录
[root@k8s-master test02]# kubectl exec -it test-emptydir-pod -c test02 -- ls /test02_volume
info.txt
hostPath

hostPath 卷将主机节点的文件系统中的文件或目录挂载到集群中。

在Kubernetes(k8s)中,HostPath是一种特殊的卷类型,它允许将节点(Node)上的文件或目录直接挂载到Pod中。这种挂载方式使得Pod能够访问宿主机上的文件系统,从而实现了数据的持久化存储,即使Pod被删除或重建,只要宿主机上的文件或目录仍然存在,数据就不会丢失。

HostPath的配置参数

在Kubernetes中配置HostPath卷时,通常需要指定以下参数:

  • path:指定宿主机上的目录或文件路径,这是必选字段。
  • type(可选):指定节点之上存储类型,包括以下几种:
  • DirectoryOrCreate:如果给定的路径不存在,则创建一个空目录,权限设置为755。
  • Directory:目录必须存在。
  • FileOrCreate:如果给定的文件不存在,则创建一个空文件,权限设置为644。
  • File:文件必须存在。
  • Socket:UNIX套接字,必须存在。
  • CharDevice:字符设备,必须存在。
  • BlockDevice:块设备,必须存在。

HostPath卷适用于以下场景:

  • 需要Pod直接访问宿主机上的特定文件或目录,例如访问Docker内部机制或系统文件。
  • 在某些特定场景下,如运行管理任务的系统级Pod资源,需要访问节点上的特定资源。

示例:

[root@master ~]# vim web1.yaml
---
kind: Pod
apiVersion: v1
metadata:
  name: web1
spec:
  volumes:                              # 卷定义
  - name: logdata                       # 卷名称
    hostPath:                           # 资源类型
      path: /var/weblog                 # 宿主机路径
      type: DirectoryOrCreate           # 目录不存在就创建
  containers:
  - name: nginx
    image: myos:nginx
    volumeMounts:                       # mount 卷
    - name: logdata                     # 卷名称
      mountPath: /usr/local/nginx/logs  # 容器内路径
      
[root@master ~]# kubectl apply -f web1.yaml 
pod/web1 created
[root@master ~]# kubectl get pods -o wide
NAME   READY   STATUS    RESTARTS   AGE     IP             NODE
web1   1/1     Running   0          45m     10.244.2.16    node-0002

[root@master ~]# curl http://10.244.2.16/
Nginx is running !

# 删除Pod ,日志数据也不会丢失
[root@master ~]# kubectl delete pod web1
pod "web1" deleted

# 来到 node 上查看日志
[root@node-0002 ~]# cat /var/weblog/access.log 
10.244.0.0 - - [27/Jun/2022:02:00:12 +0000] "GET / HTTP/1.1" 200 19 "-" "curl/7.29.0"
NFS

k8s 中允许将 nfs 存储以卷的方式挂载到你的 Pod 中。在删除 Pod 时,nfs 存储卷会被卸载(umount),而不是被删除。nfs 卷可以在不同节点的 Pod 之间共享数据。

NFS卷的用途

NFS最大的功能就是在不同节点的不同Pod中共享读写数据。本地 NFS 的客户端可以透明地读写位于远端 NFS 服务器上的文件,就像访问本地文件一样

示例:

# 创建共享目录,并部署测试页面,这里harbor主机充当nfs服务器
[root@harbor ~]# mkdir -p /var/webroot
[root@harbor ~]# echo "nfs server" >/var/webroot/index.html

# 部署 NFS 服务
[root@harbor ~]# dnf install -y nfs-utils
[root@harbor ~]# vim /etc/exports
/var/webroot    192.168.0.0/16(rw,no_root_squash)
[root@harbor ~]# systemctl enable --now nfs-server.service
#----------------------------------------------------------#
# 所有 node 节点都要安装 nfs 软件包
[root@node ~]# dnf install -y nfs-utils
[root@master day05]# vim web1.yaml 
---
kind: Pod
apiVersion: v1
metadata: 
  name: test
spec: 
  volumes:
  - name: logdata
    hostPath:
      path: /var/weblog
      type: DirectoryOrCreate
  - name: website
    nfs: 
      server: 192.168.88.240   # nfs服务器的地址
      path: /var/webroot       # nfs共享的目录
  containers:
  - name: web
    image: myos:nginx
    volumeMounts:
    - name: logdata
      mountPath: /usr/local/nginx/logs
    - name: website
      mountPath: /usr/local/nginx/html # 映射到容器中的路径

[root@master ~]# kubectl apply -f web1.yaml 
pod/web1 created

[root@master day05]# kubectl get pods -owide
NAME   READY   STATUS    RESTARTS   AGE   IP              NODE        NOMINATED NODE   READINESS GATES
test   1/1     Running   0          9s    10.244.147.29   node-0002   <none>           <none>

[root@master day05]# curl 10.244.147.29
nfs server

# 在nfs服务器上添加数据
[root@harbor ~]# echo wo shi k8s >> /var/webroot/index.html 

[root@master day05]# curl 10.244.147.29
nfs server
wo shi k8s
使用流程

使用K8s Volume的一般流程如下:

  1. 创建存储卷:根据需求选择合适的Volume类型,并创建相应的存储卷资源。
  2. 挂载存储卷:在Pod的配置文件中指定要挂载的存储卷,并将其挂载到Pod中的容器上。
  3. 访问存储卷中的数据:在Pod的容器中,通过挂载路径访问存储卷中的数据。
注意事项
  • Volume的生命周期与Pod相关,但与容器的生命周期不相关。当Pod被删除时,与其关联的Volume(除非设置为持久化存储)也会被删除。
  • 在使用网络存储或持久化存储时,需要确保存储系统的稳定性和可靠性,以避免数据丢失或损坏。
  • 对于敏感数据的存储,建议使用Secret或ConfigMap等机制来保护数据安全。

总之,K8s Volume是K8s中非常重要的一个概念,它为Pod中的容器提供了持久化存储和数据共享的能力。通过合理使用不同类型的Volume和正确的配置方法,可以确保应用程序的稳定性和可靠性。

 PV/PVC

在Kubernetes(K8s)中,PV(Persistent Volume)和PVC(Persistent Volume Claim)是两个重要的概念,用于管理集群中的持久化存储资源。以下是对PV和PVC的详细解析:

PV(Persistent Volume)

定义与功能:

  • PV是Kubernetes中用于表示持久化存储资源的API对象。它是一块网络存储,独立于Pod存在,可以是云提供商的存储、NFS、iSCSI、本地存储等多种类型。
  • 管理员负责创建PV,并配置其细节,如容量、访问模式(ReadWriteOnce、ReadOnlyMany、ReadWriteMany)、存储类别等。
  • PV有自己的生命周期,包括可用(Available)、绑定(Bound)、释放(Released)、回收(Retained)等状态。

访问模式:

  • ReadWriteOnce(RWO):单个节点读写模式,即卷可以被一个节点以读写方式挂载。
  • ReadOnlyMany(ROX):多个节点只读模式,即卷可以被多个节点以只读方式挂载
  • ReadWriteMany(RWX):多个节点读写模式,即卷可以被多个节点以读写方式挂载。
  • ReadWriteOncePod(RWOP):卷可以被单个 Pod 以读写方式挂载。 如果你想确保整个集群中只有一个 Pod 可以读取或写入该 PVC, 请使用 ReadWriteOncePod 访问模式。这只支持 CSI 卷以及需要 Kubernetes 1.22 以上版本。

PVC(Persistent Volume Claim)

定义与功能:

  • PVC是用户对PV的存储请求。用户在PVC中定义存储的大小、访问模式等需求,而不需要指定具体的PV。
  • 当PVC被创建时,Kubernetes会尝试将其与满足其要求的PV进行绑定。如果没有合适的PV可以绑定,PVC将处于Pending状态,直到有合适的PV可用或动态创建一个新的PV为止。
  • PVC的存在使得Pod与具体的存储实现解耦,提高了可移植性。

工作流程:

  1. 用户根据需求创建PVC,声明所需的存储资源规格。
  2. Kubernetes根据PVC中的需求寻找合适的PV进行绑定。
  3. 如果环境支持动态存储配额,当没有合适的PV可用时,可以根据PVC请求动态创建一个新的PV。
  4. Pod在定义中引用PVC,当Pod被调度到节点上时,PV会被挂载到Pod指定的路径上,供Pod使用。

PV与PVC的关系

  • PV和PVC之间的关系是一种动态的匹配和绑定关系。PVC声明了对存储资源的需求,而PV则是提供这些资源的实际载体。
  • 当PVC被创建时,Kubernetes会尝试将其与满足其要求的PV进行绑定。匹配的过程是根据PVC的标签选择器和PV的标签进行匹配,只有匹配成功的PV才能被绑定到PVC。
  • 一旦绑定成功,Pod可以通过PVC访问PV提供的存储资源。如果没有合适的PV可以绑定,PVC将处于Pending状态,直到有合适的PV可用为止。

PV与PVC的关联条件

  • 存储类一致:如果 PV 指定了存储类,PVC 必须请求相同的存储类,除非 PVC 不指定存储类。
  • 访问模式兼容:PVC 请求的访问模式必须与 PV 支持的访问模式兼容。
  • 容量足够:PVC 请求的存储容量不能超过 PV 的容量。
  • 选择器匹配:如果 PV 定义了选择器(标签),PVC 必须匹配这些选择器才能绑定。
  • 绑定策略:PV 可以指定绑定策略(动态分配或静态绑定),PVC 必须满足这些策略要求。
  • 状态要求:PVC 必须处于待处理状态(Pending),PV 必须处于可用状态(Available),才能成功绑定。

简而言之,PVC 必须符合 PV 的要求,才能成功绑定并使用 PV 提供的持久化存储。

回收策略

Retain(保留):手动回收

Recycle(回收):基本擦除( 相当于执行了 rm -rf /thevolume/* )

Delete(删除):关联的存储资产(例如 AWS EBS、GCE PD、Azure Disk 和 OpenStack Cinder 卷)将被删除

当前,只有 NFS 和 HostPath 支持回收策略。AWS EBS、GCE PD、Azure Disk 和 Cinder 卷支持删除策略

状态

卷可以处于以下的某种状态:

Available(可用):一块空闲资源还没有被任何声明绑定

Bound(已绑定):卷已经被声明绑定

Released(已释放):声明被删除,但是资源还未被集群重新声明

Failed(失败):该卷的自动回收失败

命令行会显示绑定到 PV 的 PVC 的名称。

示例:

在master部署nfs服务端,node01和node02为客户端

yum install -y nfs-common nfs-utils rpcbind
# 使用master上面的主机作nfs磁盘分享
mkdir /nfs
chmod 666 /nfs
chown nfsnobody /nfsdata # 没有nfsnobody 使用nobody

[root@k8s-master ~]# vim mkdirnfs.sh 
#!/bin/bash
for i in {0..9}
do
        mkdir /nfs/$i
        echo "$i" > /nfs/$i/index.html
        echo "/nfs/$i *(rw,no_root_squash,no_all_squash,sync)" >> /etc/exports
done
# 执行上面的脚本,查看/nfs
[root@k8s-master ~]# tree /nfs
/nfs
├── 0
│   └── index.html
├── 1
│   └── index.html
├── 2
│   └── index.html
├── 3
│   └── index.html
├── 4
│   └── index.html
├── 5
│   └── index.html
├── 6
│   └── index.html
├── 7
│   └── index.html
├── 8
│   └── index.html
└── 9
    └── index.html

10 directories, 10 files

root@k8s-master ~]# cat /etc/exports
/nfs/0 *(rw,no_root_squash,no_all_squash,sync)
/nfs/1 *(rw,no_root_squash,no_all_squash,sync)
/nfs/2 *(rw,no_root_squash,no_all_squash,sync)
/nfs/3 *(rw,no_root_squash,no_all_squash,sync)
/nfs/4 *(rw,no_root_squash,no_all_squash,sync)
/nfs/5 *(rw,no_root_squash,no_all_squash,sync)
/nfs/6 *(rw,no_root_squash,no_all_squash,sync)
/nfs/7 *(rw,no_root_squash,no_all_squash,sync)
/nfs/8 *(rw,no_root_squash,no_all_squash,sync)
/nfs/9 *(rw,no_root_squash,no_all_squash,sync)
[root@k8s-master ~]# showmount -e localhost
Export list for localhost:
/nfs/9 *
/nfs/8 *
/nfs/7 *
/nfs/6 *
/nfs/5 *
/nfs/4 *
/nfs/3 *
/nfs/2 *
/nfs/1 *
/nfs/0 *
[root@k8s-master ~]# cat /nfs/9/index.html 
9

# 验证nfs共享
[root@k8s-node01 ~]# mkdir /testnfs
[root@k8s-node01 ~]# mount k8s-master:/nfs/9 /testnfs
[root@k8s-node01 ~]# tree /testnfs/
/testnfs/
└── index.html

0 directories, 1 file
[root@k8s-node01 ~]# cat /testnfs/index.html 
9
[root@k8s-node01 ~]# umount /testnfs 
[root@k8s-node01 ~]# tree /testnfs/
/testnfs/

0 directories, 0 files

部署pv示例:
[root@k8s-master test02]# vim pv.yaml 
---
apiVersion: v1
kind: PersistentVolume
metadata:
 name: nfspv0 # pv 名字
spec:
 capacity: #容量
  storage: 0.5Gi #存储空间
 accessModes: #存储模式
  - ReadWriteOnce #单个节点读写模式,即卷可以被一个节点以读写方式挂载
 persistentVolumeReclaimPolicy: Recycle #持久卷回收策略
 storageClassName: nfs # 存储类的名字
 nfs:
  path: /nfs/0 # nfs共享路径
  server: 192.168.88.120 # nfs服务器地址
--- 
apiVersion: v1
kind: PersistentVolume
metadata:
 name: nfspv1 # pv 名字
spec:
 capacity: #容量
  storage: 1Gi #存储空间
 accessModes: #存储模式
  - ReadWriteMany #单个节点读写模式,即卷可以被一个节点以读写方式挂载
 persistentVolumeReclaimPolicy: Recycle #持久卷回收策略
 storageClassName: nfs # 存储类的名字
 nfs:
  path: /nfs/1 # nfs共享路径
  server: 192.168.88.120
--- 
apiVersion: v1
kind: PersistentVolume
metadata:
 name: nfspv2 # pv 名字
spec:
 capacity: #容量
  storage: 1Gi #存储空间
 accessModes: #存储模式
  - ReadWriteOnce #单个节点读写模式,即卷可以被一个节点以读写方式挂载
 persistentVolumeReclaimPolicy: Recycle #持久卷回收策略
 storageClassName: nfs1 # 存储类的名字
 nfs:
  path: /nfs/2 # nfs共享路径
  server: 192.168.88.120
--- 
apiVersion: v1
kind: PersistentVolume
metadata:
 name: nfspv3 # pv 名字
spec:
 capacity: #容量
  storage: 1Gi #存储空间
 accessModes: #存储模式
  - ReadWriteOnce #单个节点读写模式,即卷可以被一个节点以读写方式挂载
 persistentVolumeReclaimPolicy: Retain #持久卷回收策略
 storageClassName: nfs # 存储类的名字
 nfs:
  path: /nfs/3 # nfs共享路径
  server: 192.168.88.120
--- 
apiVersion: v1
kind: PersistentVolume
metadata:
 name: nfspv4 # pv 名字
spec:
 capacity: #容量
  storage: 1Gi #存储空间
 accessModes: #存储模式
  - ReadWriteOnce #单个节点读写模式,即卷可以被一个节点以读写方式挂载
 persistentVolumeReclaimPolicy: Recycle #持久卷回收策略
 storageClassName: nfs # 存储类的名字
 nfs:
  path: /nfs/4 # nfs共享路径
  server: 192.168.88.120
--- 
apiVersion: v1
kind: PersistentVolume
metadata:
 name: nfspv5 # pv 名字
spec:
 capacity: #容量
  storage: 1Gi #存储空间
 accessModes: #存储模式
  - ReadWriteOnce #单个节点读写模式,即卷可以被一个节点以读写方式挂载
 persistentVolumeReclaimPolicy: Recycle #持久卷回收策略
 storageClassName: nfs # 存储类的名字
 nfs:
  path: /nfs/5 # nfs共享路径
  server: 192.168.88.120
--- 
apiVersion: v1
kind: PersistentVolume
metadata:
 name: nfspv6 # pv 名字
spec:
 capacity: #容量
  storage: 1.5Gi #存储空间
 accessModes: #存储模式
  - ReadWriteOnce #单个节点读写模式,即卷可以被一个节点以读写方式挂载
 persistentVolumeReclaimPolicy: Recycle #持久卷回收策略
 storageClassName: nfs # 存储类的名字
 nfs:
  path: /nfs/6 # nfs共享路径
  server: 192.168.88.120
--- 
apiVersion: v1
kind: PersistentVolume
metadata:
 name: nfspv7 # pv 名字
spec:
 capacity: #容量
  storage: 1Gi #存储空间
 accessModes: #存储模式
  - ReadWriteOnce #单个节点读写模式,即卷可以被一个节点以读写方式挂载
 persistentVolumeReclaimPolicy: Recycle #持久卷回收策略
 storageClassName: nfs # 存储类的名字
 nfs:
  path: /nfs/7 # nfs共享路径
  server: 192.168.88.120
--- 
apiVersion: v1
kind: PersistentVolume
metadata:
 name: nfspv8 # pv 名字
spec:
 capacity: #容量
  storage: 1Gi #存储空间
 accessModes: #存储模式
  - ReadWriteOnce #单个节点读写模式,即卷可以被一个节点以读写方式挂载
 persistentVolumeReclaimPolicy: Recycle #持久卷回收策略
 storageClassName: nfs # 存储类的名字
 nfs:
  path: /nfs/8 # nfs共享路径
  server: 192.168.88.120
--- 
apiVersion: v1
kind: PersistentVolume
metadata:
 name: nfspv9 # pv 名字
spec:
 capacity: #容量
  storage: 1Gi #存储空间
 accessModes: #存储模式
  - ReadWriteOnce #单个节点读写模式,即卷可以被一个节点以读写方式挂载
 persistentVolumeReclaimPolicy: Recycle #持久卷回收策略
 storageClassName: nfs # 存储类的名字
 nfs:
  path: /nfs/9 # nfs共享路径
  server: 192.168.88.120
  
[root@k8s-master test02]# kubectl apply -f pv.yaml 
persistentvolume/nfspv0 created
persistentvolume/nfspv1 created
persistentvolume/nfspv2 created
persistentvolume/nfspv3 created
persistentvolume/nfspv4 created
persistentvolume/nfspv5 created
persistentvolume/nfspv6 created
persistentvolume/nfspv7 created
persistentvolume/nfspv8 created
persistentvolume/nfspv9 created
[root@k8s-master test02]# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
nfspv0   512Mi      RWO            Recycle          Available           nfs            <unset>                          13s
nfspv1   1Gi        RWX            Recycle          Available           nfs            <unset>                          13s
nfspv2   1Gi        RWO            Recycle          Available           nfs1           <unset>                          13s
nfspv3   1Gi        RWO            Retain           Available           nfs            <unset>                          13s
nfspv4   1Gi        RWO            Recycle          Available           nfs            <unset>                          13s
nfspv5   1Gi        RWO            Recycle          Available           nfs            <unset>                          13s
nfspv6   1536Mi     RWO            Recycle          Available           nfs            <unset>                          13s
nfspv7   1Gi        RWO            Recycle          Available           nfs            <unset>                          13s
nfspv8   1Gi        RWO            Recycle          Available           nfs            <unset>                          13s
nfspv9   1Gi        RWO            Recycle          Available           nfs            <unset>                          13s
创建服务与pvc示例:

本案例是基于StatefuSet控制器的方式创建的pvc:

[root@k8s-master test02]# vim pvc.yaml 
---
apiVersion: v1
kind: Service #service类
metadata:
 name: nginx
 labels:
  app: nginx
spec:
 ports:
 - port: 80
   name: web
# clusterIP模式没有vip IPVS工作方式 没有负载均衡
# 无头服务专门给StatefulSet使用
 clusterIP: None #没有vip
 selector:
  app: nginx
---
apiVersion: apps/v1
kind: StatefulSet #有状态服务 数据可能发生改变的服务 如mysql
metadata:
 name: web
spec:
 selector:
  matchLabels:
   app: nginx
 serviceName: "nginx" # 匹配无头服务service nginx
 replicas: 5
 template:
  metadata:
   labels:
    app: nginx
  spec:
   containers:
   - name: nginx
     image: myos:nginx
     ports: # 定义端口
     - containerPort: 80 #端口80 
       name: web #端口名称web
     volumeMounts: # 卷绑定
     - name: www #卷名
       mountPath: /usr/local/nginx/html # 卷挂载路径
 volumeClaimTemplates: # pvc模版
 - metadata:
    name: www
   spec:
    accessModes: [ "ReadWriteOnce" ] # 单节点读取
    storageClassName: "nfs" #存储类
    resources:
     requests:
      storage: 1Gi # 存储期望
      
[root@k8s-master test02]# kubectl apply -f pvc.yaml 
service/nginx unchanged
statefulset.apps/web configured

# 查看 pvc,每个Pod有一个pvc,是一个一个创建的
[root@k8s-master test02]# kubectl get pvc
NAME        STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
www-web-0   Bound    nfspv5   1Gi        RWO            nfs            <unset>                 8m20s
www-web-1   Bound    nfspv7   1Gi        RWO            nfs            <unset>                 6m24s
www-web-2   Bound    nfspv8   1Gi        RWO            nfs            <unset>                 6m20s
www-web-3   Bound    nfspv4   1Gi        RWO            nfs            <unset>                 6m16s
www-web-4   Bound    nfspv3   1Gi        RWO            nfs            <unset>                 6m10s

# 查看pv
[root@k8s-master test02]# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM               STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
nfspv0   512Mi      RWO            Recycle          Available                       nfs            <unset>                          53m
nfspv1   1Gi        RWX            Recycle          Available                       nfs            <unset>                          53m
nfspv2   1Gi        RWO            Recycle          Available                       nfs1           <unset>                          53m
nfspv3   1Gi        RWO            Retain           Bound       default/www-web-4   nfs            <unset>                          53m
nfspv4   1Gi        RWO            Recycle          Bound       default/www-web-3   nfs            <unset>                          53m
nfspv5   1Gi        RWO            Recycle          Bound       default/www-web-0   nfs            <unset>                          53m
nfspv6   1536Mi     RWO            Recycle          Available                       nfs            <unset>                          53m
nfspv7   1Gi        RWO            Recycle          Bound       default/www-web-1   nfs            <unset>                          53m
nfspv8   1Gi        RWO            Recycle          Bound       default/www-web-2   nfs            <unset>                          53m
nfspv9   1Gi        RWO            Recycle          Available                       nfs            <unset>                          53m

# 获取podIP
[root@k8s-master test02]# kubectl get pods -o wide
NAME                READY   STATUS    RESTARTS   AGE     IP              NODE         NOMINATED NODE   READINESS GATES
web-0               1/1     Running   0          10m     10.244.58.193   k8s-node02   <none>           <none>
web-1               1/1     Running   0          8m15s   10.244.85.193   k8s-node01   <none>           <none>
web-2               1/1     Running   0          8m11s   10.244.85.194   k8s-node01   <none>           <none>
web-3               1/1     Running   0          8m7s    10.244.58.195   k8s-node02   <none>           <none>
web-4               1/1     Running   0          8m1s    10.244.85.195   k8s-node01   <none>           <none>
[root@k8s-master test02]# curl 10.244.58.193
5
# 在 NFS 服务器的 /nfs/5 目录中添加数据,然后通过 nginx 来访问
[root@k8s-master test02]# echo hehe >>  /nfs/5/index.html 
[root@k8s-master test02]# curl 10.244.58.193
5
hehe

注意:StatefulSet是有序部署的,当有Pod的PVC没有绑定到一个PV,就会处于Pending状态,后序的Pod也没法创建了

尝试删除 Pod,pv 中的数据不会丢失

[root@k8s-master ~]# kubectl delete pods web-0
pod "web-0" deleted
# 删除pod后,重新创建的pod读取nfs数据,更改后的数据依然存在 pod级别数据持久化
[root@k8s-master ~]# kubectl get pods -owide
NAME    READY   STATUS    RESTARTS   AGE     IP              NODE         NOMINATED NODE   READINESS GATES
web-0   1/1     Running   0          15s     10.244.58.196   k8s-node02   <none>           <none>
web-1   1/1     Running   0          5h24m   10.244.85.193   k8s-node01   <none>           <none>
web-2   1/1     Running   0          5h23m   10.244.85.194   k8s-node01   <none>           <none>
web-3   1/1     Running   0          5h23m   10.244.58.195   k8s-node02   <none>           <none>
web-4   1/1     Running   0          5h23m   10.244.85.195   k8s-node01   <none>           <none>
[root@k8s-master ~]# curl 10.244.58.196 
5
hehe

# pod内部互相访问使用域名
# 域名格式
#podName.headlessSvcName.nsName.svc.cluster.local.
#statefulSetName-num.headlessSvcName.nsName.svc.cluster.local.
[root@k8s-master test]# kubectl exec -it web-0 -- bash
[root@web-0 html]# curl http://web-1.nginx.default.svc.cluster.local.
7
[root@web-0 html]# curl http://web-2.nginx.default.svc.cluster.local.
8

删除 StatefulSet 后,pvc 不会自动删除,pv也不会自动释放,需要手动删除

# 删除 StatefulSet 后,pvc 仍然存在
[root@k8s-master test]# kubectl delete statefulset web
statefulset.apps "web" deleted
[root@k8s-master test]# kubectl get pvc
NAME        STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
www-web-0   Bound    nfspv5   1Gi        RWO            nfs            <unset>                 5h53m
www-web-1   Bound    nfspv7   1Gi        RWO            nfs            <unset>                 5h51m
www-web-2   Bound    nfspv8   1Gi        RWO            nfs            <unset>                 5h51m
www-web-3   Bound    nfspv4   1Gi        RWO            nfs            <unset>                 5h51m
www-web-4   Bound    nfspv3   1Gi        RWO            nfs            <unset>                 5h50m
# 删除 pvc 后,pv 没有自动释放
[root@k8s-master test]# kubectl delete pvc --all
persistentvolumeclaim "www-web-0" deleted
persistentvolumeclaim "www-web-1" deleted
persistentvolumeclaim "www-web-2" deleted
persistentvolumeclaim "www-web-3" deleted
persistentvolumeclaim "www-web-4" deleted
[root@k8s-master test]# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM               STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
nfspv0   512Mi      RWO            Recycle          Available                       nfs            <unset>                          6h38m
nfspv1   1Gi        RWX            Recycle          Available                       nfs            <unset>                          6h38m
nfspv2   1Gi        RWO            Recycle          Available                       nfs1           <unset>                          6h38m
nfspv3   1Gi        RWO            Retain           Released    default/www-web-4   nfs            <unset>                          6h38m
nfspv4   1Gi        RWO            Recycle          Released    default/www-web-3   nfs            <unset>                          6h38m
nfspv5   1Gi        RWO            Recycle          Released    default/www-web-0   nfs            <unset>                          6h38m
nfspv6   1536Mi     RWO            Recycle          Available                       nfs            <unset>                          6h38m
nfspv7   1Gi        RWO            Recycle          Failed      default/www-web-1   nfs            <unset>                          6h38m
nfspv8   1Gi        RWO            Recycle          Released    default/www-web-2   nfs            <unset>                          6h38m
nfspv9   1Gi        RWO            Recycle          Available                       nfs            <unset>            

# 手动释放pv
[root@k8s-master test]# kubectl edit pv nfspv3
# 将下面的 spec.claimRef 删除
	spec:
	  claimRef:
	    apiVersion: v1
	    kind: PersistentVolumeClaim
	    name: www-web-0
	    namespace: default
	    resourceVersion: "619064"
	    uid: 99cea07e-339e-431c-bcb6-c398c884b29c
# 再次查看 pv nfspv3已经得到释放
[root@k8s-master test]# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM               STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
nfspv0   512Mi      RWO            Recycle          Available                       nfs            <unset>                          6h41m
nfspv1   1Gi        RWX            Recycle          Available                       nfs            <unset>                          6h41m
nfspv2   1Gi        RWO            Recycle          Available                       nfs1           <unset>                          6h41m
nfspv3   1Gi        RWO            Retain           Available                       nfs            <unset>                          6h41m
nfspv4   1Gi        RWO            Recycle          Released    default/www-web-3   nfs            <unset>                          6h41m
nfspv5   1Gi        RWO            Recycle          Released    default/www-web-0   nfs            <unset>                          6h41m
nfspv6   1536Mi     RWO            Recycle          Available                       nfs            <unset>                          6h41m
nfspv7   1Gi        RWO            Recycle          Failed      default/www-web-1   nfs            <unset>                          6h41m
nfspv8   1Gi        RWO            Recycle          Released    default/www-web-2   nfs            <unset>                          6h41m
nfspv9   1Gi        RWO            Recycle          Available                       nfs            <unset>                   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值