目录

ConfigMap配置管理

使用configmap设置环境变量

通过数据卷使用configmap 

configmap热更新

​Secret配置管理 

​Volumes配置管理 

 emptyDir卷(临时卷)

hostPath 卷

​实现不同节点之间文件共享

 PersistentVolume(持久卷) PV

静态PV创建

NFS动态分配PV

使用statefullset部署mysql主从集群:

          部署 MySQL

StatefulSet


ConfigMap配置管理

Configmap用于保存配置数据,以键值对形式存储。

configMap 资源提供了向 Pod 注入配置数据的方法。 旨在让镜像和配置文件解耦,以便实现镜像的可移植性和可复用性。 典型的使用场景:

填充环境变量的值
设置容器内的命令行参数
填充卷的配置文件

创建ConfigMap的方式有4种: 使用字面值创建 使用文件创建 使用目录创建 编写configmap的yaml文件创建

mkdir configmap
cd configmap/
ls
kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2

#使用字面值创建ConfigMap
kubectl get cm
kubectl describe cm my-config #可以看到键值对
kubectl create configmap my-config-2 --from-file=/etc/resolv.conf #使用文件创建
kubectl get cm
kubectl describe cm my-config-2 #可以看到key是文件名

mkdir test
ls
cp /etc/resolv.conf /etc/fstab test/
ls test/
kubectl create configmap my-config-3 --from-file=test #使用目录创建
kubectl describe cm my-config-3 #读取目录里面的所有文件,文件名是key,文件内容是值

vim cm1.yml #编写configmap的yaml文件
kubectl apply -f cm1.yml
kubectl get cm
kubectl describe cm cm1-config #直接输出所需要的值

使用configmap设置环境变量

vim pod1.yaml #将db_host数值赋给key1,db_port值赋给key2
kubectl get pod
kubectl delete pod demo #删除多余的pod
cd
cd calico/
ls
kubectl delete -f policy.yaml
kubectl delete deployments.apps deployment-nginx
kubectl get svc
kubectl delete svc myapp-v1
kubectl get pod
cd
cd configmap
ls
kubectl apply -f pod1.yaml
kubectl get pod
kubectl logs pod1 #环境变量输出cm1-config的内容

kubectl delete pod pod1
vim pod2.yaml #设置全部输出
kubectl apply -f pod2.yaml
kubectl get pod
kubectl logs pod1
kubectl delete pod pod1
vim pod3.yaml #使用conigmap设置命令行参数
kubectl apply -f pod3.yaml
kubectl logs pod1 #输出指定的数值
kubectl delete pod pod1

通过数据卷使用configmap 

vim pod4.yaml #设定查看指定的db_port
kubectl apply -f pod4.yaml
kubectl logs pod2 #只显示port
kubectl delete pod pod2
vim pod4.yaml #设定查看/config/*
kubectl apply -f pod4.yaml
 kubectl logs pod2
kubectl describe cm cm1-config

 vim pod4.yaml #修改镜像为nginx
 kubectl delete pod pod2
kubectl apply -f pod4.yaml
kubectl get pod
kubectl exec pod2 -- ls /config #进入pod2看到文件的内容
kubectl exec pod2 -- cat /config/db_host
kubectl exec pod2 -- cat /config/db_port
kubectl edit cm cm1-config #编辑configmap修改port为8080
kubectl exec pod2 -- cat /config/db_port #之后生效
kubectl delete pod pod2

configmap热更新

vim nginx.conf
kubectl create configmap nginxconf --from-file=nginx.conf
kubectl get cm
kubectl delete cm my-config my-config-2 my-config-3 cm1-config #清除环境
kubectl get cm
kubectl describe cm nginxconf
ls
vim nginx.yaml #创建nginx服务
kubectl apply -f nginx.yaml
kubectl get pod
kubectl get pod -o wide
curl 10.244.141.211 #不能用这种方式访问,里面的端口设定为8000
curl 10.244.141.211:8000 #成功访问

