K8S数据管理
1 数据管理
1.1 数据持久化
1.1.1 存储方案
学习目标
这一节,我们从 存储原理、方案解读、小结 三个方面来学习。
存储原理
容器存储
Docker的文件系统 与Docker容器具有相同的生命周期,但是Docker容器肯定会遇到同时运行到多节点场景中,这个时候,会因为节点崩溃、服务崩溃、网络原因,导致容器异常退出,所以一旦我们将数据存储到容器内部,肯定会导致数据丢失。
- Docker镜像是只读的文件,Docker容器可读可写,但是不能够数据持久化。
所以为了避免这种数据异常丢失的情况,我们一般会将 容器的数据(程序状态数据、应用存储数据等),存储在容器的文件系统之外。
- 通过引入外部的存储空间来实现 数据的可持久化效果。
存储方式
host存储方式
- 通过数据卷 或者 数据卷容器,将当前宿主机上面的文件系统目录与容器里面的工作目录进行一一的关联。
- 即使我们对本地是磁盘做 raid等冗余功能,但是这种等级的安全很鸡肋。
网络存储方式
- 通过网络的方式,将外部的存储空间挂载到当前宿主机,然后借助于host机制实现容器数据的可持久化。
k8s支持的存储类型
本地数据卷 emptyDir、hostPath、local等
云存储数据卷 gcePersistentDisk、awsElasticBlockStore等
网络存储卷 NFS、gitRepo、NAS、SAN等
分布式存储卷 GlusterFS、CephFS、rdb(块设备)、iscsi等
信息数据卷 flocker、secret等
资源对象属性
spec:
volumes:
- name <string> # 存储卷名称标识,仅可使用DNS标签格式的字符,在当前Pod中必须唯一
VOL_TYPE <Object> # 存储卷插件及具体的目标存储供给方的相关配置
containers:
- name: …
image: …
volumeMounts:
- name <string> # 要挂载的存储卷的名称,必须匹配存储卷列表中某项的定义
mountPath <string> # 容器文件系统上的挂载点路径
readOnly <boolean> # 是否挂载为只读模式,默认为“否”
subPath <string> # 挂载存储卷上的一个子目录至指定的挂载点
subPathExpr <string> # 挂载由指定的模式匹配到的存储卷的文件或目录至挂载点
方案解读
场景需求
虽然这种借助于k8s存储插件的方式,为pod应用引入各种存储机制,但是这种方案有天然的劣势:
1 要保证所有的pod节点支持后端的指定类型的存储服务。
2 所有的后端指定服务的配置都要在pod上自定义
3 这些卷插件将pod定制的配置属性传递给kubelet,然后实现对应的效果。
-- 从字面上来理解,如果一个开发者要开发一个pod对象,必须首先是一个存储专家
-- 而这是不可能的。
所以,使用k8s的门槛高多了。而k8s为了避免这种为用户带来不好影响的现象,引入了两个非常重要的存储资源对象 -- PV 和 PVC
kubernetes根据资源对象创建的灵活的度实现了两种数据持久化解决方案:
手工方式: PVC + PV
自动方式: VCT + SC
1 由专业的存储管理员来管理所有的存储后端:
- 在专用的存储设备上,创建各种类型级别的PV(Persistent Volume)
- 或者通过存储模板文件SC(storageclasses)来自动创建大量不同类型的PV对象。
2 由开发人员定制需要的PVC(Persistent Volume Claim),然后关联到pod上
3 Pod通过PVC到PV上请求一块独立大小的网络存储空间,然后直接使用
这样的话,通过这种分层的管理机制,让开发人员和存储人员专人做专事,大大的减轻工作的负载。
小结
1.1.2 EmptyDir实践
学习目标
这一节,我们从 原理解读、简单实践、小结 三个方面来学习。
基础知识
简介
一个emptyDir volume在pod被调度到某个Node时候自动创建的,无需指定宿主机上对应的目录。特点如下:
1、跟随Pod初始化而来,开始是空数据卷
2、Pod移除,emptyDir中数据随之永久消除
3、emptyDir一般做本地临时存储空间使用
4、emptyDir数据卷介质种类跟当前主机的磁盘一样。
属性解析
kubectl explain pod.spec.volumes.emptyDir
medium 指定媒介类型,主要有 disk Memory(默认) 两种
sizeLimit 现在资源使用情况
kubectl explain pod.spec.containers.volumeMounts
mountPath 挂载到容器中的路径
name 指定挂载的volumes名称
readOnly 是否只读挂载
subPath 是否挂载子路径
配置样式
# volume配置样式
volumes:
- name: volume_name
emptyDir: {}
# volume使用样式
containers:
- volumeMounts:
- name: volume_name
mountPath: /path/to/container/
注意:
关于volume和容器的关系,每个容器都可以单独挂载多个volume,每种volume都可以被多个容器挂载
简单实践
临时存储演示
准备清单目录
[root@kubernetes-master1 ~]# mkdir /data/kubernetes/storage -p ;cd /data/kubernetes/storage
[root@kubernetes-master1 /data/kubernetes/storage]#
准备资源清单文件
[root@kubernetes-master1 /data/kubernetes/storage]# cat 01_kubernetes-storage_emptydir.yml
apiVersion: v1
kind: Pod
metadata:
name: superopsmsb-emptydir
spec:
containers:
- name: nginx-web
image: kubernetes-register.superopsmsb.com/superopsmsb/nginx_web:v0.1
volumeMounts:
- name: nginx-index
mountPath: /usr/share/nginx/html
- name: change-index
image: kubernetes-register.superopsmsb.com/superopsmsb/busybox:1.28
# 每过2秒更改一下文件内容
command: ['sh', '-c', 'for i in $(seq 100); do echo index-$i > /testdir/index.html;sleep 2;done']
volumeMounts:
- name: nginx-index
mountPath: /testdir
volumes:
- name: nginx-index
emptyDir: {}
执行资源清单文件
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl apply -f 01_kubernetes-storage_emptydir.yml
pod/superopsmsb-emptydir created
查看效果
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl get pod -o wide
NAME READY ... IP NODE ...
superopsmsb-emptydir 2/2 ... 10.244.1.5 kubernetes-node1 ...
[root@kubernetes-master1 /data/kubernetes/storage]# curl 10.244.1.5
index-38
[root@kubernetes-master1 /data/kubernetes/storage]# curl 10.244.1.5
index-39
查看描述信息
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl describe pod superopsmsb-emptydir
Name: superopsmsb-emptydir
...
Containers:
nginx-web:
...
Mounts:
/usr/share/nginx/html from nginx-index (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-gbwh8 (ro)
change-index:
...
Mounts:
/testdir from nginx-index (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-gbwh8 (ro)
...
Volumes:
nginx-index:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
...
文件在哪里?
关于临时存储的文件存放的位置在指定节点的/var/lib/kubelet目录下
查找文件
[root@kubernetes-node1 ~]# find /var/lib/kubelet/ -name "index.html"
/var/lib/kubelet/pods/9b086c71-ad40-4c59-8525-17a97ae0a95b/volumes/kubernetes.io~empty-dir/nginx-index/index.html
查看文件
[root@kubernetes-node1 ~]# cat /var/lib/kubelet/pods/9b086c71-ad40-4c59-8525-17a97ae0a95b/volumes/kubernetes.io~empty-dir/nginx-index/index.html
index-46
结果显示:
文件是随着pod而存在的,一旦pod删除了,文件也丢失了。
小结
1.1.3 hostPath实践
学习目标
这一节,我们从 原理解读、简单实践、小结 三个方面来学习。
基础知识
场景需求
hostPath将宿主机上的目录挂载到Pod中作为数据的存储目录,一般用在如下场景:
1、容器应用程序中某些文件需要永久保存
2、某些容器应用需要用到容器的内部数据结构,可将宿主机的/var/lib/docker挂载到Pod中
3、Pod删除,宿主机文件不受影响
hostPath使用注意事项:
1、不同宿主机的文件内容不一定完全相同,所以Pod迁移前后的访问效果不一样
2、宿主机的目录不属于资源对象的资源,所以我们对资源设置的资源配额限制对hostPath目录无效
配置属性
配置格式:
volumes:
- name: volume_name
hostPath:
path: /path/to/host
配置属性解读
kubectl explain pod.spec.volumes.hostPath
path 指定宿主机的路径
type 指定路径的类型,一共有7种,默认的类型是没有指定的话则自己创建
DirectoryOrCreate 宿主机上不存在,创建此0755权限的空目录,属主属组均为kubelet
Directory 必须存在挂载已存在的目录,最常用
FileOrCreate 宿主机上不存在挂载文件,就创建0644权限的空文件,属主和属组同为kubelet
File 必须存在文件
Socket 事先必须存在的Socket文件路径
CharDevice 事先必须存在的字符设备文件路径
BlockDevice 事先必须存在的块设备文件路径
参考资料:https://kubernetes.io/docs/concepts/storage/volumes#hostpath
简单实践
准备工作
获取互联网镜像
[root@kubernetes-master1 ~]# docker pull redis
[root@kubernetes-master1 ~]# docker history redis | grep REDIS_VER
<missing> 3 days ago /bin/sh -c #(nop) ENV REDIS_VERSION=7.0.4 0B
[root@kubernetes-master1 ~]# docker tag redis:latest kubernetes-register.superopsmsb.com/superopsmsb/redis:7.0.4
[root@kubernetes-master1 ~]# docker push kubernetes-register.superopsmsb.com/superopsmsb/redis:7.0.4
[root@kubernetes-master1 ~]# docker rmi redis:latest
创建所有主机的备份目录
[root@kubernetes-master1 ~]# for i in 15 16 17;do ssh root@10.0.0.$i "mkdir /data/backup/redis -p"; done
定制redis的数据备份功能
准备资源清单文件
[root@kubernetes-master1 /data/kubernetes/storage]# cat 02_kubernetes-storage_hostpath.yml
apiVersion: v1
kind: Pod
metadata:
name: superopsmsb-hostpath
spec:
volumes:
- name: redis-backup
hostPath:
path: /data/backup/redis
containers:
- name: hostpath-redis
image: kubernetes-register.superopsmsb.com/superopsmsb/redis:7.0.4
volumeMounts:
- name: redis-backup
mountPath: /data
注意:
redis的镜像将数据保存到了容器的/data 目录下。
创建资源对象
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl apply -f 02_kubernetes-storage_hostpath.yml
pod/superopsmsb-hostpath created
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl get pod -o wide
NAME READY ... IP NODE ...
superopsmsb-hostpath 1/1 ... 10.244.3.3 kubernetes-node3 ...
查看描述信息
查看描述信息
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl describe pod superopsmsb-emptydir
Name: superopsmsb-emptydir
...
Containers:
hostpath-redis:
...
Mounts:
/data from redis-backup (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-8x257 (ro)
...
Volumes:
redis-backup:
Type: HostPath (bare host directory volume)
Path: /data/backup/redis
...
进入容器确认效果
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl exec -it superopsmsb-hostpath -- /bin/bash
root@superopsmsb-hostpath:/data# redis-cli
127.0.0.1:6379> set volume hostpath
OK
127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379> exit
root@superopsmsb-hostpath:/data# exit
exit
到指定的node3上看效果
[root@kubernetes-master1 /data/kubernetes/storage]# ssh root@10.0.0.17 ls /data/backup/redis
dump.rdb
小结
1.1.4 NFS实践
学习目标
这一节,我们从 原理解读、简单实践、小结 三个方面来学习。
基础知识
简介
根据我们对hostpath的了解,我们发现,虽然hostpath可以根据pod的配置自动创建关联的宿主机目录,但是宿主机目录下面没有我们想要的数据文件,所以,在集群场景中,我们想要基于hostpath方式实现更强大的配置效果,就需要把所有的数据文件进行同步,而这不是我们想要的。
基于此,我们需要一种可以实现网络存储的方式,NFS就是一种很好的网络存储解决方案。
使用NFS网络文件系统提供的共享目录存储数据时,需要在系统中部署一个NFS环境,通过volume的配置,实现pod内的容器间共享nfs目录。
属性解析
配置属性:
kubectl explain pod.spec.volumes.nfs
path 指定nfs服务器暴露的共享地址
readOnly 是否只能读,默认false
server 指定nfs服务器的地址
配置格式:
volumes:
- name: 卷名称
nfs:
server: nfs_server_address
path: "共享目录"
注意事项:
要求k8s所有集群都必须支持nfs命令,即所有结点都必须执行 yum install nfs-utils -y
NFS环境准备
我们将10.0.0.18作为NFS服务环境,这里加载一块磁盘并进行格式化
[root@kubernetes-ha1 ~]# fdisk -l | grep 'sdb'
磁盘 /dev/sdb:21.5 GB, 21474836480 字节,41943040 个扇区
磁盘格式化
[root@kubernetes-ha1 ~]# mkfs.ext4 /dev/sdb
mke2fs 1.42.9 (28-Dec-2013)
[root@kubernetes-ha1 ~]# blkid | grep sdb
/dev/sdb: UUID="b01ca48c-f8a6-4817-a9b4-7bb7a53c03c2" TYPE="ext4"
创建数据目录
[root@kubernetes-ha1 ~]# mkdir /superopsmsb/nfs-data -p
部署nfs服务
[root@kubernetes-ha1 ~]# yum install -y rpcbind nfs-utils
配置共享目录
echo '/superopsmsb/nfs-data *(rw,no_root_squash,sync)' > /etc/exports
注意:
*:表示允许所有连接,该值可以是一个网段|IP|域名的形式
rw 表示读写共享权限
no_root_squash 表示root登录nfs资源的时候,虽然是以nobody身份,单不压缩其权限
sync 所有操作数据会同时写入硬盘和内存
配置生效
[root@kubernetes-ha1 ~]# exportfs -r
重启服务
[root@kubernetes-ha1 ~]# systemctl start rpcbind.service
[root@kubernetes-ha1 ~]# systemctl start nfs.service
[root@kubernetes-ha1 ~]# systemctl enable rpcbind.service nfs.service
确认效果
[root@kubernetes-ha1 ~]# showmount -e localhost
Export list for localhost:
/superopsmsb/nfs-data *
所有的k8s节点部署nfs命令
[root@kubernetes-master1 ~]# for i in {12..17};do ssh root@10.0.0.$i "yum install nfs-utils -y";done
确认效果
[root@kubernetes-master1 ~]# showmount -e 10.0.0.18
Export list for 10.0.0.18:
/superopsmsb/nfs-data *
挂载测试
[root@kubernetes-master1 ~]# mount -t nfs 10.0.0.18:/superopsmsb/nfs-data /tmp
[root@kubernetes-master1 ~]# mount | grep nfs
10.0.0.18:/superopsmsb/nfs-data on /tmp type nfs4 (rw,relatime,vers=4.1,rsize=524288,wsize=524288,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.0.0.12,local_lock=none,addr=10.0.0.18)
[root@kubernetes-master1 ~]# umount /tmp
简单实践
定制数据功能
准备资源清单文件
[root@kubernetes-master1 /data/kubernetes/storage]# cat 03_kubernetes-storage_nfs.yml
apiVersion: v1
kind: Pod
metadata:
name: superopsmsb-nfs
spec:
volumes:
- name: redis-backup
nfs:
server: 10.0.0.18
path: /superopsmsb/nfs-data
containers:
- name: nfs-redis
image: kubernetes-register.superopsmsb.com/superopsmsb/redis:7.0.4
volumeMounts:
- name: redis-backup
mountPath: /data
创建资源对象
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl apply -f 03_kubernetes-storage_nfs.yml
pod/superopsmsb-nfs created
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl get pod -o wide
NAME READY ... IP NODE ...
superopsmsb-nfs 1/1 ... 10.244.3.4 kubernetes-node3 ...
查看描述信息
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl describe pod superopsmsb-nfs
Name: superopsmsb-emptydir
...
Containers:
nfs-redis:
...
Mounts:
/data from redis-backup (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-pfz9h (ro)
...
Volumes:
redis-backup:
Type: NFS (an NFS mount that lasts the lifetime of a pod)
Server: 10.0.0.18
Path: /superopsmsb/nfs-data
...
进入容器确认效果
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl exec -it superopsmsb-nfs -- /bin/bash
root@superopsmsb-nfs:/data# redis-cli
127.0.0.1:6379> set volumes nfs
OK
127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379> exit
root@superopsmsb-nfs:/data# exit
exit
到nfs上看效果
[root@kubernetes-master1 /data/kubernetes/storage]# ssh root@10.0.0.18 ls /superopsmsb/nfs-data
dump.rdb
小结
1.2 持久化进阶
1.2.1 数据对象
学习目标
这一节,我们从 存储机制、对象解读、小结 三个方面来学习。
存储机制
资源对象
存储方案
对象解读
之前我们提到的Volume可以提供多种类型的资源存储(可持久或不持久),但是它定义在Pod上的,是属于"资源对象"的一部分。工作中的存储资源一般都是独立的,这就是资源对象Persistent Volume(PV),是由管理员设置的存储,它是群集的一部分,PV 是 Volume 之类的卷插件,但具有独立于使用 PV 的 Pod 的生命周期。。
Persistent Volume 跟Volume类似,区别就是:
PV就是Kubernetes集群中的网络存储,不属于Node、Pod等资源,但可以被他们访问。
PV是独立的网络存储资源对象,有自己的生命周期,支持很多种volume类型
Persistent Volume Claim(PVC) 是一个网络存储服务的请求。PVC和PV与Pod之间的关系。
Pod只能通过PVC到PV上请求一块独立大小的网络存储空间,而PVC 可以动态的根据用户请求去申请PV资源,不仅仅涉及到存储空间,还有对应资源的访问模式。
StorageClass(SC)
管理员可以根据 Kubernetes 的 StorageClass 对象来动态的定义各种类型的资源。
存储流程
1 用户创建了一个包含 PVC 的 Pod,该 PVC 要求使用动态存储卷;
2 Scheduler 根据 Pod 配置、节点状态、PV 配置等信息,把 Pod 调度到一个合适的 Worker 节点上;
3 PV 控制器 watch 到该 Pod 使用的 PVC 处于 Pending 状态,于是调用 Volume Plugin(in-tree)创建存储卷,并创建 PV 对象(out-of-tree 由 External Provisioner 来处理);
4 AD 控制器发现 Pod 和 PVC 处于待挂接状态,于是调用 Volume Plugin 挂接存储设备到目标 Worker 节点上
5 在 Worker 节点上,Kubelet 中的 Volume Manager 等待存储设备挂接完成,并通过 Volume Plugin 将设备挂载到全局目录: **/var/lib/kubelet/pods/[pod uid]/volumes/kubernetes.io~iscsi/[PVname]**(以 iscsi 为例);
6 Kubelet 通过 Docker 启动 Pod 的 Containers,用 bind mount 方式将已挂载到本地全局目录的卷映射到容器中。
对象解读
资源关系
用户需要存储资源的时候:
0 提取准备好对应的PV资源
1 用户根据资源需求创建PVC,由PVC自动匹配(权限、容量)合适的PV对象
2 在pod内部通过PVC将pv绑定到当前的空间,进行使用
3 如果用户不使用存储资源的话,解绑pvc和pod即可。
注意
原则上来说,pod、pvc、pv 必须在同一个命名空间
pod生命周期
状态管理
Availabled 空闲状态,表示pv没有被其他对象使用
Bound 绑定状态,表示pv已经被其他对象使用
Released 未回收状态,表示pvc已经被删除了,但是资源没有被回收
Faild 资源回收失败
访问权限
AccessModes 是用来对 PV 进行访问模式的设置,用于描述用户应用对存储资源的访问权限,访问权限包括
ReadWriteOnce(RWO)单节点读写
ReadOnlyMany(ROX)多节点只读
ReadWriteMany(RWX)多节点读写
ReadWriteOncePod(RWOP)单pod读写
小结
1.2.2 PV&PVC实践
学习目标
这一节,我们从 配置解析、简单实践、小结 三个方面来学习。
配置解析
简介
PV 作为存储资源,主要包括存储能力、访问模式、存储类型、回收策略等关键信息
kubectl explain pv.spec
capacity 定义pv使用多少资源,仅限于空间的设定
accessModes 访问模式
存储类型 每种存储类型的样式的属性名称都是专有的。
persistentVolumeReclaimPolicy 资源回收策略,主要三种Retain、Delete、Recycle
pvc是属于名称空间级别的资源对象,也就是说只有特定的资源才能使用
kubectl explain pods.spec.volumes.persistentVolumeClaim
claimName 定义pvc的名称
readOnly 设定pvc是否只读
kubectl explain pvc.spec
accessModes 访问模式 *
resources 资源限制 *
selector 标签选择器
storageClassName 动态存储名称
volumeMode 后端存储卷的模式
volumeName 指定卷(pv)的名称
注意:
只有 accessModes 和 resources 都匹配成功后,PVC 才会与 PV 绑定在一起。
简单实践
PV&PVC实践
定制资源清单
[root@kubernetes-master1 /data/kubernetes/storage]# vim 04_kubernetes-storage_pv_pvc.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: superopsmsb-pv
spec:
capacity:
storage: 3Gi
accessModes:
- ReadWriteOnce
nfs:
path: /superopsmsb/nfs-data
server: 10.0.0.18
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: superopsmsb-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
创建资源对象
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl apply -f 04_kubernetes-storage_pv_pvc.yml
persistentvolume/superopsmsb-pv created
persistentvolumeclaim/superopsmsb-pvc created
检查效果
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
superopsmsb-pv 3Gi RWO Retain Bound default/superopsmsb-pvc 36s
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
superopsmsb-pvc Bound superopsmsb-pv 3Gi RWO 39s
结果显示:
PVC 和 PV 已经绑定到一起了
pod使用PVC
定制资源清单
[root@kubernetes-master1 /data/kubernetes/storage]# vim 05_kubernetes-storage-pod.yml
apiVersion: v1
kind: Pod
metadata:
name: superopsmsb-nginx
spec:
volumes:
- name: nginx-volume
persistentVolumeClaim:
claimName: superopsmsb-pvc
containers:
- name: nginx-web
image: kubernetes-register.superopsmsb.com/superopsmsb/nginx_web:v0.1
volumeMounts:
- name: nginx-volume
mountPath: "/usr/share/nginx/html"
属性解析:
spec.volumes 是针对pod资源申请的存储资源来说的,我们这里使用的主要是pvc的方式。
spec.containers.volumeMounts 是针对pod资源对申请到的存储资源的具体使用信息。
这里将本地的nfs目录挂载到
创建资源对象
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl apply -f 05_kubernetes-storage-pod.yml
pod/superopsmsb-nginx created
查看Pod对象信息
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl describe pod superopsmsb-nginx
Name: superopsmsb-nginx
...
Containers:
nginx-pv:
...
Mounts:
/usr/share/nginx/html from nginx-volume (rw)
...
Volumes:
nginx-volume:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: superopsmsb-pvc
...
查看pod地址
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl get pod -o wide
NAME READY ... IP NODE ...
superopsmsb-nginx 1/1 ... 10.244.3.5 kubernetes-node3 ...
浏览器访问效果
[root@kubernetes-master1 /data/kubernetes/storage]# curl 10.244.3.5
Hello Nginx, superopsmsb-nginx-1.23.0
查看nfs地址效果
[root@kubernetes-ha1 ~]# cat /superopsmsb/nfs-data/index.html
Hello Nginx, superopsmsb-nginx-1.23.0
结果显示:
默认将nginx的首页存放到了nfs中
修改nfs的首页内容
[root@kubernetes-ha1 ~]# echo 'Hello NFS Nginx Website' > /superopsmsb/nfs-data/index.html
浏览器访问效果
[root@kubernetes-master1 /data/kubernetes/storage]# curl 10.244.3.5
Hello NFS Nginx Website
小结
1.2.3 SC解析
学习目标
这一节,我们从 原理解读、环境实践、小结 三个方面来学习。
原理解读
简介
Kubernetes 提供了一种StorageClass的资源对象:在StorageClass的环境基础上,它可以让我们用户将存储资源定义为某种类型的资源,比如存储质量、快速存储、慢速存储等,然后自由的去申请合适的存储资源了。
StorageClass根据自由申请后端存储的类型,有很多不同的实现方式,在我们的试验环境中,我们这里用nfs-client-provisioner的方式来演示StorageClass。
SC原理解读
实践步骤
1 部署 SC的提供者环境
2 设置 SC的存储属性
3 定制 Pod资源对象属性(PVC采用SC机制)
4 综合测试
环境现状
自从kubernetes 1.20版本禁用了 selfLink,所以默认情况下,我们在创建SC提供者环境的时候,会发生报错,只能首先修改kubernetes的启动属性。
参考资料:
https://stackoverflow.com/questions/65376314/kubernetes-nfs-provider-selflink-was-empty
https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner/issues/25
编辑/etc/kubernetes/manifests/kube-apiserver.yaml
...
spec:
containers:
- command:
- kube-apiserver
- --feature-gates=RemoveSelfLink=false # 添加这条配置
由于是静态文件,所以该pod会自动更改属性,查看效果
[root@kubernetes-master1 ~]# kubectl get pod -n kube-system -l component=kube-apiserver
NAME READY STATUS RESTARTS AGE
kube-apiserver-kubernetes-master1 1/1 Running 0 79s
kube-apiserver-kubernetes-master2 1/1 Running 0 41s
kube-apiserver-kubernetes-master3 1/1 Running 0 40s
环境实践
准备资源清单文件
准备专属目录
[root@kubernetes-master1 /data/kubernetes/storage]# mkdir sc-provider
[root@kubernetes-master1 /data/kubernetes/storage]# cd sc-provider/
[root@kubernetes-master1 /data/kubernetes/storage/sc-provider]#
准备镜像
docker pull registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner
docker tag registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner kubernetes-register.superopsmsb.com/google_containers/nfs-client-provisioner:latest
docker push kubernetes-register.superopsmsb.com/google_containers/nfs-client-provisioner:latest
docker rmi registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner
准备NFS的控制器
[root@kubernetes-master1 /data/kubernetes/storage/sc-provider]# cat 01_kubernetes_sc_provisioner.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
# 命名空间要与定制的rbac的一致
namespace: superopsmsb
spec:
replicas: 1
selector:
matchLabels:
app: nfs-client-provisioner
strategy:
type: Recreate
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccount: nfs-provisioner
containers:
- name: nfs-client-provisioner
image: kubernetes-register.superopsmsb.com/google_containers/nfs-client-provisioner:latest
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
# 该变量的值,必须与nfs的storageclass的provisioner的值一致
value: "nfsprovisioner"
- name: NFS_SERVER
# 设置NFS服务器的ip地址
value: "10.0.0.18"
- name: NFS_PATH
# 设置NFS服务器分享的目录
value: "/superopsmsb/nfs-data"
volumes:
- name: nfs-client-root
nfs:
# 直接使用nfs来挂载该目录,方便storageclass基于该pod对pv和pvc进行自动处理
server: "10.0.0.18"
path: "/superopsmsb/nfs-data"
准备NFS操作k8s资源的权限
[root@kubernetes-master1 /data/kubernetes/storage/sc-provider]# cat 02_kubernetes_sc_rbac.yaml
apiVersion: v1
kind: Namespace
metadata:
name: nfsstorageclass
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-provisioner
namespace: superopsmsb
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: nfs-provisioner
namespace: superopsmsb
rules:
- 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: ["watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["services", "endpoints"]
verbs: ["get","create","patch","list", "watch","update"]
- apiGroups: ["extensions"]
resources: ["podsecuritypolicies"]
resourceNames: ["nfs-provisioner"]
verbs: ["use"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-provisioner
namespace: superopsmsb
subjects:
- kind: ServiceAccount
name: nfs-provisioner
namespace: superopsmsb
roleRef:
kind: ClusterRole
name: nfs-provisioner
apiGroup: rbac.authorization.k8s.io
准备NFS操作的StorageClass资源
[root@kubernetes-master1 /data/kubernetes/storage/sc-provider]# cat 03_kubernetes_sc_pv.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: storageclass
namespace: superopsmsb
# 每个 StorageClass 都包含 provisioner、parameters 和 reclaimPolicy 字段
# provisioner用来决定使用哪个卷插件分配PV,必须与nfs-client的容器内部的 PROVISIONER_NAME 变量一致
# reclaimPolicy指定创建的Persistent Volume的回收策略
provisioner: "nfsprovisioner"
reclaimPolicy: Retain
parameters:
# archiveOnDelete: "false"表示在删除时不会对数据进行打包,当设置为true时表示删除时会对数据进行打包
archiveOnDelete: "false"
注意:
StorageClass 的name不允许出现 大写字母
创建环境
创建专属命名空间
[root@kubernetes-master1 /data/kubernetes/storage/sc-provider]# kubectl create ns superopsmsb
namespace/superopsmsb created
创建资源对象
[root@kubernetes-master1 /data/kubernetes/storage/sc-provider]# kubectl apply -f ./
deployment.apps/nfs-client-provisioner created
namespace/nfsstorageclass created
serviceaccount/nfs-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-provisioner created
clusterrolebinding.rbac.authorization.k8s.io/nfs-provisioner created
storageclass.storage.k8s.io/storageclass created
检查效果
[root@kubernetes-master1 /data/kubernetes/storage/sc-provider]# kubectl get all -n superopsmsb
NAME READY STATUS RESTARTS AGE
pod/nfs-client-provisioner-797775d949-pf9x2 1/1 Running 0 38s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nfs-client-provisioner 1/1 1 1 38s
NAME DESIRED CURRENT READY AGE
replicaset.apps/nfs-client-provisioner-797775d949 1 1 1 38s
小结
1.2.4 SC实践
学习目标
这一节,我们从 案例解读、简单实践、小结 三个方面来学习。
基础知识
简介
我们准备将nginx的web数据存储通过Sc的方式来实现。
简单实践
创建资源清单
定制PVC使用SC的资源清单文件
[root@kubernetes-master1 /data/kubernetes/storage]# cat 06_kubernetes_sc_nginx_pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: sc-pvc
namespace: superopsmsb
spec:
storageClassName: storageclass
accessModes:
- ReadWriteOnce
# 定义资源要求PV满足这个PVC的要求才会被匹配到
resources:
requests:
storage: 200Mi
定制pod使用pvc
[root@kubernetes-master1 /data/kubernetes/storage]# cat 07_kubernetes_sc_nginx_pod.yaml
kind: Pod
apiVersion: v1
metadata:
name: storageclass-nginx
namespace: superopsmsb
spec:
containers:
- name: nginx-web
image: kubernetes-register.superopsmsb.com/superopsmsb/nginx_web:v0.1
volumeMounts:
- name: test-storage
mountPath: /usr/share/nginx/html
- name: storageclass-pod-test
image: kubernetes-register.superopsmsb.com/superopsmsb/busybox:1.28
command:
- "/bin/sh"
args:
- "-c"
- "while true; do echo $(date) > /data/index.html; sleep 2; done"
volumeMounts:
- name: test-storage
mountPath: "/data"
restartPolicy: "Never"
volumes:
- name: test-storage
persistentVolumeClaim:
claimName: sc-pvc
应用资源对象
使用资源对象
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl apply -f 06_kubernetes_sc_nginx_pvc.yaml -f 07_kubernetes_sc_nginx_pod.yaml
persistentvolumeclaim/sc-pvc created
pod/storageclass-nginx created
检查效果
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl get pod -n superopsmsb
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-797775d949-pf9x2 1/1 Running 0 9m13s
storageclass-nginx 2/2 Running 0 29s
查看pv 和pvc
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl get pv,pvc -n superopsmsb
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-6e467991-e4b0-45dd-a3e0-e28b15fd3762 200Mi RWO Delete Bound superopsmsb/sc-pvc storageclass 64s
persistentvolume/superopsmsb-pv 3Gi RWO Retain Bound default/superopsmsb-pvc 153m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/sc-pvc Bound pvc-6e467991-e4b0-45dd-a3e0-e28b15fd3762 200Mi RWO storageclass 67s
查看nfs的自动创建的数据
[root@kubernetes-ha1 ~]# tree /superopsmsb/nfs-data/
/superopsmsb/nfs-data/
└── superopsmsb-sc-pvc-pvc-6e467991-e4b0-45dd-a3e0-e28b15fd3762
└── index.html
1 directory, 1 file
结果显示:
nfs的存储目录下,自动生成了pvc专属的pv目录
小结
1.3 配置管理
1.3.1 配置基础
学习目标
这一节,我们从 基础知识、简单实践、小结 三个方面来学习。
基础知识
场景需求
生产中所有的应用程序中,都涉及到配置文件,而配置文件经常会有变更,比如数据库连接、代码版本号等,最典型场景就是:
项目经历开发环境、测试环境、预发布环境、线上环境才能完成发布,而每个环境都有定义其独立的各种配置,这些配置手工操作很繁杂,所以好多大公司专门开发了专用配置管理中心,如百度的disconf等。
如何为容器化应用提供配置信息?
1 启动容器时,直接向应用程序传递参数,args: []
2 将定义好的配置文件焙进镜像之中;
3 通过环境变量向容器传递配置数据:有个前提要求,应用得支持从环境变量加载配置信息;
4 制作镜像时,使用entrypoint脚本来预处理变量,常见的做法就是使用非交互式编辑工具,将环境变量的值替换到应用的配置文件中;
5 基于存储卷向容器传递配置文件;
注意:
对于运行容器中的配置改变,需要通过应用程序重载相关配置
k8s的配置管理
kubernetes作为分布式容器调度平台,肯定会遇到同样的问题,那么遇到这种问题后,我们不可能把资源删除后,重新修改一下,然后在启动生成,这种方法就太繁琐的。kubernetes提供了对pod中容器应用的集中配置管理组件:ConfigMap、Secret、downwardAPI。通过这些组件来实现向pod中的容器中注入配置信息的机制。
简单实践
Configmap
Configmap是k8s集群中非常重要的一种配置管理资源对象。借助于ConfigMap API向pod中的容器中注入配置信息的机制。ConfigMap不仅仅可以保存单个属性,也可以用来保存整个配置文件或者JSON二进制文件。
各种配置属性和数据以 k/v或嵌套k/v 样式 存在到Configmap中
注意:
所有的配置信息都是以明文的方式来进行传递,实现资源配置的快速获取或者更新。
secret
在k8s集群中,有一些核心的配置属性信息是非常敏感的,所以这些信息在传递的过程中,是不希望外人能够看到的,所以,k8s提供了一种加密场景中的配置管理资源对象 -- secret。它在进行数据传输之前,会对数据进行编码,在数据获取的时候,会对数据进行解码。从而保证整个数据传输过程的安全。
注意:
这些数据是根据不同的应用场景,采用不同的加密机制。
downwardAPI
从严格意义上来说,downwardAPI不是存储卷,它自身就存在。相较于configmap、secret等资源对象需要创建后才能使用,而downwardAPI引用的是Pod自身的运行环境信息,这些信息在Pod启动的时候就存在。
downwardAPI 为运行在pod中的应用容器提供了一种反向引用。让容器中的应用程序了解所处pod或Node的一些基础属性信息。
小结
1.3.2 CM
学习目标
这一节,我们从 基础知识、简单实践、小结 三个方面来学习。
基础知识
k8s的配置管理
kubernetes作为分布式容器调度平台,肯定会遇到同样的问题,那么遇到这种问题后,我们不可能把资源删除后,重新修改一下,然后在启动生成,这种方法就太繁琐的。kubernetes提供了对pod中容器应用的集中配置管理组件:ConfigMap。通过ConfigMap来实现,借助于ConfigMap API向pod中的容器中注入配置信息的机制。
ConfigMap不仅仅可以保存单个属性,也可以用来保存整个配置文件或者JSON二进制文件。
注意:
虽然configmap可以对各种应用程序提供定制配置服务,但是我们不能用它来替代专门的配置文件,我们可以简单的把它理解为Linux系统中的/etc目录,专门用来存储配置文件的目录
基本属性
确认属性
kubectl explain cm
binaryData 使用二进制传递数据
data 传递数据
注意:
基于data的方式传递信息的话,他会在pod的容器内部生成一个单独的数据文件
数据的表现样式:
普通数据:
属性名称: 属性值
文件数据:
文件名称: |
文件内容
注意:
| 是"多行键值"的标识符
注意:
cm资源配置文件修改完毕后,会自动更新到所有应用该CM的pod里面
简单实践
准备工作
准备nginx容器的配置目录
[root@kubernetes-master1 /data/kubernetes/storage]# mkdir nginx-conf
创建主配置文件
[root@kubernetes-master1 /data/kubernetes/storage]# vim nginx-conf/superopsmsb.conf
server {
listen 8080;
server_name www.superopsmsb.com;
include /etc/nginx/conf.d/superopsmsb-*.cfg;
location / {
root /usr/share/nginx/html;
}
}
创建状态配置片段文件
[root@kubernetes-master1 /data/kubernetes/storage]# vim nginx-conf/superopsmsb-status.cfg
location /nginx-status {
stub_status on;
}
创建资源对象
方法1:制定文件方法
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl create configmap nginx-conf1 --from-file=nginx-conf/superopsmsb.conf --from-file=nginx-conf/superopsmsb-status.cfg
方法2:指定目录方法
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl create configmap nginx-conf2 --from-file=nginx-conf/
确认效果
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl get cm
NAME DATA AGE
kube-root-ca.crt 1 6h39m
nginx-conf1 2 38s
nginx-conf2 2 29s
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl describe cm nginx-conf1
Name: nginx-conf1
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
superopsmsb.conf:
----
server {
listen 8080;
server_name www.superopsmsb.com;
include /etc/nginx/conf.d/superopsmsb-*.cfg;
location / {
root /usr/share/nginx/html;
}
}
superopsmsb-status.cfg:
----
location /nginx-status {
stub_status on;
}
BinaryData
====
Events: <none>
小结
1.3.3 CM案例
学习目标
这一节,我们从 案例解读、简单实践、小结 三个方面来学习。
案例解读
简介
简单实践
资源对象
准备资源清单文件
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl get cm nginx-conf1 -o yaml > 08_kubernetes_cm_nginx_conf.yml
修改资源清单文件
[root@kubernetes-master1 /data/kubernetes/storage]# cat 08_kubernetes_cm_nginx_conf.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: superopsmsb-nginxconf
data:
superopsmsb-status.cfg: |
location /nginx-status {
stub_status on;
}
default.conf: |
server {
listen 80;
server_name www.superopsmsb.com;
include /etc/nginx/conf.d/superopsmsb-*.cfg;
location / {
root /usr/share/nginx/html;
}
}
准备nginx的首页文件内容
[root@kubernetes-master1 /data/kubernetes/storage]# cat 09_kubernetes_cm_nginx_index.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: superopsmsb-nginx-index
data:
index.html: "Hello Nginx, This is Configmap\n"
创建nginx的清单文件
[root@kubernetes-master1 /data/kubernetes/storage]# vim 10_kubernetes_cm_nginx_pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: superopsmsb-nginx
spec:
containers:
- image: kubernetes-register.superopsmsb.com/superopsmsb/nginx_web:v0.1
name: nginx-web
volumeMounts:
- name: nginxconf
mountPath: /etc/nginx/conf.d/
readOnly: true
- name: nginxindex
mountPath: /usr/share/nginx/html/
readOnly: true
volumes:
- name: nginxconf
configMap:
name: superopsmsb-nginxconf
optional: false
- name: nginxindex
configMap:
name: superopsmsb-nginx-index
optional: false
应用资源清单文件
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl apply -f 08_kubernetes_cm_nginx_conf.yml -f 09_kubernetes_cm_nginx_index.yml -f 10_kubernetes_cm_nginx_pod.yml
configmap/superopsmsb-nginxconf created
configmap/superopsmsb-nginx-index created
pod/superopsmsb-nginx created
查看效果
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
superopsmsb-nginx 1/1 Running 0 16s 10.244.3.8 kubernetes-node2 <none> <none>
页面访问效果
[root@kubernetes-master1 /data/kubernetes/storage]# curl 10.244.3.8
Hello Nginx, This is Configmap
[root@kubernetes-master1 /data/kubernetes/storage]# curl 10.244.3.8/nginx-status
Active connections: 1
server accepts handled requests
2 2 2
Reading: 0 Writing: 1 Waiting: 0
修改配置
修改配置文件
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl edit cm superopsmsb-nginxconf
...
apiVersion: v1
data:
default.conf: |
server {
listen 8080;
...
确认效果
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl exec -it superopsmsb-nginx -- grep listen /etc/nginx/conf.d/default.conf
listen 8080;
cm同步成功了,但是nginx的程序没有加载,我们重载一下配置文件
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl exec -it superopsmsb-nginx -- nginx -s reload
2022/07/22 05:33:33 [notice] 16#16: signal process started
[root@kubernetes-master1 /data/kubernetes/storage]# curl 10.244.3.8
curl: (7) Failed connect to 10.244.3.8:80; 拒绝连接
[root@kubernetes-master1 /data/kubernetes/storage]# curl 10.244.3.8:8080
Hello Nginx, This is Configmap
小结
1.3.4 Secret
学习目标
这一节,我们从 属性解读、命令实践、小结 三个方面来学习。
基础知识
简介
secret volume为Pod提供加密的信息,相比于直接将敏感数据配置在Pod的定义或者镜像中,Secret提供了更加安全的机制,将共享的数据进行加密,防止数据泄露。
Secret的对象需要单独定义并创建,然后以数据卷的形式挂载到Pod中,Secret的数据将以文件的形式保存,容器通过读取文件可以获取需要的数据。
secret volume是通过tmpfs(内存文件系统)实现的,所以这种类型的volume不是永久存储的。
创建方式
手动创建:大部分情况用来存储用户私有的一些信息
-- 创建方式与CM的方式一致
自动创建:用来作为集群中各个组件之间通信的身份校验使用
secret类型
generic
通用类型,基于base64编码的,长用来存储密码,公钥之类的。常见的子类型有:kubernetes.io/basic-auth、kubernetes.io/rbd、kubernetes.io/ssh-auth(比较重要)
docker-registry
专用于让kubelet启动Pod时从私有镜像仓库pull镜像时,首先认证到Registry时使用
tls
专门用于保存tls/ssl用到证书和配对儿的私钥
简单实践
准备信息
我们以用户名和密码的加密方式进行认证,首先对用户名和密码进行base64加密
]# echo -n 'admin' | base64
YWRtaW4=
]# echo -n 'password' | base64
cGFzc3dvcmQ=
注意:
-n的作用是仅仅传递字符串内容,而不包括字符串末尾的换行符
创建资源对象
secret资源定义文件
[root@kubernetes-master1 /data/kubernetes/storage]# cat 11_kubernetes_secret_data.yml
apiVersion: v1
kind: Secret
metadata:
name: superopsmsb-secret
type: kubernetes.io/basic-auth
data:
username: YWRtaW4=
password: cGFzc3dvcmQ=
生成新的对象
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl apply -f 11_kubernetes_secret_data.yml
secret/superopsmsb-secret created
pod应用资源对象
创建资源对象
[root@kubernetes-master1 /data/kubernetes/storage]# vim 12_kubernetes_secret_nginx_pod.yml
apiVersion: v1
kind: Pod
metadata:
name: superopsmsb-secret
spec:
volumes:
- name: secret
secret:
secretName: superopsmsb-secret
containers:
- name: nginx-web
image: kubernetes-register.superopsmsb.com/superopsmsb/nginx_web:v0.1
volumeMounts:
- name: secret
mountPath: /nginxsecret/
readOnly: true
创建资源对象
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl apply -f 12_kubernetes_secret_nginx_pod.yml
pod/superopsmsb-secret created
查看效果
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl describe pod superopsmsb-secret
Name: superopsmsb-secret
...
Containers:
nginx-web:
...
Mounts:
/nginxsecret/ from secret (ro)
...
Volumes:
secret:
Type: Secret (a volume populated by a Secret)
SecretName: superopsmsb-secret
Optional: false
查看文件内容效果
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl exec -it superopsmsb-secret -- /bin/bash
root@superopsmsb-secret:/# ls /nginxsecret/
password username
root@superopsmsb-secret:/# cat /nginxsecret/password
passwordroot@superopsmsb-secret:/#
root@superopsmsb-secret:/# cat /nginxsecret/username
adminroot@superopsmsb-secret:/#
小结
1.3.5 Secret案例
学习目标
这一节,我们从 案例解读、简单实践、小结 三个方面来学习。
案例解读
需求
实践一个基于https来访问的nginx的web服务
准备工作
准备nginx容器的配置目录
[root@kubernetes-master1 /data/kubernetes/storage]# mkdir nginx-conf-tls
创建主配置文件
[root@kubernetes-master1 /data/kubernetes/storage]# vim nginx-conf-tls/superopsmsb.conf
server {
listen 443 ssl;
server_name www.superopsmsb.com;
ssl_certificate /etc/nginx/certs/tls.crt;
ssl_certificate_key /etc/nginx/certs/tls.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
include /etc/nginx/conf.d/myserver-*.cfg;
location / {
root /usr/share/nginx/html;
}
}
server {
listen 80;
server_name www.superopsmsb.com;
return 301 https://$host$request_uri;
}
创建证书
准备nginx容器的配置目录
[root@kubernetes-master1 /data/kubernetes/storage]# mkdir tls-key
做证书
[root@kubernetes-master1 /data/kubernetes/storage]# openssl genrsa -out tls-key/tls.key 2048
做成自签证书
[root@kubernetes-master1 /data/kubernetes/storage]# openssl req -new -x509 -key tls-key/tls.key -out tls-key/tls.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=www.superopsmsb.com
注意:
域名必须是我们使用的域名信息
简单实践
创建资源对象文件
创建cm资源对象
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl create configmap nginx-ssl-conf --from-file=nginx-conf-tls/
创建secret资源对象
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl create secret tls nginx-ssl-secret --cert=tls-key/tls.crt --key=tls-key/tls.key
创建应用资源对象
创建资源配置文件
[root@kubernetes-master1 /data/kubernetes/storage]# vim 13_kubernetes_cm_secret_nginx.yml
apiVersion: v1
kind: Pod
metadata:
name: superops-nginx-ssl
spec:
containers:
- image: kubernetes-register.superopsmsb.com/superopsmsb/nginx_web:v0.1
name: nginx-web
volumeMounts:
- name: nginxcerts
mountPath: /etc/nginx/certs/
readOnly: true
- name: nginxconfs
mountPath: /etc/nginx/conf.d/
readOnly: true
volumes:
- name: nginxcerts
secret:
secretName: nginx-ssl-secret
- name: nginxconfs
configMap:
name: nginx-ssl-conf
optional: false
应用资源配置文件
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl apply -f 13_kubernetes_cm_secret_nginx.yml
检查效果
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE ...
superops-nginx-ssl 1/1 Running 0 79s 10.244.2.6 node2
使用https测试
[root@kubernetes-master1 /data/kubernetes/storage]# curl -H "Host:www.superopsmsb.com" https://10.244.2.6
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.haxx.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
结果提示:
由于是自签证书,所以默认不允许通过,我们可以通过 -k的方式,让它忽略警告。
[root@kubernetes-master1 /data/kubernetes/storage]# curl -k -H "Host:www.superopsmsb.com" https://10.244.2.6
Hello Nginx, superops-nginx-ssl-1.23.0
使用http访问
[root@kubernetes-master1 /data/kubernetes/storage]# curl http://10.244.2.6
<html>
<head><title>301 Moved Permanently</title></head>
...
结果显式:
这个 301 就是我们定制的返回信息。
小结
1.4 状态管理
1.4.1 状态基础
学习目标
这一节,我们从 原理解读、资源对象、小结 三个方面来学习。
原理解读
简介
我们知道,http协议是无状态的,而http应用是有状态的。所谓的无状态指的是 -- 每次的请求都是独立的,它的执行情况和结果与前面的请求和之后的请求是无直接关系的,它不会受前面的请求应答情况直接影响,也不会直接影响后面的请求应答情况。也就是说,对于http协议本身的请求-应答模式来说它是独立的,彼此之间没有关联关系。
而我们使用的web程序是需要有大量的业务逻辑相互关联才可以实现最终的目标,也就是说基于http协议的web应用程序是有状态的。只不过这个状态是需要借助于其他的机制来实现,比如 cookies、session、token以及其他辅助的机制。
场景需求
生产中,一些中间件业务集群,比如MySQL集群、MongoDB集群、Zookeeper集群等,这些应用集群有一下特点:
1、每个节点都有固定的身份ID,集群成员通过身份ID进行通信
2、集群的规模是比较固定的,一般不能随意变动
3、节点都是由状态的,而且状态数据会做持久化存储
4、集群中某个节点出现故障,集群功能肯定受到影响。
像这种状态类型的服务,只要过程中存在一点问题,那么影响及范围都是不可预测。
到目前为止,我们学习到了Pod的管理对象有RC、Rs、Deployment,这三个都是面向无状态的服务,满足不了上述的有状态集群的场景需求,所以Kubernetes从V1.4版本引入了集群状态管理的功能,V1.5版本更名为StatefulSet[有状态应用副本集]。
简单实践
简介
StatefulSets 旨在与有状态的应用及分布式系统一起使用。然而在 Kubernetes 上管理有状态应用和分布式系统是一个宽泛而复杂的话题。StatefulSet有以下特点(使用场景):
- 每个Pod都有稳定、唯一的网络标识,彼此间可以通信
- StatefulSet控制的Pod副本启动、扩展、删除、更新等操作都是有顺序的。
- StatefulSet里的Pod采用独立的持久化存储卷,存储状态数据
Headless service会给一个StatufulSet控制的Pod提供一个唯一的DNS域名来作为每个成员的网络标识,集群内部成员之间使用域名通信。
DNS域名格式:
$(podname).$(headless service name).$(namespace name).svc.cluster.local
StatefulSet组件
headless service
自启动/重启pod名称是随机的,而为了statefulset特性一,所以借用headless service通过唯一的"网络标识"来直接指定的pod应用,所以它要求我们的dns环境是完好的。
当一个StatefulSet挂掉,新创建的StatefulSet会被赋予跟原来的Pod一样的名字,通过这个名字来匹配到原来的存储,实现了状态保存。
volumeClaimTemplate
自启动/重启pod的存储是共享的,但是集群中的副本数据是不一样的(例:redis),如果用共享存储的话,会导致多副本间的数据被覆盖,为了statefulsed的特性三,我们需要将pod和其申请的数据卷隔离开,每一种pod都有其对应的数据卷配置模板,来满足该要求。
小结
1.4.2 sts基础
学习目标
这一节,我们从 基础知识、简单实践、小结 三个方面来学习。
基础知识
属性解析
apiVersion: apps/v1 # API群组及版本;
kind: StatefulSet # 资源类型的特有标识
metadata:
name <string> # 资源名称,在作用域中要唯一
namespace <string> # 名称空间;StatefulSet隶属名称空间级别
spec:
replicas <integer> # 期望的Pod副本数,默认为1
selector <object> # 标签选择器,须匹配Pod模板中的标签,必选字段
template <object> # Pod模板对象,必选字段
revisionHistoryLimit <integer> # 滚动更新历史记录数量,默认为10
updateStrategy <Object> # 滚动更新策略
type <string> # 滚动更新类型,可用值有OnDelete和Rollingupdate
rollingUpdate <Object> # 滚动更新参数,专用于RollingUpdate类型
partition <integer> # 分区指示索引值,默认为0,一般用于版本分区域更新场景
serviceName <string> # 相关的Headless Service的名称,必选字段
volumeClaimTemplates <[]Object> # 存储卷申请模板
apiVersion <string> # PVC资源所属的API群组及版本,可省略
kind <string> # PVC资源类型标识,可省略
metadata <Object> # 卷申请模板元数据
spec <Object> # 期望的状态,可用字段同PVC
podManagementPolicy <string> # Pod管理策略,默认的“OrderedReady”表示顺序创建并逆序删
# 除,另一可用值“Parallel”表示并行模式
简单实践
实践
定制资源清单文件
[root@kubernetes-master1 /data/kubernetes/storage]# cat 14_kubernetes_sts_nginx.yml
apiVersion: v1
kind: Service
metadata:
name: superopsmsb-sc-headless-svc
spec:
ports:
- name: myweb
port: 80
selector:
app: sts-nginx-web
clusterIP: None
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: statefulset
spec:
serviceName: storageclass-headless-svc
replicas: 5
selector:
matchLabels:
app: sts-nginx-web
template:
metadata:
labels:
app: sts-nginx-web
spec:
containers:
- name: nginx-web
image: kubernetes-register.superopsmsb.com/superopsmsb/nginx_web:v0.1
volumeMounts:
- name: nginx-storage
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: nginx-storage
spec:
storageClassName: storageclass
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
应用资源清单文件
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl apply -f 14_kubernetes_sts_nginx.yml
service/superopsmsb-sc-headless-svc created
statefulset.apps/statefulset created
查看资源对象创建
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl get pod
NAME READY STATUS RESTARTS AGE
statefulset-0 1/1 Running 0 40s
statefulset-1 1/1 Running 0 34s
statefulset-2 1/1 Running 0 31s
statefulset-3 1/1 Running 0 26s
statefulset-4 1/1 Running 0 17s
结果显示:
pod的名称按照顺序进行基于statefulset拼接而成的
查看pvc效果
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl get pvc
NAME STATUS VOLUME ... AGE
nginx-storage-statefulset-0 Bound pvc-1d90d499-7c03-4422-b593-4f8d5fa8ba5d ... 2m47s
nginx-storage-statefulset-1 Bound pvc-ee5753a1-4e5b-4d17-846f-79c1e2efe79c ... 2m41s
nginx-storage-statefulset-2 Bound pvc-74210b7a-3f16-491b-9e53-b30f616008d8 ... 2m38s
nginx-storage-statefulset-3 Bound pvc-b88e378f-c025-469f-9409-4f062ae107cc ... 2m33s
nginx-storage-statefulset-4 Bound pvc-e6bb732e-cc5e-4aaa-b8e9-566521f5a79a ... 2m24s
查看pv效果
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl get pv
NAME ... STORAGECLASS ... AGE
pvc-1d90d499-7c03-4422-b593-4f8d5fa8ba5d ... storageclass ... 2m53s
pvc-74210b7a-3f16-491b-9e53-b30f616008d8 ... storageclass ... 2m47s
pvc-b88e378f-c025-469f-9409-4f062ae107cc ... storageclass ... 2m39s
pvc-e6bb732e-cc5e-4aaa-b8e9-566521f5a79a ... storageclass ... 2m29s
pvc-ee5753a1-4e5b-4d17-846f-79c1e2efe79c ... storageclass ... 2m50s
结果显示:
所有的资源对象(pod+pv)都是按照顺序创建的,而且每个pv都有自己独有的标识符
定制各自的首页
定制各自nginx的首页
[root@kubernetes-ha1 /superopsmsb/nfs-data]# echo nginx-1 > default-nginx-storage-statefulset-0-pvc-1d90d499-7c03-4422-b593-4f8d5fa8ba5d/a.html
[root@kubernetes-ha1 /superopsmsb/nfs-data]# echo nginx-2 > default-nginx-storage-statefulset-1-pvc-ee5753a1-4e5b-4d17-846f-79c1e2efe79c/a.html
[root@kubernetes-ha1 /superopsmsb/nfs-data]# echo nginx-3 > default-nginx-storage-statefulset-2-pvc-74210b7a-3f16-491b-9e53-b30f616008d8/a.html
[root@kubernetes-ha1 /superopsmsb/nfs-data]# echo nginx-4 >default-nginx-storage-statefulset-3-pvc-b88e378f-c025-469f-9409-4f062ae107cc/a.html
[root@kubernetes-ha1 /superopsmsb/nfs-data]# echo nginx-5 > default-nginx-storage-statefulset-4-pvc-e6bb732e-cc5e-4aaa-b8e9-566521f5a79a/a.html
...
资源的关闭和删除
关闭资源
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl delete -f 14_kubernetes_sts_nginx.yml
pv和pvc效果
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nginx-storage-statefulset-0 Bound pvc-1d90d499-7c03-4422-b593-4f8d5fa8ba5d 100Mi RWO storageclass 16m
nginx-storage-statefulset-1 Bound pvc-ee5753a1-4e5b-4d17-846f-79c1e2efe79c 100Mi RWO storageclass 16m
nginx-storage-statefulset-2 Bound pvc-74210b7a-3f16-491b-9e53-b30f616008d8 100Mi RWO storageclass 16m
nginx-storage-statefulset-3 Bound pvc-b88e378f-c025-469f-9409-4f062ae107cc 100Mi RWO storageclass 16m
nginx-storage-statefulset-4 Bound pvc-e6bb732e-cc5e-4aaa-b8e9-566521f5a79a 100Mi RWO storageclass 16m
结果显示:
由于pod 和 pv、pvc是独立的生命周期,所以他们之间互不影响。仅仅是通过名称关联在一起的。
启动资源
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl apply -f 14_kubernetes_sts_nginx.yml
查看资源启动
[root@kubernetes-master1 /data/kubernetes/storage]# kubectl get pod -o wide
NAME READY... AGE IP ...
statefulset-0 1/1 ... 10s 10.244.3.12 ...
statefulset-1 1/1 ... 8s 10.244.2.8 ...
statefulset-2 1/1 ... 7s 10.244.1.9 ...
statefulset-3 1/1 ... 6s 10.244.3.13 ...
statefulset-4 1/1 ... 4s 10.244.2.9 ...
可以看到:
资源启动的方式仍然是按照顺序来启动的,因为名称不变,所以pvc会自动关联原来的pod,从而实现每个pod访问的都是之前的数据
尝试访问数据
[root@kubernetes-master1 /data/kubernetes/storage]# curl 10.244.2.8/a.html
nginx-2
[root@kubernetes-master1 /data/kubernetes/storage]# curl 10.244.2.9/a.html
nginx-5
结果显示:
仍然是各自的数据
小结