Kubernetes 有状态应用基本概念&Nginx部署

时间:2022-03-22 03:52:57

Kubernetes 有状态应用基本概念&Nginx部署

1、无状态与有状态

Deployment控制器设计原则:管理的所有Pod一模一样,提供同一个服务,也不考虑在哪台Node运行,可随意扩容和缩容。这种应用称为“无状态”,例如Web服务

但是,在实际的场景中,并不能满足所有应用,尤其是分布式应用,会部署多个实例,这些实例之间往往有依赖关系,例如主从关系、主备关系,这种应用称为“有状态”,例如MySQL主从、Etcd集群、redis-cluster 等等

2、StatefulSet 控制器概述

StatefulSet控制器用于部署有状态应用,满足一些有状态应用的需求:

  • Pod有序的部署、扩容、删除和停止
  • Pod分配一个稳定的且唯一的网络标识
  • Pod分配一个独享的存储

3、StatefulSet 控制器:网络标识

稳定的网络标识:

使用无头服务 Headless Service(相比普通Service只是将spec.clusterIP定义为None,也就是没有clusterIP,使用endport 来通信)来维护Pod网络身份,会为每个Pod分配一个数字编号并且按照编号顺序部署。还需要在StatefulSet添加serviceName: “nginx”字段指定StatefulSet控制器要使用这个Headless Service。

稳定主要体现在主机名和Pod A记录:

  • 主机名:-<编号>
  • Pod DNS A记录:. ..svc.cluster.local (POD 之间通过DNS A 记录通信)

例如: web-0.web.default.svc.cluster.local

  1. 备注:
  2. A记录:将域名指向一个IPv4地址(例如:100.100.100.100),需要增加A记录
  3. CNAME记录:如果将域名指向一个域名,实现与被指向域名相同的访问效果,需要增加CNAME记录。这个域名一般是主机服务商提供的一个域名
  4. MX记录:建立电子邮箱服务,将指向邮件服务器地址,需要设置MX记录。建立邮箱时,一般会根据邮箱服务商提供的MX记录填写此记录
  5. NS记录:域名解析服务器记录,如果要将子域名指定某个域名服务器来解析,需要设置NS记录
  6. TXT记录:可任意填写,可为空。一般做一些验证记录时会使用此项,如:做SPF(反垃圾邮件)记录
  7. AAAA记录:将主机名(或域名)指向一个IPv6地址(例如:ff03:0:0:0:0:0:0:c1),需要添加AAAA记录

案例:

通过创建一个 nginx 应用的statefluset 控制器

创建 Headless Service ,定义 clusterIP: None (表示K8S 不会在给这个service 去颁发一个clusterIP 了;相比 deployment 控制器 的每个POD 都是相同的,而 statefuset 控制器的每个POD 都是有状态的

需要单独去访问 )

  1. [root@master-1statefulset]#vimservice.yaml
  2. apiVersion:v1
  3. kind:Service
  4. metadata:
  5. name:web
  6. spec:
  7. clusterIP:None
  8. ports:
  9. -protocol:TCP
  10. port:80
  11. selector:
  12. app:nginx
  13. [root@master-1statefulset]#kubectlapply-fservice.yaml
  14. [root@master-1statefulset]#kubectlgetservice
  15. NAMETYPECLUSTER-IPEXTERNAL-IPPORT(S)AGE
  16. webClusterIPNone80/TCP8m18s

#创建statefulset,指定serviceName

  1. [root@master-1statefulset]#catstatefulset.yaml
  2. apiVersion:apps/v1
  3. kind:StatefulSet
  4. metadata:
  5. name:web
  6. spec:
  7. serviceName:"web"
  8. replicas:3
  9. selector:
  10. matchLabels:
  11. app:nginx
  12. template:
  13. metadata:
  14. labels:
  15. app:nginx
  16. spec:
  17. containers:
  18. -name:nginx
  19. image:nginx
  20. ports:
  21. -containerPort:80
  22. name:web
  23. [root@master-1statefulset]#kubectlapply-fstatefulset.yaml
  24. statefulset.apps/webcreated
  25. #发现pod名称带有序号
  26. [root@master-1statefulset]#kubectlgetpods
  27. NAMEREADYSTATUSRESTARTSAGE
  28. web-01/1Running016s
  29. web-11/1Running013s
  30. web-21/1Running06s
  31. #查了POD的主机名
  32. 主机名默认与POD名一致,即使POD飘逸到其他node上或者删除后重建主机名都是和POD名一致。有个稳定的主机名
  33. [root@master-1statefulset]#kubectlexec-itweb-0--hostname
  34. web-0
  35. [root@master-1statefulset]#kubectlexec-itweb-1--hostname
  36. web-1
  37. [root@master-1statefulset]#kubectlexec-itweb-2--hostname
  38. web-2
  39. #临时启动一个busyboxpod,测试dns解析(注意这里的busybox版本为1.28.4最新版的busyboxnslookup会有问题)
  40. [root@master-1statefulset]#kubectlrun-itdns-test--rm--image=busybox:1.28.4--sh
  41. /#nslookupweb
  42. Server:10.0.0.2
  43. Address1:10.0.0.2kube-dns.kube-system.svc.cluster.local
  44. Name:web
  45. Address1:10.244.2.114web-2.web.default.svc.cluster.local
  46. Address2:10.244.2.113web-0.web.default.svc.cluster.local
  47. Address3:10.244.1.65web-1.web.default.svc.cluster.local
  48. 可以看到解析出3条记录出来,解析出对应的三个PodIP记录,其他Pod可使用这个名称访问
  49. 模拟测试删除这些pod,升级镜像版本,发现podip虽然发生变化,但是主机名,PodDNSA记录不会发生变化
  50. /#nslookupweb
  51. Server:10.0.0.2
  52. Address1:10.0.0.2kube-dns.kube-system.svc.cluster.local
  53. Name:web
  54. Address1:10.244.2.116web-2.web.default.svc.cluster.local
  55. Address2:10.244.2.115web-0.web.default.svc.cluster.local
  56. Address3:10.244.1.66web-1.web.default.svc.cluster.local

