如何在K8S中優雅的使用私有映象庫 (Docker版)
阿新 • • 發佈:2020-12-31
# 前言
在企業落地 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
```
# 最後
如果大家的私有映象庫還沒有采用認證,就趕緊行動起來吧!
血的教訓,安全問題刻不