Kubernetes-存储(一)

简介: 对于这个问题其实很简单,容器中持久化的文件生命周期是短暂的,如果容器中程序崩溃宕机,kubelet 就会重新启动,容器中的文件将会丢失,所以对于有状态的应用容器中持久化存储是至关重要的一个环节;另外很多时候一个 Pod 中可能包含多个 Docker 镜像,在 Pod 内数据也需要相互共享,Kubernetes 中 Pod 也可以增加副本数量,遇到故障时 Pod 可以转移到其它节点,为了浮动节点都能够访问统一的持久化存储以及容器间共享数据,Kubernetes 中定义了 Volume 来解决这些问题 ,从本质上讲,Volume 只是一个目录,可能包含一些数据,Pod 中的容器可以访问它。

一、前言


本篇是Kubernetes第十二篇,大家一定要把环境搭建起来,看是解决不了问题的,必须实战。

Kubernetes系列文章:
  1. Kubernetes介绍
  2. Kubernetes环境搭建
  3. Kubernetes-kubectl介绍
  4. Kubernetes-Pod介绍(-)
  5. Kubernetes-Pod介绍(二)-生命周期
  6. Kubernetes-Pod介绍(三)-Pod调度
  7. Kubernetes-Pod介绍(四)-Deployment
  8. Kubernetes-Service介绍(一)-基本概念
  9. Kubernetes-Service介绍(二)-服务发现
  10. Kubernetes-Service介绍(三)-Ingress(含最新版安装踩坑实践)
  11. Kubernetes-网络


二、为什么需要存储


对于这个问题其实很简单,容器中持久化的文件生命周期是短暂的,如果容器中程序崩溃宕机,kubelet 就会重新启动,容器中的文件将会丢失,所以对于有状态的应用容器中持久化存储是至关重要的一个环节;另外很多时候一个 Pod 中可能包含多个 Docker 镜像,在 Pod 内数据也需要相互共享,Kubernetes 中 Pod 也可以增加副本数量,遇到故障时 Pod 可以转移到其它节点,为了浮动节点都能够访问统一的持久化存储以及容器间共享数据,Kubernetes 中定义了 Volume 来解决这些问题 ,从本质上讲,Volume 只是一个目录,可能包含一些数据,Pod 中的容器可以访问它。该目录是何种形式,是由所使用的 Volume 类型决定的。


三、Volume介绍


Kubernetes 支持很多 Volume类型,可以分为以下类型:

img

我们重点介绍下资源对象映射为存储卷、Node本地存储卷和持久卷。

资源对象映射为存储卷

在 Kubernetes中ConfigMap、Serect、DownwardAPI和ServiceAccountToken四种存储卷,存在的意义不是为了存放容器里的数据,也不是用来进行容器和宿主机之间的数据交换,是为容器提供预先定义好的数据。从容器的角度来看,这些 Volume里的信息就是被映射到容器当中的。

ConfigMap

ConfigMap用于保存应用程序的配置信息,可以通过Volume的形式挂载到容器内部文件系统中,供容器内的应用程序读取。

使用
  1. 创建configMap文件;
apiVersion: v1
kind: ConfigMap
metadata:
  name: env-config
data:
  env-key: test
  1. 创建Pod文件,在Pod使用configMap配置信息;
apiVersion: v1
kind: Pod
metadata:
  name: configmap-pod
spec:
  containers:
  - name: configmap-pod
    image: busybox:1.28.3
    command: [ "/bin/sh", "-c", "env" ]
    env:
     - name: ENV
       valueFrom:
         configMapKeyRef:
           name: env-config
           key: env-key 
  restartPolicy: Never
  1. 启动configMap和Pod;
kubectl apply -f env-configMap.yaml
kubectl apply -f configmap-pod.yaml
  1. 查看启动日志;
kubectl logs configmap-pod

image.png

Secret

Secret功能与ConfigMap类似,它与ConfigMap的区别在于,Secret保存的是需要加密的、应用所需的配置信息。Secret与ConfigMap用法完全相同:你可以使用 kubectl create secret从文件或者目录创建 Secret,也可以直接编写Secret对象的YAML文件。

Downward API

Downward API的作用是让Pod里的容器能够直接获取到这个Pod API对象本身的元数据信息。

使用
  1. 创建Pod,该Pod声明了一个projected类型的Volume,Volume的数据来源为Downward API,而这个 Downward API Volume,要暴露Pod的metadata.labels 信息给容器,容器启动以后,则是不断打印出 /etc/podinfo/labels 里的内容;
apiVersion: v1
kind: Pod
metadata:
  name: downwardapi-demo-pod
  labels:
    cluster: demo-test
spec:
  containers:
    - name: downwardapi-demo
      image: busybox:1.28.3
      command: ["sh", "-c"]
      args:
      - while true; do
          if [[ -e /etc/podinfo/labels ]]; then
            echo -en '\n\n'; cat /etc/podinfo/labels; fi;
          sleep 5;
        done;
      volumeMounts:
        - name: podinfo
          mountPath: /etc/podinfo
          readOnly: false
  volumes:
    - name: podinfo
      projected:
        sources:
        - downwardAPI:
            items:
              - path: "labels"
                fieldRef:
                  fieldPath: metadata.labels
  1. 启动Pod和查看日志;
