Kubernetes In Action 學習筆記 Chapter3,4,5 (一)Pod,副本機制,守護進程與Job

Pod

background

K8s的基本調度單位,一個Pod可以運行一個或者以上數量的容器.

我們知道Docker的一個container實際上是一個進程,那麼每一個container只能運行一個進程(除非產生子進程).
由於不能把多個進程聚集在一個單獨的容器中,因此我們需要一個更高級的結構來組織容器,把他們作爲一個單獨的單元進行管理.

隔離程度

一個Pod內的所有容器共享Linux Namespace,包括UTC namespace,Network namespace, IPC namespace等

也就意味着:

  • 一個pod內的容器能夠共享相同的host和網絡接口

  • 容器能夠通過進程間通信

  • PID也可以共享,共享之後能夠看到彼此運行的進程

  • 但是文件系統是沒有共享的,要靠Volume來實現共享文件目錄

  • 一個Pod中所有容器都有相同的迴環網絡接口,因此容器可以通過localhost和同一個pod的其他容器進行通信

  • Pod之間的網絡是平坦的(無需NAT進行網絡地址轉換),就是說pod之間的關係類似於局域網中的主機,每個pod都有相應的IP地址,並且可以通過這個網絡實現Pod之間的相互訪問

因此可以把Pod當做一個邏輯主機,Pod內部運行的container相當於主機內運行的進程

存活指針 liveness probe

下面介紹pod是如何保證容器的健康的

K8s有三種探測容器的機制:

  • HTTP GET探測 嘗試對容器的ip地址發起HTTP GET請求,根據響應碼來判斷容器是否健康

  • TCP套接字探針 嘗試與容器指定端口建立TCP鏈接,如果鏈接成功建立,則說明成功建立

  • Exec探針 在容器內執行任意命令,並且檢查命令的退出狀態嗎,如果退出狀態碼是0,說明探測成功

創建基於HTTP的存活指針

容器開始後,會在端口8080路徑上執行HTTP GET請求,以確定容器是否健康

apiVersion: v1
kind: Pod
metadata:
  name: kubia-liveness
spec:
  containers:
  - image: luksa/kubia-unhealthy
    name: kubia
    livenessProbe:
      httpGet:
        path: /
        port: 8080
     initialDelaySeconds: 15

配置存活探針的初始屬性
如果沒有設置初始延遲,那麼探針將會在啓動的時候立即開始探測容器,通常會導致探測失敗,因爲應用程序還沒有準備好開始接受請求.

因此通常在創建探測指針的時候,需要設定初始延遲時間

如何創建有效的存活指針

  • 探針配置爲請求特定的URL路徑,讓應用從內部對內部所有重要組件執行狀態檢查,以確保沒有終止或者停止響應
  • 保持探針的輕量級
    不應該消耗太多計算資源,例如運行JVM程序,應該使用HTTP GET探針而不是exec探針,因爲啓動JVM的時候要大量的計算資源
  • 無需在探針中實現重試循環

小結

  • 如果容器崩潰或者存活探針失敗的時候,需要重啓容器,這項工作是由Kubelet進行的
  • 但是如果節點本身崩潰,kubelet也崩潰了,需要使用ReplicationController或者類似機制來管理Pod
  • 也就是在其他節點重啓崩潰節點上的所有Pod

ReplicationController

如果Pod因爲任何原因消失,ReplicationController將會注意到缺少了Pod進而創建替代的Pod

簡而言之,RC是爲了讓當前的運行狀態向"期望"狀態靠攏

當集羣節點發生故障的時候,會爲故障節點上運行的所有Pod創建全新的替代副本

一個ReplicationController由三個部分組成:

  • label selector 用於確定RC作用於有哪些Pod,確定RC的作用範圍
  • replica count
  • pod template
apiVersion: v1
kind: ReplicationController
metadata:
  name: kubia
spec:
  replicas: 3
  selector:
    app: kubia
  template:
    metadata:
      labels:
        app: kubia
    spec:
      containers:
      - name: kubia
        image: luksa/kubia
        ports:
        - containerPort: 8080

如果修改了RC的label selector將會發生什麼?

原先創建的所有pod都會脫離RC的控制,然後RC重新創建一套新的pod副本

那如果修改了RC 的Pod template呢?

原先創建好的Pod不會發生變化,只會影響新創建的Pod

可以通過修改replicas的數字來實現簡單的擴容縮容,屬於聲明式的伸縮集羣

刪除RC,如果採用的是級聯刪除=false,那麼刪除RC的時候並不會影響pod,只是pod會脫離這個RC的控制

