k8s 主要概念大梳理!

k8s 已經成爲了絕對熱門的技術,一個上點規模的公司,如果不搞 k8s,都不好意思出去見人。安裝 k8s 要突破種種網絡阻礙,但更大的阻礙還在後面...

我發現,很多 k8s 的文章,根本不說人話,包括那要命的官網。

要弄明白 k8s 的細節,需要知道 k8s 是個什麼東西。它的主要功能,就是容器的調度 -- 也就是把部署實例,根據整體資源的使用狀況,部署到任何地方。先不要扯別的,那會擾亂視線,增加複雜性。

注意任何這兩個字,預示着你並不能夠通過常規的 IP、端口方式訪問部署的實例。複雜性由此而生。

我們學 k8s,就要看它要調度哪些資源。以傳統的感覺來看,無非就是cpu內存網絡io等。在瞭解怎麼對這些資源調度之前,先要搞懂什麼叫 Pod,這可是 k8s 的核心概念之一。

搞不懂 Pod,就沒法玩 k8s。

本文的腦圖,可以在這裏在線查看:http://mind.xjjdog.cn/mind/cloud-k8s

  1. Pod

pod 是 k8s 調度的最小單元,包含一個或者多個容器(這裏的容器你可以暫時認爲是 docker)。

Pod 擁有一個唯一的 IP 地址,在包含多個容器的時候,依然是擁有一個 IP 地址,它是怎麼辦到的呢?

xjjdog之前寫過兩篇 Docker 原理的文章,指出其中兩個使用到的底層技術,就是 namespacecgroup,k8s 在使用多個容器的時候,用到的就是共享namespace,這樣 Pod 裏的容器就可以通過 localhost 通信了,就像兩個進程一樣。同理的,Pod 可以掛載多個共享的存儲卷(Volume),這時內部的各個容器就可以訪問共享的 Volume 進行數據的讀寫。

一些邊車 (Sidecar),以及存活探針等,也是以容器的形式,存在於 Pod 中的。所以 Pod 是一個大雜燴,它取代了 docker 容器的一部分工作(這既是Pause容器的職責),比如創建一些共享的net namespace等。

那如何表示、聲明一個 Pod 呢?又如何指定這些容器與 Pod 的關係呢?k8s 選用了yaml這種配置方式,初衷是避免過度的 API 設計。

很好,這又引入了另外一個問題,那就是 yml 文件的膨脹。所有的 k8s 運維,都有過被 yml 文件給支配的恐懼。

沒有銀彈,只不過把問題轉移到另外一個場景罷了。

聲明一個 Pod,就是寫 yml 文件。一個 Pod 的 yml 樣例,可能長得像下面這樣。

apiVersion: v1           #本版號
kind: Service            #創建的資源類型
metadata:                #元數據必選
  namespace: bcmall      #綁定命名空間
  name: bcmall-srv       #Service資源名稱
spec:                    #定義詳細信息
  type: NodePort         #類型
  selector:              #標籤選擇器
    app: container-bcmall-pod 
  ports:                 #定義端口
    - port: 8080         #port 指定server端口,此端口用於集羣內部訪問
      targetPort: 80     #綁定pod端口
      nodePort: 14000    #將server 端口映射到Node節點的端口,用於外網訪問
      protocol: TCP      #端口協議

注意kind這個選項,這將是 k8s 概念膨脹的噩夢!k8s 的各種配置,基本上都是圍着這裏轉。哦對了,要讓這些 yml 文件生效,你需要用到 kubectl 命令,就像這樣。

kubectl create -f ./bcmall.yaml

訪問一個 Pod,可以通過它的 IP,也可以通過內部的域名(這時候就需要 CoreDNS)。當這麼用的時候,其實 Pod 的表現,就相當於一臺普通的機器,裏面的容器就是一堆進程而已。

  1. 探針和鉤子

一個 Pod 被調度之後,就要進行初始化。初始化肯定是得有一個反饋的,否則都不知道最終有沒有啓動成功。這些健康檢查的功能,叫做探針(Probe),一個比較怪異的英文名詞。

常見的有 livenessProbe、readinessProbe、startupProbe 等三種探針。

livenessProbe有點像心跳,如果判定不在線了,就會把它幹掉;readinessProbe 一般表示就緒狀態,也比較像心跳,證明你的服務在正常跑着;startupProbe 用於判斷容器是否已經啓動好,避免一些超時等,比如你的 JVM 啓動完畢了,才能對外提供服務。

一般,花費 120s startupProbe 的啓動實踐,每隔 5s 檢測一下 livenessProbe,每隔 10s 檢測一下 readinessProbe, 是常用的操作。

這些信息,也是在 yml 中配置的,具體的配置層次如何,這裏不羅嗦,您就查文檔去吧。

再說一下鉤子(Hook)。主要有PostStartPreStop兩種。PostStart 可以在容器啓動之後就執行,PreStop 則在容器被終止之前被執行。這沒什麼神奇的,就是執行一些 shell 腳本而已,只不過比較常用,就提升到了關鍵字的級別。

我們來看看它長什麼樣子。由於這些配置文件大同小異,後面就不再貼這樣的代碼了。

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5
  1. 高可用引起的名詞爆炸

上面說到,yaml 的複雜性,是由於 kind 的種類多所引起的。首先我們要接觸的,就是ReplicaSet

我們需要多個副本,才能做高可用。

原因很簡單,一個 Pod 就相當於一臺機器,當掉之後,就無法提供服務了,這是哪門子的高可用?所以對等的 Pod,要有多份纔行。

