k8s中的存储

news2024/11/13 9:36:34

目录

一 configmap

1.1 configmap的功能

1.2 configmap的使用场景

1.3 configmap创建方式

1.3.1 字面值创建

1.3.2 通过文件创建

1.3.3 通过目录创建

1.3.4 通过yaml文件创建

1.3.5 configmap的使用方式

1.3.5.1 使用configmap填充环境变量

1.3.5.2 通过数据卷使用configmap

1.3.5.3  利用configMap填充pod的配置文件

1.3.5.4 通过热更新cm修改配置

二 secrets配置管理

2.1 secrets的功能介绍

2.2 secrets的创建

2.2.1从文件创建

2.2.2 编写yaml文件

2.3 Secret的使用方法

2.3.1 将Secret挂载到Volume中

2.3.2 向指定路径映射 secret 密钥

2.3.3 将Secret设置为环境变量

2.3.4 存储docker registry的认证信息

三 volumes配置管理

3.1 kubernets支持的卷的类型

3.2 emptyDir卷

3.3 hostpath卷

3.4 nfs卷

3.4.1 部署一台nfs共享主机并在所有k8s节点中安装nfs-utils

3.4.2 部署nfs卷

3.5 PersistentVolume持久卷

3.5.1 静态持久卷pv与静态持久卷声明pvc

PersistentVolume(持久卷,简称PV)

PersistentVolumeClaim(持久卷声明,简称PVC)

volumes访问模式

volumes回收策略

volumes状态说明

静态pv实例:

在pod中使用pvc

四 存储类storageclass

4.1 StorageClass说明

4.2 StorageClass的属性

4.3 存储分配器NFS Client Provisioner

4.4 部署NFS Client Provisioner

4.4.1 创建sa并授权

4.4.2 部署应用

4.4.3 创建存储类

4.4.4 创建pvc

4.4.5 创建测试pod

4.4.6 设置默认存储类

五 statefulset控制器

5.1 功能特性

5.2 StatefulSet的组成部分

5.3 构建方法

5.4 测试:

5.5 statefulset的弹缩


一 configmap

1.1 configmap的功能

  • configMap用于保存配置数据,以键值对形式存储。

  • configMap 资源提供了向 Pod 注入配置数据的方法。

  • 镜像和配置文件解耦,以便实现镜像的可移植性和可复用性。

  • etcd限制了文件大小不能超过1M

1.2 configmap的使用场景

  • 填充环境变量的值

  • 设置容器内的命令行参数

  • 填充卷的配置文件

1.3 configmap创建方式

1.3.1 字面值创建

#创建一个名为 “superhowe-config” 的 ConfigMap,其中包含两个键值对:“fname=super” 和 “lname=howe”

[root@k8s-master ~]# kubectl create cm superhowe-config --from-literal fname=super --from-literal lname=howe
configmap/superhowe-config created

[root@k8s-master ~]# kubectl describe cm superhowe-config
Name:         superhowe-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data		#键值信息显示
====
fname:
----
super
lname:
----
howe

BinaryData
====

Events:  <none>

1.3.2 通过文件创建

[root@k8s-master ~]# cat /etc/resolv.conf 
# Generated by NetworkManager
search exam.com
nameserver 172.25.250.2

[root@k8s-master ~]# kubectl create cm howe-config --from-file /etc/resolv.conf 
configmap/howe-config created

[root@k8s-master ~]# kubectl describe cm howe-config 
Name:         howe-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
resolv.conf:
----
# Generated by NetworkManager
search exam.com
nameserver 172.25.250.2


BinaryData
====

Events:  <none>

1.3.3 通过目录创建

[root@k8s-master ~]# mkdir config
[root@k8s-master ~]# cp /etc/fstab /etc/rc.d/rc.local config/
[root@k8s-master ~]# kubectl create cm howe2-config --from-file config/
configmap/howe2-config created
[root@k8s-master ~]# kubectl describe cm howe2-config 
Name:         howe2-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
rc.local:
----
#!/bin/bash
# THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES
#
# It is highly advisable to create own systemd services or udev rules
# to run scripts during boot instead of using this file.
#
# In contrast to previous versions due to parallel execution during boot
# this script will NOT be run after all other services.
#
# Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure
# that this script will be executed during boot.

touch /var/lock/subsys/local
mount /dev/sr0   /rhel9

fstab:
----

#
# /etc/fstab
# Created by anaconda on Wed Jul 31 03:08:58 2024
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
/dev/mapper/rhel-root   /                       xfs     defaults        0 0
UUID=15f86ce4-5a55-499e-8510-36a08ab8db17 /boot                   xfs     defaults        0 0
#/dev/mapper/rhel-swap   none                    swap    defaults        0 0


BinaryData
====

Events:  <none>

1.3.4 通过yaml文件创建

[root@k8s-master ~]# kubectl create cm howe3-config --from-literal db_host=172.25.250.100 --from-literal db_port=3306 --dry-run=client -o yaml > howe-config.yaml

[root@k8s-master ~]# vim howe-config.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: howe3-config
data:
  db_host: 172.25.250.100
  db_port: "3306"
  
[root@k8s-master ~]# kubectl apply -f howe-config.yaml 
configmap/howe3-config created
[root@k8s-master ~]# kubectl describe cm howe3-config 
Name:         howe3-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
db_host:
----
172.25.250.100
db_port:
----
3306

BinaryData
====

Events:  <none>

1.3.5 configmap的使用方式

  • 通过环境变量的方式直接传递给pod

  • 通过pod的 命令行运行方式

  • 作为volume的方式挂载到pod内

1.3.5.1 使用configmap填充环境变量
#讲cm中的内容映射为指定变量
[root@k8s-master ~]# vim testpod1.yml
apiVersion: v1
kind: Pod 
metadata:
  labels:
    run: testpod
  name: testpod
spec:
  containers:
  - image: busyboxplus:latest
    name: testpod
    command:
    - /bin/sh
    - -c
    - env
    env:
    - name: key1
      valueFrom:
        configMapKeyRef:
          name: howe-config
          key: db_host
    - name: key2
      valueFrom:
        configMapKeyRef:
          name: howe-config
          key: db_port
  restartPolicy: Never

[root@k8s-master ~]# kubectl apply -f testpod1.yml 
pod/testpod created

