1. 程式人生 > >如何在K8S中優雅的使用私有映象庫 (Docker版)

如何在K8S中優雅的使用私有映象庫 (Docker版)

# 前言 在企業落地 K8S 的過程中,私有映象庫 (專用映象庫) 必不可少,特別是在 Docker Hub 開始對免費使用者限流之後, 越發的體現了搭建私有映象庫的重要性。 私有映象庫不但可以加速映象的拉取還可以避免因特有的"網路問題"導致映象拉取失敗尷尬。 當然部署了私有映象庫之後也需要對映象庫設定一些安全策略,大部分私有映象庫採用 IP訪問策略+認證 (非公開專案) 的方式對映象庫進行安全保護。 那麼對於含有認證限制的映象庫,在 K8S 中該如何優雅的整合呢? 下文就總結了在 K8S 中使用私有映象庫的幾種情況和方式。 # 在 K8S 中使用私有映象庫 首先要確定私有映象庫的授權使用方式,在針對不同的使用方式選擇對應的認證配置。 1. 針對節點 (Node) > 這個應該是企業使用 K8S 時最常用的方式,一般也只要使用這個就夠了,並且該方案几乎是使用了私有映象庫之後必不可少的配置,它可以做到: 在節點環境中進行一定的配置,不需要在 K8S 中進行其它的配置即可享有具體私有庫的許可權。 該方案對該節點上的所有 Pods 生效,**同時還對非 Pods 映象生效,例如: kubelet 的 pause 映象,這個非常關鍵**。 2. 針對服務賬號 (ServiceAccount)、針對名稱空間 (Namespace) > 配置了該 ServiceAccount 的 Pod 都享有這個 ServiceAccount 所配置的映象庫認證設定。 > 還可以利用 K8S 中 default ServiceAccount 機制,達到對一個具體名稱空間中沒有特殊設定的所有 Pod 生效。 3. 針對 Pod > 針對具體的 Pod 進行認證配置,該 Pod 就會具有私有庫的許可權。 > > *Deployment、DaemonSet、StatefulSet、CronJob、Job 等資源都使用了PodTemplate 最終都會以具體的 Pod 資源體驗,所以在 PodTemplate 中配置也算對 Pod 配置。* # 配置步驟 ## 前提條件 1. 一個可用私有映象庫 (可用採用 Harbor 搭建) 2. 私有映象庫的賬號和密碼 (推薦只給只讀許可權) 3. CRI 基於 Docker (其它的 CRI 暫沒有驗證) ## 針對節點 (Node) 配置 1. 編寫 Docker 配置檔案 2. 將 Docker 配置檔案放在指定位置 3. 重啟 kubelet ### 編寫 Docker 配置檔案 首先編寫 Docker 的認證配置檔案, 格式如下: ```json { "auths": { "": { "auth": "" } } } ``` `` 為私有映象庫的地址, 例如: `hub.docker.com` `` 為 `BASE64(:)` 例如: `cmVhZGVyOjEyMzQ1Ng==`, 其中賬號是: `reader`, 密碼是: `123456` 使用 `:` 拼接後進行 base64 完整的配置檔案, 例 ```json { "auths": { "hub.docker.com": { "auth": "cmVhZGVyOjEyMzQ1Ng==" }, "harbor.domain.cn": { "auth": "cmVhZGVyOiFAIzQ1Ng==" } } } ``` 如有多個映象庫在 `auths` 節中進行新增即可。 ### 將 Docker 配置檔案放在指定位置 推薦放在 kubelet 根目錄中, 配置檔案需以 `config.json` 命名。 預設的 kubelet 根目錄一般為 `/var/lib/kubelet` (如有修改進行替換即可) 也就是需要放置在 `/var/lib/kubelet/config.json`。 還可以放在以下位置: ```sh {--root-dir:-/var/lib/kubelet}/config.json {cwd of kubelet}/config.json ${HOME}/.docker/config.json /.docker/config.json {--root-dir:-/var/lib/kubelet}/.dockercfg {cwd of kubelet}/.dockercfg ${HOME}/.dockercfg /.dockercfg ``` > 參考文件: > https://kubernetes.io/docs/concepts/containers/images/#configuring-nodes-to-authenticate-to-a-private-registry #### 放在 ${HOME} 開頭的位置 需要在 kubelet service 環境中配置 HOME 的路徑, 不然不會生效, 例如: HOME=/root **下面是使用 `kubeadm` 安裝的環境中可用的指令碼, 如果不是請自行配置** ```sh echo "HOME=${HOME}" >> /var/lib/kubelet/kubeadm-flags.env ``` ### 重啟 kubelet 如果 init 不是 systemd,請自行替換服務重啟的命令 ```sh systemctl daemon-reload; systemctl restart kubelet ``` ## 針對服務賬號 (ServiceAccount)、針對名稱空間 (Namespace) 1. 建立一個 Docker 登錄檔機密資源 2. 設定 ServiceAccount 的 imagePullSecrets 3. 將 Pod 的 serviceAccountName 設定為該 ServiceAccount 的名稱 ### 建立一個 Docker 登錄檔機密資源 #### 使用 kubectl cli 建立登錄檔機密資源 ```sh kubectl create secret docker-registry --docker-server= --docker-username= --docker-password= -n ``` 其中 `` 是機密資源的名稱, 在編輯 sa 資源的時需要引用 `` 是私有映象庫的伺服器地址 `` 是私有映象庫認證的賬號 `` 是私有映象庫認證的密碼 `` 是名稱空間名稱 示例命令如下: ```sh kubectl create secret docker-registry docker-reader-secret --docker-server=harbor.domain.cn --docker-username=reader --docker-password=123456 -n basic ``` #### 使用 yaml 建立登錄檔機密資源 ```yaml apiVersion: v1 data: .dockerconfigjson: eyJhdXRocyI6eyJET0NLRVJfUkVHSVNUUllfU0VSVkVSIjp7InVzZXJuYW1lIjoiRE9DS0VSX1VTRVIiLCJwYXNzd29yZCI6IkRPQ0tFUl9QQVNTV09SRCIsImF1dGgiOiJSRTlEUzBWU1gxVlRSVkk2UkU5RFMwVlNYMUJCVTFOWFQxSkUifX19 kind: Secret metadata: name: docker-reader-secret namespace: default type: kubernetes.io/dockerconfigjson ``` `.dockerconfigjson` 是base64之後的字串, 具體內容參考 *"編寫 Docker 配置檔案"* 節中的內容 ```sh kubectl apply -f docker-reader-secret.yaml ``` ### 設定 ServiceAccount 的 imagePullSecrets ```yaml apiVersion: v1 kind: ServiceAccount metadata: name: service1 namespace: basic secrets: - name: service1-token-mp4qs imagePullSecrets: - name: docker-reader-secret ``` ### 將資源的 serviceAccountName 設定為該 ServiceAccount 的名稱 ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 serviceAccountName: service1 ``` ### 如何針對名稱空間內的所有Pod? K8S 中有個預設的機制,會在名稱空間中建立一個名稱為 `default` 的 ServiceAccount (sa) 資源。 並且在資源沒有單獨指定 `serviceAccountName` 時, 預設使用 `default` 作為serviceAccountName。 所以我們只需設定 default ServiceAccount 的 imagePullSecrets 即可對該名稱空間中沒有特殊指定 `serviceAccountName` 欄位的 Pod 生效了。 ## 針對 Pod 1. 建立一個 Docker 登錄檔機密資源 2. 設定 Pod 的 imagePullSecrets ### 建立一個 Docker 登錄檔機密資源 參考 *"建立一個 Docker 登錄檔機密資源"* 節中的內容 ### 一個具體的 Pod ```yaml apiVersion: v1 kind: Pod metadata: name: foo namespace: awesomeapps spec: containers: - name: foo image: janedoe/awesomeapp:v1 imagePullSecrets: - name: docker-reader-secret ``` ### 針對具有 PodTemplate 內容的資源 ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 imagePullSecrets: - name: docker-reader-secret ``` # 最後 如果大家的私有映象庫還沒有采用認證,就趕緊行動起來吧! 血的教訓,安全問題刻不