掘金 后端 ( ) • 2024-05-14 16:43

service介绍

解决什么问题

Pod的生命是有限的,死亡过后不会复活了,尽管每个Pod都有自己的IP地址,但是如果Pod重新启动了的话那么他的IP很有可能也就变化了。这就会带来一个问题:比如我们有一些后端的Pod的集合为集群中的其他前端的Pod集合提供API服务,如果我们在前端的Pod中把所有的这些后端的Pod的地址都写死,然后去某种方式去访问其中一个Pod的服务,这样看上去是可以工作的,对吧?但是如果这个Pod挂掉了,然后重新启动起来了,是不是IP地址非常有可能就变了,这个时候前端就极大可能访问不到后端的服务了。

在部署 WEB 服务时,通常会使用 Nginx 作为服务的入口,Nginx 后面会挂载大量的后端服务。以前,我们可能需要手动更改 Nginx 配置中的 upstream 选项来动态改变提供服务的数量,但随着服务发现工具的出现,如 Consul、ZooKeeper 和 etcd 等,我们现在只需要将服务注册到这些服务发现中心,然后让工具动态地更新 Nginx 的配置就可以了,完全不需要手工操作,非常方便。

同样的,如果我们要解决前端 Pod 如何连接到后端 Pod 集合的问题,也可以使用类似的方式。当后端 Pod 被销毁或新建时,我们可以将这些 Pod 的地址注册到服务发现中心。然后,前端 Pod 可以连接到这个服务发现中心,从中获取后端 Pod 的地址信息,实现动态的服务发现和连接。这样,我们就可以将服务发现的逻辑从应用中解耦出来,让前端 Pod 只需要连接到一个能够做服务发现的中间件上面,而不需要直接与后端 Pod 集合交互。

三种IP

学习Service之前,我们需要先弄明白Kubernetes系统中的三种IP这个问题

  1. Node IP:Node IP 是 Kubernetes 集群中节点(物理机器)的 IP 地址,通常是节点的物理网卡 IP 地址(内网 IP)。Node IP 允许集群内的节点之间进行直接通信。如果要从 Kubernetes 集群外部访问集群内的节点或服务,通常需要通过节点的 Node IP 进行通信。
  2. Pod IP:Pod IP 是每个 Pod 的 IP 地址,由 Docker Engine 根据 docker0 网桥的 IP 地址段进行分配。Pod IP 用于在 Kubernetes 集群内部实现 Pod 之间的通信。通常情况下,Pod IP 由网络插件(如 Flannel、Calico 等)负责管理和分配,确保在整个集群中不会发生 IP 地址冲突。
  3. Cluster IP:Cluster IP 是 Kubernetes 中 Service 对象的虚拟 IP 地址,仅作用于 Kubernetes Service。Cluster IP 由 Kubernetes 自己管理和分配,用于提供抽象的服务访问接口。通过 Service 的 Cluster IP 和端口,其他 Pod 或外部客户端可以访问 Service 提供的服务。需要注意的是,Cluster IP 没有实际的物理实体对象来响应,它只是一个虚拟的地址,用于标识 Service。

定义service

定义一个名为 myservice 的 Kubernetes Service,假定我们有一组Pod服务,它们对外暴露了 8080 端口,同时都被打上了app=myapp这样的标签,那么我们就可以像下面这样来定义一个Service对象:

apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  selector:
    app: myapp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
    name: myapp-http

  • apiVersion: v1:指定了 Kubernetes API 的版本,这里使用的是 v1 版本。

  • kind: Service:指定了要创建的 Kubernetes 资源类型,这里是一个 Service。

  • metadata: name: myservice:指定了 Service 的元数据,其中 name 字段为 myservice,表示该 Service 的名称。

  • spec: selector: app: myapp:这里定义了 Service 的选择器,指定了哪些 Pod 将会被该 Service 匹配到。这个 Service 会将流量转发给具有标签 app: myapp 的 Pod。

  • ports: - protocol: TCP port: 80 targetPort: 8080 name: myapp-http:这个部分定义了 Service 暴露的端口。具体解释如下:

    • protocol: TCP:指定了端口使用的协议,这里是 TCP 协议。
    • port: 80:指定了 Service 暴露给其他 Pod 或外部客户端的端口号,这里是 80 端口。
    • targetPort: 8080:指定了后端 Pod 上实际运行服务的端口号,这里是 8080 端口。当请求到达 Service 时,Service 会将流量转发到具有标签 app: myapp 的 Pod 上的 8080 端口。
    • name: myapp-http:指定了该端口的名称,用于标识这个端口。