#查看日志
[root@k8s-master ~]# kubectl logs pods/testpod 
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
MYAPP_V1_SERVICE_HOST=10.102.186.55
HOSTNAME=testpod
SHLVL=1
MYAPP_V2_SERVICE_HOST=10.96.232.137
HOME=/
MYAPP_V1_SERVICE_PORT=80
MYAPP_V1_PORT=tcp://10.102.186.55:80
MYAPP_V2_PORT=tcp://10.96.232.137:80
MYAPP_V2_SERVICE_PORT=80
MYAPP_V1_PORT_80_TCP_ADDR=10.102.186.55
MYAPP_V2_PORT_80_TCP_ADDR=10.96.232.137
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
MYAPP_V1_PORT_80_TCP_PORT=80
MYAPP_V1_PORT_80_TCP_PROTO=tcp
MYAPP_V2_PORT_80_TCP_PORT=80
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MYAPP_V2_PORT_80_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
key1=172.25.250.100
key2=3306
MYAPP_V1_PORT_80_TCP=tcp://10.102.186.55:80
MYAPP_V2_PORT_80_TCP=tcp://10.96.232.137:80
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
PWD=/
KUBERNETES_SERVICE_HOST=10.96.0.1

#把cm中的值直接映射为变量
[root@k8s-master ~]# vim testpod2.yml 
apiVersion: v1
kind: Pod 
metadata:
  labels:
    run: testpod
  name: testpod
spec:
  containers:
  - image: busyboxplus:latest
    name: testpod
    command:
    - /bin/sh
    - -c
    - env
    envFrom:
    - configMapKeyRef:
          name: howe3-config
  restartPolicy: Never
  
#查看日志
[root@k8s-master ~]# kubectl logs pods/testpod 
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
MYAPP_V1_SERVICE_HOST=10.102.186.55
HOSTNAME=testpod
SHLVL=1
MYAPP_V2_SERVICE_HOST=10.96.232.137
HOME=/
MYAPP_V1_SERVICE_PORT=80
MYAPP_V1_PORT=tcp://10.102.186.55:80
MYAPP_V2_PORT=tcp://10.96.232.137:80
MYAPP_V2_SERVICE_PORT=80
MYAPP_V1_PORT_80_TCP_ADDR=10.102.186.55
MYAPP_V2_PORT_80_TCP_ADDR=10.96.232.137
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
MYAPP_V1_PORT_80_TCP_PORT=80
MYAPP_V1_PORT_80_TCP_PROTO=tcp
MYAPP_V2_PORT_80_TCP_PORT=80
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MYAPP_V2_PORT_80_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
key1=172.25.250.100
key2=3306
MYAPP_V1_PORT_80_TCP=tcp://10.102.186.55:80
MYAPP_V2_PORT_80_TCP=tcp://10.96.232.137:80
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
PWD=/
KUBERNETES_SERVICE_HOST=10.96.0.1

#在pod命令行中使用变量
[root@k8s-master ~]# vim testpod3.yml
apiVersion: v1
kind: Pod 
metadata:
  labels:
    run: testpod
  name: testpod
spec:
  containers:
  - image: busyboxplus:latest
    name: testpod
    command:
    - /bin/sh
    - -c
    - echo ${db_host} ${db_port}
    envFrom:
    - configMapKeyRef:
          name: howe3-config
  restartPolicy: Never
  
#查看日志
[root@k8s-master ~]# kubectl logs pods/testpod
1.3.5.2 通过数据卷使用configmap
[root@k8s-master ~]# vim testpod4.yml
apiVersion: v1
kind: Pod 
metadata:
  labels:
    run: testpod
  name: testpod
spec:
  containers:
  - image: busyboxplus:latest
    name: testpod
    command:
    - /bin/sh
    - -c
    - cat /config/db_host
    volumeMounts:				#调用卷策略
    - name: config-volume		 #卷名称
      mountPath: /config
    volumes:					#声明卷的配置
    - name: config-volume		 #卷名称
      configMap:
        name: howe3-config
    restartPolicy: Never
    
#查看日志
[root@k8s-master ~]# kubectl logs testpod
key1=172.25.250.100
key2=3306
1.3.5.3  利用configMap填充pod的配置文件
#建立配置文件模板
[root@k8s-master ~]# vim nginx.conf
server {
  listen 8000;
  server_name _;
  root /usr/share/nginx/html;
  index index.html;
}

#利用模板生成cm
[root@k8s-master ~]# kubectl create cm nginx-conf --from-file nginx.conf 
configmap/nginx.conf created

[root@k8s-master ~]# kubectl get cm nginx-conf 
NAME         DATA   AGE
nginx-conf   1      32s

[root@k8s-master ~]# kubectl describe cm nginx-conf 
Name:         nginx-conf
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
nginx.conf:
----
server {
  listen 8000;
  server_name _;
  root /usr/share/nginx/html;
  index index.html;
}


BinaryData
====

Events:  <none>


#建立nginx控制器文件
[root@k8s-master ~]# kubectl create deployment nginx --image nginx:latest --replicas 1 --dry-run=client -o yaml > nginx.yml

#设定nginx.yml中的卷
[root@k8s-master ~]# vim nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:latest
        name: nginx
        volumeMounts:
        - name: config-volume
          mountPath: /etc/nginx/conf.d

      volumes:
        - name: config-volume
          configMap:
            name: nginx-conf
            

[root@k8s-master ~]# kubectl apply -f nginx.yml 
deployment.apps/nginx created

#测试
[root@k8s-master ~]# kubectl get deployments.apps 
NAME       READY   UP-TO-DATE   AVAILABLE   AGE
nginx      1/1     1            1           16m

[root@k8s-master ~]# kubectl get pods -o wide 
NAME                        READY   STATUS      RESTARTS       AGE     IP           NODE                 NOMINATED NODE   READINESS GATES
nginx-8487c65cfc-v8q2g      1/1     Running     0              17m     10.244.1.9   k8s-node1.exam.com   <none>           <none>

[root@k8s-master ~]# curl 10.244.1.9:8000
1.3.5.4 通过热更新cm修改配置
#如需更改端口
[root@k8s-master ~]# kubectl edit cm nginx-conf 
9       listen 8080;

[root@k8s-master ~]# kubectl exec pods/nginx-8487c65cfc-v8q2g -- cat /etc/nginx/conf.d/nginx.conf
server {
  listen 8080;
  server_name _;
  root /usr/share/nginx/html;
  index index.html;
}

[root@k8s-master ~]# kubectl delete pods nginx-8487c65cfc-v8q2g 
pod "nginx-8487c65cfc-v8q2g" deleted

[root@k8s-master ~]# kubectl get pods -o wide 
NAME                        READY   STATUS      RESTARTS       AGE     IP           NODE                 NOMINATED NODE   READINESS GATES
nginx-8487c65cfc-7s4lh      1/1     Running     0              92s     10.244.2.6   k8s-node2.exam.com   <none>           <none>

[root@k8s-master ~]# curl 10.244.2.6:8080

二 secrets配置管理

2.1 secrets的功能介绍

  • Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 ssh key。

  • 敏感信息放在 secret 中比放在 Pod 的定义或者容器镜像中来说更加安全和灵活

  • Pod 可以用两种方式使用 secret:

    • 作为 volume 中的文件被挂载到 pod 中的一个或者多个容器里。

    • 当 kubelet 为 pod 拉取镜像时使用。

  • Secret的类型:

    • Service Account:Kubernetes 自动创建包含访问 API 凭据的 secret,并自动修改 pod 以使用此类型的 secret。

    • Opaque:使用base64编码存储信息,可以通过base64 --decode解码获得原始数据,因此安全性弱。

    • kubernetes.io/dockerconfigjson:用于存储docker registry的认证信息

