1. 程式人生 > >從零開始入門 K8s | 應用配置管理

從零開始入門 K8s | 應用配置管理

一、需求來源

背景問題

首先一起來看一下需求來源。大家應該都有過這樣的經驗,就是用一個容器映象來啟動一個 container。要啟動這個容器,其實有很多需要配套的問題待解決:

  • 第一,比如說一些可變的配置。因為我們不可能把一些可變的配置寫到映象裡面,當這個配置需要變化的時候,可能需要我們重新編譯一次映象,這個肯定是不能接受的;
  • 第二就是一些敏感資訊的儲存和使用。比如說應用需要使用一些密碼,或者用一些 token;
  • 第三就是我們容器要訪問叢集自身。比如我要訪問 kube-apiserver,那麼本身就有一個身份認證的問題;
  • 第四就是容器在節點上執行之後,它的資源需求;
  • 第五個就是容器在節點上,它們是共享核心的,那麼它的一個安全管控怎麼辦?
  • 最後一點我們說一下容器啟動之前的一個前置條件檢驗。比如說,一個容器啟動之前,我可能要確認一下 DNS 服務是不是好用?又或者確認一下網路是不是聯通的?那麼這些其實就是一些前置的校驗。

Pod 的配置管理

在 Kubernetes 裡面,它是怎麼做這些配置管理的呢?如下圖所示:

  • 可變配置就用 ConfigMap;
  • 敏感資訊是用 Secret;
  • 身份認證是用 ServiceAccount 這幾個獨立的資源來實現的;
  • 資源配置是用 Resources;
  • 安全管控是用 SecurityContext;
  • 前置校驗是用 InitContainers 這幾個在 spec 裡面加的欄位,來實現的這些配置管理。

二、ConfigMap

ConfigMap 介紹

下面我們來介紹第一個部分,就是 ConfigMap。我們先來介紹 ConfigMap 它是用來做什麼的、以及它帶來的一個好處。它其實主要是管理一些可變配置資訊,比如說我們應用的一些配置檔案,或者說它裡面的一些環境變數,或者一些命令列引數。

它的好處在於可以讓一些可變配置和容器映象進行解耦,這樣也保證了容器的可移植性。看一下下圖中右邊的編排檔案截圖。

這是 ConfigMap 本身的一個定義,它包括兩個部分:一個是 ConfigMap 元資訊,我們關注 name 和 namespace 這兩個資訊。接下來這個 data 裡面,可以看到它管理了兩個配置檔案。它的結構其實是這樣的:從名字看 ConfigMap 中包含 Map 單詞,Map 其實就是 key:value,key 是一個檔名,value 是這個檔案的內容。

ConfigMap 建立

看過介紹之後,再具體看一下它是怎麼建立的。我們推薦用 kubectl 這個命令來建立,它帶的引數主要有兩個:一個是指定 name,第二個是 DATA。其中 DATA 可以通過指定檔案或者指定目錄,以及直接指定鍵值對,下面可以看一下這個例子。

指定檔案的話,檔名就是 Map 中的 key,檔案內容就是 Map 中的 value。然後指定鍵值對就是指定資料鍵值對,即:key:value 形式,直接對映到 Map 的 key:value。

ConfigMap 使用

建立完了之後,應該怎麼使用呢?

如上圖所示,主要是在 pod 裡來使用 ConfigMap:

  • 第一種是環境變數。環境變數的話通過 valueFrom,然後 ConfigMapKeyRef 這個欄位,下面的 name 是指定 ConfigMap 名,key 是 ConfigMap.data 裡面的 key。這樣的話,在 busybox 容器啟動後容器中執行 env 將看到一個 SPECIAL_LEVEL_KEY 環境變數;
  • 第二個是命令列引數。命令列引數其實是第一行的環境變數直接拿到 cmd 這個欄位裡面來用;
  • 最後一個是通過 volume 掛載的方式直接掛到容器的某一個目錄下面去。上面的例子是把 special-config 這個 ConfigMap 裡面的內容掛到容器裡面的 /etc/config 目錄下,這個也是使用的一種方式。

ConfigMap 注意要點