kubectl edit cm nginxconf #修改端口为8080
kubectl get pod
kubectl exec my-nginx-7b84dc948c-tkm84 -- cat /etc/nginx/conf.d/nginx.conf #可以看到修改的已经变了
curl 10.244.141.211:8000 #还是可以访问之前的8000
curl 10.244.141.211:8080 #访问不了8080,没有生效,因为修改的是纯文本(相当于修改了配置文件没有重启)可以看出configmap热更新以生效,但访问Pod的8080端口是无效的
kubectl get all
kubectl patch deployments.apps my-nginx --patch '{"spec": {"template": {"metadata": {"annotations": {"version/config": "20220330"}}}}}' #需要手动触发Pod滚动更新, 这样才能再次加载nginx.conf配置文件
 kubectl get all
kubectl get pod -o wide #ip已经改变
curl 10.244.141.212:8080 #不能访问
curl 10.244.141.212:8000 #成功访问

kubectl edit cm nginxconf #修改端口为80
kubectl get pod
kubectl delete pod my-nginx-69566b85d5-f4zrd #删除pod
kubectl get pod #控制器会自动检测到副本数量,重新生成pod(相当于自动更新)
kubectl get pod -o wide
curl 10.244.141.213:80 #可以成功访问

Secret配置管理 

Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 ssh key。  
敏感信息放在 secret 中比放在 Pod 的定义或者容器镜像中来说更加安全和灵活。 
Pod 可以用两种方式使用 secret:
      作为 volume 中的文件被挂载到 pod 中的一个或者多个容器里。 
      当 kubelet 为 pod 拉取镜像时使用。
Secret的类型:
Service Account:Kubernetes 自动创建包含访问 API 凭据的 secret,并自动修改pod 以使用此类型的 secret。
Opaque:使用base64编码存储信息,可以通过base64 --decode解码获得原始数据,因此安全性弱。
kubernetes.io/dockerconfigjson:用于存储docker registry的认证信息。

kubectl delete -f nginx.yaml
kubectl get pod
kubectl get secrets
kubectl get secrets -n test
kubectl get sa #所有的namespace创建的pod通过默认的sa连接APIserver完成身份鉴全的过程。sa里面有default-token
kubectl run demo --image=nginx
kubectl describe pod demo ##serviceaccout 创建时 Kubernetes 会默认创建对应的 secret。对应的 secret 会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中
kubectl create secret generic dev-db-secret --from-literal=username=devuser --from-literal=password=S\!B\\*d\$zDsb #创建secret,如果密码具有特殊字符,则需要使用 \ 字符对其进行转义
kubectl get secrets ##每个namespace下有一个名为default的默认的ServiceAccount对象
kubectl describe secrets dev-db-secret #默认情况下 kubectl get和kubectl describe 为了安全是不会显示密码的内容,
kubectl get secrets dev-db-secret -o yaml #可以通过此方式查看密码
echo "ZGV2dXNlcg==" |base64 --decode #base64编码的值
ls

vim secret.yaml ##编写一个 secret 对象
kubectl apply -f secret.yaml
kubectl get secrets
kubectl get secrets mysecret   -o yaml #查看密码内容
vim secret.yaml ##将Secret挂载到Volume中
kubectl apply -f secret.yaml
kubectl get pod
kubectl delete pod demo
kubectl exec mysecret -- ls /secret ##进入容器查看
kubectl exec mysecret -- cat /secret/username
kubectl exec mysecret -- cat /secret/password
kubectl delete pod mysecret

vim secret.yaml #向指定路径映射 secret 密钥
kubectl apply -f secret.yaml
kubectl exec mysecret --ls /secret
kubectl exec mysecret -- ls /secret
kubectl exec mysecret -- ls /secret/my-group
kubectl exec mysecret -- ls /secret/my-group/my-username
kubectl exec mysecret -- cat /secret/my-group/my-username #只有所需要的key信息在指定的路径
kubectl delete pod mysecret