2.2 secrets的创建

在创建secrets时我们可以用命令的方法或者yaml文件的方法

2.2.1从文件创建

[root@k8s-master ~]# echo -n howe > username.txt
[root@k8s-master ~]# echo -n www > password.txt
[root@k8s-master ~]# kubectl create secret generic userlist --from-file username.txt --from-file password.txt 
secret/userlist created
[root@k8s-master ~]# kubectl get secrets userlist -o yaml 
apiVersion: v1
data:
  password.txt: d3d3
  username.txt: aG93ZQ==
kind: Secret
metadata:
  creationTimestamp: "2024-09-08T13:02:06Z"
  name: userlist
  namespace: default
  resourceVersion: "222543"
  uid: 30dfc207-da48-47d4-98db-fe4aa1dca592
type: Opaque

2.2.2 编写yaml文件

#howe的Base64编码表示
[root@k8s-master ~]# echo -n howe | base64 	#用户名
aG93ZQ==
[root@k8s-master ~]# echo -n www | base64 	#密码
d3d3

[root@k8s-master ~]# kubectl create secret generic userlist --dry-run=client -o yaml > userlist.yml

[root@k8s-master ~]# vim userlist.yml
apiVersion: v1
kind: Secret
metadata:
  name: userlist
type: Opaque
data:
  username: aG93ZQ==
  password: d3d3
  
[root@k8s-master ~]# kubectl delete secrets userlist 
secret "userlist" deleted

[root@k8s-master ~]# kubectl get secrets userlist -o yaml
apiVersion: v1
data:
  password: d3d3
  username: aG93ZQ==

2.3 Secret的使用方法

2.3.1 将Secret挂载到Volume中

[root@k8s-master ~]# kubectl run nginx --image nginx --dry-run=client -o yaml > pod1.yaml

#向固定路径映射
[root@k8s-master ~]# vim pod1.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: nginx
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx
    volumeMounts:
    - name: secrets
      mountPath: /secret
      readOnly: true

  volumes:
  - name: secrets
    secret:
      secretName: userlist
      
[root@k8s-master ~]# kubectl apply -f pod1.yaml 
pod/nginx created

[root@k8s-master ~]# kubectl exec pods/nginx -it -- /bin/bash
root@nginx:/# cd /secret/
root@nginx:/secret# ls
password  username
root@nginx:/secret# cat password 
wwwroot@nginx:/secret# cat username 
howeroot@nginx:/secret# 

2.3.2 向指定路径映射 secret 密钥

#向指定路径映射
[root@k8s-master ~]# vim pod2.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: nginx1
  name: nginx1
spec:
  containers:
  - image: nginx
    name: nginx1
    volumeMounts:
    - name: secrets
      mountPath: /secret
      readOnly: true

  volumes:
  - name: secrets
    secret:
      secretName: userlist
      items:
      - key: username
        path: my-users/username
        
[root@k8s-master ~]# kubectl apply -f pod2.yaml 
pod/nginx1 created

[root@k8s-master ~]# kubectl exec pods/nginx1 -it -- /bin/bash
root@nginx1:/# cd secret/
root@nginx1:/secret# ls
my-users
root@nginx1:/secret# cd my-users
root@nginx1:/secret/my-users# ls
username
root@nginx1:/secret/my-users# cat username 
howeroot@nginx1:/secret/my-users# 

2.3.3 将Secret设置为环境变量

[root@k8s-master ~]# vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: busybox
  name: busybox
spec:
  containers:
  - image: busybox
    name: busybox
    command:
    - /bin/sh
    - -c
    - env
    env:
    - name: USERNAME
      valueFrom:
        secretKeyRef:
          name: userlist
          key: username
    - name: PASS
      valueFrom:
        secretKeyRef:
          name: userlist
          key: password
  restartPolicy: Never
  
[root@k8s-master ~]# kubectl apply -f pod3.yaml 
pod/busybox created
[root@k8s-master ~]# kubectl logs pods/busybox 
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT=443
HOSTNAME=busybox
MYAPP_V1_SERVICE_HOST=10.102.186.55
MYAPP_V2_SERVICE_HOST=10.96.232.137
SHLVL=1
HOME=/root
MYAPP_V1_SERVICE_PORT=80
MYAPP_V1_PORT=tcp://10.102.186.55:80
MYAPP_V2_SERVICE_PORT=80
MYAPP_V2_PORT=tcp://10.96.232.137:80
MYAPP_V1_PORT_80_TCP_ADDR=10.102.186.55
USERNAME=howe
MYAPP_V2_PORT_80_TCP_ADDR=10.96.232.137
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
MYAPP_V1_PORT_80_TCP_PORT=80
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MYAPP_V2_PORT_80_TCP_PORT=80
MYAPP_V1_PORT_80_TCP_PROTO=tcp
MYAPP_V2_PORT_80_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
MYAPP_V1_PORT_80_TCP=tcp://10.102.186.55:80
MYAPP_V2_PORT_80_TCP=tcp://10.96.232.137:80
PASS=www
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/

2.3.4 存储docker registry的认证信息

建立私有仓库并上传镜像

#建立私有仓库并上传镜像
[root@k8s-master ~]# docker login reg.exam.com

#上传镜像
[root@k8s-master ~]# docker load -i game2048.tar 
[root@k8s-master ~]# docker tag timinglee/game2048:latest reg.exam.com/howe/game2048:latest
[root@k8s-master ~]# docker push reg.exam.com/howe/game2048
Using default tag: latest
The push refers to repository [reg.exam.com/howe/game2048]
88fca8ae768a: Pushed 
6d7504772167: Pushed 
192e9fad2abc: Pushed 
36e9226e74f8: Pushed 
011b303988d2: Pushed 
latest: digest: sha256:8a34fb9cb168c420604b6e5d32ca6d412cb0d533a826b313b190535c03fe9390 size: 1364


#建立用于docker认证的secret
[root@k8s-master ~]# kubectl create secret docker-registry docker-auth --docker-server reg.exam.com --docker-username admin --docker-password redhat --docker-email howe@howe.com

#编写yml文件
[root@k8s-master ~]# vim pod4.yml
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: game2048
  name: game2048
spec:
  containers:
  - image: reg.exam.com/howe/game2048:latest
    name: game2048
  imagePullSecrets:					#不设定docker认证时无法下载镜像
  - name: docker-auth
  
[root@k8s-master ~]# kubectl apply -f pod4.yml 
pod/game2048 created

[root@k8s-master ~]# kubectl get pods 
NAME                        READY   STATUS      RESTARTS        AGE
game2048                    1/1     Running     0               11s