运行命令

kubectl create -f myservice.yaml

就可以创建一个名为myserviceService对象,这个Service会被系统分配一个我们上面说的Cluster IP,它会将请求代理到使用 TCP 端口为 8080,具有标签app=myappPod上,这个过程需要负载均衡。

怎么实现负载均衡

Kubernetes集群中,每个Node会运行一个kube-proxy进程, 负责为Service实现一种 VIP(虚拟 IP,就是我们上面说的clusterIP)的代理形式,现在的Kubernetes中默认是使用的iptables这种模式来代理。

kube-proxy 是 Kubernetes 中的一个重要组件,负责为 Service 实现负载均衡和服务发现。它可以工作在多种模式下,其中最常见的是 iptables 模式。在 iptables 模式下,kube-proxy 监视 Kubernetes master 上的 Service 和 Endpoints 对象的变化,并根据这些信息为每个 Service 和对应的 Pod 部署 iptables 规则。

在 iptables 模式下,kube-proxy 会做以下工作:

  • 为 Service 创建负载均衡规则:当创建一个 Service 时,kube-proxy 会为该 Service 创建 iptables 规则,用于将访问 Service 的请求转发到后端 Pod。这些规则会捕获到达 Service 的请求,并将其重定向到 Service 后端的一组 Pod 中的某一个。
  • 为 Endpoints 创建负载均衡规则:kube-proxy 也会为每个 Endpoints 对象创建 iptables 规则,用于选择一个后端 Pod。这些规则允许 kube-proxy 在每个请求中选择一个后端 Pod,以实现负载均衡。
  • 实现会话亲和性:kube-proxy 支持会话亲和性,可以根据客户端 IP 来路由请求到同一个后端 Pod,以保持会话的一致性。这可以通过将 Service 的 sessionAffinity 属性设置为 "ClientIP" 来实现。
  • 自动重试后端 Pod:如果最初选择的后端 Pod 没有响应,kube-proxy 可以自动重试另一个后端 Pod。为了实现这一点,后端 Pod 必须具有 readiness probes,以确保它们能够接收流量。

kube-proxy 通常在 Kubernetes 集群中的每个物理机节点上都运行一个实例。kube-proxy 是 Kubernetes 中的一个核心组件,负责实现 Service 的负载均衡和服务发现功能。为了保证集群中的每个节点都能够访问到 Service,并实现负载均衡,kube-proxy 需要在每个节点上运行。

每个 kube-proxy 实例都会监听集群中的 Service 和 Endpoints 对象的变化,并根据这些变化来更新本地的负载均衡规则。通过在每个节点上运行 kube-proxy 实例,可以确保集群中的所有节点都能够正确地处理流量,并将请求转发到相应的后端 Pod。

Service 类型

定义Service的时候可以指定一个自己需要的类型的Service,如果不指定的话默认是ClusterIP类型。可以使用的服务类型如下:

  • ClusterIP:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的ServiceType。
  • NodePort:通过每个 Node 节点上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 :,可以从集群的外部访问一个 NodePort 服务。
  • LoadBalancer:使用云提供商的负载局衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务,这个需要结合具体的云厂商进行操作。
  • ExternalName:通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如, foo.bar.example.com)。没有任何类型代理被创建,这只有 Kubernetes 1.7 或更高版本的 kube-dns 才支持。

NodePort 类型

如果设置 type 的值为 "NodePort",Kubernetes master 将从给定的配置范围内(默认:30000-32767)分配端口,每个 Node 将从该端口(每个 Node 上的同一端口)代理到 Service。该端口将通过 Service 的 spec.ports[*].nodePort 字段被指定,如果不指定的话会自动生成一个端口。​编辑

创建了一个 NodePort 类型的服务,名为 myservice。这意味着该服务将会在每个节点上绑定一个端口,并将流量转发到后端 Pod 的 80 端口。

myservice:这是你创建的 Service 的名称。

NodePort:这是 Service 的类型,表示这是一个 NodePort 类型的服务。

