K8s無狀態控制器原理介紹


Pod控制器:

  ReplicationController:早期K8s只有這一個控制器,但后來發現讓這一個來完成所有任務,太復雜.因此被廢棄.
  ReplicaSet: 它用於幫助用戶創建指定數量的Pod副本,並確保Pod副本數量一直滿足用戶期望的副本數量。
        副本數量"多退少補"等機制。【它可認為就是ReplicationController的新版本。】
   它由三個主要組件組成:
     1. 用戶期望的Pod的副本數量.
        2. 標簽選擇器: 使用它來選擇自己管理的Pod
        3. Pod模板: 若標簽選擇器選擇的副本數量不足,則根據Pod模板來新建.
  Deployment: 它用於幫我們管理無狀態Pod的最好的控制器.
      它支持滾動更新,回滾,它還提供了聲明式配置的功能,它允許我們將來根據聲明的配置邏輯來定義,
      所有定義的資源都可隨時進行重新聲明,只要該資源定義允許動態更新。
  DaemonSet:用於確保集群節點上只運行一個Pod的控制器。它一般用於構建系統級應用時使用。
      它不能定義副本數量,副本數量要根據集群的規模來自動創建, 即: 若集群中新加入了一個
      node節點,DaemonSet將自動使用Pod模板在新節點上創建一個Pod,並精確保障每個節點上僅
      運行一個Pod. 所以此控制器,必須要有Pod模板 和 標簽選擇器。
      它還有另一個作用:就是用於控制Pod僅運行在指定滿足條件的節點上,並精確確保其只運行一個Pod.
    它所管理的Pod:
      1. 必須是守護進程,要持續運行在后台。
      2. 它沒有終止那一刻,即便不忙,它也監聽文件的變動 或 用戶對某套接字的請求
  Job: 主要用於創建一個完整指定任務的Pod,一旦任務完成,就會退出;但是若任務未完成,則會重新啟動,直到任務完成.
  Cronjob: 它是定義一個周期性任務,Pod啟動后,和Job啟動的Pod類似,也是任務執行完成后才會終止重啟。
      同時它還會自動處理一個任務還未完成,下一個啟動時間已經到了的問題。


控制器示例:
  ReplicaSet控制器示例:
  #若想了解下面每個參數的含義,可查看 kubectl  explain  replicaset

  vim replicaset.yaml
    apiVersion: apps/v1           #一般來說,一個清單文件的基本格式:
    kind: ReplicaSet      #apiVersion,kind,metadata這是必須的,下面對 spec是replicaSet的一個必要參數.
    metadata:          #要查看spec支持那些參數: kubectl  explain  replicaset.spec 即可.
      name: myapp
      namespace: default
    spec:
      replicas: 2         #這里是定義ReplicaSet的副本數量.
      selector:
       matchLabels:
        app: myapp
        release: canary
      template:    #查看template支持那些參數: kubectl  explain replicaset.spec.template即可查看.
        metadata:
         name: myapp-pod    #通常Pod的名稱空間必須和控制器的名稱空間一致,故可省略.
         labels:      #這里創建Pod的標簽必須和selector的標簽符合,否則此Pod將永久被創建下去。
          app: myapp
          release: canary
        spec:
         containers:
         -  name: myapp-container
          image: busybox
          ports:
          -  name:http
           containerPort: 80

#啟動:
  kubectl create -f replicaSet.yaml
  kubectl get pods
  kubectl get rs

  kubectl delete pods PodName
  kubectl get pods        #可以查看控制器控制下的Pod個數少了,會自動被創建.

  #接下來測試,控制器控制下的Pod多了會怎么
    kubectl label pods PodName release=canary,app=myapp #給Pod添加標簽
    kubectl get pods --show-labels
    注:
        此測試也說明: 在定義控制器所管理的Pod時,一定要精確定義Pod的標簽,
     盡量避免出現,用戶創建的Pod標簽正好和你定義的控制器符合,產生悲劇!
    另外:
      service 和 控制器它們沒有直接關系,只是它們都使用標簽選擇器來獲取Pod,
      這也意味着一個Service可管理多個控制器所創建的Pod.