三 volumes配置管理

  • 容器中文件在磁盘上是临时存放的,这给容器中运行的特殊应用程序带来一些问题

  • 当容器崩溃时,kubelet将重新启动容器,容器中的文件将会丢失,因为容器会以干净的状态重建。

  • 当在一个 Pod 中同时运行多个容器时,常常需要在这些容器之间共享文件。

  • Kubernetes 卷具有明确的生命周期与使用它的 Pod 相同

  • 卷比 Pod 中运行的任何容器的存活期都长,在容器重新启动时数据也会得到保留

  • 当一个 Pod 不再存在时,卷也将不再存在。

  • Kubernetes 可以支持许多类型的卷,Pod 也能同时使用任意数量的卷。

  • 卷不能挂载到其他卷,也不能与其他卷有硬链接。 Pod 中的每个容器必须独立地指定每个卷的挂载位置。

3.1 kubernets支持的卷的类型

官网:卷 | Kubernetes

k8s支持的卷的类型如下:

  • awsElasticBlockStore 、azureDisk、azureFile、cephfs、cinder、configMap、csi

  • downwardAPI、emptyDir、fc (fibre channel)、flexVolume、flocker

  • gcePersistentDisk、gitRepo (deprecated)、glusterfs、hostPath、iscsi、local、

  • nfs、persistentVolumeClaim、projected、portworxVolume、quobyte、rbd

  • scaleIO、secret、storageos、vsphereVolume

3.2 emptyDir卷

功能:

当Pod指定到某个节点上时,首先创建的是一个emptyDir卷,并且只要 Pod 在该节点上运行,卷就一直存在。卷最初是空的。 尽管 Pod 中的容器挂载 emptyDir 卷的路径可能相同也可能不同,但是这些容器都可以读写 emptyDir 卷中相同的文件。 当 Pod 因为某些原因被从节点上删除时,emptyDir 卷中的数据也会永久删除

emptyDir 的使用场景:

  • 缓存空间,例如基于磁盘的归并排序。

  • 耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。

  • 在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。

示例:

[root@k8s-master volumes]# vim pod1.yml
apiVersion: v1
kind: Pod
metadata:
  name: vol1
spec:
  containers:
  - image: busyboxplus:latest
    name: vm1
    command:
    - /bin/sh
    - -c
    - sleep 30000000
    volumeMounts:
    - mountPath: /cache
      name: cache-vol
  - image: nginx:latest
    name: vm2
    volumeMounts:
    - mountPath: /usr/share/nginx/html
      name: cache-vol
  volumes:
  - name: cache-vol
    emptyDir:
      medium: Memory
      sizeLimit: 100Mi
      
[root@k8s-master volumes]# kubectl apply -f pod1.yml 
pod/vol1 created

#查看pod中卷的使用情况
[root@k8s-master volumes]# kubectl describe pods vol1 

#测试效果
[root@k8s-master volumes]# kubectl exec -it pods/vol1 -c vm1 -- /bin/sh
/ # cd cache/
/cache # ls
/cache # echo haha > index.html
/cache # curl localhost
haha
/cache # 
/cache # dd if=/dev/zero of=bigfile bs=1M count=101
dd: writing 'bigfile': No space left on device
101+0 records in
99+1 records out

3.3 hostpath卷

功能:

hostPath 卷能将主机节点文件系统上的文件或目录挂载到您的 Pod 中,不会因为pod关闭而被删除

hostPath 的一些用法

  • 运行一个需要访问 Docker 引擎内部机制的容器,挂载 /var/lib/docker 路径。

  • 在容器中运行 cAdvisor(监控) 时,以 hostPath 方式挂载 /sys。

  • 允许 Pod 指定给定的 hostPath 在运行 Pod 之前是否应该存在,是否应该创建以及应该以什么方式存在

hostPath的安全隐患

  • 具有相同配置(例如从 podTemplate 创建)的多个 Pod 会由于节点上文件的不同而在不同节点上有不同的行为。

  • 当 Kubernetes 按照计划添加资源感知的调度时,这类调度机制将无法考虑由 hostPath 使用的资源。

  • 基础主机上创建的文件或目录只能由 root 用户写入。您需要在 特权容器 中以 root 身份运行进程,或者修改主机上的文件权限以便容器能够写入 hostPath 卷。

示例:

[root@k8s-master volumes]# vim pod2.yml
apiVersion: v1
kind: Pod
metadata:
  name: vol1
spec:
  containers:
  - image: nginx:latest
    name: vm1
    volumeMounts:
    - mountPath: /usr/share/nginx/html
      name: cache-vol
  volumes:
  - name: cache-vol
    hostPath:
      path: /data				
      type: DirectoryOrCreate		#当/data目录不存在时自动建立
      
#测试:
[root@k8s-master volumes]# kubectl apply -f pod2.yml 
pod/vol1 created

[root@k8s-master volumes]# kubectl get pods -o wide 
NAME                        READY   STATUS      RESTARTS       AGE     IP            NODE                 NOMINATED NODE   READINESS GATES
vol1                        1/1     Running     0              24s     10.244.2.8    k8s-node2.exam.com   <none>           <none>

[root@k8s-master volumes]# curl 10.244.2.8
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.27.1</center>
</body>
</html>

#通过kubectl get pods -o wide查看挂载到了哪个主机 比如这里为node2
[root@k8s-node2 ~]# echo xixi > /data/index.html

#回到master
[root@k8s-master volumes]# curl 10.244.2.8
xixi

#当pod被删除后hostPath不会被清理
[root@k8s-master volumes]# kubectl delete -f pod2.yml 
pod "vol1" deleted
[root@k8s-node2 ~]# ls /data/
index.html

3.4 nfs卷

NFS 卷允许将一个现有的 NFS 服务器上的目录挂载到 Kubernetes 中的 Pod 中。这对于在多个 Pod 之间共享数据或持久化存储数据非常有用

例如,如果有多个容器需要访问相同的数据集,或者需要将容器中的数据持久保存到外部存储,NFS 卷可以提供一种方便的解决方案。

3.4.1 部署一台nfs共享主机并在所有k8s节点中安装nfs-utils

#部署nfs主机
[root@harbor ~]# mkdir /nfsdata
[root@harbor ~]# dnf install nfs-utils -y
[root@harbor ~]# systemctl enable --now nfs-server.service 

[root@harbor ~]# vim /etc/exports
/nfsdata   *(rw,sync,no_root_squash)	#no_root_squash因为管理用户为root
[root@harbor ~]# ls -ld /nfsdata/
drwxr-xr-x 2 root root 6 Sep  9 05:58 /nfsdata/
[root@harbor ~]# exportfs -rv			#重启
exporting *:/nfsdata

[root@k8s-master ~]# showmount -e 172.25.250.250	#每台主机都要能看到
Export list for 172.25.250.250:
/nfsdata *

