【Kubernetes】centos7搭建k8s集群(三) - 存储使用与讲解
文章目录一、存储卷基础1.emptyDir目录2.gitrepo目录3.hostPath目录4.nfs共享存储卷4.1.节点安装配置nfs4.2.node节点挂载4.3.测试NFS二、k8s的namespace概念三、PVC和PV1.PV概念与使用2.PVC的概念与使用3.PVC的阻塞四、statefulset控制器1.PV资源配置2.创建StatefulSet服务五、configmap与secr
文章目录
一、存储卷基础
在docker容器中,为了实现数据的持久性存储,在宿主机和容器内做映射,可以保证在容器的生命周期结束,数据依旧可以实现持久性存储。
但是在k8s中,由于pod分布在各个不同的节点之上,并不能实现不同节点之间持久性数据的共享,并且,在节点故障时,可能会导致数据的永久性丢失。为此,k8s就引入了外部存储卷的功能。
1.emptyDir目录
emptyDir:Pod挂载在本地的磁盘或者内存,被称为emptyDir ,称为临时空目录,随着Pod删除,也会被删除。注意:一个容器崩溃了不会导致数据的丢失,因为容器的崩溃并不移除pod.
做一个empty数据卷示例:
示例1
vi pod-emp.yaml
---
apiVersion: v1 # 配置格式的版本
kind: Pod # 创建的资源类型,这里是pod
metadata: # 元数据
name: empty-pod
spec:
containers:
- name: emptydir
image: busybox
command: [ "sleep", "3600" ]
volumeMounts:
- mountPath: /data # 将数据卷挂载到/data下
name: data-volume
volumes:
- name: data-volume
emptyDir: {} # 定义一个empty类型挂载
创建运行
kubectl create -f pod-emp.yaml
查看挂载描述
kubectl describe pod empty-pod
使用场景,容器共享文件。在一个pod中有两类容器,一个是主容器,一个是辅助容器,两个容器使用同一个存储卷。
辅助容器用来生成新的内容,主容器加载使用。
示例2
vi pod-empty.yaml
---
apiVersion: v1 # 配置格式的版本
kind: Pod # 创建的资源类型,这里是pod
metadata: # 元数据
name: emp
namespace: default
labels:
app: emp
spec:
containers:
- name: empapp
image: nginx:1.9.7
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
volumeMounts:
- mountPath: /usr/share/nginx/html/ # 将数据卷挂载到/usr/share/nginx/html/下
name: html
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /data/ # 将数据卷挂载到/data/下
name: html
command: [ '/bin/sh','-c', "while true;do echo $(date) >> /data/index.html;sleep 2;done;" ] # 间隔2秒向/data/index.html写入date
volumes:
- name: html # 共享一个html目录
emptyDir: {} # 定义一个empty类型挂载
创建运行
kubectl create -f pod-empty.yaml
运行后,可看到页面内容不断增加
2.gitrepo目录
gitrepo实际上并不是一个新的存储类型,只是emptydir上补添一个git命令来拉取文件而已。
当pod创建时候,会拉取git(依赖于宿主机git命令驱动)仓库中数据克隆到本地,并且作为存储卷定义在pod之上。gitrepo基于emptyDir,此存储卷是emptyDir,git仓库中拉取的代码存放在emptyDir后被定义到pod。
因为拉取git仓库的动作,仅仅是在pod创建时触发一次,并不会待续更新文件,因此在工作中基本上无用处。在这里不做过多讲解。
3.hostPath目录
hostPath类型则是映射node文件系统中的文件或者目录到pod里。可实现针对某一节点的数据持久化,如果节点宕机了,那数据就丢失了
示例
vi pod-hostpath.yaml
---
apiVersion: v1 # 配置格式的版本
kind: Pod # 创建的资源类型,这里是pod
metadata: # 元数据
name: hostpath-pod
spec:
containers:
- name: hostpath
image: busybox
command: [ "sleep", "3600" ]
volumeMounts:
- mountPath: /test-data # 将数据卷挂载到/test-data下
name: host-volume
volumes:
- name: host-volume
hostPath: # 挂载类型为hostPath
path: /data # 挂载到node节点的/data下
type: Directory
创建运行
kubectl create -f pod-hostpath.yaml
进入到容器内部
kubectl exec -it hostpath-pod /bin/sh
创建测试文件
查看pod的node节点
我们登录到work2服务器上,查看/data文件夹,可以看到文件被保存到work2节点的data中
此后,删除掉pod,此文件也依然存在
4.nfs共享存储卷
nfs使的我们可以挂在已经存在的共享到的我们的Pod中,nfs不会被删除,仅仅是解除挂在状态而已,这就意味着NFS能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间相互传递.并且,nfs可以同时被多个pod挂在并进行读写
4.1.节点安装配置nfs
安装nfs
yum install -y nfs-utils
配置nfs
创建文件夹
mkdir -p /data/volumes
编辑配置
vi /etc/exports
插入以下内容
/data/volumes *(rw,no_root_squash)
启动并查看
systemctl start nfs
systemctl start rpcbind
showmount -e localhost
showmount -e
4.2.node节点挂载
需要在所有节点安装 nfs-utils
组件,否则当Pod被分配到没有组件的节点,会启动失败,因为没有mount.nfs
安装nfs:yum install -y nfs-utils
挂载nfs:mount -t nfs master1:/data/volumes /nfs
(没有则先新建nfs目录)
master1为k8s-master的host名称,需要提前在work服务器配置,方式如下
vi /etc/hosts
插入
192.168.23.101 master1
解除挂载:umount /nfs
查看挂载效果:mount
进入node节点,可查看/nfs目录下文件与master已互通
4.3.测试NFS
先在nfs服务内,加一个html测试页面
echo '<h1>NFS success</h1>' > /data/volumes/index.html
创建一个pod测试
vi vol-nfs.yaml
---
apiVersion: v1 # 配置格式的版本
kind: Pod # 创建的资源类型,这里是pod
metadata: # 元数据
name: pod-vol-nfs
namespace: default
spec:
containers:
- name: myapp
image: nginx:1.9.7
volumeMounts:
- mountPath: /usr/share/nginx/html/ # 将数据卷挂载到/usr/share/nginx/html/下
name: html
volumes:
- name: html
nfs: # 挂载类型为nfs
path: /data/volumes # 引入nfs的路径
server: 192.168.23.101 # 引入nfs的IP
运行pod后测试,可看到nginx输出页面
kubectl create -f vol-nfs.yaml
pod的删除重建,不影响pod服务效果
二、k8s的namespace概念
一个namespaces可以理解为kubernetes集群中的一个虚拟化集群。
在一个Kubernetes集群中可以拥有多个命名空间,它们在逻辑上彼此隔离。 这样可以方便我们区分各个团队的不同服务,增加安全甚至性能方面的帮助!
K8S默认已经为了我们初始化了三个namespace:
- default:你的service和app默认被创建于此。
- kube-system:kubernetes系统组件使用。
- kube-public:公共资源使用。但实际上现在并不常用。
总而言之,namespace是一种为了你方便管理服务的辅助,你可以根据需要创建若干个namespace供业务服务分组治理。从另一方面来说,K8s的任何一个服务,都是归属于某一个namespace的。
三、PVC和PV
通过上面的存储卷的基础知识,我们大概了解了在K8S中,要持久化存储数据,最好还是存入到第三方服务里更安全,如NFS等。而在业界,这样的存储很多,使用方式五花八门,这就要求运维工程师必须要精通这些存储才能用好它。
PersistentVolume(pv)和PersistentVolumeClaim(pvc)就是k8s提供的两种API资源,用于抽象存储细节:
- 管理员关注于如何通过pv提供存储功能而无需如何使用
- 用户只需要挂载pvc到容器中而不需要关注存储卷采用何种技术实现。
pvc和pv的关系与pod和node关系类似,前者消耗后者的资源。pvc可以向pv申请指定大小的存储资源并设置访问模式。
接下来我们使用PV与PVC的方式,实现上面nfs模式的资源挂载效果。
定义一个PV资源
1.PV概念与使用
PersistentVolume(PV)是集群中由管理员配置的一段网络存储。 它是集群中的资源,就像节点是集群资源一样。因此PV是全局资源,不归属于任何namespace的。
vi vol-pv.yaml
---
apiVersion: v1 # 配置格式的版本
kind: PersistentVolume # 创建的资源类型,这里是PersistentVolume
metadata: # 元数据
name: pv-nfs # pv的名称
spec:
storageClassName: manual
capacity:
storage: 1Gi # 存储的容量
accessModes: # 访问模式
- ReadWriteMany # 读写权限,可以被多个节点挂载
nfs: # 引入nfs服务
path: /data/volumes # 引入nfs的路径
server: 192.168.23.101 # 引入nfs的IP
创建PV
kubectl create -f vol-pv.yaml
此处的RWX是PV资源的AccessModes (访问模式),有以下几种模式。
- ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
- ReadOnlyMany(ROX):只读权限,可以被多个节点挂载
- ReadWriteMany(RWX):读写权限,可以被多个节点挂载
此处的NFS资源,是支持多个pod同时挂载使用的。
同时,PV同一时间只能被一个PVC申请使用,这里有个状态变迁过程:
- Available(可用):表示可用状态,还未被任何 PVC 绑定
- Bound(已绑定):表示 PV 已经被 PVC 绑定
- Released(已释放):PVC 被删除,但是资源还未被集群重新声明
- Failed(失败): 表示该 PV 的自动回收失败
2.PVC的概念与使用
PersistentVolumeClaim(PVC)是由用户进行存储的请求。 它类似于pod。 Pod消耗节点资源,PVC消耗PV资源。因此PVC是归属于某个namespace的。
vi vol-pvc.yaml
---
apiVersion: v1 # 配置格式的版本
kind: PersistentVolumeClaim # 创建的资源类型,这里是PersistentVolumeClaim
metadata: # 元数据
name: pvc-nfs # pv的名称
namespace: default
spec:
storageClassName: manual
accessModes: # 访问模式
- ReadWriteMany # 读写权限
resources:
requests:
storage: 1Gi # 要求的容量
创建PVC
kubectl create -f vol-pvc.yaml
现在查看PV的状态,发现其已经被绑定使用了
测试一个pod的使用效果,将上面的pvc引入这里使用
vi pod-pvc.yaml
---
apiVersion: v1 # 配置格式的版本
kind: Pod # 创建的资源类型,这里是Pod
metadata: # 元数据
name: testpv
spec:
containers:
- name: nginx
image: nginx:1.9.7
ports:
- containerPort: 80
volumeMounts:
- mountPath: /usr/share/nginx/html/ # 将pvc挂载到/usr/share/nginx/html/下
name: pvc-nfs
volumes:
- name: pvc-nfs
persistentVolumeClaim:
claimName: pvc-nfs # 申请PVC的名字
创建Pod
kubectl create -f pod-pvc.yaml
查看效果
3.PVC的阻塞
我们再创建一个新的pvc
vi vol-pvc2.yaml
---
apiVersion: v1 # 配置格式的版本
kind: PersistentVolumeClaim # 创建的资源类型,这里是PersistentVolumeClaim
metadata: # 元数据
name: pvc-nfs2 # pv的名称
namespace: default
spec:
storageClassName: manual
accessModes: # 访问模式
- ReadWriteMany # 读写权限
resources:
requests:
storage: 1Gi # 要求的容量
kubectl create -f vol-pvc2.yaml
我们可以看到,当PVC没有足够的PV来满足时,状态为挂起pending
我们再新建一个PV
vi vol-pv2.yaml
---
apiVersion: v1 # 配置格式的版本
kind: PersistentVolume # 创建的资源类型,这里是PersistentVolume
metadata: # 元数据
name: pv-nfs2 # pv的名称
spec:
storageClassName: manual
capacity:
storage: 1Gi # 存储的容量
accessModes: # 访问模式
- ReadWriteMany # 读写权限,可以被多个节点挂载
nfs: # 引入nfs服务
path: /data/volumes # 引入nfs的路径
server: 192.168.23.101 # 引入nfs的IP
kubectl create -f vol-pv2.yaml
如果有PV被释放,或者新建了PV能满足请求时,自动绑定占用
四、statefulset控制器
现实工作中,我们的应用,分两类,有状态和无状态
- 无状态的, 关注的是群体,如nginx,tomcat等
- 有状态的, 关注的是个体,如redis,mysql等
我们前面的控制器,对无状态的应用操作很好,但对有状态的应用完全不实用。
有状态应用集的特点:
①稳定且需要唯一的网络标识符;
如: Redis集群,
在Redis集群中,它是通过槽位来存储数据的,假如:第一个节点是0 ~ 1000,第二个节点是1001 ~ 2000,第三个节点2001 ~ 3000…等等,这就使得Redis集群中每个节点要通过ID来标识自己,如:
第二个节点宕机了,重建后它必须还叫第二个节点,或者说第二个节点叫R2,它必须还叫R2,这样在获取1001~2000槽位的数据时,才能找到数据,否则Redis集群将无法找到这段数据。
② 稳定且持久的存储;
可实现持久存储,新增或减少pod,存储不会随之发生变化。
针对这样的特点,k8s推出StatefulSet
1.PV资源配置
制做三个基础PV资源,需要分别在/data/volumes
下添加文件夹v1
,v2
,v3
vi pv.yaml
---
apiVersion: v1 # 配置格式的版本
kind: PersistentVolume # 创建的资源类型,这里是PersistentVolume
metadata: # 元数据
name: pv001 # pv的名称
labels:
name: pv001
spec:
capacity:
storage: 1Gi # 存储的容量
accessModes: ["ReadWriteMany","ReadWriteOnce"]
nfs: # 引入nfs服务
path: /data/volumes/v1 # 引入nfs的路径
server: 192.168.23.101 # 引入nfs的IP
---
apiVersion: v1 # 配置格式的版本
kind: PersistentVolume # 创建的资源类型,这里是PersistentVolume
metadata: # 元数据
name: pv002 # pv的名称
labels:
name: pv002
spec:
capacity:
storage: 2Gi # 存储的容量
accessModes: ["ReadWriteOnce"]
nfs: # 引入nfs服务
path: /data/volumes/v2 # 引入nfs的路径
server: 192.168.23.101 # 引入nfs的IP
---
apiVersion: v1 # 配置格式的版本
kind: PersistentVolume # 创建的资源类型,这里是PersistentVolume
metadata: # 元数据
name: pv003 # pv的名称
labels:
name: pv003
spec:
capacity:
storage: 3Gi # 存储的容量
accessModes: ["ReadWriteMany","ReadWriteOnce"]
nfs: # 引入nfs服务
path: /data/volumes/v3 # 引入nfs的路径
server: 192.168.23.101 # 引入nfs的IP
创建PV
kubectl create -f pv.yaml
2.创建StatefulSet服务
StatefulSet资源清单包含三个部分:
- headless service 用于定义网络标识(DNS)
- StatefulSet 控制器,用于定义具体应用
- volumeClaimTemplate 存储卷申请模板,用于创建PVC
vi stateful.yaml
---
apiVersion: v1 # 配置格式的版本
kind: Service # 创建的资源类型
metadata: # 元数据
name: myapp-svc # 名称
namespace: default
labels:
name: myapp
spec:
ports:
- port: 80
name: web
clusterIP: None # 配置headless service,此处为没有网络头
selector:
app: myapp-pod # 匹配Pod标签
---
apiVersion: apps/v1 # 配置格式的版本
kind: StatefulSet # 控制器
metadata: # 元数据
name: myapp # 名称
spec:
serviceName: myapp # 服务名称
replicas: 2
selector:
matchLabels:
app: myapp-pod # 匹配Pod
template:
metadata:
labels:
app: myapp-pod
spec:
containers:
- name: myapp
image: nginx:1.9.7
ports:
- containerPort: 80
name: web
volumeMounts:
- name: myappdata
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: myappdata # pvc 名称
spec:
accessModes: ["ReadWriteOnce"] # 权限
resources:
requests:
storage: 1Gi # pvc 大小
创建
kubectl create -f stateful.yaml
查看pod,发现sts创建的pod集群,是有序编号的,从第0个开始,依次创建。
查看pvc列表(sts自动创建管理的),它与上面的pod是序号一一对应的。也就是说,此pod重启重建,对应的pvc都是一样的
服务扩容:
可以看到,pod扩展,会连带pvc一起扩容。但是缩容却不会
删除pod:
可以看到,新建出来的pod名称/node都是不变的,对应 的PVC当然也不变。
五、configmap与secret
secret和configmap可以理解为特殊的存储卷,但是它们不是给Pod提供存储功能的,而是提供了从集群外部向集群内部的应用注入配置信息的功能。ConfigMap扮演了K8S集群中配置中心的角色。
ConfigMap定义了Pod的配置信息,可以以存储卷的形式挂载至Pod中的应用程序配置文件目录,从configmap中读取配置信息;也可以基于环境变量的形式,从ConfigMap中获取变量注入到Pod容器中使用。
1.命令行方式创建ConfigMap
--from-literal=key=value
格式直接赋值,示例如下
kubectl create configmap web-config --from-literal=db.host=192.168.23.80 --from-literal=db.port='3306'
查看这个configmap信息:
kubectl get configmap -o yaml
--from-file=path
方式,将文件中信息存入configmap
先将值放入文件中
echo -n 192.168.23.80 > ./db.host
echo -n 3306 > ./db.port
再合建configmap
kubectl create cm config2 --from-file=./db.host --from-file=./db.port
查看信息,效果一样
kubectl get cm config2 -o yaml
2.YAML 配置文件方式创建ConfigMap
直接创建一个yaml文件,配置好信息
vi db.yaml
---
apiVersion: v1 # 配置格式的版本
kind: ConfigMap # 创建的资源类型
metadata: # 元数据
name: config3 # 名称
data:
db.host: 192.168.23.80
db.port: "3306"
spring.datasource.type: "com.alibaba.druid.pool.DruidDataSource"
blog: "moonce"
创建
kubectl apply -f db.yaml
查验
kubectl get cm config3 -o yaml
3.环境变量方式使用configmap
使用valueFrom
、configMapKeyRef
、name
、key
指定要用的key。
vi cm-pod.yaml
---
apiVersion: v1 # 配置格式的版本
kind: Pod # 创建的资源类型
metadata: # 元数据
name: cmpod # 名称
spec:
containers:
- name: myapp
image: busybox
args: ["/bin/sh","-c","sleep 3000"]
env:
- name: DB_HOST # pod环境变量中的名字
valueFrom:
configMapKeyRef:
name: config3 # 到config3中取值
key: db.host # 取config3中的db.host的值
- name: DB_PORT # pod环境变量中的名字
valueFrom:
configMapKeyRef:
name: config3 # 到config3中取值
key: db.port # 取config3中的db.port的值
运行pod
kubectl create -f cm-pod.yaml
进入pod容器中,查看环境信息已经引入
kebectl exec -it cmpod /bin/sh
4.volume挂载使用
把configmap当作文件挂载进pod容器
vi cm-pod2.yaml
---
apiVersion: v1 # 配置格式的版本
kind: Pod # 创建的资源类型
metadata: # 元数据
name: cmpod2 # 名称
spec:
containers:
- name: myapp
image: busybox
args: ["/bin/sh","-c","sleep 3000"]
volumeMounts:
- name: db
mountPath: "/etc/db" # 挂载到/etc/db路径下
readOnly: true
volumes:
- name: db
configMap:
name: config3 # 挂载config3
运行pod
kubectl create -f cm-pod2.yaml
进入容器
kebectl exec -it cmpod2 /bin/sh
可以看到在挂载点/etc/db
下,configMap
的值被引入
相关文章
【Kubernetes】centos7搭建k8s集群(一) - 环境搭建与安装
【Kubernetes】centos7搭建k8s集群(二) - 操作命令与讲解
【Kubernetes】centos7搭建k8s集群(三) - 存储使用与讲解
【Kubernetes】centos7搭建k8s集群(四) - 网络原理讲解
更多推荐
所有评论(0)