<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] 參考:[https://blog.51cto.com/newfly/2140004](https://blog.51cto.com/newfly/2140004) 參考:[https://jimmysong.io/kubernetes-handbook/concepts/statefulset.html](https://jimmysong.io/kubernetes-handbook/concepts/statefulset.html) ## 背景 用戶通過 Deployment、ReplicationController 可以方便地在 kubernetes 中部署一套高可用、可擴展的**分布式無狀態服務**。這類應用不在本地存儲數據,通過簡單的負載均衡策略可實現請求分發。隨著 k8s 的普及和云原生架構的興起,越來越多的人希望把數據庫這類有狀態服務也通過 k8s 進行編排。但因為有狀態服務的復雜性,這一過程并不容易。本文將以最流行的開源數據庫 MySQL 為例,介紹如何在 k8s 上部署運維有狀態服務。本文所作的調研基于`k8s 1.18`。 ## StatefulSet 簡介 [Deployment](https://link.zhihu.com/?target=https%3A//kubernetes.io/docs/concepts/workloads/controllers/deployment/)、[ReplicationController](https://link.zhihu.com/?target=https%3A//kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/)是為無狀態服務而設計的,它們中 pod 的名稱、主機名、存儲都是不穩定的,且 pod 的啟動、銷毀順序隨機,并不適合數據庫這樣的有狀態應用。為此,k8s 推出了面向有狀態服務的工作負載[StatefulSet](https://link.zhihu.com/?target=https%3A//kubernetes.io/docs/concepts/workloads/controllers/statefulset/)。其管理的 pod 具有如下特點: 1. 唯一性 - 對于包含 N 個副本的 StatefulSet,每個 pod 會被分配一個 \[0,N)范圍內的唯一序號。 2. 順序性 - StatefulSet 中 pod 的啟動、更新、銷毀默認都是按順序進行的。 3. 穩定的網絡身份標識 - pod 的主機名、DNS 地址不會隨著 pod 被重新調度而發生變化。 4. 穩定的持久化存儲 - 當 pod 被重新調度后,仍然能掛載原有的 PersistentVolume,保證了數據的完整性和一致性。 StatefulSet在Headless Service的基礎上又為StatefulSet控制的每個Pod副本創建了一個DNS域名,這個域名的格式為: ``` $(podname).(headless server name) FQDN: $(podname).(headless server name).namespace.svc.cluster.local ``` ## 創建 StatefulSet 作為開始,使用如下示例創建一個 StatefulSet。它和[StatefulSets](https://kubernetes.io/zh/docs/concepts/abstractions/controllers/statefulsets/)概念中的示例相似。它創建了一個[Headless Service](https://kubernetes.io/zh/docs/user-guide/services/#headless-services)`nginx`用來發布 StatefulSet`web`中的 Pod 的 IP 地址。 ``` apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: v1 kind: PersistentVolume metadata: name: "www-data-pv" labels: name: www-data-pv release: stable spec: capacity: storage: 5Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle nfs: path: /nfs/www/data server: 192.168.84.75 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: www-data-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 5Gi selector: matchLabels: name: www-data-pv release: stable --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: "nginx" replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/html volumes: - name: www persistentVolumeClaim: claimName: www-data-pvc ``` 通過該配置文件,可看出StatefulSet的三個組成部分: * Headless Service:名為nginx,用來定義Pod網絡標識( DNS domain)。 * StatefulSet:定義具體應用,名為Nginx,有三個Pod副本,并為每個Pod定義了一個域名。 * persistentVolumeClaim: 是由**用戶進行存儲的請求**。它類似于pod。Pod消耗節點資源,PVC消耗PV資源。Pod可以請求特定級別的資源(CPU和內存)。聲明可以請求特定的大小和訪問模式(例如,可以一次讀/寫或多次只讀)。**【persistentVolumeClaim的細節請看k8s的持久化存儲PVC】** >**為什么需要 headless service 無頭服務?** 在用Deployment時,每一個Pod名稱是沒有順序的,是隨機字符串,因此是Pod名稱是無序的,但是在statefulset中要求必須是有序 ,每一個pod不能被隨意取代,pod重建后pod名稱還是一樣的。而pod IP是變化的,所以是以Pod名稱來識別。pod名稱是pod唯一性的標識符,必須持久穩定有效。這時候要用到無頭服務,它可以給每個Pod一個唯一的名稱 。 使用`kubectl apply`中的 Headless Service 和 StatefulSet。 ``` kubectl apply -f web.yaml service/nginx created statefulset.apps/web created ``` >最后三個Pod全部running且ready, 且順序是web-0.web-1,web-2 ## 測試pod間是否相通 每個 Pod 都擁有一個基于其順序索引的穩定的主機名。使用`kubectl exec`在每個 Pod 中執行`hostname`。 ``` $ for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done web-0 web-1 ``` 使用`kubectl run`運行一個提供`nslookup`命令的容器,該命令來自于`dnsutils`包。通過對 Pod 的主機名執行`nslookup`,你可以檢查他們在集群內部的 DNS 地址。 ``` $ kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm nslookup web-0.nginx Server: 10.0.0.10 Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local Name: web-0.nginx Address 1: 10.244.1.6 nslookup web-1.nginx Server: 10.0.0.10 Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local Name: web-1.nginx Address 1: 10.244.2.6 ``` 另外一種方法是可以直接在web-0 pod中執行 nslookup + 域名 指令。 ``` kubectl exec web-0 -- nslookup web-1.nginx.svc.cluster.local 格式是:${podname}.${servername}.svc.cluster.local ``` ## 擴容/縮容 StatefulSet 擴容/縮容 StatefulSet 指增加或減少它的副本數。這通過更新`replicas`字段完成。你可以使用[`kubectl scale`](https://kubernetes.io/zh/docs/user-guide/kubectl/v1.18/#scale)或者[`kubectl patch`](https://kubernetes.io/zh/docs/user-guide/kubectl/v1.18/#patch)來擴容/縮容一個 StatefulSet。 ### 擴容 在一個終端窗口觀察 StatefulSet 的 Pod。 ``` kubectl get pods -w -l app=nginx ``` 在另一個終端窗口使用`kubectl scale`擴展副本數為 5。 ``` kubectl scale sts web --replicas=5 statefulset.apps/web scaled ``` 在第一個 終端中檢查`kubectl get`命令的輸出,等待增加的 3 個 Pod 的狀態變為 Running 和 Ready。 StatefulSet 控制器擴展了副本的數量。StatefulSet 按序號索引順序的創建每個 Pod,并且會等待前一個 Pod 變為 Running 和 Ready 才會啟動下一個 Pod。 ### 縮容 在一個終端觀察 StatefulSet 的 Pod。 ``` kubectl get pods -w -l app=nginx ``` 在另一個終端使用`kubectl patch`將 StatefulSet 縮容回三個副本。 ``` kubectl patch sts web -p '{"spec":{"replicas":3}}' statefulset.apps/web patched ``` ### 順序終止 Pod 控制器會按照與 Pod 序號索引相反的順序每次刪除一個 Pod。在刪除下一個 Pod 前會等待上一個被完全關閉。 **規律總結:** * 匹配Pod name(網絡標識)的模式為:**$(statefulset名稱)-$(序號)**,比如上面的示例:web-0,web-1,web-2。 * StatefulSet為每個Pod副本創建了一個DNS域名,這個域名的格式為:**$(podname).(headless server name)**,也就意味著服務間是通過Pod域名來通信而非Pod IP,因為當Pod所在Node發生故障時,Pod會被飄移到其它Node上,Pod IP會發生變化,但是Pod域名不會有變化。 * StatefulSet使用Headless服務來控制Pod的域名,這個域名的FQDN為:**$(service name).$(namespace).svc.cluster.local**,其中,“cluster.local”指的是集群的域名。 * 根據volumeClaimTemplates,為每個Pod創建一個pvc,pvc的命名規則匹配模式:**(volumeClaimTemplates.name)-(pod\_name)**,比如上面的volumeMounts.name=www, Pod name=web-\[0-2\],因此創建出來的PVC是www-web-0、www-web-1、www-web-2。 * 刪除Pod不會刪除其pvc,手動刪除pvc將自動釋放pv。 ## 域名示例 關于Cluster Domain、headless service名稱、StatefulSet 名稱如何影響StatefulSet的Pod的DNS域名的示例: | Cluster Domain | Service (ns/name) | StatefulSet (ns/name) | StatefulSet Domain | Pod DNS | Pod Hostname | | --- | --- | --- | --- | --- | --- | | cluster.local | default/nginx | default/web | nginx.default.svc.cluster.local | web-{0..N-1}.nginx.default.svc.cluster.local | web-{0..N-1} | | cluster.local | foo/nginx | foo/web | nginx.foo.svc.cluster.local | web-{0..N-1}.nginx.foo.svc.cluster.local | web-{0..N-1} | | kube.local | foo/nginx | foo/web | nginx.foo.svc.kube.local | web-{0..N-1}.nginx.foo.svc.kube.local | web-{0..N-1} | ## 更新策略 在Kubernetes 1.7及更高版本中,通過.spec.updateStrategy字段允許配置或禁用Pod、labels、source request/limits、annotations自動滾動更新功能。 **OnDelete:**通過.spec.updateStrategy.type 字段設置為OnDelete,StatefulSet控制器不會自動更新StatefulSet中的Pod。用戶必須手動刪除Pod,以使控制器創建新的Pod。 **RollingUpdate:**通過.spec.updateStrategy.type 字段設置為RollingUpdate,實現了Pod的自動滾動更新,如果.spec.updateStrategy未指定,則此為默認策略。 StatefulSet控制器將刪除并重新創建StatefulSet中的每個Pod。它將以Pod終止(從最大序數到最小序數)的順序進行,一次更新每個Pod。在更新下一個Pod之前,必須等待這個Pod Running and Ready。 **Partitions:**通過指定 .spec.updateStrategy.rollingUpdate.partition 來對 RollingUpdate 更新策略進行分區,如果指定了分區,則當 StatefulSet 的 .spec.template 更新時,具有大于或等于分區序數的所有 Pod 將被更新。 具有小于分區的序數的所有 Pod 將不會被更新,即使刪除它們也將被重新創建。如果 StatefulSet 的 .spec.updateStrategy.rollingUpdate.partition 大于其 .spec.replicas,則其 .spec.template 的更新將不會傳播到 Pod。在大多數情況下,不需要使用分區。 ## 外部訪問集群內部 ### 土方法 ?對pod打標簽,然后映射成服務 ``` kubectl label pod web-0 webInst=0 -n sy-platform-demo kubectl expose pod web-0 --port=80--target-port=80--name=web-0 --selector=web=0 --type=NodePort -n sy-platform-demo ``` 修改web-0?的nodeport?端口號 ``` kubectl edit service web-0 -n sy-platform-demo ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看