#在k8s所有节点中安装nfs-utils
[root@k8s-master ~]# dnf install nfs-utils -y
[root@k8s-master ~]# systemctl enable --now nfs-server.service
[root@k8s-node1 ~]# dnf install nfs-utils -y
[root@k8s-node1 ~]# systemctl enable --now nfs-server.service
[root@k8s-node2 ~]# dnf install nfs-utils -y
[root@k8s-node2 ~]# systemctl enable --now nfs-server.service

3.4.2 部署nfs卷

[root@k8s-master volumes]# vim pod3.yml
apiVersion: v1
kind: Pod 
metadata:
  name: vol1
spec:
  containers:
  - image: nginx:latest
    name: vm1 
    volumeMounts:
    - mountPath: /usr/share/nginx/html
      name: cache-vol
  volumes:
  - name: cache-vol
    nfs:
      server: 172.25.250.250		#nfs服务器IP
      path: /nfsdata			    #nfs服务器共享目录

[root@k8s-master volumes]# kubectl apply -f pod3.yml 
pod/vol1 created

#测试
[root@k8s-master volumes]# kubectl get pods -o wide 
NAME                        READY   STATUS      RESTARTS        AGE     IP            NODE                 NOMINATED NODE   READINESS GATES
vol1                        1/1     Running     0               50s     10.244.2.9    k8s-node2.exam.com   <none>           <none>

[root@k8s-master volumes]# curl 10.244.2.9
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.27.1</center>
</body>
</html>

#在nfs主机中
[root@harbor ~]# echo welcome back! > /nfsdata/index.html
[root@k8s-master volumes]# curl 10.244.2.9
welcome back!

3.5 PersistentVolume持久卷

3.5.1 静态持久卷pv与静态持久卷声明pvc

PersistentVolume(持久卷,简称PV)
  • pv是集群内由管理员提供的网络存储的一部分。

  • PV也是集群中的一种资源。是一种volume插件,

  • 但是它的生命周期却是和使用它的Pod相互独立的。

  • PV这个API对象,捕获了诸如NFS、ISCSI、或其他云存储系统的实现细节

  • pv有两种提供方式:静态和动态

    • 静态PV:集群管理员创建多个PV,它们携带着真实存储的详细信息,它们存在于Kubernetes API中,并可用于存储使用

    • 动态PV:当管理员创建的静态PV都不匹配用户的PVC时,集群可能会尝试专门地供给volume给PVC。这种供给基于StorageClass

PersistentVolumeClaim(持久卷声明,简称PVC)
  • 是用户的一种存储请求

  • 它和Pod类似,Pod消耗Node资源,而PVC消耗PV资源

  • Pod能够请求特定的资源(如CPU和内存)。PVC能够请求指定的大小和访问的模式持久卷配置

  • PVC与PV的绑定是一对一的映射。没找到匹配的PV,那么PVC会无限期得处于unbound未绑定状态

volumes访问模式
  • ReadWriteOnce -- 该volume只能被单个节点以读写的方式映射

  • ReadOnlyMany -- 该volume可以被多个节点以只读方式映射

  • ReadWriteMany -- 该volume可以被多个节点以读写的方式映射

  • 在命令行中,访问模式可以简写为:

    • RWO - ReadWriteOnce

  • ROX - ReadOnlyMany

  • RWX – ReadWriteMany

volumes回收策略
  • Retain:保留,需要手动回收

  • Recycle:回收,自动删除卷中数据(在当前版本中已经废弃)

  • Delete:删除,相关联的存储资产,如AWS EBS,GCE PD,Azure Disk,or OpenStack Cinder卷都会被删除

注意:只有NFS和HostPath支持回收利用

AWS EBS,GCE PD,Azure Disk,or OpenStack Cinder卷支持删除操作

volumes状态说明
  • Available 卷是一个空闲资源,尚未绑定到任何申领

  • Bound 该卷已经绑定到某申领

  • Released 所绑定的申领已被删除,但是关联存储资源尚未被集群回收

  • Failed 卷的自动回收操作失败

静态pv实例:
#在nfs主机中建立实验目录
[root@harbor ~]# mkdir /nfsdata/pv{1..3}

#编写创建pv的yml文件,pv是集群资源,不在任何namespace中
[root@k8s-master pvc]# vim pv.yml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv1
spec:
  capacity:
    storage: 1Gi
  volumeMode: Filesystem		#注意缩进
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
    path: /nfsdata/pv1
    server: 172.25.250.250

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv2
spec:
  capacity:
    storage: 3Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
    path: /nfsdata/pv2
    server: 172.25.250.250
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv3
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadOnlyMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
    path: /nfsdata/pv3
    server: 172.25.250.250

    
[root@k8s-master pvc]# kubectl apply -f pv.yml 
persistentvolume/pv1 unchanged
persistentvolume/pv2 unchanged
persistentvolume/pv3 created

[root@k8s-master pvc]# kubectl get pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM          STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pv1    1Gi        RWO            Retain           Bound       default/pvc1   nfs            <unset>                          3m26s
pv2    3Gi        RWX            Retain           Available                  nfs            <unset>                          3m26s
pv3    5Gi        ROX            Retain           Available                  nfs            <unset>                          3m8s


#建立pvc,pvc是pv使用的申请,需要保证和pod在一个namesapce中
[root@k8s-master pvc]# vim pvc.ym
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc1
spec:
  storageClassName: nfs
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc2
spec:
  storageClassName: nfs
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 3Gi

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc3
spec:
  storageClassName: nfs
  accessModes:
    - ReadOnlyMany
  resources:
    requests:
      storage: 5Gi

[root@k8s-master pvc]# kubectl apply -f pvc.ym 
persistentvolumeclaim/pvc1 created
persistentvolumeclaim/pvc2 created
persistentvolumeclaim/pvc3 created

[root@k8s-master pvc]# kubectl get pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM          STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pv1    1Gi        RWO            Retain           Bound    default/pvc1   nfs            <unset>                          3m20s
pv2    3Gi        RWX            Retain           Bound    default/pvc2   nfs            <unset>                          3m20s
pv3    5Gi        ROX            Retain           Bound    default/pvc3   nfs            <unset>                          3m20s

[root@k8s-master pvc]# kubectl get pvc
NAME         STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
pvc1         Bound     pv1      1Gi        RWO            nfs            <unset>                 18s
pvc2         Bound     pv2      3Gi        RWX            nfs            <unset>                 18s
pvc3         Bound     pv3      5Gi        ROX            nfs            <unset>                 18s
test-claim   Pending                                      nfs-client     <unset>                 2m35s
www-web-0    Pending                                      nfs-client     <unset>                 3h29m


#在其他namespace中无法应用
[root@k8s-master pvc]# kubectl -n kube-system get pvc
No resources found in kube-system namespace.
在pod中使用pvc
[root@k8s-master pvc]# vim pod.yml
apiVersion: v1
kind: Pod
metadata:
  name: howe