vim secret2.yaml  #将Secret设置为环境变量
kubectl apply -f secret2.yaml
kubectl get pod
kubectl exec secret-env -- env #进入使用env查看
echo redhat | base64 #编码redhat为base64
kubectl edit secrets mysecret #修改password
kubectl exec secret-env -- env #还是原来的password,环境变量读取Secret很方便,但无法支撑Secret动态更新
 kubectl delete -f secret2.yaml #删除重新运行使之生效
kubectl apply -f secret2.yaml
kubectl exec secret-env -- env #password变为redhat
kubectl delete -f secret2.yaml
kubectl get pod

ls
vim demo.yaml
kubectl apply -f demo.yaml
kubectl get pod #出现镜像拉取失败
kubectl describe pod mypod #查看具体信息发现私有仓库westos需要认证
kubectl delete -f demo.yaml
kubectl create secret docker-registry myregistrykey --docker-server=reg.westos.org --docker-username=wxh --docker-password=Westos007 --docker-email=yakexi007@westos.org

##kubernetes.io/dockerconfigjson用于存储docker registry的认证信息
kubectl get secrets

 在harbor仓库中新建用户

 将用户加入到私有仓库中

vim demo.yaml #在yaml文件中加入镜像拉取secret
kubectl apply -f demo.yaml
kubectl get pod #pod为runnng
kubectl delete -f demo.yaml

 kubectl get sa
 kubectl describe sa default

 kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "myregistrykey"}]}'##将认证信息添加到serviceAccount中,要比直接在Pod指定imagePullSecrets要安全很多

 kubectl describe sa default #将认证信息添加进去,运行pod时如果没有指定则使用默认的
vim demo.yaml #注释掉认证信息
kubectl apply -f demo.yaml
kubectl get pod #可以看到pod运行
kubectl describe pod mypod #查看详细信息
kubectl exec mypod -- ls /var/run/secrets/kubernetes.io/serviceaccount #进入pod查看挂载信息

Volumes配置管理 

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

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

卷不能挂载到其他卷,也不能与其他卷有硬链接。 Pod 中的每个容器必须独立地指定每个卷的挂载位置

 Kubernetes 支持下列类型的卷: awsElasticBlockStore 、azureDisk、azureFile、cephfs、cinder、configMap、csi downwardAPI、emptyDir、fc (fibre channel)、flexVolume、flocker gcePersistentDisk、gitRepo (deprecated)、glusterfs、hostPath、iscsi、local、 nfs、persistentVolumeClaim、projected、portworxVolume、quobyte、rbd scaleIO、secret、storageos、vsphereVolume 

 emptyDir卷(临时卷)

    当 Pod 指定到某个节点上时,首先创建的是一个 emptyDir 卷,并且只要 Pod 在该节点上运行,卷就一直存在。 就像它的名称表示的那样,卷最初是空的。 尽管 Pod 中的容器挂载 emptyDir 卷的路径可能相同也可能不同,但是这些容器都可以读写 emptyDir 卷中相同的文件。 当 Pod 因为某些原因被从节点上删除时,emptyDir 卷中的数据也会永久删除

    emptyDir 的使用场景: 缓存空间,例如基于磁盘的归并排序。 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。 在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件

   默认情况下, emptyDir 卷存储在支持该节点所使用的介质上;这里的介质可以是磁盘或 SSD 或网络存储,这取决于您的环境。 但是,您可以将 emptyDir.medium 字段设置为 "Memory",以告诉 Kubernetes 为您安装 tmpfs(基于 RAM 的文件系统)。 虽然 tmpfs 速度非常快,但是要注意它与磁盘不同。 tmpfs 在节点重启时会被清除,并且所写入的所有文件都会计入容器的内存消耗,受容器内存限制约束。

 mkdir volume
cd volume/
 ls
