kubernetes基础实践之存储

前面的文章讲到k8s基本概念中的网络和存储部分是比较难的,今天我们来啃下网络这个硬骨头。

一、kubernetes存储背景

容器中的文件在磁盘上是临时存放的,这给容器中运行的特殊应用程序带来一些问题。 首先,当容器崩溃时,kubelet 将重新启动容器,容器中的文件将会丢失——因为容器会以干净的状态重建。 其次,当在一个 Pod 中同时运行多个容器时,常常需要在这些容器之间共享文件。 Kubernetes 抽象出 Volume 对象来解决这两个问题。

二、docker和 kubernetes存储区别

  • docker存储

Docker 也有 Volume 的概念,但对它只有少量且松散的管理。在 Docker 中,Volume 是磁盘上或者另外一个容器内的一个目录。

在Docker中创建持久化存储非常简单。早期版本中,用户可以使用-v来创建一个新的未定义大小的匿名空卷或者在主机上的目录中创建绑定挂载。那个时候,虽然可以很容易地通过挂载那些已经被存储供应商挂载在主机上的目录,但没有第三方接口帮助你直接挂载到Docker上。2015年8月,Docker发布了v1.8版本,正式引入了卷插件,允许第三方连接它们的存储解决方案。Docker会调用已安装的卷插件来创建/删除/挂载/卸载/get/list那些相关卷,而且每个卷都有一个名字,直到今天,卷插件的框架基本仍保持不变。

  • kubernetes存储

Kubernetes 卷具有明确的生命周期(与对应的 Pod 相同)。 因此,卷比 Pod 中运行的任何容器的存活期都长,在容器重新启动时数据也会得到保留。 当然,当一个 Pod 不再存在时,卷也将不再存在。也许更重要的是,Kubernetes 可以支持许多类型的卷,Pod 也能同时使用任意数量的卷。

卷的核心是包含一些数据的目录,Pod 中的容器可以访问该目录。 特定的卷类型可以决定这个目录如何形成的,并能决定它支持何种介质,以及目录中存放什么内容。

使用卷时, Pod 声明中需要提供卷的类型 (.spec.volumes 字段)和卷挂载的位置 (.spec.containers.volumeMounts 字段).

三、kubernetes存储的几个重要概念

image.png

于在K8S使用存储,主要分为两类用户:

  • 管理员:主要负责创建Storage Class和Persistent Volume

  • 使用者:主要是创建Persistent Volume Claim给Pod使用

  • PV

PersistentVolume(PV)是集群中由 管理员配置的一块存储。它是集群中的资源,就和节点是集群资源一样。PV是卷插件比如Volumes,但是它的生命周期独立于使用PV的任何pod个体。该API对象捕获实现存储的详细信息,包括NFS、iSCSI或着是云服务商特定的存储系统。

  • PVC

PersistentVolumeClaim(PVC)是 用户关于存储的请求。它类似于一个pod,pod消耗节点资源,而PVC消耗PV资源。Pods可以请求特定级别的资源(CPU和内容),而Claim可以请求特定的大小和访问模式(例如,可以一次读/写或者多次只读)。

简而言之,Kubernetes将基本存储单元分为两个概念。PV是一个存储器,应该由管理员预先分配,而PVC是用户对存储的请求。

也就是说,Kubernetes希望管理员来实现分配各种大小的PV。当用户创建PVC来请求存储时,Kubernetes将尝试用该PVC和预先分配的PV匹配。如果可以找到匹配项,就将PVC绑定到PV,用户就可以开始使用这片预分配的存储区。

  • Storage Class

看上去,这样的方式很好了,但是其实有问题。PV已经从存储池中分割了出来,等待和PVC进行匹配,因此用户只能请求到预先分配的固定大小的存储空间。因为强制执行单独的分配(PV)和使用(PVC),使用起来太麻烦了。

随着v1.6版本的发布,Kubernetes引入了动态纳管(dynamic provisioning)、Storage Class和Provisioner的概念。动态纳管与传统存储方法类似。管理员可以使用Storage Class来描述他们提供的存储“class”。Storage Class可以有不同的容量限制、不同的IOPS或其他Provisioner支持的参数。特定于存储供应商的Provisioner将与Storage Class一起使用,根据Storage Class对象中设置的参数自动分配PV。此外,Provisioner现在能够强制执行用户的报价(quotes)和权限要求。在这种设计中,管理员已经从预测和分配PV的繁琐中摆脱出来,这样的方式更有意义。

四、kubernetes存储的设计和实现

Kubernete存储在设计的时候遵循着Kubernetes的一贯哲学,即声明式(Declarative)架构。同时为了尽可能多地兼容各种存储平台,Kubernetes以in-tree plugin的形式来对接不同的存储系统,满足用户可以根据自己业务的需要使用这些插件给容器提供存储服务。

容器存储接口(Container Storage Interface,CSI )是一项跨行业标准倡议,旨在降低云原生存储开发工作的门槛,从而进一步确保兼容性水平。Kubernetes v1.9已经引入了 CSI的一套alpha实现版本,将新分卷插件的安装流程简化至与安装pod相当,并允许第三方存储供应商在无需接触核心Kubernetes代码库的前提下开发自己的解决方案。

image.png

Kubernetes中mount 一个PV的基本过程包括:

  1. 用户通过API创建一个包含PVC的Pod;
  2. Scheduler把这个Pod分配到某个节点,比如Node1;
  3. Node1上的Kubelet开始等待Volume Manager准备device;
  4. PV controller调用相应Volume Plugin(in-tree或者out-of-tree),创建PV,并在系统中与对应的PVC绑定;
  5. Attach/Detach controller或者Volume Manager通过Volume Plugin实现device挂载(Attach);
  6. Volume Manager等待device挂载完成后,将卷挂载到节点指定目录(mount), 比如/var/lib/kubelet/pods/xxxxxxxxxxx/volumes/aws-ebs/vol-xxxxxxxxxxxxxxxxx;
  7. Node1上的Kubelet此时被告知volume已经准备好后,开始启动Pod,通过volume mapping将PV已经挂载到相应的容器中去。

正是因为灵活的插件机制,Kubernetes 支持很多种类型的卷,包括并不限于下列类型:

五、kubernetes存储的使用

以部署我们熟悉的 WordPress and MySQL 为例
定义mysql的部署文件 [application/wordpress/mysql-deployment.yaml]

application/wordpress/mysql-deployment.yaml 
apiVersion: v1
kind: Service
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  ports:
    - port: 3306
  selector:
    app: wordpress
    tier: mysql
  clusterIP: None
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim

定义workpress的部署文件[application/wordpress/wordpress-deployment.yaml]

application/wordpress/wordpress-deployment.yaml 
apiVersion: v1
kind: Service
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  ports:
    - port: 80
  selector:
    app: wordpress
    tier: frontend
  type: LoadBalancer
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wp-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: frontend
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: frontend
    spec:
      containers:
      - image: wordpress:4.8-apache
        name: wordpress
        env:
        - name: WORDPRESS_DB_HOST
          value: wordpress-mysql
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        ports:
        - containerPort: 80
          name: wordpress
        volumeMounts:
        - name: wordpress-persistent-storage
          mountPath: /var/www/html
      volumes:
      - name: wordpress-persistent-storage
        persistentVolumeClaim:
          claimName: wp-pv-claim

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容