現在對 ConfigMap 的使用做一個總結,以及它的一些注意點,注意點一共列了以下五條:

  1. ConfigMap 檔案的大小。雖然說 ConfigMap 檔案沒有大小限制,但是在 ETCD 裡面,資料的寫入是有大小限制的,現在是限制在 1MB 以內;
  2. 第二個注意點是 pod 引入 ConfigMap 的時候,必須是相同的 Namespace 中的 ConfigMap,前面其實可以看到,ConfigMap.metadata 裡面是有 namespace 欄位的;
  3. 第三個是 pod 引用的 ConfigMap。假如這個 ConfigMap 不存在,那麼這個 pod 是無法建立成功的,其實這也表示在建立 pod 前,必須先把要引用的 ConfigMap 建立好;
  4. 第四點就是使用 envFrom 的方式。把 ConfigMap 裡面所有的資訊匯入成環境變數時,如果 ConfigMap 裡有些 key 是無效的,比如 key 的名字裡面帶有數字,那麼這個環境變數其實是不會注入容器的,它會被忽略。但是這個 pod 本身是可以建立的。這個和第三點是不一樣的方式,是 ConfigMap 檔案存在基礎上,整體匯入成環境變數的一種形式;
  5. 最後一點是:什麼樣的 pod 才能使用 ConfigMap?這裡只有通過 K8s api 建立的 pod 才能使用 ConfigMap,比如說通過用命令列 kubectl 來建立的 pod,肯定是可以使用 ConfigMap 的,但其他方式建立的 pod,比如說 kubelet 通過 manifest 建立的 static pod,它是不能使用 ConfigMap 的。

三、Secret

Secret 介紹

現在我們講一下 Secret,Secret 是一個主要用來儲存密碼 token 等一些敏感資訊的資源物件。其中,敏感資訊是採用 base-64 編碼儲存起來的,我們來看下圖中 Secret 資料的定義。

元資料的話,裡面主要是 name、namespace 兩個欄位;接下來是 type,它是非常重要的一個欄位,是指 Secret 的一個型別。Secret 型別種類比較多,下面列了常用的四種類型:

  • 第一種是 Opaque,它是普通的 Secret 檔案;
  • 第二種是 service-account-token,是用於 service-account 身份認證用的 Secret;
  • 第三種是 dockerconfigjson,這是拉取私有倉庫映象的用的一種 Secret;
  • 第四種是 bootstrap.token,是用於節點接入叢集校驗用的 Secret。

再接下來是 data,是儲存的 Secret 的資料,它也是 key-value 的形式儲存的。

Secret 建立

接下來我們看一下 Secret 的建立。

如上圖所示,有兩種建立方式:

  • 系統建立:比如 K8s 為每一個 namespace 的預設使用者(default ServiceAccount)建立 Secret;

  • 使用者手動建立:手動建立命令,推薦 kubectl 這個命令列工具,它相對 ConfigMap 會多一個 type 引數。其中 data 也是一樣,它也是可以指定檔案和鍵值對的。type 的話,要是不指定,就預設是 Opaque 型別。

上圖中兩個例子。第一個是通過指定檔案,建立了一個拉取私有倉庫映象的 Secret,指定的檔案是 /root/.docker/config.json。type 的話指定的是 dockerconfigjson,另外一個我們指定鍵值對,我們 type 沒有指定,預設是 Opaque。鍵值對是 key:value 的形式,其中對 value 內容進行 base64 加密。建立 Secret 就是這麼一個情況。

Secret 使用

建立完 Secret 之後,再來看一下如何使用它。它主要是被 pod 來使用,一般是通過 volume 形式掛載到容器裡指定的目錄,然後容器裡的業務程序再到目錄下讀取 Secret 來進行使用。另外在需要訪問私有映象倉庫時,也是通過引用 Secret 來實現。

我們先來看一下掛載到使用者指定目錄的方式:

  • 第一種方式:如上圖左側所示,使用者直接指定,把 mysecret 掛載到容器 /etc/foo 目錄下面;
  • 第二種方式:如上圖右側所示,系統自動生成,把 serviceaccount-secret 自動掛載到容器 /var/run/secrets/kubernetes.io/serviceaccount 目錄下,它會生成兩個檔案,一個是 ca.crt,一個是 token。這是兩個儲存了認證資訊的證書檔案。

使用私有映象庫

下面看一下用 Secret 來使用私有映象倉庫。首先,私有映象倉庫的資訊是儲存在 Secret 裡面的(具體參照上述的Secret建立章節),然後拉取私有倉庫映象,那麼通過下圖中兩種方法的配置就可以:

  • 第一種方式:如下圖左側所示,直接在 pod 裡面,通過 imagePullSecrets 欄位來配置;
  • 第二種方式是自動注入。使用者提前在 pod 會使用的 serviceaccount 裡配置 imagePullSecrets,Pod 時系統自動注入這個 imagePullSecrets。

Secret 使用注意要點