vim pod.yaml #不同容器挂载相同卷,pod通过卷为两个容器提供共享存储,物理内存限制使用100MB
kubectl apply -f pod.yaml
kubectl get pod
kubectl delete pod mypod
kubectl get pod
kubectl get pod -o wide #调度到server3上
curl 10.244.141.229 #访问403报错,因为没有发布页面
 kubectl exec -it vol1 -c vm1 -- sh #进入容器vm1,编辑发布页
kubect get pod
kubectl get pod
kubectl delete -f pod.yaml

同一pod内容器之间的网络栈是共享的

重新打开一个终端,成功访问

使用dd命令生成200M的文件,可以看到提示报错,因为限制物理内存使用100M

emptydir缺点:
不能及时禁止用户使用内存。虽然过1-2分钟kubelet会将Pod挤出,但是这个时间内,其实对node还是有风险的;
影响kubernetes调度,因为empty dir并不涉及node的resources,这样会造成Pod“偷偷”使用了node的内存,但是调度器并不知晓;
用户不能及时感知到内存不可用

hostPath 卷

能将主机节点文件系统上的文件或目录挂载到 Pod 中。 虽然这不是大多数 Pod 需要的,但是它为一些应用程序提供了强大的逃生舱

hostPath 的一些用法有: 运行一个需要访问 Docker 引擎内部机制的容器;挂载 /var/lib/docker 路径。 在容器中运行 cAdvisor 时,以 hostPath 方式挂载 /sys。 允许 Pod 指定给定的 hostPath 在运行 Pod 之前是否应该存在,是否应该创建以及应该以什么方式存在。

当使用这种类型的卷时要小心,因为: 具有相同配置(例如从 podTemplate 创建)的多个 Pod 会由于节点上文件的不同而在不同节点上有不同的行为。 当 Kubernetes 按照计划添加资源感知的调度时,这类调度机制将无法考虑由 hostPath 使用的资源。 基础主机上创建的文件或目录只能由 root 用户写入。您需要在 特权容器 中以 root 身份运行进程,或者修改主机上的文件权限以便容器能够写入 hostPath 卷。

vim vol1.yaml #以 hostPath 方式挂载 到/data
kubectl apply -f vol1.yaml
kubectl get pod
kubectl get pod -o wide #调度到server3上
curl 10.244.141.230 #访问403报错
kubectl delete -f vol1.yaml
vim vol1.yaml #指定调度节点为server4
kubectl apply -f vol1.yaml
kubectl get pod
kubectl get pod -o wide
curl 10.244.22.10 #访问依旧报错,Pod 会由于节点上文件的不同而在不同节点上有不同的行为
kubectl delete -f vol1.yaml

在server3上自动创建/data,写入数据

在server2上可以成功访问

查看server4自动创建/data。写入数据

可以成功访问

实现不同节点之间文件共享

mkdir /nfsshare
chmod 777 /nfsshare
showmount -e

vim nfs.yaml
kubectl apply -f nfs.yaml
kubectl get pod
kubectl get pod -o wide
 curl 10.244.141.231
kubectl delete -f nfs.html
kubectl delete -f nfs.yaml
vim nfs.yaml #指定调度节点为server4
kubectl apply -f nfs.yaml
kubectl get pod -o wide
 curl 10.244.22.11 #直接可以访问实现数据共享

server3和server4node节点安装nfs,并且挂到server1的/nfsshare

 在/nfsshare目录下写入数据

pod 可以成功访问

 PersistentVolume(持久卷) PV

 PersistentVolume(持久卷,简称PV)是集群内,由管理员提供的网络存储的一部分。就像集群中的节点一样,PV也是集群中的一种资源。它也像Volume一样,是一种volume插件,但是它的生命周期却是和使用它的Pod相互独立的。PV这个API对象,捕获了诸如NFS、ISCSI、或其他云存储系统的实现细节。 

PersistentVolumeClaim(持久卷声明,简称PVC)是用户的一种存储请求。它和Pod类似,Pod消耗Node资源,而PVC消耗PV资源。Pod能够请求特定的资源(如CPU和内存)。PVC能够请求指定的大小和访问的模式(可以被映射为一次读写或者多次只读)