10.104.57.198:这是 Service 的 ClusterIP,即 Service 在集群内部的虚拟 IP 地址。

:这表示该服务没有关联的外部负载均衡器 IP 地址。

80:32560/TCP:这是 Service 的端口映射规则。其中,80 是 Service 的端口,32560 是每个节点上绑定的 NodePort 端口,用于从节点外部访问该服务。它告诉 Kubernetes 在每个节点上将来自此端口的流量转发到 Service 的端口。

因此,当你访问任何物理节点的 32560 端口时,Kubernetes 将会将请求转发到集群内部的service的 80 端口,然后进一步将请求转发到具有标签 app: myapp 的 Pod 上的 80 端口,而定义Pod的时候设置了Pod里的容器会把它的服务监听的端口映射到Pod的80端口,从而实现了对后端 Pod 中的web服务的访问。

实际应用

假设我们需要让一个Wordpress来访问mysql数据库,使用Deployment来管理Pod,首先创建mysql的Deployment对象,指明容器监听的端口为3306,端口的名称是"dbport" 。

---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: mysql-deploy
  namespace: blog
  labels:
    app: mysql
spec:
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 3306
          name: dbport
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: rootPassW0rd
        - name: MYSQL_DATABASE
          value: wordpress
        - name: MYSQL_USER
          value: wordpress
        - name: MYSQL_PASSWORD
          value: wordpress
        volumeMounts:
        - name: db
          mountPath: /var/lib/mysql
      volumes:
      - name: db
        hostPath:
          path: /var/lib/mysql

然后需要让Wordpress来访问,由于它们不在同一个Pod中,需要访问就可以用到service。

所以在yaml文件中添加service信息

---
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: blog
spec:
  selector:
    app: mysql
  ports:
  - name: mysqlport
    protocol: TCP
    port: 3306
    targetPort: dbport

运行

$ kubectl create -f wordpress-db.yaml
service "mysql" created
deployment.apps "mysql-deploy" created

然后查看Service的详细情况:

$ kubectl describe svc mysql -n blog
Name:              mysql
Namespace:         blog
Labels:            <none>
Annotations:       <none>
Selector:          app=mysql
Type:              ClusterIP
IP:                10.98.27.19
Port:              mysqlport  3306/TCP
TargetPort:        dbport/TCP
Endpoints:         10.244.2.213:3306
Session Affinity:  None
Events:            <none>

可以看到Endpoints部分匹配到了一个Pod,生成了一个clusterIP10.98.27.19,现在我们就可以通过这个clusterIP加上定义的3306端口就可以正常访问我们这个mysql服务了。(clusterIP是service提供给其他Pod访问的虚拟IP,Endpoints是service代理的Pod的实际IP和端口,其他Pod访问service使用的是clusterIP)。

接下来创建Wordpress服务,环境变量WORDPRESS_DB_HOST的值为上面mysql服务的clusterIP地址,这就是clusterIP类型service的使用。

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: wordpress-deploy
  namespace: blog
  labels:
    app: wordpress
spec:
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      containers:
      - name: wordpress
        image: wordpress
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
          name: wdport
        env:
        - name: WORDPRESS_DB_HOST
          value: 10.98.27.19:3306
        - name: WORDPRESS_DB_USER
          value: wordpress
        - name: WORDPRESS_DB_PASSWORD
          value: wordpress

接下来需要让外网访问开启的wordpress服务,就需要建立一个能让外网用户访问的Service,这里就需要NodePort类型的Service。

---
apiVersion: v1
kind: Service
metadata:
  name: wordpress
  namespace: blog
spec:
  type: NodePort
  selector:
    app: wordpress
  ports:
  - name: wordpressport
    protocol: TCP
    port: 80
    targetPort: wdport

创建并查看信息

$ kubectl apply -f wordpress.yaml
service "wordpress" created
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
deployment.apps "wordpress-deploy" configured

$ kubectl get svc -n blog
NAME        TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
mysql       ClusterIP   10.98.27.19   <none>        3306/TCP       25m
wordpress   NodePort    10.101.7.69   <none>        80:32255/TCP   1m

可以看到wordpress服务产生了一个32255的端口,现在可以通过任意节点的NodeIP(公网IP)加上32255端口,就可以访问我们的wordpress应用了。

架构图解