这个就验证了 statefulset 的 Pod是 有序的部署、扩容、删除和停止 且 给每一个POD 分配一个稳定的且唯一的网络标识

4、StatefulSet 控制器:独享存储

独享存储:StatefulSet的存储卷使用VolumeClaimTemplate创建,称为卷申请模板,当StatefulSet使用VolumeClaimTemplate创建一个PersistentVolume时,

同样也会为每个Pod分配并创建一个编号的PVC,每个PVC绑定对应的PV,从而保证每个Pod都拥有独立的存储。

在创建StatefulSet 控制器 独享存储前,需要先定义好存储卷,使用pv 作为持久化存储卷,后端存储为NFS

这里采用动态PV 的方式(NFS server 搭建的过程省略)

一、部署NFS服务器

  1. #服务器安装nfs服务,提供nfs存储功能
  2. 1、安装nfs-utils
  3. yuminstallnfs-utils(centos)
  4. 或者apt-getinstallnfs-kernel-server(ubuntu)
  5. 2、启动服务
  6. systemctlenablenfs-server
  7. systemctlstartnfs-server
  8. 3、创建共享目录完成共享配置
  9. mkdir/home/nfs#创建共享目录
  10. 4、编辑共享配置
  11. vim/etc/exports
  12. #语法格式:共享文件路径客户机地址(权限)#这里的客户机地址可以是IP,网段,域名,也可以是任意*
  13. /home/nfs*(rw,async,no_root_squash)
  1. 服务自检命令
  2. exportfs-arv
  3. 5、重启服务
  4. systemctlrestartnfs-server
  5. 6、本机查看nfs共享目录
  6. #showmount-e服务器IP地址(如果提示命令不存在,则需要yuminstallshowmount)
  7. showmount-e127.0.0.1
  8. /home/nfs/nginx*
  9. 7、客户端模拟挂载[所有k8s的节点都需要安装客户端]
  10. [root@master-1~]#yuminstallnfs-utils(centos)
  11. 或者apt-getinstallnfs-common(ubuntu)
  12. [root@master-1~]#mkdir/test
  13. [root@master-1~]#mount-tnfs172.16.201.209:/home/nfs/test
  14. #取消挂载
  15. [root@master-1~]#umount/test

二、配置PV 动态供给(NFS StorageClass),创建pvc

#部署NFS实现自动创建PV插件: 一共设计到4个yaml 文件 ,官方的文档有详细的说明

https://github.com/kubernetes-incubator/external-storage

Kubernetes 有状态应用基本概念&Nginx部署
Kubernetes 有状态应用基本概念&Nginx部署
  1. root@k8s-master1:~#mkdir/root/pvc
  2. root@k8s-master1:~#cd/root/pvc