最後來看一下 Secret 使用的一些注意點,下面列了三點:

  1. 第一個是 Secret 的檔案大小限制。這個跟 ConfigMap 一樣,也是 1MB;

  2. 第二個是 Secret 採用了 base-64 編碼,但是它跟明文也沒有太大區別。所以說,如果有一些機密資訊要用 Secret 來儲存的話,還是要很慎重考慮。也就是說誰會來訪問你這個叢集,誰會來用你這個 Secret,還是要慎重考慮,因為它如果能夠訪問這個叢集,就能拿到這個 Secret。
    如果是對 Secret 敏感資訊要求很高,對加密這塊有很強的需求,推薦可以使用 Kubernetes 和開源的 vault做一個解決方案,來解決敏感資訊的加密和許可權管理。

  3. 第三個就是 Secret 讀取的最佳實踐,建議不要用 list/watch,如果用 list/watch 操作的話,會把 namespace 下的所有 Secret 全部拉取下來,這樣其實暴露了更多的資訊。推薦使用 GET 的方法,這樣只獲取你自己需要的那個 Secret。

四、ServiceAccount

ServiceAccount 介紹

接下來,我們講一下 ServiceAccount。ServiceAccount 首先是用於解決 pod 在叢集裡面的身份認證問題,身份認證資訊是存在於 Secret 裡面。

先看一下上面的左側截圖,可以看到最下面的紅框裡,有一個 Secret 欄位,它指定 ServiceAccount 用哪一個 Secret,這個是 K8s 自動為 ServiceAccount 加上的。然後再來看一下上圖中的右側截圖,它對應的 Secret 的 data 裡有兩塊資料,一個是 ca.crt,一個是 token。ca.crt 用於對服務端的校驗,token 用於 Pod 的身份認證,它們都是用 base64 編碼過的。然後可以看到 metadata 即元資訊裡,其實是有關聯 ServiceAccount 資訊的(這個 secret 被哪個 ServiceAccount 使用)。最後我們注意一下 type,這個就是 service-account-token 這種型別。

舉例:Pod 裡的應用訪問它所屬的 K8s 叢集

介紹完 ServiceAccount 以及它對應的 secret 後,我們來看一下,pod 是怎麼利用 ServiceAccount 或者說它是怎麼利用 secret 來訪問所屬 K8s 叢集的。
其實 pod 建立的時候,首先它會把這個 secret 掛載到容器固定的目錄下,這是 K8s 功能上實現的。它要把這個 ca.crt 和 token 這兩個檔案掛載到固定目錄下面。
pod 要訪問叢集的時候,它是怎麼來利用這個檔案的呢?我們看一下下面的程式碼截圖:

我們在 Go 裡面實現 Pod 訪問 K8s 叢集時,一般直接會調一個 InClusterConfig 方法,來生成這個訪問服務 Client 的一些資訊。然後可以看一下,最後這個 Config 裡面有兩部分資訊:

  • 一個是 tlsClientConfig,這個主要是用於 ca.crt 校驗服務端;
  • 第二個是 Bearer Token,這個就是 pod 的身份認證。在服務端,會利用 token 對 pod 進行一個身份認證。

再次回到上圖左側。認證完之後 pod 的身份資訊會有兩部分:一個是 Group,一個是 User。身份認證是就是認證這兩部分資訊。接著可以使用 RBAC 功能,對 pod 進行一個授權管理。

假如 RBAC 沒有配置的話,預設的 pod 具有資源 GET 許可權,就是可以從所屬的 K8s 叢集裡 get 資料。如果是需要更多的許可權,那麼就需要自行配置 RBAC 。RBAC 的相關知識,我們在後面的課程裡面會詳細介紹,大家可以關注一下。

五、Resource

容器資源配合管理

下面介紹一下 Resource,即:容器的一個資源配置管理。

目前內部支援型別有三種:CPU、記憶體,以及臨時儲存。當用戶覺得這三種不夠,有自己的一些資源,比如說 GPU,或者其他資源,也可以自己來定義,但配置時,指定的數量必須為整數。目前資源配置主要分成 request 和 limit 兩種型別,一個是需要的數量,一個是資源的界限。CPU、記憶體以及臨時儲存都是在 container 下的 Resource 欄位裡進行一個宣告。

舉個例子,wordpress 容器的資源需求,一個是 request ,一個是 limits,它分別對需要的資源和資源臨界進行一個宣告。

Pod 服務質量 (QoS) 配置

