K8s有状态应用部署
目录:分为两类
1.Headless Service
2.StatefulSethtml
• 部署有状态应用
• 解决Pod独立生命周期,保持Pod启动顺序和惟一性 mysql
说在前面的话,像咱们的Mysql或者Redis了,Zookerper等等这些适不适合部署在K8s中,其实呢不是太适合,但部署在里面也能够,好比部署一个Mysql来说吧,部署到k8s中仍是很容易的就一个Mysql实例,就像部署其余应用同样,经过service、IP去访问它,可是要是做为集群的状态去部署的话,那可能就比较麻烦了。 第一点:好比作一个Mysql的主从,Mysql主从它是有主从拓扑关系的,一个主一个从,并且各自的数据都不同,这就意味着,你要想搭建一个Mysql的主从,你要知道它的相互的ip地址,就是从确定要知道主的ip地址,而后从链接主的ip地址,作数据的同步。 第二点:它的存储,它两个存储的信息都不太同样,那怎么去保证它两个数据的存储保证持久化呢,一个集群中可能会有多个节点,要是部署到k8s中,必需要保证部署的应用,在任意的节点都能使用原来的状态,也就是说某一个节点挂了,上面的pod飘移到另外一个节点,能不能用到以前的状态,因此要考虑这些问题。 而k8s设计的精髓在于并非你部署一个单的实例,而是在于它的一个分布式一个部署,具备故障恢复能力的应用,因此就谈到了有状态和无状态应用。
有状态应用:DB,比如一个Mysql主从,考虑两点(本身的存储,必须是远程的存储,在任意节点挂载都恢复原来的状态)并且还有网络ID的惟一,须要作主从的链接,咱们的pod是短暂的,重建一个ip就换了,得保证这个ip一直去使用,不论是重建仍是迁移pod,都能去使用。
无状态应用:典型的就是web系统,自己就没有什么状态去维护,好比部署了三个副本,不须要考虑其余两个副本是什么样的,跟它没有直接的关系,本地也没有什么持久化的数据,即便其中有一个副本挂了,帮它在其余节点起来,仍然能够继续提供服务,对原基础服务是没有任何影响的,因此这是一个前提,典型的就是web。nginx
在k8s中呢在1.10版本以后有状态部署才支持好一点,可是刚开始在落地K8s的时候,而不会去考虑有状态部署的,主要作无状态的部署,而数据库适不适合部署在k8s中,在看k8s的一些特性,k8s有适合的一些特性,好比具备一些访问比较大的应用,版本迭代快的应用,或者弹性伸缩的一些应用,凡是这些是适合放在k8s,k8s最先就支持无状态,也是一直在推荐,有状态的也是比较复杂,复杂点就在与有状态的都是一些集群化的,好比zookerper,
Mysql主从,这些都是须要自身的一个状态维护的,这些部署进去呢,可能去考虑它这个网络拓扑关系,还有存储状态的持久化,而数据库不具有这些特色,部署一个数据库通常配置比较高一些,能够会抗不少的并发量,并且要扩容的话也是很方便,并且传统的部署文章也不少,也比较成熟,在k8s中部署这些东西,那绝对是一种挑战,因此要根据不一样的应用特色去考虑上k8s,不要一味地上k8s,并且得不偿失,达不到预期的效果,领导也会批你,因此在谈有状态部署的话,能够在二者出发,一个是Headless Service维护网络的,一个是StatefulSet维护存储状态的。web
statefulSet是一个控制器,与Deployment存在的原则同样,都是部署应用的,而Statefulset它主要是部署有状态应用的,而deployment是部署无状态应用的sql
Headless Service 其实和service差很少,这不过定义的这个叫无头服务,它们之间惟一的区别就是将Cluster ip 设置为了none,不会帮你配置ip数据库
[root@k8s-master demo]# mkdir headless-service [root@k8s-master demo]# cd headless-service/ [root@k8s-master headless-service]# vim headless-svc.yaml apiVersion: v1 kind: Service metadata: name: my-service spec: clusterIP: None selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 9376 [root@k8s-master headless-service]# kubectl create -f headless-svc.yaml service/my-service created [root@k8s-master headless-service]# kubectl get svc kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 23h my-service ClusterIP None <none> 80/TCP 6s service NodePort 10.1.207.32 <none> 80:30963/TCP 87m zhao ClusterIP 10.1.75.232 <none> 80/TCP 9m1s zhaocheng ClusterIP 10.1.27.206 <none> 80/TCP 10m
怎么去访问?咱们给它定义一个标识
建立完以后会有这个标识符,它会使用这个DNS来解析这个名称,来相互的访问,headless就不会经过ip去访问了,必须经过名称去访问,vim
[root@k8s-master headless-service]# vim statefulset.yaml apiVersion: apps/v1beta1 kind: StatefulSet metadata: name: nginx-statefulset namespace: default spec: serviceName: my-service replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 [root@k8s-master headless-service]# kubectl create -f statefulset.yaml [root@k8s-master headless-service]# kubectl get pod my-pod 1/1 Running 0 3h50m nfs-744d977b46-dh9xj 1/1 Running 0 22h nfs-744d977b46-kcx6h 1/1 Running 0 22h nfs-744d977b46-wqhc6 1/1 Running 0 22h nfs-client-provisioner 1/1 Running 0 4h nginx-797db8dc57-tdd5s 1/1 Running 0 100m nginx-statefulset-0 1/1 Running 0 73s nginx-statefulset-1 1/1 Running 0 46s nginx-statefulset-2 1/1 Running 0 24s
这里的statfulset的 serviceName: my-service字段要关联起来,这样才能去基于名称去访问
能够经过busybox测试工具经过nslookup去测试解析。解析咱们的my-service就能解析到
这里会分配一个名称,这个my-service和这个编号是永久的,能够经过这个名称访问pod
要是mysql主从的话就能够经过访问这个标签来链接咱们从库的状态,这个是维护的网络状态
而后再来看一下存储状态api
官方文档这个实例
https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/
这个其实咱们也是部署一个nginx,使用的headless,ClusterIP为none,而后用headless来维护statefulset起得pod网络id为1,以 volumeClaimTemplates:来维护pod独立的一个存储网络
apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: selector: matchLabels: app: nginx # has to match .spec.template.metadata.labels serviceName: "nginx" replicas: 3 # by default is 1 template: metadata: labels: app: nginx # has to match .spec.selector.matchLabels spec: terminationGracePeriodSeconds: 10 containers: - name: nginx image: nginx ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "managed-nfs-storage" resources: requests: storage: 1Gi
这是咱们的存储要写咱们nfs的名称
managed-nfs-storage并发
[root@k8s-master headless-service]# kubectl get sc managed-nfs-storage fuseim.pri/ifs 22h
这里会给咱们自动建立pv,并挂载到咱们的NFS上
[root@k8s-master headless-service]# kubectl get pod my-pod 1/1 Running 0 6h4m nfs 1/1 Running 0 24h nfs 1/1 Running 0 24h nfs 1/1 Running 0 24h nfs-client-provisioner-fbc 1/1 Running 0 6h23m nginx-797db8dc57-tdd5s 1/1 Running 0 3h54m nginx-a1-6d5fd7b8dd-w647x 1/1 Running 0 3m28s nginx-statefulset-0 1/1 Running 0 135m nginx-statefulset-1 1/1 Running 0 135m nginx-statefulset-2 1/1 Running 0 134m web-0 1/1 Running 0 3 web-1 1/1 Running 0 85s web-2 1/1 Running 0 57s [root@k8s-master headless-service]# kubectl get pv pvc-06 1Gi RWO Delete Bound default/www-web-2 managed-nfs-storage 63s pvc-4f 1Gi RWO Delete Bound default/www-web-0 managed-nfs-storage 6m3s pvc-a2 5Gi RWX Delete Bound default/my-pvc managed-nfs-storage 6h4m pvc-bc 1Gi RWO Delete Bound default/www-web-1 managed-nfs-storage
headless保证它的网络,statefulset存储模版来保证每一个pod存储的惟一性,这样才解决了有状态应用的两大痛点