创建rbac.yaml 文件

  1. root@k8s-master1:pvc#catrbac.yaml
  2. kind:ServiceAccount
  3. apiVersion:v1
  4. metadata:
  5. name:nfs-client-provisioner
  6. ---
  7. kind:ClusterRole
  8. apiVersion:rbac.authorization.k8s.io/v1
  9. metadata:
  10. name:nfs-client-provisioner-runner
  11. rules:
  12. -apiGroups:[""]
  13. resources:["persistentvolumes"]
  14. verbs:["get","list","watch","create","delete"]
  15. -apiGroups:[""]
  16. resources:["persistentvolumeclaims"]
  17. verbs:["get","list","watch","update"]
  18. -apiGroups:["storage.k8s.io"]
  19. resources:["storageclasses"]
  20. verbs:["get","list","watch"]
  21. -apiGroups:[""]
  22. resources:["events"]
  23. verbs:["create","update","patch"]
  24. ---
  25. kind:ClusterRoleBinding
  26. apiVersion:rbac.authorization.k8s.io/v1
  27. metadata:
  28. name:run-nfs-client-provisioner
  29. subjects:
  30. -kind:ServiceAccount
  31. name:nfs-client-provisioner
  32. namespace:default
  33. roleRef:
  34. kind:ClusterRole
  35. name:nfs-client-provisioner-runner
  36. apiGroup:rbac.authorization.k8s.io
  37. ---
  38. kind:Role
  39. apiVersion:rbac.authorization.k8s.io/v1
  40. metadata:
  41. name:leader-locking-nfs-client-provisioner
  42. rules:
  43. -apiGroups:[""]
  44. resources:["endpoints"]
  45. verbs:["get","list","watch","create","update","patch"]
  46. ---
  47. kind:RoleBinding
  48. apiVersion:rbac.authorization.k8s.io/v1
  49. metadata:
  50. name:leader-locking-nfs-client-provisioner
  51. subjects:
  52. -kind:ServiceAccount
  53. name:nfs-client-provisioner
  54. #replacewithnamespacewhereprovisionerisdeployed
  55. namespace:default
  56. roleRef:
  57. kind:Role
  58. name:leader-locking-nfs-client-provisioner
  59. apiGroup:rbac.authorization.k8s.io

创建deployment.yaml 文件

#官方默认的镜像地址,国内可能无法下载,可以使用 image:

fxkjnj/nfs-client-provisioner:latest

#定义NFS 服务器的地址,共享目录名称

  1. root@k8s-master1:pvc#catdeployment.yaml
  2. apiVersion:v1
  3. kind:ServiceAccount
  4. metadata:
  5. name:nfs-client-provisioner
  6. ---
  7. kind:Deployment
  8. apiVersion:apps/v1
  9. metadata:
  10. name:nfs-client-provisioner
  11. spec:
  12. replicas:1
  13. strategy:
  14. type:Recreate
  15. selector:
  16. matchLabels:
  17. app:nfs-client-provisioner
  18. template:
  19. metadata:
  20. labels:
  21. app:nfs-client-provisioner
  22. spec:
  23. serviceAccountName:nfs-client-provisioner
  24. containers:
  25. -name:nfs-client-provisioner
  26. image:fxkjnj/nfs-client-provisioner:latest
  27. volumeMounts:
  28. -name:nfs-client-root
  29. mountPath:/persistentvolumes
  30. env:
  31. -name:PROVISIONER_NAME
  32. value:fuseim.pri/ifs
  33. -name:NFS_SERVER
  34. value:172.16.201.209
  35. -name:NFS_PATH
  36. value:/home/nfs
  37. volumes:
  38. -name:nfs-client-root
  39. nfs:
  40. server:172.16.201.209
  41. path:/home/nfs

创建class.yaml

# archiveOnDelete: "true" 表示当PVC 删除后,后端数据不直接删除,而是归档

  1. root@k8s-master1:pvc#catclass.yaml
  2. apiVersion:storage.k8s.io/v1
  3. kind:StorageClass
  4. metadata:
  5. name:managed-nfs-storage
  6. provisioner:fuseim.pri/ifs#orchooseanothername,mustmatchdeployment'senvPROVISIONER_NAME'
  7. parameters:
  8. archiveOnDelete:"true"

查看存储类

  1. root@k8s-master1:~/kubernetes/redis#kubectlgetsc
  2. NAMEPROVISIONERRECLAIMPOLICYVOLUMEBINDINGMODEALLOWVOLUMEEXPANSIONAGE
  3. managed-nfs-storagefuseim.pri/ifsDeleteImmediatefalse6s