有两种PV提供的方式:静态和动态。

静态PV:集群管理员创建多个PV,它们携带着真实存储的详细信息,这些存储对于集群用户是可用的。它们存在于Kubernetes API中,并可用于存储使用。 

动态PV:当管理员创建的静态PV都不匹配用户的PVC时,集群可能会尝试专门地供给volume给PVC。这种供给基于StorageClass。

PVC与PV的绑定是一对一的映射。没找到匹配的PV,那么PVC会无限期得处于unbound未绑定状态。

静态PV创建

server1中创建两个目录

mkdir pvc
cd pvc/
vim pv1.yaml
kubectl apply -f pv1.yaml
kubectl get pv

vim pv1.yaml #创建NFS PV卷
kubectl apply -f pv1.yaml
kubectl get pv #当前是空闲的资源,未绑定给PVC

vim pvc1.yaml #创建PVC
kubectl apply -f pvc1.yaml
kubectl get pvc
kubectl get pv #绑定给了PVC1

vim pvc1.yaml
kubectl apply -f pvc1.yaml
kubectl get pvc
kubectl get pv #pv1和pv2都绑定了

vim pod.yaml #Pod挂载PV 
kubectl get pod
 kubectl delete pod test-pd
kubectl apply -f pod.yaml
kubectl get pod
kubectl get pod -o wide #调度到server3
curl 10.244.141.232 #访问403报错
kubectl delete -f pod.yaml
kubectl get pvc
kubectl delete pvc pvc1 #删除pvc1
kubectl get pv #PVC已经删除了,但是PV还没有被集群回收
kubectl describe pv pv1 #查看信息可知在回收时在拉取镜像busybox
kubectl delete pv pv1
kubectl get pv

在server1的/nfsshare/pv1写入数据

可以成功访问

NFS动态分配PV

StorageClass提供了一种描述存储类(class)的方法,不同的class可能会映射到不同的服务质量等级和备份策略或其他策略等。 

每个 StorageClass 都包含 provisioner、parameters 和 reclaimPolicy 字段, 这些字段会在StorageClass需要动态分配 PersistentVolume 时会使用到。 

StorageClass的属性

Provisioner(存储分配器):用来决定使用哪个卷插件分配 PV,该字段必须指定。可以指定内部分配器,也可以指定外部分配器。外部分配器的代码地址为: kubernetes-incubator/external-storage,其中包括NFS和Ceph等。 

Reclaim Policy(回收策略):通过reclaimPolicy字段指定创建的Persistent Volume的回收策略,回收策略包括:Delete 或者 Retain,没有指定默认为Delete。

NFS Client Provisioner是一个automatic provisioner,使用NFS作为存储,自动创建PV和对应的PVC,本身不提供NFS存储,需要外部先有一套NFS存储服务。 PV以 ${namespace}-${pvcName}-${pvName}的命名格式提供(在NFS服务器上) PV回收的时候以 archieved-${namespace}-${pvcName}-${pvName} 的命名格式(在NFS服务器上) 

 删除之前创建的pv目录,动态pv会自动创建

kubectl get pod
kubectl get pvc
kubectl get pv
kubectl delete pv pv2
kubectl delete pvc pvc2
kubectl get pvc
kubectl get pv
mkdir nfs
cd nfs/
ls
kubectl create namespace nfs-client-provisioner #创建namespace
kubectl get ns

vim deploy.yaml #默认回收打包
kubectl apply -f deploy.yaml
kubectl get pod -n nfs-client-provisioner
kubectl get storageclasses.storage.k8s.io 

上传所需镜像到本地仓库

vim pvc.yaml
kubectl apply -f pvc.yaml
kubectl get pvc #获取pvc处于绑定状态
kubectl get pv
kubectl get pod
kubectl get pod -o wide
curl 10.244.141.236 #访问失败,因为没有默认发布页面
kubectl delete -f pvc.yaml #在删除pvc时会连pv一起删掉
kubectl get pod
kubectl get pvc
kubectl get pv