NodePort模式的service绑定在每个k8s物理节点的32057端口,访问它就可以访问到service,然后service又会通过endpoint找到对应的Pod(因为它记录了这些Pod的内部 IP 地址),并访问它们的80端口。如果想让内部Pod访问service的时候,能访问到集群外部的服务,那么可以单独配置endpoint,这样service通过endpoint找的就是外部的ip地址。一般情况下不用NodePort模式的service来对外暴露服务,因为效率低,并且不支持http/https的通信,仅用于集群内部的通信,对外暴露服务需要使用ingress。

​编辑

Ingress介绍

解决什么问题

把集群内部的Service暴露给外网访问,实现南北流量的互通。Service仅支持通过IP地址和端口来进行路由,不能进行HTTP请求的路径或主机头的路由。Ingress的功能和Nginx类似。

定义Ingress

路径匹配和虚拟主机匹配是两种常见的路由规则,它们根据请求的路径或主机头来路由流量到不同的后端服务。

路径匹配

路径匹配是根据请求的URL路径来进行路由的,将请求路由到不同的后端服务。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /app1
        pathType: Prefix
        backend:
          service:
            name: app1-service
            port:
              number: 80
      - path: /app2
        pathType: Prefix
        backend:
          service:
            name: app2-service
            port:
              number: 80

在上面的示例中,当请求的路径是 /app1 时,流量将被路由到 app1-service;当请求的路径是 /app2 时,流量将被路由到 app2-service

虚拟主机匹配

虚拟主机匹配是根据请求的主机头(即域名)来进行路由的。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
spec:
  rules:
  - host: app1.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app1-service
            port:
              number: 80
  - host: app2.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app2-service
            port:
              number: 80

在上面的示例中,当请求的主机头是 app1.example.com 时,流量将被路由到 app1-service;当请求的主机头是 app2.example.com 时,流量将被路由到 app2-service

路径匹配适用于将不同的路径映射到不同的服务,通常用于在同一个域名下托管多个应用的情况。

虚拟主机匹配适用于将不同的主机头(域名)映射到不同的服务,通常用于在同一个集群中托管多个域名的情况。

ConfigMap介绍

解决什么问题

  • 将应用程序的配置信息(如数据库连接字符串、日志级别、端口号等)存储在ConfigMap中,然后在应用程序中通过环境变量或文件挂载的方式引用这些配置信息。
  • 对于需要加载静态文件的应用程序(如网页服务器、静态资源服务器等),可以将静态文件的路径、URL映射等配置信息存储在ConfigMap中,然后在应用程序中读取这些配置信息来加载静态文件。

定义ConfigMap

一个简单的Web应用程序,它连接到一个数据库,并且需要以下配置信息:

  • 数据库主机地址
  • 数据库端口号
  • 数据库用户名
  • 数据库密码

首先,创建一个ConfigMap来存储这些配置信息:

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-app-config
data:
  DB_HOST: "db.example.com"
  DB_PORT: "3306"
  DB_USERNAME: "admin"
  DB_PASSWORD: "password123"

然后,在部署应用程序的Deployment或Pod配置中,将这些配置信息注入到应用程序的环境变量中:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app-container
        image: my-app-image:latest
        ports:
        - containerPort: 8080
        envFrom:
        - configMapRef:
            name: my-app-config

我们通过envFrom字段将ConfigMap中的配置信息注入到了应用程序的环境变量中。这样,在应用程序启动时,就可以通过环境变量来访问数据库的配置信息。

Volumes介绍

解决什么问题

用于持久化存储数据。

Volume 类型

HostPath

和docker中的挂载主机目录类似。用例:一个基于 MySQL 数据库的应用程序,并且希望将数据库文件存储在宿主机上的特定目录中。

apiVersion: v1
kind: Pod
metadata:
  name: mysql-pod
spec:
  containers:
  - name: mysql
    image: mysql:latest
    volumeMounts:
    - name: mysql-data
      mountPath: /var/lib/mysql
  volumes:
  - name: mysql-data
    hostPath:
      path: /data/mysql

创建了一个 Pod,其中包含一个名为 mysql 的容器,它使用 MySQL 镜像。我们定义了一个 HostPath Volume,它将宿主机上的 /data/mysql 目录挂载到容器内的 /var/lib/mysql 目录。简单来说相当于volumeMounts指定了用volumes作为磁盘加载到容器中。

