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

前言

在企業落地 K8S 的過程當中,私有鏡像庫 (專用鏡像庫) 必不可少,特別是在 Docker Hub 開始對免費用戶限流以後, 愈加的體現了搭建私有鏡像庫的重要性。node

私有鏡像庫不但能夠加速鏡像的拉取還能夠避免因特有的"網絡問題"致使鏡像拉取失敗尷尬。nginx

固然部署了私有鏡像庫以後也須要對鏡像庫設置一些安全策略,大部分私有鏡像庫採用 IP訪問策略+認證 (非公開項目) 的方式對鏡像庫進行安全保護。docker

那麼對於含有認證限制的鏡像庫,在 K8S 中該如何優雅的集成呢?
下文就總結了在 K8S 中使用私有鏡像庫的幾種狀況和方式。json

在 K8S 中使用私有鏡像庫

首先要肯定私有鏡像庫的受權使用方式,在針對不一樣的使用方式選擇對應的認證配置。api

  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 配置。app

配置步驟

前提條件

  1. 一個可用私有鏡像庫 (可用採用 Harbor 搭建)
  2. 私有鏡像庫的帳號和密碼 (推薦只給只讀權限)
  3. CRI 基於 Docker (其它的 CRI 暫沒有驗證)

針對節點 (Node) 配置

  1. 編寫 Docker 配置文件
  2. 將 Docker 配置文件放在指定位置
  3. 重啓 kubelet

編寫 Docker 配置文件

首先編寫 Docker 的認證配置文件, 格式以下:dom

{
  "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

參考文檔:
https://kubernetes.io/docs/concepts/containers/images/#configuring-nodes-to-authenticate-to-a-private-registry

放在 ${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)

  1. 建立一個 Docker 註冊表機密資源
  2. 設置 ServiceAccount 的 imagePullSecrets
  3. 將 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

  1. 建立一個 Docker 註冊表機密資源
  2. 設置 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

最後

若是你們的私有鏡像庫尚未採用認證,就趕忙行動起來吧! 血的教訓,安全問題刻不容緩。

相關文章
相關標籤/搜索