kubectl apply -f downwardapi-demo-pod.yaml
kubectl logs downwardapi-demo-pod

image.png

Service Account Token

Service Account Token是一种针对Pod的账号,它是Kubernetes进行权限分配的对象。比如Service Account A,可以只被允许对 Kubernetes API 进行 GET 操作,而 Service Account B,则可以有 Kubernetes API 的所有操作权限。Service Account的授权信息和文件,实际上保存在它所绑定的一个特殊的 Secret 对象里的,对于Service Account Token可以理解为一种特殊的Secret对象。

Kubernetes对所有的Pod都提供了一个default Service Account,任何一个运行在 Kubernetes的Pod,都可以直接使用这个默认的 Service Account,而无需显示地声明挂载它。

原理探索

实现方式还是靠Projected Volume机制

  1. 查看该Pod的详细信息,可以看到该Po的默认挂载一个serviceaccount的路径;
kubectl describe pod downwardapi-demo-pod

image.png

  1. 我们进入容器内部查看下serviceaccount具体内容,我们可以看到包括3方面内容,分别是token、ca.crt、namespace;
#进入容器
kubectl exec -it downwardapi-demo-pod -- /bin/sh
#查看具体内容
ls /var/run/secrets/kubernetes.io/serviceaccount

image.png

  1. 接下来我们看下系统中的Service Account对象,可以看到有一个default-token-q4qts的Secret对象,该对象是一个Mountable secrets对象,说明此对象需要被挂载的;

image.png

  1. 接下来我们看下default-token-q4qts包含什么东西,我们可以看到包含了token、ca.crt、namespace三类对象;

image.png

通过Mountable secrets标识、Pod内容对象以及Secrets包含的对象,我们可以证明每个命名空间下面都会有一个名为default默认的Service Account,在Pod启动的时候,Secret对象会自动挂载到Pod指定的目录下,帮助Pod来完成API Server的身份鉴权。

使用
  1. 创建Service Account资源;
#创建Service Account资源
kubectl create serviceaccount sa-demo
#查看Service Account资源
kubectl get sa

image.png

  1. 查看下是否创建Secret;
#查看是否创建Secret
kubectl describe sa sa-demo、
#查看具体的Secret内容
kubectl describe secret sa-demo-token-k4t96

image.png

  1. 创建使用sa-demo的Pod;
apiVersion: v1
kind: Pod
metadata:
  name: sa-demo-pod
spec:  
  serviceAccountName: sa-demo
  containers:
  - image: nginx          
    name: sa-demo-pod               
    resources:                      
      limits:
        cpu: 100m
        memory: 200Mi
      requests:
        cpu: 100m
        memory: 200Mi
  1. 启动该Pod;
#创建pod资源
kubectl create -f sa-demo-pod.yaml
#查看Pod资源
kubectl get pods
#查看pod是否挂载serviceaccount
kubectl describe pod sa-demo-pod

image.pngimage.png

  1. 进入容器内部访问kubernetes服务的API,在Kubernetes集群中,默认为API Server创建了一个名为kubernetes的Service,通过这个Service可以访问API Server,使用curl命令直接访问会得到如下返回信息,表示并没有权限;
#查看服务列表
kubectl get svc
#进入容器内部
kubectl exec -it sa-demo-pod -- /bin/sh
#访问kubernetes服务
curl https://kubernetes

image.pngimage.png

  1. 使用ca.crt和Token做认证,先将ca.crt放到CURL_CA_BUNDLE这个环境变量中,curl命令使用CURL_CA_BUNDLE指定证书;再将Token的内容放到TOKEN中,然后带上TOKEN访问API Server;
#声明变量
export CURL_CA_BUNDLE=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
#携带token访问服务
curl -H "Authorization: Bearer $TOKEN" https://kubernetes

image.png

Node本地存储卷

Kubernetes管理Node本地存储卷有是那种类型:

  1. EmptyDir: 与Pod同生命周期,Node临时存储;
  2. HostPath: Node目录;
  3. Local: 基于持久卷PV管理的Node目录;
EmptyDir

当Pod被调度到某个节点上时,在Node上创建的是一个emptyDir卷,此卷刚开始是一个空目录,并且只要 Pod在该节点上运行,卷就一直存在,与Pod生命周期相同, 当Pod被销毁的时候,Node上的目录也会被销毁。同一个Pod的多个容器都可以挂载到改卷上。

emptyDir可以在以下几种场景下使用:

  1. 临时空间,例如基于磁盘的合并排序;
  2. 设置检查点以从崩溃事件中恢复未执行完毕的长计算;
  3. 保存内容管理器容器从Web服务器容器提供数据时所获取的文件;
使用
  1. 创建一个使用emptyDir volume的Pod;
apiVersion: v1
kind: Pod
metadata:
  name: emptydir-pod