kubectl delete rc kubia --cascade=false

但其實說了那麼多,ReplicaSet已經全面取代了ReplicationController了,那兩者之間有什麼區別呢?

  • label selector的表達能力更強,例如能夠匹配缺少某個標籤的Pod,支持多個標籤匹配,正則表達匹配等

可以使用matchLabels或者matchExpressions來進行匹配

apiVersion: apps/v1beta2
kind: ReplicaSet
metadata:
  name: kubia
spec:
  replicas: 3
  selector:
    matchExpressions:
      - key: app
        operator: In
        values:
         - kubia
  template:
    metadata:
      labels:
        app: kubia
    spec:
      containers:
      - name: kubia
        image: luksa/kubia

DaemonSet

可以在每一個節點上只運行一個Pod副本,例如每個節點上都要運行日誌收集器或者資源監控器等系統服務進程,如果使用RS的話,可能只會使得pod隨機調度在不同的節點上,不一定能保證所有的節點都能運行一個Pod

Daemonset在把pod部署到這些節點上的時候,會完全繞過調度器,也就是說即使節點被設置爲不可調度,Daemonset管理的Pod仍然會調度到這些節點上

Job

之前討論的Pod都是持久運行的,如果你想pod運行完成之後就結束了呢?
K8s提供了Job資源,一旦任務完成,Pod就會處於完成狀態.

同時,還提供了順序運行,併發運行Job Pod的功能

下面的Job意思是,最多可以同時啓動兩個Pod執行任務,執行完成之後再啓動新的Pod,順序執行一共5個,就是任務要完成5次

同時可以設置Pod的運行時間限制 activeDeadlineSeconds: 30

apiVersion: batch/v1
kind: Job
metadata:
  name: multi-completion-batch-job
spec:
  completions: 5
  parallelism: 2
  activeDeadlineSeconds: 30
  template:
    metadata:
      labels:
        app: batch-job
    spec:
      restartPolicy: OnFailure
      containers:
      - name: main
        image: luksa/batch-job

如果要安排Pod定期運行或者在將來運行一次,可以定義cronJob資源,此處不介紹.

Pod Hook

  • Kubernetes爲容器提供了生命週期鉤子,也就是Pod Hook
  • 由kubelet發起,在整個容器的生命週期之中運行

提供了兩種鉤子函數

  • postStart

主要用於資源部署,環境準備等

在容器創建後立即執行,但是不能保證鉤子將在容器ENTRYPOINT之前運行,因爲沒有參數傳遞給處理程序.

  • preStop

主要用於優雅地關閉應用程序,通知其他系統等.如果鉤子在執行期間掛起,Pod將會停留在running狀態並且不會到達failed狀態

在容器終止前立即被調用,是阻塞的,也就是說是同步的,必須在刪除容器的調用發出之前完成.

  • 鉤子函數應該儘量輕量級
  • 實現的方法
  1. Exec
  2. HTTP

eg:

那麼鉤子(Hook)和探針又有什麼區別呢?

個人理解鉤子側重於對容器生命週期的管理,兩個鉤子函數分別作用時間是容器創建之後立刻執行以及終止之前立即被調用,主要實現資源的部署準備,關閉應用程序

而探針側重於容器健康狀態的監控,每隔一段週期都會執行一次

下面是實例:

postStart: 在容器創建之後,把一句話寫入到/usr/share/message


apiVersion: v1
kind: Pod
metadata:
  name: hook-demo1
spec:
  containers:
  - name: hook-demo1
    image: nginx
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]

這裏先說一下如何優雅地刪除資源對象,(意思就是讓程序完成正在處理的請求後再關閉軟件)

  • 默認:docker首先會向容器中PID爲1的進程發送系統信號SIGTERM,如果在等待時間內仍然沒有終止執行,那麼會繼續發送SIGKILL信號強行殺掉進程

  • 使用pod生命週期,利用preStop回調函數,執行在發送終止信號之前

apiVersion: v1
kind: Pod
metadata:
  name: hook-demo2
spec:
  containers:
  - name: hook-demo2
    image: nginx
    lifecycle:
      preStop:
        exec:
          command: ["/usr/sbin/nginx","-s","quit"]

ref

https://www.qikqiak.com/k8s-book/docs/20.Pod%20Hook.html
https://www.cnblogs.com/crazy-chinese/p/10234746.html
https://www.qikqiak.com/k8s-book/docs/22.%E5%88%9D%E5%A7%8B%E5%8C%96%E5%AE%B9%E5%99%A8.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章