#控制器的配置是支持動態更新的.
  kubectl edit rs replicaset   #將其副本數量修改一個再查看效果。

#它還支持動態更新Pod的鏡像版本.
  kubectl edit rs replicaset
  kubectl get rs -o wide
  注:
   這里查看到Pod鏡像版本修改了,但實際上正在運行的Pod的鏡像版本並沒有改變.
  這時若你手動刪除一個Pod,新建的Pod將使用新版本創建.
  這樣就可以輕松實現 金絲雀 發布更新了,即: 先刪除一個,讓一個Pod使用新版本,使用新版本Pod
  會得到一部分流量,這一部分流量就可以作為測試流量,若2天后,沒有發現用戶抱怨Bug,則可以
  手動將Pod一個一個刪除,並替換成新版本的Pod。

 

Deployment:

  

    它是ReplicaSet控制器的控制器,即: Deployment控制器它不直接用於管理Pod,它是用來管理
  ReplicaSet控制器的,這樣做的好處是,可實現動態更新和回滾,如上圖所示,它能實現
  多種更新方式,上圖顯示的是 灰度更新 過程,它將ReplicaSetV1控制的Pod,每次一個的
  刪除,並在ReplicaSetV2上重建,若ReplicaSetV2上線后,有問題,還能快速回滾到V1.
  通常來說Deployment不會直接刪除ReplicaSet,它會保留10個版本,以便回滾使用。

 它通過更新Pod的粒度來實現 灰度更新,金絲雀更新,藍綠更新。
 它控制Pod創建粒度是 比如:
  1.在刪除時,必須保障有5個Pod,但可臨時多一個Pod,則它會創建一個,刪除一個. 直到全部替換。
  2.必須保障有5個,但可臨時少一個Pod,則它會先刪除一個,在創建一個,直到全部替換。
  3.必須保障有5個,但可多一個,也可少一個,此時它會創建一個,刪除兩個,再創建2個,再刪除2個,直到全部替換。
  4.還有一種是允許臨時多出一倍,則它會一次性創建5個,然后直接替換使用新的Pod,在把老的Pod刪除。

Deployment控制參數:
  strategy:    #設置更新策略
  type <Recreate|RollingUpdate>    #指定更新策略類型.Recreate: 它是刪除一個,重建一個.
                           RollingUpdate: 這是滾動更新。
  rollingUpdate:
    maxSurge: 用於定義滾動更新時,副本最多允許增加幾個. 它支持兩種值:
          5: 表示副本數最多增加5個。
          20%: 若你有10個Pod副本, 20%就是最多增加2個副本.
    maxUnavailable: 最多允許幾個不可用.它也支持整數 或 百分比.
  revisionHistoryLimit <Int>    #設置保存幾個歷史ReplicaSet版本.默認10個
  paused <boolean>       #是否在更新前先暫停

vim  myapp-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
     name: myapp-deploy
     namespace: default
spec:
     replicas: 2
     selector:
         matchLabels:
             app:myapp
             release: canary
     template:
            metadata:
                labels:
                     app:myapp
                     release: canary
            spec:
                 cantainers:
                  -   name: myapp
                       image: busybox
                       ports:
                       -   name:http
                           containerPort: 80

 

#編寫以上清單文件后,就可以執行:
  kubectl apply -f deploy-demo.yaml

  kubectl get deploy
  kubectl get rs

  vim deploy-demo.yaml
    #修改副本數量為4

  kubectl apply -f deploy-demo.yaml    #修改后再次apply是運行,apply可應用配置多次,並且它會自動反映出清單的變化.

  kubectl describe deploy myapp-deploy    #查看Annotaions,RollingUpdateStrategy.


  #測試動態滾動更新
    vim deploy-demo.yaml
      修改鏡像的版本為新版本.

  終端2:
    kubectl get pods -l app=myapp -w

  終端1:
    kubectl apply -f deploy-demo.yaml

  再到終端2上查看滾動更新的效果。
    kubectl get rs -o wide    #可查看到多了一個rs,而且舊版rs的數據都是0.

    kubectl rollout history deployment myapp-deploy    #查看滾動更新的歷史

