3

kubernetes学习笔记八(存储)

 3 years ago
source link: https://www.ishells.cn/archives/kubernetes-study-8-storage
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
kubernetes学习笔记八(存储)

kubernetes学习笔记八(存储)

37 次访问 2020-12-09
一、四种存储方案

configMap:在k8s中起到专一存储配置文件的目的

Secret:一种加密的方案,比如密钥、用户密码信息,base64

volume:为pod提供一种共享存储卷的能力,比如nfs共享、本地磁盘下某个目录的共享等

Persistent Volume ( PV ):持久卷

二、ConfigMap

ConfigMap描述信息:

ConfigMap 功能在 Kubernetes1.2 版本中引入,许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。ConfigMap API 给我们提供了向容器中注入配置信息的机制,ConfigMap 可以被用来保存单个属性,也可以用来保存整个配置文件或者 JSON 二进制大对象

使用场景:

当我们有很多nginx节点时,如果我们需要修改nginx的配置文件的时候,我们可以通过脚本等方案来批量修改nginx节点的配置文件,但是如果我们的nginx节点分属于不同的组( 即不同组需要不同的配置文件 ),这个时候修改不同组的配置文件就比较繁琐了。

nginxregister.jpg

如图,这时候就有了名叫 配置文件注册中心的这样一种解决方案,不同的nginx应用程序会向配置文件注册中心索要配置信息,配置文件注册中心会根据它的主机名、IP等信息向其分配配置文件。当然,不同的应用程序索要到的配置文件是不同的,包括后期需要修改这些配置文件的话,只用修改配置文件注册中心的文件,就会触动更新相应节点中的配置文件。这样就使维护与更新变得更简单一些

nginxconfigMap.jpg

ConfigMap的作用机制就与上面提到的配置文件注册中心几乎一致,当Pod被创建的时候被指定从ConfigMap引入配置文件,当后期ConfigMap中的配置文件被修改之后,Pod中引入的配置文件也会自动更新,pod重新载入配置文件的话,可能需要重启、重载等操作

ConfigMap的创建:

1、使用目录创建

使用目录创建ConfigMap的话,目录下的文件名会作为键值对的key,文件的内容会作为键值对的value

createconfigmapdir.jpg
getconfigmap.PNG
describeconfigmapdir.jpg
# kubectl create configmap game-config --from-file=/root/configMap# --from-file指定,在目录下的所有文件都会被用在 ConfigMap 里面创建一个键值对,键的名字就是文件名,值就是文件的内容

2、使用文件创建

只要指定为一个文件就可以从单个文件中创建 ConfigMap,--from-file这个参数可以使用多次,指定多个文件

# kubectl create configmap game-config-2 --from-file=/root/configMap/game.properties --from-file=/root/configMap/ui.properties
create_cm_file.png
get_cm_yaml.png

3、使用字面值创建

使用文字值创建,利用--from-literal参数传递配置信息,该参数可以使用多次,格式如下:

# kubectl create configmap 名称 --from-literal=键名称=值名称 --from-literal=键名称=值名称 # kubectl get configmaps config名称  -o yaml
createconfigfromliteral.jpg

在Pod中使用ConfigMap

1、使用ConfigMap来代替环境变量

for_env_create_configmap.png
create_configmap_from_yaml.jpg
create_pod_use_configmap.png
look_pod_env.jpg

2、使用Configmap作为命令行参数

use_configmap_for_command.jpg

3、通过数据卷插件使用ConfigMap

意思就是将configmap挂载到容器中的某一个位置下进行使用,即将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容

config_mount_volume_pod.jpg
# 检查哪些api支持当前的kubernetes对象# kubectl api-resources | grep deployment

ConfigMap的热更新

热更新意为,将ConfigMap挂载到Pod内部后,通过命令kubectl edit configmap cm名称修改configmap的话,Pod内部挂载的Configmap也会被更新,但是默认情况下仅会更新Pod内挂载的ConfigMap值,如果该ConfigMap被nginx等应用使用,其实并不会触发nginx的重载等动作

1、创建ConfigMap、Deployment,并将ConfigMap挂载到Pod中

create_configmappod.png

2、exec进入Pod查看挂载的ConfigMap值

get_pod_configmap_data.png

3、edit修改ConfigMap的值

kubectl_edit_configmap.png

edit_configmap_data.png

5、等待大概10s左右时间,查看Pod中的ConfigMap值是否发生了改变

get_changed_configmap.png

更新 ConfigMap 目前并不会触发相关 Pod 的滚动更新,可以通过修改 pod annotations 的方式强制触发滚动更新

