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