k8s中的存储

Kubernetes (K8S)讲解存储/网络/运维 本文是关于 K8S 的技术文章简介。首先是基本概念,包括 K8S 的定义、在容器编排领域的地位,以及 API Server 等核心组件功能。接着阐述资源对象,如 Pod 概念、生命周期,Deployment、StatefulSet、DaemonSet 的区别与应用场景,还有 Service 类型与作用。然后是存储部分,涵盖存储卷类型及 PV 和 PVC 的关系与原理。网络方面涉及 K8S 网络模型原理和 CNI 插件。最后是运维与监控,包括 K8S 集群监控方法和集群升级回滚的流程及注意事项。 阅读详情

目录

一 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

【kubernetes】关于k8s集群的存储卷 metadata: #由于 PV 是集群级别的资源,即 PV 可以跨 namespace 使用,所以 PV 的 metadata 中不用配置 namespacename:spec#查看pv定义的规格spec:nfs:(定义存储类型)path:(定义挂载卷路径)server:(定义服务器名称)accessModes:(定义访问模型,有以下三种访问模型,以列表的方式存在,也就是说可以定义多个访问模式)- ReadWriteOnce #(RWO)卷可以被一个节点以读写方式挂载。 阅读详情

相关推荐

Kubernetes K8S之存储ConfigMap详解

K8S之存储ConfigMap概述与说明,并详解常用ConfigMap示例

踏歌行的专栏 4993

k8s挂载映射操作详解

在 k8s 中,有几种特殊的 Volume,它们的意义不是为了存放容器里的数据,也不是用来进行容器和宿主机之间的数据交换。"而是为容器提供预先定义好的数据。从容器的角度来看,这些 Volume 里的信息仿佛是被 k8s "投射"(Project)进入容器当中的。k8s 支持的 Projected Volume 一共有四种:SecretConfigMapServiceAccountToken 不常用没有写。

W1124824402的博客 4508

云原生(二十五) | Kubernetes篇之Kubernetes(k8s)临时存储

Kubernetes 为了不同的目的,支持几种不同类型的临时卷:emptyDir: Pod 启动时为空,存储空间来自本地的 kubelet 根目录(通常是根磁盘)或内存configMap、downwardAPI 、 secret: 将不同类型的 Kubernetes 数据注入到 Pod 中CSI 临时卷: 类似于前面的卷类型,但由专门支持此特性的指定 CSI 驱动程序提供通用临时卷: 它可以由所有支持持久卷的存储驱动程序提供当 Pod 分派到某个 Node 上时, 卷会被创建在 Pod 在该节点上运行期间,

Lansonli(蓝深李)的博客 1797

K8s卷存储详解(二)

因此PVC是用户对存储的请求,期望。PV访问模式(accessModes)每个 PV 卷的访问模式都会设置为对应卷所支持的模式值。

抽象空间的博客 1830

【K8S系列】深入解析K8S存储

在 Kubernetes 中,存储具有非常广泛的应用场景。可以根据实际需求选择适合自己的存储方案,以便更好地管理容器化应用程序中的数据和资源。 本文会从以下三个方面,带你了解k8s存储:1.k8s存储类型;2.存储使用场景;3.存储使用案例

颜淡慕潇 2万+

【云原生kubernetes】k8s数据存储之Volume使用详解【转】

通过之前学习了解到,k8s中Pod是最小的运行单元,Pod中运行的是一个个容器,但是容器的生命周期可能很短,被频繁地创建和销毁。当容器崩溃时文件丢失,kubelet 会重新启动容器,但容器会以干净的状态重启,之前保存在容器中的数据也会被清除;当在一个 Pod 中同时运行多个容器时,常常需要在这些容器之间共享文件;基于这些问题,k8s中就出现了“卷”这个组件来解决Kubernetes 卷(Volume) 这一抽象概念能够解决这两个问题,卷的核心是包含一些数据的目录,Pod 中的容器可以访问该目录。

m0_58523831的博客 2万+

K8S中的数据存储之基本存储

tmpfs。

杜小帅的博客 1558

TJA1445/TJA1465 CAN收发器硬件设计与软件配置实战指南

控制器局域网(CAN)总线是汽车电子和工业控制领域实现电子控制单元(ECU)间可靠通信的核心技术。其工作原理是将数字信号转换为差分信号进行抗干扰传输,技术价值在于构建稳定、高效的分布式实时控制系统。随着汽车电子架构向域集中式演进,对CAN总线的通信速率、网络复杂度和静态功耗提出了更高要求,这催生了支持CAN FD协议和智能电源管理的新一代高速CAN收发器。在车载网关、域控制器及工业网络节点等应用场景中,NXP的TJA1445和TJA1465系列收发器凭借其部分组网(Partial Networking)和选