# kubectl patch deployment my-nginx --patch'{"spec": {"template": {"metadata": {"annotations":{"version/config": "20201209" }}}}}'# 这个例子里我们在.spec.template.metadata.annotations中添加version/config# 每次通过修改version/config来触发滚动更新

更新 ConfigMap 后:

使用该 ConfigMap 挂载的 Env 不会同步更新

使用该 ConfigMap 挂载的 Volume 中的数据需要一段时间(实测大概10秒)才能同步更新

三、Secret

Secret在yaml资源清单中是加密的,但是如果以卷的形式挂载到pod中。在pod中是自动解密的

1、Secret

Secret 解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者 Pod Spec中。Secret 可以以 Volume 或者环境变量的方式使用

Secret有三种类型:

**Service Account:**用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 Pod 的/run/secrets/kubernetes.io/serviceaccount目录中

**Opaque:**base64编码格式的Secret,用来存储密码、密钥等(因为base64加密解密都是固定的,其实他认识可以根据加密后的敏感数据得到原数据的)

**kubernetes.io/dockerconfigjson:**用来存储私有 docker registry 的认证信息

Service Account

Service Account 用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 Pod的/run/secrets/kubernetes.io/serviceaccount目录中

describe_serviceaccount_secret.png

2、Opaque Secret

Opaque 类型的数据是一个 map 类型,要求 value 是 base64 编码格式( base64对同一字符加密解密得到的结果都是固定的,这就使解密很容易 )

① 创建一个base64编码的账户密码

# echo -n "admin" | base64YWRtaW4=# echo -n "1f2d1e2e67df" | base64MWYyZDFlMmU2N2Rm
base64.png

使用方式:

② 将Secret挂载到Volume中

apply_opaque_secret.png

查看挂载到Pod中的Secret

exec_cat_opaque_secret.png

③ 将 Secret 导出到Pod环境变量中

这个测试中我遇到了一个奇怪的问题,将Opaque Secret作为Env挂载到Pod中时,Pod也无报错,也无异常,但是就是Opaque Secret没有生效成为Pod的Env。然后经我多方测试之后,最终确定了containers.env.name 用了横杠"-"就导致该Secret在Pod中未生效

wrong_envname.png

当我修改了containers.env.name 字段无横杠"-"时,就成功得到了该Env值,就很迷

describe_pod_get_info.png
no_opaque_env.png
edit_env_name_success.png

3、kubernetes.io/dockerconfigjson

此种类型的Secret主要是为了应用在镜像仓库认证时使用,用户从镜像仓库拉取镜像需要进行登陆验证,否则无法拉取、推送镜像

如果镜像仓库的镜像是私有的,那么你在拉取镜像时如果不加以认证就会无法拉取该镜像,所以docker-registry的方式就是:先创建一个docker-registry 类型的Secret,然后创建Pod、Deployment的时候通过imagePullSecrets字段来引用创建的docker-registry 类型的Secret,便可以与镜像仓库进行认证并下载镜像

① 使用kubectl创建docker registry认证的secret

# kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAI docker-registry 是Secret的类型,名称是myregistrykey

② 在创建Pod的时候,通过imagePullSecrets来引用刚创建的myregistrykey

apiVersion: v1kind: Podmetadata: name: foospec:containers:    - name: foo      image: nginx  imagePullSecrets:    - name: myregistrykey

四、Volume

Volume

容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)重新启动。其次,在Pod中同时运行多个容器时,这些容器之间通常需要共享文件。Kubernetes 中的Volume抽象就很好的解决了这些问题

docker与k8s的模式还不太一样,在docker中,如果容器意外崩溃且重启策略为Always的话,容器重启时并不会清除原有的数据,而在k8s中,如果Pod意外崩溃,那么Pod重启时就会以最干净的状态(即镜像最初的状态)重新启动。

背景

Kubernetes 中的卷有明确的寿命 —— 与封装它的 Pod 相同。所f以,卷的生命比 Pod 中的所有容器都长,当这个容器重启时数据仍然得以保存。当然,当 Pod 不再存在时,卷也将不复存在。也许更重要的是,Kubernetes支持多种类型的卷,Pod 可以同时使用任意数量的卷

那为什么以卷volume的形式挂载到Pod中之后,容器的崩溃不会造成数据的丢失呢?

pod_volume.gif

在上图中,volume卷挂载到了Pod的pause容器上,容器1、2共享pause容器的存储卷,当容器1、2意外崩溃的时候,实际环境的 Deployment 等控制器会重建新的容器1、2,但是挂载卷volume是始终没有发生变化,变化被重启的只是容器本身,这样就避免了数据的丢失。