可以看到动态创建的目录,在目录地下写入数据

 访问成功

看到挂接的目录中变为回收打包状态

vim pvc.yaml #创建三个pvc
kubectl apply -f pvc.yaml
kubectl get pvc #绑定状态
kubectl get pv
kubectl delete -f pvc.yaml
kubectl delete storageclasses.storage.k8s.io nfs-client #删除创建的StorageClass存储类

创建三个pvc之后目录动态更新

删除之后变为回收打包,手动删除

vim deploy.yaml #将PV回收时改为不打包,直接删除
kubectl apply -f deploy.yaml
kubectl get storageclasses.storage.k8s.io
kubectl apply -f pvc.yaml
kubectl get pv
kubectl get pvc

可以看到自动创建

kubectl delete -f pvc.yaml
kubectl get pvc
kubectl get pv 

删除pvc之后,目录自动清除

默认的 StorageClass 将被用于动态的为没有特定 storage class 需求的 PersistentVolumeClaims配置存储:(只能有一个默认StorageClass) 如果没有默认StorageClass,PVC 也没有指定storageClassName 的值,那么意味着它只能够跟 storageClassName的 PV 进行绑定。  

kubectl patch storageclass nfs-client -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}' ##添加nfs-client为默认的 storage class
kubectl get storageclasses.storage.k8s.io
vim pvc.yaml #注释掉yaml文件中添加的 storage class
kubectl apply -f pvc.yaml
kubectl get pvc #可以成功获得pvc
kubectl delete -f pvc.yaml

StatefulSet如何通过Headless Service维持Pod的拓扑状态

打开server1上nfs

kubectl get pod -n nfs-client-provisioner
kubectl get pod
mkdir statefulset
cd statefulset/
ls
vim headless.yaml # 创建nginx service
kubectl apply -f headless.yaml
kubectl get svc
kubectl describe svc nginx #可以看到endpoint没有端口,还没创建后端的pod,service是pod的访问入口,所有的外部流量都要通过svc来访问pod

 StatefulSet将应用状态抽象成了两种情况:

拓扑状态:应用实例必须按照某种顺序启动。新创建的Pod必须和原来Pod的网络标识一样

存储状态:应用的多个实例分别绑定了不同存储数据。 

StatefulSet给所有的Pod进行了编号,编号规则是:$(statefulset名称)-$(序号),从0开始。 

vim statefulset.yaml #创建statefulset控制器
kubectl apply -f statefulset.yaml
kubectl get pod #有序创建,所有pod从0开始,依次往上单调递增
kubectl describe svc nginx #出现两个endpoint

vim statefulset.yaml #将副本数改为0
kubectl apply -f statefulset.yaml
kubectl get pod #有序回收
kubectl get all #控制器还在

vim statefulset.yaml #将副本数改为3
kubectl apply -f statefulset.yaml
kubectl get pod #有序创建,网络标识和之前的一样
kubectl get svc

Pod的拓扑状态按照Pod的“名字+编号”的方式固定下来,并且为每个Pod提供了一个固定且唯一的访问入口,即Pod对应的DNS记录
dig -t A nginx.default.svc.cluster.local. @10.96.0.10  #service有解析
dig -t A web-0.nginx.default.svc.cluster.local. @10.96.0.10 #pod 有唯一的解析,重建之前地址会变
dig -t A web-1.nginx.default.svc.cluster.local. @10.96.0.10

删除过程

vim statefulset.yaml #将副本数改为0
kubectl apply -f statefulset.yaml #回收pod
kubectl delete -f statefulset.yaml #之后删除

 PV和PVC的设计,使得StatefulSet对存储状态的管理

vim statefulset.yaml #挂载卷到nginx发布目录,调用pvc模板,存储类为默认的,创建pvc,后端有动态存储,自动绑定
kubectl apply -f statefulset.yaml
kubectl get pod #有序创建,并且创建存储
kubectl get pv
kubectl get pvc #创建成功