EmptyDir

EmptyDir 是一个临时目录,它的生命周期与 Pod 的生命周期相同。当 Pod 被删除时,EmptyDir 中的数据也会被清除。常见使用场景是一个Pod中的不同容器共享数据。​编辑

用例:一个 Web 服务器应用程序,它由两个容器组成:一个容器负责生成静态网页文件,另一个容器负责提供这些网页文件。你希望生成的网页文件能够在提供容器中进行访问。在这种情况下,你可以使用 EmptyDir 来共享生成的网页文件。

apiVersion: v1
kind: Pod
metadata:
  name: web-server-pod
spec:
  containers:
  - name: webpage-generator
    image: webpage-generator:latest
    volumeMounts:
    - name: shared-data
      mountPath: /data
  - name: web-server
    image: nginx:latest
    volumeMounts:
    - name: shared-data
      mountPath: /usr/share/nginx/html
  volumes:
  - name: shared-data
    emptyDir: {}

创建了一个 Pod,其中包含两个容器:一个是 webpage-generator,负责生成网页文件;另一个是 web-server,负责提供网页文件。我们创建了一个 EmptyDir Volume,并将其挂载到两个容器中。webpage-generator 容器可以将生成的网页文件写入 EmptyDir,而 web-server 容器可以读取并提供这些网页文件。在这个例子中,EmptyDir 提供了一个临时的共享存储介质,使得两个容器可以轻松地共享数据。

NFS介绍

解决什么问题

NFS 卷是一种用于挂载远程 NFS 服务器上的目录的卷类型,可以将远程存储中的文件或目录挂载到 Kubernetes Pod 中的容器中,相当于把 ****HostPath和EmpytDir结合起来,既可以实现数据共享,又可以持久化。

使用场景

有一个Web 应用程序,需要在多个 Pod 中共享静态文件,比如图片、视频或者其他资源文件。

  • 设置一个 NFS 服务器。假设 NFS 服务器的 IP 地址为 192.168.1.100,共享的目录为 /nfs/shared
  • 在Kubernetes 中创建一个 NFS 卷,以便 Pod 可以挂载这个共享目录。
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-volume
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteMany
  nfs:
    path: /nfs/shared
    server: 192.168.1.100

  • 在应用程序的 Pod 配置中引用这个 NFS 卷。
apiVersion: v1
kind: Pod
metadata:
  name: webapp-pod
spec:
  containers:
  - name: webapp-container
    image: your-webapp-image
    volumeMounts:
    - name: nfs-volume
      mountPath: /app/static
  volumes:
  - name: nfs-volume
    persistentVolumeClaim:
      claimName: nfs-pvc

  • 在 Kubernetes 集群中创建一个持久卷声明,以便动态地分配 NFS 卷给 Pod。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi

通过这个示例,Web 应用程序的所有 Pod 都可以共享 NFS 服务器上的/nfs/shared目录中的静态文件,无论 Pod 在 Kubernetes 集群中的哪个节点上运行,它们都可以访问相同的文件。

PV和PVC介绍

PV是Kubernetes中的存储资源的抽象,独立于任何单个Pod,PVC则是Pod对PV的请求。

解决什么问题

​编辑

在没有pv的情况,每个节点使用的远程存储的方案不规范,各用各的,每个服务器都要管理自己的配置和依赖,没有统一的标准。pv对这些资源进行了抽象,关联了这些存储卷,通过在Pod上绑定PVC,就可以让Pod通过PVC去请求PV。

​编辑 使用场景

下面是一个包含标签选择器的 PV 的 YAML 示例:
apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /data/my-pv
  persistentVolumeReclaimPolicy: Retain
  labels:
    app: my-app

  • apiVersion: v1 指定了 Kubernetes API 的版本。
  • kind: PersistentVolume 表示这是一个 PersistentVolume 对象。
  • metadata.name 指定了 PV 的名称。
  • spec.capacity.storage 指定了 PV 的容量。
  • spec.accessModes 指定了 PV 的访问模式,这里设置为 ReadWriteOnce,表示可以被单个节点挂载为读写模式。
  • spec.nfs.path 指定了 PV 的路径,这里使用 NFS 协议。
  • spec.nfs.server 指定了 NFS 服务器的地址。
  • spec.persistentVolumeReclaimPolicy 指定了 PV 回收策略,这里设置为 Recycle,表示删除 PV 时会清空其中的数据。