weixin_29655587的博客 409

StorageClass存储类

PS: nfs-client-provisioner这个镜像的作用,它通过k8s集群内置的NFS驱动,挂载远端的NFS服务器到本地目录(这里的本地目录指的是容器内的目录),然后将自身作为storage provisioner,关联到storageclass。provisioner: bdqn-test #存储提供者是谁 需要和上段env里指定的name下的 value:bdqn-test一致。value: bdqn-test #真正提供存储的是bdqn-test。并且暴露了一个环境变量。

li175325的博客 1393

微信小程序导航栏滑动一定距离后固定到顶部

接上一篇文章的内容,通常在一个页面中部会有一个导航栏查看不同的内容,这篇文章旨在实现在页面下滑的过程中导航栏自动固定到顶部以便我们阅读过程中的切换。 下滑一段距离后自动固定到顶部 首先,思考这个功能应该是怎么实现的: 在页面下滑的过程中,我们希望系统应当能识别下滑了多少距离,当原本的导航栏逐渐被遮住以后(遮住意味着下滑了特定距离),触发这个功能,执行另一种样式,将导航栏固定在页面顶端,同时如果我们将页面往上滑,系统能识别到原来的导航栏能露出来了(即距离顶端的高度小于一个特定的值),这时候又执行最初的样式

Oblivision_Geek的博客 4031

AR-HMM模型 自回归隐马尔可夫模型

AR-HMM模型 自回归隐马尔可夫模型 数据处理过程 输入的视频数据首先需要被裁剪以适合动物的大小,在这之后考虑到模型建立的目的为行为状态的分类,于是需要消除可能一帧里带有多个动作状态的行为成分,这个过程也就是对帧。对帧之后我们的为了适应模型训练还需要对每一帧的数据进行小波分解(类似傅里叶变换的信号重构),此时数据预处理阶段完成。 信号重构后的数据拥有的特征维度过多,因此需要应用主成分分析法(PCA)来选出对于分类结果贡献度最高的前十个分类特征。至此自回归隐马尔可夫模型的准备工作就完成了。 AR-HMM自

weixin_46263718的博客 2283

Kubernetes第八章--存储类型

在Kubernetes(K8s)中,存储系统是一个关键的组成部分,用于管理容器化应用的数据持久性和共享性。K8s的存储分类可以从多个维度进行理解,但主要分为两大类:临时存储和持久存储。关于元数据和真实数据的分类,虽然这两个概念在存储系统中普遍存在,但在K8s的存储分类中,它们并不是直接用于分类存储类型的标准。不过,可以从K8s存储类型如何管理和使用这些数据的角度来探讨。k8s支持的卷类型持久卷:持久卷是集群中的存储资源,就像他的名字一样,在里面存储的数据不会随着 Pod 的删除而丢失。临时卷:有些应用程序需

hehe228的博客 1206

从零搭建AMESim与Matlab/Simulink联合仿真环境(2024版软件配置详解)

本文详细介绍了2024年最新版AMESim与Matlab/Simulink联合仿真环境的搭建与配置方法。从软件安装顺序、路径设置到编译器配置,逐步指导如何实现高效联合仿真,特别强调了版本兼容性和环境变量设置等关键细节,帮助工程师快速解决常见问题并优化仿真性能。

weixin_42538752的博客 735

Kubernetes K8S之存储PV-PVC详解

Kubernetes K8S之存储PV-PVC详解概述PV概述PVC概述volume 和 claim的生命周期供应绑定使用持久化声明保护回收策略Persistent Volumes类型PV示例与参数说明PV示例PV卷状态PV类型与支持的访问模式PV-PVC示例主机信息NFS服务部署PV部署StatefulSet创建并使用PVCPV和PVC状态信息查看curl访问验证删除sts并回收PVStatefulSet网络标识与PVC 原文链接: Kubernetes K8S之存储PV-PVC详解 概述 与管理计算实例

爱是与世界平行 2102

第2章: MMU Notifier 全局通知器的核心原理⭐

