k8s配置中心-configmap,Secret密碼

Jeff的技術棧發表於2021-12-09

k8s配置中心-configmap,Secret

​ 在生產環境中經常會遇到需要修改配置檔案的情況,傳統的修改方式不僅會影響到服務的正常執行,而且操作步驟也很繁瑣。為了解決這個問題,kubernetes專案從1.2版本引入了ConfigMap功能,用於將應用的配置資訊與程式的分離。這種方式不僅可以實現應用程式被的複用,而且還可以通過不同的配置實現更靈活的功能。在建立容器時,使用者可以將應用程式打包為容器映象後,通過環境變數或者外接掛載檔案的方式進行配置注入。ConfigMap && Secret 是K8S中的針對應用的配置中心,它有效的解決了應用掛載的問題,並且支援加密以及熱更新等功能,可以說是一個k8s提供的一件非常好用的功能。

建立ConfigMap

# 建立名稱空間
apiVersion: v1
kind: Namespace
metadata:
  name: sg-bs
  labels:
    app: sg-bs
---

# ConfigMap是名稱空間級資源
apiVersion: v1
kind: ConfigMap
metadata:
  name: test-configmap
  namespace: sg-bs
data: # 健 : 值
  level: debug

使用ConfigMap

## 使用掛載方式,將配置檔案掛載到容器中
# 使用
kind: Deployment
apiVersion: apps/v1
metadata:
  name: nginx-config
spec:
  selector:
    matchLabels:
      app: nginx-config
  template:
    metadata:
      labels:
        app: nginx-config
    spec:
      containers:
        - name: nginx
          image: nginx
          volumeMounts: # 掛載
            - mountPath: /etc/nginx/conf.d  # 掛載路徑
              name: nginx-config-configmap # 儲存卷名字
    
      volumes:
        - name: nginx-config
          persistentVolumeClaim:
            claimName: nginx-config
        - name: nginx-config-configmap
          configMap:
            name: test-configmap # ConfigMap名字
            items:
              - key: level
                path: level # 最終路徑為:/etc/nginx/conf.d/level

subPath引數

# configmap熱更新
## 修改configmap中的檔案,可以同步到所有的掛載此configmap的容器中(僅僅同步到容器中),但是如果使用subPath引數,則熱更新失效。

## configMap掛載會直接覆蓋原來的目錄,如果不覆蓋則需要使用subPath引數(subPath引數只能夠針對檔案,同時不支援熱更新)


apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  default.conf: |
    server {
        listen       80;
        listen  [::]:80;
        server_name  _;
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.php;
        }
        location ~ \.php$ {
            root           /usr/share/nginx/html;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /usr/share/nginx/html$fastcgi_script_name;
            include        fastcgi_params;
        }
    }
  index.php: |
    <?php

    phpinfo();

    ?>
---
kind: Service
apiVersion: v1
metadata:
  name: nginx-config
spec:
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30089
  selector:
    app: nginx-config
  type: NodePort
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: nginx-config
spec:
  selector:
    matchLabels:
      app: nginx-config
  template:
    metadata:
      labels:
        app: nginx-config
    spec:
      containers:
        - name: php
          image: alvinos/php:wordpress-v2
          volumeMounts:
            - mountPath: /usr/share/nginx/html
              name: nginx-config-configmap

        - name: nginx
          image: alvinos/nginx:wordpress-v2
          volumeMounts:
            - mountPath: /usr/share/nginx/html/index.php
              name: nginx-config-configmap
              subPath: index.php

            - mountPath: /etc/nginx/conf.d
              name: nginx-config-configmap
      volumes:
        - name: nginx-config-configmap
          configMap:
            name: nginx-config
            items:
              - key: index.php
                path: index.php

Secret

​ Secret解決了密碼、token、金鑰等敏感資料的配置問題,而不需要把這些敏感資料暴露到映象或者Pod Spec中。Secret可以以Volume或者環境變數的方式使用。

Secret用來儲存敏感資料,儲存之前就必須將檔案進行base64加密,掛載到pod中,自動解密。
預設使用Opaque型別。

Secret有四種型別:
Service Account :用來訪問Kubernetes API,由Kubernetes自動建立,並且會自動掛載到Pod的/run/secrets/kubernetes.io/serviceaccount目錄中;

Opaque :base64編碼格式的Secret,用來儲存密碼、金鑰等;

kubernetes.io/dockerconfigjson :用來儲存私有docker registry的認證資訊

tls型別:訪問證照

官方文件

https://kubernetes.io/zh/docs/concepts/configuration/secret/

編寫secret清單

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  password: YWRtaW4xMjMK
  username: YWRtaW4K

使用secret