StatefulSet会为每一个Pod分配并创建一个同样编号的PVC。这样,kubernetes就可以通过Persistent Volume机制为这个PVC绑定对应的PV,从而保证每一个Pod都拥有一个独立的Volume

 自动创建了三个存储目录

在目录中写入测试页,便于查看

dig -t A web-0.nginx.default.svc.cluster.local. @10.96.0.10
dig -t A web-1.nginx.default.svc.cluster.local. @10.96.0.10 #标识依旧没有变
kubectl run demo --image=busyboxplus -it --restart=Never#进入容器访问,可以看到发布页,负载均衡
kubectl get pod
kubectl delete pod demo 

唯一的标识

vim statefulset.yaml #有序回收,将副本数改为0
kubectl apply -f statefulset.yaml
kubectl get pod
kubectl get pvc #存储保留下来
kubectl get pv

vim statefulset.yaml #再次创建将副本数改为3
kubectl apply -f statefulset.yaml
kubectl get pod
kubectl run demo --image=busyboxplus -it --restart=Never #进入容器访问svc,并且访问web-0原来的标识没变,说明pod重建之后存储是稳定持久的,标识不变,有序的

使用statefullset部署mysql主从集群:

kubectl delete pod demo #清理实验环境
kubectl get pod
kubectl get pv
kubectl delete -f headless.yaml
kubectl delete pvc --all
kubectl get pv

部署 MySQL

MySQL 示例部署包含一个 ConfigMap、两个 Service 与一个 StatefulSet

mkdir mysql/
cd mysql/
ls
vim cm.yaml #创建 ConfigMap,这个 ConfigMap 提供 my.cnf 覆盖设置,可以独立控制 MySQL 主服务器和从服务器的配置
kubectl apply -f cm.yaml
kubectl get cm
kubectl describe cm mysql

 master.cnf #主服务器的配置文件

slave.cnf # 从服务器的配置文件

这个无头服务给 StatefulSet 控制器为集合中每个 Pod 创建的 DNS 条目提供了一个宿主。 因为无头服务名为 mysql,所以可以通过在同一 Kubernetes 集群和命名空间中的任何其他 Pod 内解析 <Pod 名称>.mysql 来访问 Pod。

客户端服务称为 mysql-read,是一种常规服务,具有其自己的集群 IP。 该集群 IP 在报告就绪的所有MySQL Pod 之间分配连接。 可能的端点集合包括 MySQL 主节点和所有副本节点。

vim svc.yaml #创建服务
 kubectl apply -f svc.yaml
kubectl get svc

StatefulSet

vim mysql.yaml #创建 StatefulSet,首先设置副本数为1,启动pod
kubectl apply -f mysql.yaml#该脚本通过从 Pod 名称的末尾提取索引来确定自己的序号索引,而 Pod 名称由 hostname 命令返回。 然后将序数(带有数字偏移量以避免保留值)保存到 MySQL conf.d 目录中的文件 server-id.cnf
kubectl get pod #运行Init 容器
kubectl get pvc #获得pvc
kubectl get pv
dig -t A mysql-0.mysql.default.svc.cluster.local @10.96.0.10 #可以解析到ip

 同时在共享的目录下生成mysql目录

vim mysql.yaml #设置副本数为0,回收pod
kubectl apply -f mysql.yaml
kubectl get pod

vim mysql.yaml #加入clone-mysql 的 Init 容器
kubectl apply -f mysql.yaml

第二个名为 clone-mysql 的 Init 容器,第一次在带有空 PersistentVolume 的副本 Pod 上启动时,会在从属 Pod 上执行克隆操作。 这意味着它将从另一个运行中的 Pod 复制所有现有数据,使此其本地状态足够一致, 从而可以开始从主服务器复制。