创建一个 PVC 的 YAML 文件,如下所示:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  selector:
    matchLabels:
      app: my-app

创建一个 Pod 的 YAML 文件,如下所示:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: nginx
    volumeMounts:
    - name: my-volume
      mountPath: /usr/share/nginx/html
  volumes:
  - name: my-volume
    persistentVolumeClaim:
      claimName: my-pvc

这样就创建了一个 PV、一个 PVC 和一个 Pod,并将它们关联起来。Pod 将使用 PVC 中的存储资源,并将其挂载到容器中的指定路径。

PV的回收策略

有不同的回收策略,用于确定当 PV 不再被使用时应如何处理其资源。

  1. Retain:在 PV 被释放后,保留 PV 的数据,不对其进行任何处理。这意味着 PV 的数据将保留在存储中,需要手动清理。这种策略适用于需要手动处理 PV 数据的情况。
  2. Delete:在 PV 被释放后,删除 PV 中的数据。这意味着 PV 的存储资源将被释放,并且 PV 中的数据将被永久删除。这种策略适用于不需要保留 PV 数据的情况,或者希望在释放 PV 时自动清理数据的情况。

PV的访问模式

指定了如何将存储资源挂载到 Pod 中。

  1. ReadWriteOnce (RWO) :该模式表示卷可以挂载到单个节点上的一个 Pod,并且可以被该 Pod 以读写的方式使用。这意味着卷不能同时被多个节点上的 Pod 挂载,但可以被同一节点上的多个 Pod 挂载。
  2. ReadOnlyMany (ROX) :该模式表示卷可以同时被多个节点上的多个 Pod 以只读的方式挂载。这意味着多个 Pod 可以同时读取卷的内容,但不能对其进行写操作。
  3. ReadWriteMany (RWX) :该模式表示卷可以同时被多个节点上的多个 Pod 以读写的方式挂载。这意味着多个 Pod 可以同时读取和写入卷的内容。

要选择正确的访问模式,需要根据你的应用程序和场景来确定。例如,如果你的应用程序需要多个 Pod 同时读写存储资源,那么就需要选择 RWX 访问模式。如果只需要一个 Pod 读写存储资源,那么就可以选择 RWO 访问模式。

PVC的访问模式

PV 和 PVC 的访问模式并不需要设置为完全相同。但是,PV 的访问模式必须满足 PVC 的访问需求。换句话说,PVC 可以请求比 PV 更灵活的访问模式,但不能请求更严格的访问模式。

例如:

  • 如果一个 PV 的访问模式是 ReadWriteOnce(RWO),那么它只能被单个 Pod 以读写模式挂载。其他 Pod 只能以只读模式挂载该 PV。
  • 如果一个 PVC 请求的访问模式是 ReadOnlyMany(ROX),那么它可以绑定到支持 ReadOnlyMany 或 ReadWriteMany(RWX)访问模式的 PV 上。

因此,PV 和 PVC 的访问模式可以不完全一样,但必须满足 PVC 的访问需求。

Storageclass介绍

以上构建PV的方式为静态构建,即提前手动创建好PV,等待PVC来绑定。利用storageclass可以实现动态构建,storageclass关联PVC后,可以根据PVC的需求自动创建PV。

使用场景

  1. 定义 StorageClass 的 YAML 文件:在 YAML 文件中指定 StorageClass 的名称、存储提供者、存储类型、卷大小等参数。
  2. 为 PVC 指定 StorageClass:在创建 PVC 的 YAML 文件中,通过 storageClassName 属性指定所需的 StorageClass。
  3. 使用 PVC:创建 Pod 时,将 PVC 指定为 Volume, Pod 将使用动态创建的 PV。

下面是一个 StorageClass 的简单示例:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
  zone: us-west-1

这个示例中的 StorageClass 名称为 "fast",使用 AWS EBS 作为存储提供者,并指定了一些参数,如存储类型为 gp2、区域为 us-west-1 等。创建 PVC 时,可以通过 storageClassName: fast 来使用这个 StorageClass,然后 Kubernetes 将会根据定义的策略动态地创建 PV。