基于上面的内容创建 statefulset.yaml 文件

  1. root@k8s-master1:~#mkdir/root/statefulset
  2. root@k8s-master1:~#cd/root/statefulset
  3. root@k8s-master1:statefulset#vimstatefulset.yaml
  4. apiVersion:apps/v1
  5. kind:StatefulSet
  6. metadata:
  7. name:web
  8. spec:
  9. serviceName:"web"
  10. replicas:3
  11. selector:
  12. matchLabels:
  13. app:nginx
  14. template:
  15. metadata:
  16. labels:
  17. app:nginx
  18. spec:
  19. containers:
  20. -name:nginx
  21. image:nginx:1.16
  22. ports:
  23. -containerPort:80
  24. name:web
  25. volumeMounts:
  26. -name:nginx-pvc#指定PVC名称
  27. mountPath:/usr/share/nginx/html
  28. volumeClaimTemplates:#相当于pvc模板
  29. -metadata:
  30. name:nginx-pvc#创建的PVC名称
  31. spec:
  32. storageClassName:"managed-nfs-storage"#指定动态PV名称
  33. accessModes:
  34. -ReadWriteOnce#访问模式,读写在单台机器
  35. resources:
  36. requests:
  37. storage:1Gi
  38. root@k8s-master1:statefulset#kubectlapply-fstatefulset.yaml
  39. statefulset.apps/webcreated
  40. root@k8s-master1:~/kubernetes/statefulset#kubectlgetpv
  41. NAMECAPACITYACCESSMODESRECLAIMPOLICYSTATUSCLAIMSTORAGECLASSREASONAGE
  42. pvc-8eacbe25-3875-4f78-91ca-ba83b6967a8a100GiRWXDeleteBoundredis/nfs-redismanaged-nfs-storage6d
  43. pvc-935033b7-9ac8-4346-8543-1f95492dcde91GiRWODeleteBounddefault/nginx-pvc-web-1managed-nfs-storage39s
  44. pvc-bd3a8c59-b66d-457b-a6f2-90f3b7f9ebf01GiRWODeleteBounddefault/nginx-pvc-web-2managed-nfs-storage19s
  45. pvc-be5cf42a-aeaa-4667-901c-77e1d2350f491GiRWODeleteBounddefault/nginx-pvc-web-0managed-nfs-storage61s
  46. root@k8s-master1:~/kubernetes/statefulset#kubectlgetpvc
  47. NAMESTATUSVOLUMECAPACITYACCESSMODESSTORAGECLASSAGE
  48. nginx-pvc-web-0Boundpvc-be5cf42a-aeaa-4667-901c-77e1d2350f491GiRWOmanaged-nfs-storage82s
  49. nginx-pvc-web-1Boundpvc-935033b7-9ac8-4346-8543-1f95492dcde91GiRWOmanaged-nfs-storage61s
  50. nginx-pvc-web-2Boundpvc-bd3a8c59-b66d-457b-a6f2-90f3b7f9ebf01GiRWOmanaged-nfs-storage40s
  51. oot@k8s-master1:~/kubernetes/statefulset#kubectlgetpods--show-labels
  52. NAMEREADYSTATUSRESTARTSAGELABELS
  53. web-01/1Running04m50sapp=nginx,controller-revision-hash=web-b56c497b,statefulset.kubernetes.io/pod-name=web-0
  54. web-11/1Running04m29sapp=nginx,controller-revision-hash=web-b56c497b,statefulset.kubernetes.io/pod-name=web-1
  55. web-21/1Running04m8sapp=nginx,controller-revision-hash=web-b56c497b,statefulset.kubernetes.io/pod-name=web-2
  56. #分别进入到3个pod中,写入一个数据,验证各自的独享存储
  57. root@k8s-master1:~/kubernetes/statefulset#kubectlgetpods-owide--selectorapp=nginx
  58. NAMEREADYSTATUSRESTARTSAGEIPNODENOMINATEDNODEREADINESSGATES
  59. web-01/1Running07m6s10.244.169.179k8s-node2
  60. web-11/1Running06m45s10.244.107.228k8s-node3
  61. web-21/1Running06m24s10.244.169.180k8s-node2
  62. [root@master-1~]#kubectlexec-itweb-0--bash-c"echo'congratulationsweb-0fork8s'>/usr/share/nginx/html/index.html"
  63. [root@master-1~]#kubectlexec-itweb-1--bash-c"echo'congratulationsweb-1fork8s'>/usr/share/nginx/html/index.html"
  64. [root@master-1~]#kubectlexec-itweb-2--bash-c"echo'congratulationsweb-2fork8s'>/usr/share/nginx/html/index.html"
  65. #直接访问podIP测试内容:
  66. root@k8s-master1:~/kubernetes/statefulset#curl10.244.169.179
  67. congratulationsweb-0fork8s
  68. root@k8s-master1:~/kubernetes/statefulset#curl10.244.107.228
  69. congratulationsweb-1fork8s
  70. root@k8s-master1:~/kubernetes/statefulset#curl10.244.169.180
  71. congratulationsweb-2fork8s

删除statefulset

删除statefulset 有两张方法,级联删除 和 非级联删除

  • 使用非级联删除 statefulset 时,statefulset 的POD 不会被删除
  • 使用级联删除时,statefulset 和 pod 都会被删除
  1. (1)、非级联删除
  2. 使用kubectldeletestatefulsetXXXX删除statefulset,只需要提供--cascade=false参数,就会采用非联机删除,此时删除statefulset不会删除pod
  3. kubectldeletestatefulsetweb--cascade=false
  4. (2)、级联删除
  5. 省略--cascade=false参数即可
  6. kubectldeletestatefulsetweb

原文链接:https://www.toutiao.com/a7024051811204088350/