#通過給配置文件打補丁的方式來動態更新:
  kubectl patch deployment myapp-deploy -p '{"spec":{"replicas":5}}'
    注: 這樣也可以動態修改 myapp-deploy這個Deployment控制器的參數.

  kubectl get pods #可看到Pod個數已經動態創建了。

#動態修改Deployment控制器滾動更新的策略:
  kubectl patch deployment myapp-deploy -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0}}}}'

  kubectl describe deploy myapp-deploy    #查看更新策略

#修改Deployment控制器下Pod的鏡像為新版本,然后實現金絲雀更新.
  終端1:
    kubectl get pods -l app=myapp -w

  終端2:
    kubectl set image deployment myapp-deploy myapp=busybox:v3
    kubectl rollout pause deployment myapp-deploy

  終端3:
    kubectl rollout status deployment myapp-deploy

  終端2:
    kubectl rollout resume deployment myapp-deploy

    kubectl get rs -o wide


#回滾到指定版本
  kubectl rollout history deployment myapp-deploy
    deployment.extensions/myapp-deploy
    REVISION CHANGE-CAUSE
      0    <none>
      2    <none>
      3   <none>
      4    <none>
      5    <none>

  kubectl rollout undo deployment myapp-deploy --to-revision=3

  kubectl rollout history deployment myapp-deploy    #可以看到第一版成為第四版.
    deployment.extensions/myapp-deploy
    REVISION CHANGE-CAUSE
      0    <none>
      4    <none>
      5    <none>
      6    <none> #先回到3版本,這里顯示為第6版
      7    <none> #接着又嘗試回到2版本, 這里顯示就是7版本.

 

daemonSet控制器:
  #查看daemonSet控制器的語法
    kubectl explain ds
    kubectl explain ds.spec

vim  ds-demo.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
   name: filebeat-ds
   namespace: default
spec:
  selector:
     matchLabels:
       app:filebeat
       release:stable
  template:
    metadata:
       labels:
         app: filebeat
         release: stable
    spec:
      containers:
      -  name: filebeat
         image: ikubernetes/filebeat:5.6.5-alpine
         env:          #env的用法: kubectl explain  pods.spec.containers.env
         - name: REDIS_HOST
           value: redis.default.svc.cluster.local
         - name: REDIS_LOG_LEVEL
           value: info

  #接着使用apply來應用daemonSet控制器的配置清單創建Pod資源.
  kubectl apply -f ds-demo.yaml

#將多個相關的資源定義在一起的方式,這是工作中常用的方式.
vim  ds-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
     app: redis
     role: logstor
  template:
    metadata:
     labels:
        app: redis
        role: logstor
     spec:
       containers:
       -  name: redis
          image: redis:4.0-alpine
          ports:
          - name: redis
            containerPort:6379
---      #這表示分隔符.
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: filebeat-ds
  namespace: default
spec:
  selector:
    matchLabels:
       app:filebeat
       release:stable
  template:
    metadata:
      labels:
       app: filebeat
       release: stable
    spec:
      containers:
      - name: filebeat
        image: ikubernetes/filebeat:5.6.5-alpine
        env:
        -  name: REDIS_HOST
           value: redis.default.svc.cluster.local
           #fiebeat通過環境變量找到redis的前端service,注意這里指定的名字是redis的前端服務名,而非隨意寫!
        -  name: REDIS_LOG_LEVEL
           value: info

  #因為此前通過daemonSet創建了兩個Pod資源,為了避免沖突,先刪除Pod資源.
  kubectl delete -f ds-demo.yaml