摘要 MMU Notifier机制是Linux内核中用于处理内存地址空间变化通知的关键框架。其设计遵循解耦与标准化、最小侵入性、高性能和安全性四大原则,采用三层架构实现上层应用、核心层与内存管理层的协作。框架提供两种通知模型:全局订阅的mmu_notifier和区间订阅的mmu_interval_notifier,分别适用于KVM虚拟化和GPU共享虚拟内存等不同场景。核心数据结构mmu_notifier_ops定义了设备驱动需要实现的回调函数集合,包括进程退出处理、页面老化管理、地址范围失效通知等功能。

图形/计算GPU的驱动与虚拟化技术分享园地 4561

基于强化学习控制策略的三相逆变器仿真

强化学习控制器的核心在于定义状态空间、动作空间、奖励函数以及选择合适的强化学习算法(例如DQN、DDPG等)。对于三相逆变器,状态可以是输出电压、电流等信息;动作则可能是调制指数的变化量;奖励函数则应鼓励快速准确地跟踪参考信号。定义状态空间和动作空间状态空间可以包括逆变器的输出电压、电流及其变化率等信息。动作空间则是控制器可执行的动作,例如PWM信号的调整幅度。matlab深色版本% 定义状态和动作空间维度numObs = 6;% 假设有六个状态变量(例如三相电压和电流)

amy_mhd的博客 135

用NFS存储挂载Kubernetes(K8S)容器中的文件

Kubernetes通过Volume实现容器数据持久化,NFS是常用解决方案,本文详细介绍了在K8S集群中配置NFS存储的步骤

CLASSXY的博客 671

嵌入式工程师成长之路(7)——算法学习

算法大全1、风仲达——算法笔记2、坐在马桶上学算法3、啊哈算法4、深度强化学习实验室。

云轩阁 4万+

Kubernetes K8S之存储Volume详解

Kubernetes K8S之存储Volume详解Volume概述Volume类型emptyDir卷emptyDir的一些用途:emptyDir示例emptyDir验证hostPath卷hostPath 的一些用法有支持类型注意事项hostPath示例hostPath验证 原文地址: Kubernetes K8S之存储Volume详解 Volume概述 在容器中的文件在磁盘上是临时存放的,当容器关闭时这些临时文件也会被一并清除。这给容器中运行的特殊应用程序带来一些问题。 首先,当容器崩溃时,kubelet

爱是与世界平行 1695

华为OD机试 - 直捣黄龙 - 广度优先搜索BFS(Python/JS/C/C++ 新系统 200分)

从样例 1 可知:5 / 2,2 -> 输出 2 9如果按“移动步数”计算应该是 8,但题目输出是 9,说明这里的“路径长度”统计的是 路径上经过的节点数量。最短路径条数:ways[end]路径长度:dist[end] + 1。

学Java,找哪吒 125

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

解决K8s持久化存储痛点:Kubernetes The Hard Way存储卷实战指南

你是否还在为容器数据丢失而烦恼?部署了无状态服务却不知如何处理数据库存储需求?本文将通过Kubernetes The Hard Way项目的实战场景,带你从零掌握存储卷(Volume)配置与管理,解决容器数据持久化难题。读完本文你将获得:理解K8s存储卷核心概念、掌握PV/PVC配置方法、学会调试常见存储问题的技巧。 ## 存储卷核心概念与架构 Kubernetes存储卷(Volume)是解决

gitblog_01102的博客 1025

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

【Kubernetes】K8s 持久化存储方式

由于容器是一种无状态的服务,所以容器中的文件在宿主机上表现出来的都是临时存放(当容器崩溃或者重启时,容器中的文件会丢失)。另外,Kubernetes 也需要在 Pod 之间实现数据共享。为了解决这些问题,Kubernetes 与 Docker 一样,也通过使用数据卷的方式来实现数据持久化。

Data · Model · Agent · Repeat 2777

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

k8s-kubernetes存储卷

我们知道默认情况下容器的数据都是非持久化的,在容器消亡以后数据也跟着丢失,所 以Docker提供了Volume机制以便将数据持久化存储。类似的,Kubernetes提供了更强 大的Volume机制和丰富的插件,解决了容器数据持久化和容器间共享数据的问题。

a18792721831的博客 932

【Kubernetes】k8s集群存储卷(pvc存储卷)

人生没有不可逾越的天堑,只要一步步走过去,前方就是幸福的彼岸

F12138X的博客 2497
上一篇: k8s 微服务 ingress-nginx 金丝雀发布
下一篇: k8s网络通信与调度
HoweWWW
博客等级 码龄4年 429粉丝 36原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值