spec:
  containers:
  - image: nginx
    name: nginx
    volumeMounts:
    - mountPath: /usr/share/nginx/html
      name: vol1
  volumes:
  - name: vol1
    persistentVolumeClaim:
      claimName: pvc1
      
[root@k8s-master pvc]# kubectl apply -f pod.yml 
pod/howe created

[root@k8s-master pvc]# kubectl get pods -o wide 
NAME                        READY   STATUS      RESTARTS       AGE     IP           NODE                 NOMINATED NODE   READINESS GATES
howe                        1/1     Running     0              46s     10.244.1.8   k8s-node1.exam.com   <none>           <none>

[root@k8s-master pvc]# kubectl exec -it pods/howe -- /bin/bash
root@howe:~# cd /usr/share/nginx/html/
root@howe:/usr/share/nginx/html# ls

#nfs主机写入共享目录
[root@harbor nfsdata]# echo hehehe > /nfsdata/pv1/index.html

root@howe:/usr/share/nginx/html# ls
index.html
root@howe:/usr/share/nginx/html# curl localhost
hehehe

四 存储类storageclass

官网: GitHub - kubernetes-sigs/nfs-subdir-external-provisioner: Dynamic sub-dir volume provisioner on a remote NFS server.

4.1 StorageClass说明

  • StorageClass提供了一种描述存储类(class)的方法,不同的class可能会映射到不同的服务质量等级和备份策略或其他策略等。

  • 每个 StorageClass 都包含 provisioner、parameters 和 reclaimPolicy 字段, 这些字段会在StorageClass需要动态分配 PersistentVolume 时会使用到

4.2 StorageClass的属性

属性说明:存储类 | Kubernetes

Provisioner(存储分配器):用来决定使用哪个卷插件分配 PV,该字段必须指定。可以指定内部分配器,也可以指定外部分配器。外部分配器的代码地址为: kubernetes-incubator/external-storage,其中包括NFS和Ceph等。

Reclaim Policy(回收策略):通过reclaimPolicy字段指定创建的Persistent Volume的回收策略,回收策略包括:Delete 或者 Retain,没有指定默认为Delete。

4.3 存储分配器NFS Client Provisioner

源码地址:GitHub - kubernetes-sigs/nfs-subdir-external-provisioner: Dynamic sub-dir volume provisioner on a remote NFS server.

  • NFS Client Provisioner是一个automatic provisioner,使用NFS作为存储,自动创建PV和对应的PVC,本身不提供NFS存储,需要外部先有一套NFS存储服务。

  • PV以 ${namespace}-${pvcName}-${pvName}的命名格式提供(在NFS服务器上)

  • PV回收的时候以 archieved-${namespace}-${pvcName}-${pvName} 的命名格式(在NFS服务器上)

4.4 部署NFS Client Provisioner

#上传镜像仓库
[root@k8s-master ~]# docker load -i nfs-subdir-external-provisioner-4.0.2.tar
Loaded image: registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2

[root@k8s-master ~]# docker tag registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2 reg.exam.com/sig-storage/nfs-subdir-external-provisioner:v4.0.2

[root@k8s-master ~]# docker push reg.exam.com/sig-storage/nfs-subdir-external-provisioner:v4.0.2
The push refers to repository [reg.exam.com/sig-storage/nfs-subdir-external-provisioner]
ad321585b8f5: Pushed 
1a5ede0c966b: Pushed 
v4.0.2: digest: sha256:f741e403b3ca161e784163de3ebde9190905fdbf7dfaa463620ab8f16c0f6423 size: 739

4.4.1 创建sa并授权

[root@k8s-master nfs]# vim rbac.yml
apiVersion: v1
kind: Namespace
metadata:
  name: nfs-client-provisioner
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  namespace: nfs-client-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: nfs-client-provisioner
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: nfs-client-provisioner
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: nfs-client-provisioner
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io
  
#查看rbac信息
[root@k8s-master nfs]# kubectl apply -f rbac.yml 
namespace/nfs-client-provisioner created
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created

[root@k8s-master nfs]# kubectl -n nfs-client-provisioner get sa
NAME                     SECRETS   AGE
default                  0         26s
nfs-client-provisioner   0         27s

4.4.2 部署应用

[root@k8s-master nfs]# vim deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  namespace: nfs-client-provisioner
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: sig-storage/nfs-subdir-external-provisioner:v4.0.2
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: k8s-sigs.io/nfs-subdir-external-provisioner
            - name: NFS_SERVER
              value: 172.25.250.250
            - name: NFS_PATH
              value: /nfsdata
      volumes:
        - name: nfs-client-root
          nfs:
            server: 172.25.250.250
            path: /nfsdata
            

[root@k8s-master nfs]# kubectl apply -f deployment.yml 
deployment.apps/nfs-client-provisioner created

[root@k8s-master nfs]# kubectl -n nfs-client-provisioner get deployments.apps nfs-client-provisioner 
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
nfs-client-provisioner   1/1     1            1           4s

4.4.3 创建存储类

[root@k8s-master nfs]# vim class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-client
provisioner: /nfs-subdir-external-provisioner
parameters:
  archiveOnDelete: "false"
  
[root@k8s-master nfs]# kubectl apply -f class.yaml 
storageclass.storage.k8s.io/nfs-client created

[root@k8s-master nfs]# kubectl get storageclasses.storage.k8s.io 
NAME         PROVISIONER                                   RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs-client   k8s-sigs.io/nfs-subdir-external-provisioner   Delete          Immediate           false                  26s

4.4.4 创建pvc

[root@k8s-master nfs]# vim pvc.yml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
spec:
  storageClassName: nfs-client
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1G
      
[root@k8s-master nfs]# kubectl apply -f pvc.yml 
persistentvolumeclaim/test-claim created

#pending问题 可能由于没有pv资源
[root@k8s-master nfs]# kubectl get pvc
NAME         STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
test-claim   Pending                                      nfs-client     <unset>                 10s

#检查nfs插件是否上传到镜像仓库
[root@k8s-master nfs]# kubectl get pvc
NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
test-claim   Bound    pvc-7f3fd08b-186e-42fa-9e0d-02ef7f0c9b36   1G         RWX            nfs-client     <unset>                 27s

4.4.5 创建测试pod

[root@k8s-master nfs]# vim pod.yml
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
  - name: test-pod
    image: busybox
    command:
      - "/bin/sh"
    args:
      - "-c"
      - "touch /mnt/SUCCESS && exit 0 || exit 1"
    volumeMounts:
      - name: nfs-pvc
        mountPath: "/mnt"
  restartPolicy: "Never"
  volumes:
    - name: nfs-pvc
      persistentVolumeClaim:
        claimName: test-claim

[root@k8s-master nfs]# kubectl apply -f pod.yml 
pod/test-pod created