#接着再同時創建redis和fliebeat兩個Pod資源.
  kubectl apply -f ds-demo.yaml

#接着為redis創建一個服務,來暴露redis的服務端口,以便filebeat可以將日志發送給服務,服務再將日志轉發給redis.
  kubectl expose deployment redis --port=6379
  kubectl get svc      #查看創建的service

#驗證redis是否可以收到filebeat的日志.
  kubectl get pods      #等redis處於running狀態就可以登陸查看了.
  kubectl exec -it redis-5b5d.... -- /bin/sh
  / data # netstat -tnl
  / data # nslookup redis.default.svc.cluster.local    #解析redis的域名.
  / data # redis-cli -h redis.default.svc.cluster.local     #驗證能否通過域名直接登陸redis
  / data # keys *          #登陸redis成功后,查看是否有key被創建.

#登陸filebeat查看狀態
  kubectl exec -it filebeat-ds-h776m -- /bin/sh
  / # ps uax
  / # cat /etc/filebeat/filebeat.yml    #查看其配置文件中redis的定義.
  / # printenv            #查看環境變量.
  / # kill -1 1            #使用-1信號 讓filebeat重讀配置文件,這會導致Pod重啟,不過沒事.

#另外,通過-o wide 可以看到daemonSet定義的Pod一定是一個節點上運行一個Pod.
  kubectl get pods -l app=filebeat -o wide    #daemonSet定義的Pod不運行在主節點上,
                      #主要是因為前面部署時,定義了Master節點是不調度的.
#測試時,發現以下問題:
  # kubectl get node
    NAME STATUS ROLES AGE VERSION
    192.168.111.80 Ready node 2d21h v1.13.5
    192.168.111.81 Ready node 2d21h v1.13.5
    192.168.111.84 Ready,SchedulingDisabled master 2d21h v1.13.5 #主節點配置了,不調度,即污點.
    192.168.111.85 NotReady,SchedulingDisabled master 2d21h v1.13.5

  # kubectl get pod -l app=filebeat -o wide
    NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
    filebeat-ds-8gfdr 1/1 Running 0 13m 10.10.171.2 192.168.111.81 <none> <none>
    filebeat-ds-ml2bk 1/1 Running 1 13m 10.10.240.193 192.168.111.84 <none> <none> #竟然運作在主節點上了!!
    filebeat-ds-zfx57 1/1 Running 0 13m 10.10.97.58 192.168.111.80 <none> <none>
    #從運行狀態上看, 符合DaemonSet的特性,每個節點都運行一個. 但為啥它能運行在Master上,原因不明?



#daemonSet也是支持滾動更新的,怎么更新?
  kubectl explain ds.spec.updatestrategy.rollingUpdate    #它只支持先刪一個在創建一個, 因為一個節點只能運行一個Pod.

#定義daemonSet控制器filebeat-ds 滾動更新其下管理的Pod的image 升級到filebeat:5.6.6-alpine
  kubectl set image daemonsets filebeat-ds filebeat=ikubernetes/filebeat:5.6.6-alpine

#查看Pod的更新過程
  kubectl get pods -w

DaemonSet的更新策略:
  updateStrategy:
  type <RollingUpdate |OnDelete>    #OnDelete: 即刪除時創建。

#動態更新DaemonSet:
  kubectl get ds
  kubectl set image daemonSets filebeat-ds filebeat=ikubernetes/filebeat:5.6.6-alpine

  終端2:
    kubectl get pods -w

  #讓pod和宿主機的共享名稱空間:
  Pods:
    hostNetwork <boolean> #讓Pod共享宿主機的網絡名稱空間,啟動Pod后,可直接訪問宿主機的80,來訪問容器.
    hostPID <boolean>   #這其實就是Docker網絡模型中與宿主機共享網絡名稱空間的模型.
    hostIPC <boolean>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM