從零開始入門 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做一個解決方案,來解決敏感信息的加密和權限管理。

  1. 第三個就是 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)。

相關閱讀:

從零開始入門 K8s:應用編排與管理:Job & DaemonSet

從零開始入門 K8s:應用編排與管理

從零開始入門 K8s:K8s 的應用編排與管理

從零開始入門 K8s:詳解 Pod 及容器設計模式

從零開始入門 K8s:詳解 K8s 容器基本概念

從零開始入門 K8s:詳解 K8s 核心概念

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