ReplicaSet簡稱RS,可以讓你的 Pod 數量一直保持在某個水平。但它在操作起來還是有點麻煩了,所以一般使用更加高級的Deployment。Deployment 可以實現一些滾動升級的需求,但前提是你需要在spec.template.metadata.labels中設置了相應的鍵值對。

k8s 的一些過濾工作,都是通過 labels 來實現的。這其實是一種非常折衷的做法,因爲它本身並沒有做一些類似於 sql 查詢之類的工作,就只能在這一堆 map 的鍵值對上做文章。比如這樣:

kubectl get pod -n demo -l app=nginx,version=v1

是不是很魔幻的寫法?不要緊,習慣了就好了。

這些 yml 配置,通常都是一環套一環的,還會有交叉引用,所以也會有優先級。高階的 kind 會直接順帶把低階的 kind 一起創建了,屬於一個級聯關係。

一切不過是 yml 文件包了一層而已。

好了,我們要接觸下一個 kind:service了。

爲什麼需要 Service?因爲我們上面創建的 Pod,哪怕是Deployment創建的 Pod,你訪問它都要費些功夫。雖然 Pod 有 IP,但如果它重啓了,或者銷燬了,IP 就會動態變化。因爲 Pod 是被調度的,它並不知道自己會被調度到哪一臺機器。

Service 這個東西,就是要提供一種非 IP 的訪問途徑,使得不論 Pod 在哪裏,我們都能訪問的到它。

如圖所示,通過 Labels 的過濾,可以把多個 Pod 歸結爲一類,然後以某種類型對外暴露服務。Service 說白了也是一個組合後的東西。

對外訪問的類型,這裏要着重說明一下,因爲它重要,所以要敲黑板。主要有 4 種:

但是等等。k8s 是如何實現跨主機的 Pod 相互訪問的呢?

在單個 Node 上的 Pod 相互訪問可以理解,直接通過 docker0 網橋分配的 IP,就可相互訪問。

那 k8s 的底層網絡是真麼設置的呢?答案可能令人沮喪。k8s 本身並不負責網絡管理,也不爲容器提供具體的網絡設置,它是通過 CNI(容器網絡接口)來實現的。在不同的 Node 之上,不同的 Pod 訪問就費了點勁,這正是 CNI 的工作。常用的 CNI 插件有:Flannel、Calico、Canal、Weave。

沒錯,又是一堆名詞,而且各個都很難搞。

網絡方面是 k8s 最複雜的知識點,框架也奇多,後面的文章會專門進行介紹。

  1. 內部組件

在開啓更多的 Kind 之前,我們來看一下 k8s 的內部組件。

下面這張圖,就是官網的一張圖片,說明了 k8s 的一系列必要的組件。其中,etcd根本就不是這個體系裏的,但 k8s 的一些持久化狀態,需要有個地方存,就引入了這麼一個組件,用來存儲配置信息。

其中左半部分,是 k8s 自身的組件;右半部分,就在每個 Node(也就是物理機)上的守護進程。它們的作用如下:

這些組件的職責,已經是非常非常清楚了。難點還是在多種 Kind 概念上。

  1. 更多概念

圖中的這些概念,本質上都是在Pod之上,又包了一層。層次越高,功能越抽象,依賴的配置也越多。下面將挑主要的進行介紹。

  1. 資源限制

很好,我們終於要聊一點資源限制方面的內容了。k8s 的資源限制,仍然是通過 cgroup 來實現的。

k8s 提供了requestslimits 兩種類型參數對資源進行預分配和使用限制。

不要被這兩個詞給迷惑了。requests 就相當於 JVM 參數中的-Xms,limits 就相當於-Xmx。所以,如果你類比着把這兩個值設置成一樣的,是一種最佳的實踐方式。

只是它的設置有點怪異:

requests:
 memory: "64Mi"
 cpu: "250m"
limits:
 memory: "128Mi"
 cpu: "500m"

內存的單位是Mi,而 cpu 的單位是m,要多彆扭有多彆扭,但它是有原因的。

m毫核的意思。比如,我們的操作系統有 4 核,把它乘以 1000,那就是總 CPU 資源是 4000 毫核。如果你想要你的應用最多佔用1/4核,那就設置成250m

再來看內存,Mi 是 MiB 的意思,我也搞不懂爲啥不用 MB,而使用 Mi,可能是想讓你印象深刻吧(MB 和 MiB 還真不一樣)。

若內存使用超出限制,會引發系統的 OOM 機制,但 CPU 不會,頂多會影響系統運行罷了。

k8s 還提供了叫做LimitRangeResourceQuota的 Kind,用來限定 CPU 和 Memory 的申請範圍,功能更加高級。

  1. 集羣搭建工具

k8s 的集羣搭建,常見的有 kind,minikube,kubeadm,rancher2 等。其中 rancher2 可以說是相對來說比較容易的方式。它考慮了一些網絡不通的因素,有一些推薦的代理選項,對於新手來說,拿來嚐嚐鮮還是很好用的。

但在正常的使用中,還是推薦你使用 kubeadm 這個工具,這是官方維護和推薦的搭建工具,並做到了向下兼容,按照官方的指引,只需要kubeadm init就能搭建完畢。至於什麼監控、日誌等,反倒是好處理的了。

k8s 最麻煩的有三點:

搞懂了這三個方面,可以說玩轉 k8s 就沒問題了。

作者簡介:小姐姐味道  (xjjdog),一個不允許程序員走彎路的公衆號。聚焦基礎架構和 Linux。十年架構,日百億流量,與你探討高併發世界,給你不一樣的味道。我的個人微信 xjjdog0,歡迎添加好友,進一步交流。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/LNAKjbcTLLUfBZKYkqkTeA