[root@k8s-master nfs]# kubectl get pvc
NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
test-claim   Bound    pvc-7f3fd08b-186e-42fa-9e0d-02ef7f0c9b36   1G         RWX            nfs-client     <unset>                 27s

#nfs主机上查看
[root@harbor ~]# ls /nfsdata/default-test-claim-pvc-7f3fd08b-186e-42fa-9e0d-02ef7f0c9b36/
SUCCESS

[root@k8s-master nfs]# kubectl delete -f pod.yml 
pod "test-pod" deleted

4.4.6 设置默认存储类

  • 在未设定默认存储类时pvc必须指定使用类的名称

  • 在设定存储类后创建pvc时可以不用指定storageClassName

#一次性指定多个pvc
[root@k8s-master pvc]# vim pvc.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc1
spec:
  storageClassName: nfs-client
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc2
spec:
  storageClassName: nfs-client
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc3
spec:
  storageClassName: nfs-client
  accessModes:
    - ReadOnlyMany
  resources:
    requests:
      storage: 15Gi
      
[root@k8s-master pvc]# kubectl apply -f pvc.yml 
persistentvolumeclaim/pvc1 created
persistentvolumeclaim/pvc2 created
persistentvolumeclaim/pvc3 created

[root@k8s-master pvc]# kubectl get pvc
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
pvc1        Bound    pvc-1d48c4c3-a6ef-487d-8d88-43297ca804a2   1Gi        RWO            nfs-client     <unset>                 12s
pvc2        Bound    pvc-27223a35-32c4-4768-8267-ad1866230b0d   10Gi       RWX            nfs-client     <unset>                 12s
pvc3        Bound    pvc-8ef40d48-991a-4b9d-afd8-3be6b4f45b89   15Gi       ROX            nfs-client     <unset>                 12s

 设定默认存储类

[root@k8s-master nfs]# kubectl edit sc nfs-client 

#测试,未指定storageClassName参数
[root@k8s-master nfs]# vim pvc.yml 
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
spec:
  storageClassName: nfs-client
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
      
[root@k8s-master nfs]# kubectl apply -f pvc.yml 
persistentvolumeclaim/test-claim created

[root@k8s-master nfs]# kubectl get pvc
NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
test-claim   Bound    pvc-7900365a-ca7a-4de9-bcc4-0984b4149f58   1Gi        RWX            nfs-client     <unset>                 15s

五 statefulset控制器

5.1 功能特性

  • Statefulset是为了管理有状态服务的问提设计的

  • StatefulSet将应用状态抽象成了两种情况:

  • 拓扑状态:应用实例必须按照某种顺序启动。新创建的Pod必须和原来Pod的网络标识一样

  • 存储状态:应用的多个实例分别绑定了不同存储数据。

  • StatefulSet给所有的Pod进行了编号,编号规则是:$(statefulset名称)-$(序号),从0开始。

  • Pod被删除后重建,重建Pod的网络标识也不会改变,Pod的拓扑状态按照Pod的“名字+编号”的方式固定下来,并且为每个Pod提供了一个固定且唯一的访问入口,Pod对应的DNS记录。

5.2 StatefulSet的组成部分

  • Headless Service:用来定义pod网络标识,生成可解析的DNS记录

  • volumeClaimTemplates:创建pvc,指定pvc名称大小,自动创建pvc且pvc由存储类供应。

  • StatefulSet:管理pod的

5.3 构建方法

#建立无头服务
[root@k8s-master statefulset]# vim headless.yml
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx


[root@k8s-master statefulset]# kubectl apply -f headless.yml 
service/nginx-svc created


#建立statefulset
[root@k8s-master statefulset]# vim statefulset.yml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx-svc"
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      storageClassName: nfs-client
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi
          
[root@k8s-master statefulset]# kubectl apply -f statefulset.yml 
statefulset.apps/web created

[root@k8s-master statefulset]# kubectl get pods 
NAME	READY   STATUS             RESTARTS       AGE
web-0	1/1     Running            0              6s
web-1	1/1     Running            0              4s
web-2	1/1     Running            0              2s

[root@harbor ~]# ls /nfsdata/
default-www-web-0-pvc-a3ceae44-d7f2-4514-8591-02ab8e8bed4c
default-www-web-1-pvc-5f5756d6-5d16-4a69-89ce-beef5321ba41
default-www-web-2-pvc-31726893-6723-42ef-ab56-32a35e263fba

5.4 测试:

#在nfs主机为每个pod建立index.html文件
[root@harbor ~]# cd /nfsdata/
[root@harbor nfsdata]# echo web-0 > default-www-web-0-pvc-a3ceae44-d7f2-4514-8591-02ab8e8bed4c/index.html
[root@harbor nfsdata]# echo web-1 > default-www-web-1-pvc-5f5756d6-5d16-4a69-89ce-beef5321ba41/index.html
[root@harbor nfsdata]# echo web-2 > default-www-web-2-pvc-31726893-6723-42ef-ab56-32a35e263fba/index.html

#在master建立测试pod访问web-0~2
[root@k8s-master statefulset]# kubectl run -it testpod --image busyboxplus
/ # curl web-0.nginx-svc
web-0
/ # curl web-1.nginx-svc
web-1
/ # curl web-2.nginx-svc
web-2
/ # 

#删掉重新建立statefulset
[root@k8s-master statefulset]# kubectl delete -f statefulset.yml 
statefulset.apps "web" deleted
[root@k8s-master statefulset]# kubectl apply -f statefulset.yml 
statefulset.apps/web created

#访问依然不变
[root@k8s-master statefulset]# kubectl attach testpod -c testpod -i -t
If you don't see a command prompt, try pressing enter.
/ # curl web-0.nginx-svc
web-0
/ # curl web-1.nginx-svc
web-1
/ # curl web-2.nginx-svc
web-2
/ # 

5.5 statefulset的弹缩

首先,想要弹缩的StatefulSet. 需先清楚是否能弹缩该应用

用命令改变副本数

$ kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>

通过编辑配置改变副本数

$ kubectl edit statefulsets.apps <stateful-set-name>

statefulset有序回收

[root@k8s-master statefulset]# kubectl scale statefulset web --replicas 0
statefulset.apps/web scaled
[root@k8s-master statefulset]# kubectl delete -f statefulset.yml 
statefulset.apps "web" deleted
[root@k8s-master statefulset]# kubectl delete pvc --all
persistentvolumeclaim "www-web-0" deleted
persistentvolumeclaim "www-web-1" deleted
persistentvolumeclaim "www-web-2" deleted

[root@k8s-master statefulset]# kubectl scale statefulsets web --replicas=0

[root@k8s-master statefulset]# kubectl delete -f statefulset.yaml

[root@k8s-master statefulset]# kubectl delete pvc --all

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2141272.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《程序猿之设计模式实战 · 观察者模式》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

AJAX 进阶 day4