​ Secret 可以作為資料卷被掛載,或作為環境變數 暴露出來以供 Pod 中的容器使用。它們也可以被系統的其他部分使用,而不直接暴露在 Pod 內。 例如,它們可以儲存憑據,系統的其他部分將用它來代表你與外部系統進行互動。

在 Pod 中使用 Secret 檔案

在 Pod 中使用存放在卷中的 Secret:

  1. 建立一個 Secret 或者使用已有的 Secret。多個 Pod 可以引用同一個 Secret。
  2. 修改你的 Pod 定義,在 spec.volumes[] 下增加一個卷。可以給這個卷隨意命名, 它的 spec.volumes[].secret.secretName 必須是 Secret 物件的名字。
  3. spec.containers[].volumeMounts[] 加到需要用到該 Secret 的容器中。 指定 spec.containers[].volumeMounts[].readOnly = truespec.containers[].volumeMounts[].mountPath 為你想要該 Secret 出現的尚未使用的目錄。
  4. 修改你的映象並且/或者命令列,讓程式從該目錄下尋找檔案。 Secret 的 data 對映中的每一個鍵都對應 mountPath 下的一個檔名。

這是一個在 Pod 中使用存放在掛載卷中 Secret 的例子:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: mysecret

您想要用的每個 Secret 都需要在 spec.volumes 中引用。

如果 Pod 中有多個容器,每個容器都需要自己的 volumeMounts 配置塊, 但是每個 Secret 只需要一個 spec.volumes

您可以打包多個檔案到一個 Secret 中,或者使用的多個 Secret,怎樣方便就怎樣來。

將 Secret 鍵名對映到特定路徑

我們還可以控制 Secret 鍵名在儲存卷中對映的的路徑。 你可以使用 spec.volumes[].secret.items 欄位修改每個鍵對應的目標路徑:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: mysecret
      items:
      - key: username
        path: my-group/my-username

將會發生什麼呢:

  • username Secret 儲存在 /etc/foo/my-group/my-username 檔案中而不是 /etc/foo/username 中。
  • password Secret 沒有被對映

如果使用了 spec.volumes[].secret.items,只有在 items 中指定的鍵會被對映。 要使用 Secret 中所有鍵,就必須將它們都列在 items 欄位中。 所有列出的鍵名必須存在於相應的 Secret 中。否則,不會建立卷。

Secret 檔案許可權

你還可以指定 Secret 將擁有的許可權模式位。如果不指定,預設使用 0644。 你可以為整個 Secret 卷指定預設模式;如果需要,可以為每個金鑰設定過載值。

例如,您可以指定如下預設模式:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
  volumes:
  - name: foo
    secret:
      secretName: mysecret
      defaultMode: 256

之後,Secret 將被掛載到 /etc/foo 目錄,而所有通過該 Secret 卷掛載 所建立的檔案的許可權都是 0400

請注意,JSON 規範不支援八進位制符號,因此使用 256 值作為 0400 許可權。 如果你使用 YAML 而不是 JSON,則可以使用八進位制符號以更自然的方式指定許可權。

注意,如果你通過 kubectl exec 進入到 Pod 中,你需要沿著符號連結來找到 所期望的檔案模式。例如,下面命令檢查 Secret 檔案的訪問模式:

kubectl exec mypod -it sh

cd /etc/foo
ls -l

輸出類似於:

total 0
lrwxrwxrwx 1 root root 15 May 18 00:18 password -> ..data/password
lrwxrwxrwx 1 root root 15 May 18 00:18 username -> ..data/username

沿著符號連結,可以檢視檔案的訪問模式:

cd /etc/foo/..data
ls -l

輸出類似於:

total 8
-r-------- 1 root root 12 May 18 00:18 password
-r-------- 1 root root  5 May 18 00:18 username

你還可以使用對映,如上一個示例,併為不同的檔案指定不同的許可權,如下所示:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
  volumes:
  - name: foo
    secret:
      secretName: mysecret
      items:
      - key: username
        path: my-group/my-username
        mode: 511

在這裡,位於 /etc/foo/my-group/my-username 的檔案的許可權值為 0777。 由於 JSON 限制,必須以十進位制格式指定模式,即 511

請注意,如果稍後讀取此許可權值,可能會以十進位制格式顯示。

使用來自卷中的 Secret 值

在掛載了 Secret 卷的容器內,Secret 鍵名顯示為檔名,並且 Secret 的值 使用 base-64 解碼後儲存在這些檔案中。 這是在上面的示例容器內執行的命令的結果:

ls /etc/foo/

輸出類似於:

username
password
cat /etc/foo/username

輸出類似於:

admin
cat /etc/foo/password

輸出類似於:

1f2d1e2e67df

容器中的程式負責從檔案中讀取 secret。

相關文章