MySQL 本身不提供执行此操作的机制,因此本示例使用了一种流行的开源工具 Percona XtraBackup。 在克隆期间,源 MySQL 服务器性能可能会受到影响。 为了最大程度地减少对 MySQL 主服务器的影响,该脚本指示每个 Pod 从序号较低的 Pod 中克隆。 可以这样做的原因是 StatefulSet 控制器始终确保在启动 Pod N + 1 之前 Pod N 已准备就绪

kubectl get pod #看到pod已经running
kubectl describe pod mysql-0 #查看详细信息
kubectl logs mysql-0 -c init-mysql #查看init-mysql的日志通过从 Pod 名称的末尾提取索引来确定自己的序号索引,而 Pod 名称由 hostname 命令返回。 然后将序数(带有数字偏移量以避免保留值)保存到 MySQL conf.d 目录中的文件 server-id.cnf
kubectl logs mysql-0 -c clone-mysql #查看clone-mysql,将从另一个运行中的 Pod 复制所有现有数据,使此其本地状态足够一致, 从而可以开始从主服务器复制。
kubectl logs mysql-0 -c xtrabackup#

Init 容器成功完成后,应用容器将运行。 MySQL Pod 由运行实际 mysqld 服务的 mysql 容器和充当 辅助工具 的 xtrabackup 容器组成。

xtrabackup sidecar 容器查看克隆的数据文件,并确定是否有必要在副本服务器上初始化 MySQL 复制。 如果是这样,它将等待 mysqld 准备就绪,然后使用从 XtraBackup 克隆文件中提取的复制参数 执行 CHANGE MASTER TOSTART SLAVE 命令。

一旦副本服务器开始复制后,它会记住其 MySQL 主服务器,并且如果服务器重新启动或 连接中断也会自动重新连接。 另外,因为副本服务器会以其稳定的 DNS 名称查找主服务器(mysql-0.mysql), 即使由于重新调度而获得新的 Pod IP,它们也会自动找到主服务器。

最后,开始复制后,xtrabackup 容器监听来自其他 Pod 的连接,处理其数据克隆请求。 如果 StatefulSet 扩大规模,或者下一个 Pod 失去其 PersistentVolumeClaim 并需要重新克隆, 则此服务器将无限期保持运行。

kubectl run demo --image=mysql:5.7 --restart=Never -it bash执行

mysql -h mysql-0.mysql

#运行带有 mysql:5.7 镜像的临时容器并运行 mysql 客户端二进制文件, 将测试查询发送到 MySQL 主服务器(主机名 mysql-0.mysql)创建数据库,写入数据

 在server1上可以看到数据已经同步过来

vim mysql.yaml #设置副本数为2
kubectl apply -f mysql.yaml #创建pod mysql-1
kubetl get pod
kubectl get pod
kubectl logs mysql-1 -c init-mysql
kubectl logs mysql-1 -c clone-mysql #可以看到从mysql-0的3307端口复制数据
 kubectl get pvc#pvc与pv自动绑定
 kubectl exec mysql-1 -c mysql -it -- bash #进入mysql-1可以看到mysql-0创建的数据库已经复制过来
kubectl logs mysql-1 -c xtrabackup #可以看到从 XtraBackup 克隆文件中提取的复制参数 执行 CHANGE MASTER TOSTART SLAVE 命令。

 创建的westos数据库信息已经复制到从服务器

 


 vim mysql.yaml #设置副本数为3,创建pod mysql-2
kubectl apply -f mysql.yaml
 kubectl get pod #有序初始化
kubectl get pod -o wide
kubectl get pod
kubectl logs mysql-2 -c init-mysql #复制slave.cnf到指定目录
kubectl logs mysql-2 -c clone-mysql #从mysql-1复制数据,实现主从复制
kubectl logs mysql-2 -c xtrabackup

vim mysql.yaml #设置副本数为0,
kubectl apply -f mysql.yaml
kubectl get pod #进行pod的有序回收,删除集群
kubectl delete pvc --all
kubectl get pv
kubectl get pod
kubectl get pv

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