目录 1.同步代码和异步代码 2.回调函数地狱和 Promise 链式调用 2.1 回调函数地狱 2.2 Promise - 链式调用 2.3 Promise 链式应用 3.async 和 await 使用 3.1 async函数和await 3.2 async函数和await_捕获错误 4.事件循环-EventLoop 4.1 事件循环 4.2 宏任务与微任务…

R语言统计分析——散点图1(常规图)

参考资料&#xff1a;R语言实战【第2版】 R语言中创建散点图的基础函数是plot(x,y)&#xff0c;其中&#xff0c;x和y是数值型向量&#xff0c;代表着图形中的&#xff08;x,y&#xff09;坐标点。 attach(mtcars) plot(wt,mpg,main"Basic Scatter plot of MPG vs. Weigh…

数据结构(Day14)

一、学习内容 结构体 概念 引入&#xff1a;定义整数赋值为10 int a10; 定义小数赋值为3.14 float b3.14; 定义5个整数并赋值 int arr[5] {1 , 2 , 3 , 4 ,5}; 定义一个学生并赋值学号姓名成绩 定义一个雪糕并赋值名称产地单价 问题&#xff1a;没有学生、雪糕 数据类型 解决&…

Text2vec -文本转向量

文章目录 一、关于 Text2vec1、Text2vec 是什么2、Features3、Demo4、News5、Evaluation英文匹配数据集的评测结果&#xff1a;中文匹配数据集的评测结果&#xff1a; 6、Release Models 二、Install三、使用1、文本向量表征1.2 Usage (HuggingFace Transformers)1.3 Usage (se…

★ C++进阶篇 ★ 多态

Ciallo&#xff5e;(∠・ω< )⌒☆ ~ 今天&#xff0c;我将继续和大家一起学习C进阶篇第一章----多态 ~ ❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️ 澄岚主页&#xff1a;椎名澄嵐-CSDN博客 C基础篇专栏&#xff1a;★ C基础篇 ★_椎名澄嵐的博客-CSDN博客 …

2024/9/16 英语每日一段

Stark argues that, in their gummies, at least,“The total sugar in a serving is less than in half a cherry.”Of course, cherries also provide fibre, vitamin C, and antioxidants--and 14 of them would count as one of your five-a-day. Artificial sweeteners to…

Ubuntu24.04部署docker

1、更新软件 apt update 2、安装curl apt install apt-transport-https curl 3、导入阿里云GPG秘钥 curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg 4、添加Docker阿里云仓库到Ubuntu 24.04的…

使用 release key 对 LineageOS 进行编译和签名

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ 为什么需要使用 release key test-key 是一个公开的、众所周知的开发测试密钥&#xff0c;广泛用于测试阶段。这意味着任何人都可以获取这个密钥&#xff0c;…

详解HTTP/HTTPS协议

HTTP HTTP协议全名为超文本传输协议。HTTP协议是应用层协议&#xff0c;其传输层协议采用TCP协议。 请求—响应模型 HTTP协议采用请求-响应模型&#xff0c;通常由客户端发起请求由服务端完成响应。资源存储在服务端&#xff0c;客户端通过请求服务端获取资源。 认识URL 当…

jacoco生成单元测试覆盖率报告

前言 单元测试是日常编写代码中常用的&#xff0c;用于测试业务逻辑的一种方式&#xff0c;单元测试的覆盖率可以用来衡量我们的业务代码经过测试覆盖的比例。 目前市场上开源的单元测试覆盖率的java插件&#xff0c;主要有Emma&#xff0c;Cobertura&#xff0c;Jacoco。具体…

后台数据管理系统 - 项目架构设计-Vue3+axios+Element-plus(0916)

接口文档: https://apifox.com/apidoc/shared-26c67aee-0233-4d23-aab7-08448fdf95ff/api-93850835 接口根路径&#xff1a; http://big-event-vue-api-t.itheima.net 本项目的技术栈 本项目技术栈基于 ES6、vue3、pinia、vue-router 、vite 、axios 和 element-plus http:/…

企业社会信任数据,信任指数(2004-2022年)

企业社会信任是指公众对企业及其行为的信任程度&#xff0c;这种信任度是基于企业的商业行为、产品质量、服务态度、信息披露透明度和社会责任履行等多方面因素的综合评估。 2004年&#xff0d;2022年 企业社会信任数据&#xff08;大数据&#xff09;https://download.csdn.n…

【网络】高级IO——select版本TCP服务器

目录 前言 一&#xff0c;select函数 1.1.参数一&#xff1a;nfds 1.2.参数二&#xff1a; readfds, writefds, exceptfds 1.2.1.fd_set类型和相关操作宏 1.2.2.readfds, writefds, exceptfds 1.2.3.怎么理解 readfds, writefds, exceptfds是输入输出型参数 1.3.参数三…

LeetCode[中等] 3. 无重复字符的最长子串

给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 思路&#xff1a;滑动窗口&#xff0c;设置左右指针left与right&#xff0c;maxLength存储长度 利用HashSet性质&#xff0c;存储滑动窗口中的字符 如果没有重复的&#xff0c;那么right继续向…

5.基础漏洞——文件上传漏洞

目录 一.文件上传漏洞原理 二.文件上传漏洞条件&#xff1a; 三.上传限制手段分为两大类 (1)客户端校验 (2)服务端校验 四.具体实现 1.文件上传漏洞——绕过JS检测 2.文件上传漏洞——绕过MIME类型检测 3.文件上传漏洞——绕过黑名单检测 绕过方式:(1) 绕过方式:(2) …

yum本地源配置

yum本地源配置 1.打开虚拟机&#xff0c;点击设置。 2.选择CD/DVD&#xff0c;选择系统镜像文件&#xff0c;设备状态选择“连接”。 3.使用命令lsblk&#xff0c;查看磁盘空间&#xff0c;发现镜像文件。 4.在/dev下找到sr0镜像文件: ls /dev 5.挂载镜像文件&#xf…

闯关leetcode——27. Remove Element

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/remove-element/description/ 内容 Given an integer array nums and an integer val, remove all occurrences of val in nums in-place. The order of the elements may be changed. Then retur…

有关C# .NET Core 过滤器的使用

想用一个过滤器实现特定接口的审核日志记录&#xff0c;结果报了错&#xff0c;看了看感觉有些基础要补&#xff0c;所以想记录下来 错误&#xff1a; 在属性过滤器中使用了依赖注入&#xff0c;结果在应用在控制层接口时报了传参的错 //过滤器 public class AuditRecordFil…

C#语言依然是主流的编程语言之一,不容置疑

C#语言是由微软在2000年发布的现代面向对象编程语言。尽管在编程语言市场中的占有率相对较低&#xff0c;但C#依然保持了强大的存在感&#xff0c;并未像一些其他语言那样逐渐被淘汰。C#语言不仅有其存在的独特理由&#xff0c;而且拥有许多令人无法忽视的优势。以下从多个方面…