Kubernetes 支持以下类型的卷:

awsElasticBlockStore、azureDisk、azureFile、cephfs、csi、downwardAPI、emptyDir、

fc、flocker、gcePersistentDisk、gitRepo、glusterfs、hostPath、iscsi、local、nfs、

persistentVolumeClaim、projected、portworxVolume、quobyte、rbd、scaleIO、secret

storageos、vsphereVolume

官方示例用法

1、EmptyDir

当 Pod 被分配给节点时,首先创建emptyDir卷,并且只要该 Pod 在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。Pod 中的容器可以读取和写入emptyDir卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除 Pod 时,emptyDir中的数据将被永久删除

EmptyDir卷的原理与上面的 gif 类似,相当于将node节点的EmptyDir空卷挂载到了Pod的pause容器,当容器意外崩溃时重建的只是容器本身,EmptyDir还是依然挂载在Pause容器上的并没有改变

EmptyDir的用法

暂存空间,例如用于基于磁盘的合并排序

用作长时间计算崩溃恢复时的检查点

Web服务器容器提供数据时,保存内容管理器容器提取的文件

EmptyDir测试:

可以将该EmptyDir卷挂载到Pod的多个容器的不同路径下,使多个容器共享该EmptyDir卷

在使用yaml创建Pod多容器的时候,我忘记了一件事情:Pod内一个容器为nginx,一个镜像为centos,我在创建Pod的时候一直在纳闷为什么centos那个容器为什么没有错误日志却一直不是Ready,测试了好大一会才想起来,容器在创建成功之后如果没有后台进程存在的话,那么它就会直接退出!

所以如果我们想在一个Pod内创建多个容器挂载emptyDir卷,那么就要给无后台进程的就要给他加一个sleep避免其自动退出

apiVersion: v1kind: Podmetadata:  name: emptydirpodspec:  containers:  - image: nginx    name: container1    volumeMounts:    - mountPath: /emptydir1      name: emptydir-volume  - image: centos    name: container2    command: ['/bin/sh','-c','sleep 3600s']    volumeMounts:    - mountPath: /emptydir2      name: emptydir-volume  volumes:  - name: emptydir-volume    emptyDir: {}
emptydir_volume.gif

2、hostPath

hostPath卷能将主机节点的文件系统中的文件或目录挂载到集群的Pod中

hostpath的一些用法如下:

运行一个需要访问Docker内部的容器时,可使用hostPath 挂载 宿主机的/var/lib/docker 路径。

允许指定所需要的`hostPath在Pod运行前是否应该存在,是否应该创建等

除了必需的 path 属性之外,用户可以选择性地为 hostPath 卷指定 type

值行为 空字符串(默认)用于向后兼容,这意味着在挂载 hostPath 卷之前不会执行任何检查DirectoryOrCreate如果在给定的路径上没有任何东西存在,那么将根据需要在那里创建一个空目录,权限设置为 0755,与 Kubelet 具有相同的组和所有权Directory给定的路径下必须存在目录FileOrCreate如果在给定的路径上没有任何东西存在,那么会根据需要创建一个空文件,权限设置为 0644,与 Kubelet 具有相同的组和所有权File给定的路径下必须存在文件Socket给定的路径下必须存在 UNIX 套接字CharDevice给定的路径下必须存在字符设备BlockDevice给定的路径下必须存在块设备

使用hostPath卷类型的时候请注意:

因为hostPath是将宿主机的特定文件或目录挂载到Pod中,比如将宿主机的nfs目录挂载到Pod的test目录下,结果有一天Pod被调度到了另一个node节点,然而这个节点(即宿主机)上并没有nfs目录,这种情况下就会发生问题。所以如果想使用hostpath这种方案的话,就要确定每个node节点上都有一样的挂载目录等设置。

当 Kubernetes 按照计划添加资源感知调度时,将无法考虑hostPath使用的资源。比如hostPath设置将宿主机/data目录挂载到容器的/test目录下,不同node节点下的文件数据可能不一样,这就会导致hostPath会使用到不同的资源

在底层主机上创建的文件或目录只能由 root 写入。所以需要在特权容器中以 root 身份运行进程,或修改主机上的文件权限以便写入hostPath卷

hostPath测试:

apiVersion: v1kind: Podmetadata:  name: hostpath-test-podspec:  containers:  - image: nginx    name: container1    volumeMounts:    - mountPath: /hostpath1      name: test-hostpath-volume  volumes:  - name: test-hostpath-volume    hostPath:      path: /data      type: Directory
hostpath_volume.gif

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK