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存儲的惟一性,這樣才解決了有狀態應用的兩大痛點