spec:
  containers:
  - image: busybox:1.28.3
    name: emptydir-pod
    command: [ "sleep", "3600" ]
    volumeMounts:
    - mountPath: /data
      name: data-volume
  volumes:
  - name: data-volume
    emptyDir: {}
  1. 创建完成之后我们通过describe命令查看该Pod的详情,我们可以看到上面创建的Pod Volumes 类型是:EmptyDir;
kubectl describe pod emptydir-pod

image.png

  1. 进入容器中查看挂载情况;
kubectl exec -it emptydir-pod /bin/sh

image.png

HostPath

hostPath类型则是映射Node节点文件系统中的文件或者目录到Pod里。在使用hostPath类型的存储卷时,也可以设置type字段,支持的类型有文件、目录、File、Socket、CharDevice和BlockDevice。

hostPath可以在以下几种场景使用:

  1. 容器应用中关键的数据需要持久化到宿主机上;
  2. 需要使用运行一个访问 Docker内部数据Pod, 可以将主机的/var/lib/docker目录挂载到容器内;
  3. 监控系统,例如在容器中运行cAdvisor需要以hostPath方式挂载/sys;
  4. Pod启动需要依赖宿主机某个目录或者文件信息;
使用
  1. 创建一个使用hostPath volume的Pod;
apiVersion: v1
kind: Pod
metadata:
  name: hostpath-pod
spec:
  containers:
  - image: busybox:1.28.3
    name: hostpath-pod
    command: [ "sleep", "3600" ]
    volumeMounts:
    - mountPath: /test-data
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      # directory location on host
      path: /data
      # this field is optional
      type: Directory
  1. 创建完成之后我们通过describe命令查看该Pod的详情,我们可以看到上面创建的Pod Volumes 类型是:HostPath,如果发现有个hostPath type check failed: /data is not a directory的告警,你需要在每个节点创建/data目录;
kubectl describe pod hostpath-pod

image.pngimage.png

  1. 接下来我们进入容器,在容器中创建文件;
#进入容器
kubectl exec -it hostpath-pod /bin/sh
#编辑文件
vi 123.txt
#输出文件
cat 123.txt

image.png

  1. 查看Pod被调度到那个节点;
kubectl get pods -o wide

image.png

  1. 进入demo-slave-2查看/data目录下是否增加文件;

image.png

  1. 销毁hostpath-pod,检查文件是否存在,我们会发现Pod已经被删除了,volume卷中的数据仍然还在;
kubectl delete -f hostpath-pod.yaml

image.png

emptyDir和hostPath都可以实现本地存储卷的功能、但是二者在功能上还是有异同的:

  1. 二者都是node节点的本地存储卷方式;
  2. emptyDir可以选择把数据存到tmpfs类型的本地文件系统中去,hostPath并不支持这一点;
  3. hostPath除了支持挂载目录外,还支持File、Socket、CharDevice和BlockDevice,既支持把已有的文件和目录挂载到容器中,也提供了“如果文件或目录不存在,就创建一个”的功能;
  4. emptyDir是临时存储空间,完全不提供持久化支持;
  5. hostPath的卷数据是持久化在Node节点的文件系统中的,即便pod已经被删除了,volume卷中的数据还会留存在Node节点上;
相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
7月前
|
存储 Kubernetes Linux
解决Linux中/var/lib/docker/磁盘空间过大及k8s存储卷磁盘空间使用率过高的问题
解决Linux中/var/lib/docker/磁盘空间过大及k8s存储卷磁盘空间使用率过高的问题
922 0
|
4月前
|
存储 Kubernetes 容器
Kubernetes 存储选项:持久化卷与存储类
【8月更文第29天】随着容器化的普及,越来越多的应用程序需要持久化数据以保持状态信息。Kubernetes 提供了一套完整的解决方案来管理和配置持久化存储,包括持久卷 (Persistent Volume, PV)、持久卷声明 (Persistent Volume Claim, PVC) 和存储类 (StorageClass)。本文将详细介绍这些概念,并通过实际示例来演示如何在 Kubernetes 中配置存储。
342 1
|
4月前
|
存储 Kubernetes 容器
k8s创建NFS动态存储
k8s创建NFS动态存储
|
5月前
|
存储 Kubernetes 应用服务中间件
k8s使用rbd作为存储
k8s使用rbd作为存储
63 6
|
4月前
|
存储 Kubernetes 数据安全/隐私保护
在K8S中,如果后端nfs存储的ip发生变化如何解决?
在K8S中,如果后端nfs存储的ip发生变化如何解决?
|
4月前
|
存储 缓存 Kubernetes
在K8S中,业务Pod数据如何存储?
在K8S中,业务Pod数据如何存储?
|
4月前
|
存储 JSON Kubernetes
在K8S中,存储敏感信息方式有哪些?
在K8S中,存储敏感信息方式有哪些?
|
4月前
|
存储 Kubernetes 容器
在k8S中,所支持的存储供应模式有哪些?
在k8S中,所支持的存储供应模式有哪些?
|
4月前
|
存储 Kubernetes 调度
在k8S中,共享存储的作用是什么?
在k8S中,共享存储的作用是什么?
|
4月前
|
存储 Kubernetes 测试技术
在k8s中,有哪些存储?
在k8s中,有哪些存储?