根據 CPU 對容器記憶體資源的需求,我們對 pod 的服務質量進行一個分類,分別是 Guaranteed、Burstable 和 BestEffort。

  • Guaranteed :pod 裡面每個容器都必須有記憶體和 CPU 的 request 以及 limit 的一個宣告,且 request 和 limit 必須是一樣的,這就是 Guaranteed;
  • Burstable:Burstable 至少有一個容器存在記憶體和 CPU 的一個 request;
  • BestEffort:只要不是 Guaranteed 和 Burstable,那就是 BestEffort。

那麼這個服務質量是什麼樣的呢?資源配置好後,當這個節點上 pod 容器執行,比如說節點上 memory 配額資源不足,kubelet會把一些低優先順序的,或者說服務質量要求不高的(如:BestEffort、Burstable)pod 驅逐掉。它們是按照先去除 BestEffort,再去除 Burstable 的一個順序來驅逐 pod 的。

六、SecurityContext

SecurityContext 介紹

SecurityContext 主要是用於限制容器的一個行為,它能保證系統和其他容器的安全。這一塊的能力不是 Kubernetes 或者容器 runtime 本身的能力,而是 Kubernetes 和 runtime 通過使用者的配置,最後下傳到核心裡,再通過核心的機制讓 SecurityContext 來生效。所以這裡介紹的內容,會比較簡單或者說比較抽象一點。

SecurityContext 主要分為三個級別:

  • 第一個是容器級別,僅對容器生效;
  • 第二個是 pod 級別,對 pod 裡所有容器生效;
  • 第三個是叢集級別,就是 PSP,對叢集內所有 pod 生效。

許可權和訪問控制設定項,現在一共列有七項(這個數量後續可能會變化):

  1. 第一個就是通過使用者 ID 和組 ID 來控制檔案訪問許可權;
  2. 第二個是 SELinux,它是通過策略配置來控制使用者或者程序對檔案的訪問控制;
  3. 第三個是特權容器;
  4. 第四個是 Capabilities,它也是給特定程序來配置一個 privileged 能力;
  5. 第五個是 AppArmor,它也是通過一些配置檔案來控制可執行檔案的一個訪問控制權限,比如說一些埠的讀寫;
  6. 第六個是一個對系統呼叫的控制;
  7. 第七個是對子程序能否獲取比父親更多的許可權的一個限制。

最後其實都是落到核心來控制它的一些許可權。

上圖是對 pod 級別和容器級別配置 SecurityContext 的一個例子,如果大家對這些內容有更多的需求,可以根據這些資訊去搜索更深入的資料來學習。

七、InitContainer

InitContainer 介紹

接下來看一下 InitContainer,首先介紹 InitContainer 和普通 container 的區別,有以下三點內容:

  1. InitContainer 首先會比普通 container 先啟動,並且直到所有的 InitContainer 執行成功後,普通 container 才會被啟動;
  2. InitContainer 之間是按定義的次序去啟動執行的,執行成功一個之後再執行第二個,而普通的 container 是併發啟動的;
  3. InitContainer 執行成功後就結束退出,而普通容器可能會一直在執行。它可能是一個 longtime 的,或者說失敗了會重啟,這個也是 InitContainer 和普通 container 不同的地方。

根據上面三點內容,我們看一下 InitContainer 的一個用途。它其實主要為普通 container 服務,比如說它可以為普通 container 啟動之前做一個初始化,或者為它準備一些配置檔案, 配置檔案可能是一些變化的東西。再比如做一些前置條件的校驗,如網路是否聯通。

上面的截圖是 flannel 元件的 InitContainer 的一個配置,它的 InitContainer 主要是為 kube-flannel 這個普通容器啟動之前準備一些網路配置檔案。

本文總結

  • ConfigMap 和 Secret: 首先介紹了 ConfigMap 和 Secret 的建立方法和使用場景,然後對 ConfigMap 和 Secret 的常見使用注意點進行了分類和整理。最後介紹了私有倉庫映象的使用和配置;
  • Pod 身份認證: 首先介紹了 ServiceAccount 和 Secret 的關聯關係,然後從原始碼角度對 Pod 身份認證流程和實現細節進行剖析,同時引出了 Pod 的許可權管理(即 RBAC 的配置管理);
  • 容器資源和安全: 首先介紹了容器常見資源型別 (CPU/Memory) 的配置,然後對 Pod 服務質量分類進行詳細的介紹。同時對 SecurityContext 有效層級和許可權配置項進行簡要說明;
  • InitContainer: 首先介紹了 InitContainer 和普通 container 的區別以及 InitContainer 的用途。然後基於實際用例對 InitContainer 的用途進行了說明。

阿里巴巴雲原生微信公眾號(ID:Alicloudnative)關注微服務、Serverless、容器、Service Mesh等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的技術公眾號。