k8s env、configmap、secret外部數據加載配置

K8s提供了多種外部數據注入容器的方式,今天我們主要學習環境變量、ConfigMap以及Secret的使用和配置。

環境變量


在docker項目中,對一個容器添加環境變量可以在容器創建時通過-e ENV=name方式加載。而k8s在創建 Pod 時,也提供了其下容器環境變量配置的能力。

我們可以通過配置清單中的 envenvFrom(來自外部配置) 字段來設置環境變量。

比如如下的yaml

#busybox-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: busybox-deployment
spec:
  selector:
    matchLabels:
      app: busybox
  replicas: 1
  template:
    metadata:
      labels:
        app: busybox
    spec:
      containers:
      - name: busybox
        image: busybox:latest
        resources:
          limits:
            memory: 20Mi
        env:
        - name: DEMO_VERSION
          value: demov1
        - name: DEMO_POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: DEMO_CONT_MEM
          valueFrom:
            resourceFieldRef:
              containerName: busybox
              resource: limits.memory
        command: ['top']

在清單中我們配置了三個環境變量:

  • DEMO_VERSION:直接添加變量值demov1
  • DEMO_POD_NAME:結合valueFrom中fieldRef獲取pod名稱字段metadata.name
  • DEMO_CONT_MEM:結合valueFrom中resourceFieldRef獲取容器資源字段limits.memory

此時我們創建pod進入容器後通過printenv命令可以查看到環境變量已經被加載:

#kubectl exec busybox-deployment-5bb768546c-jbsmz -- printenv

DEMO_POD_NAME=busybox-deployment-5bb768546c-jbsmz
DEMO_CONT_MEM=20971520
    DEMO_VERSION=demov1

valueFrom中其他字段如下待會我們會用到,需要時可參考官方API文檔:envvar-v1-core

image-20220105234011959注意: 環境變量將覆蓋容器鏡像中指定的所有環境變量。

ConfigMap


ConfigMap 是一種 API 對象,用來將非機密性的數據保存到鍵值對中。使用時, Pods可以將其用作環境變量、命令行參數或者存儲卷中的配置文件。

1、用於環境變量

Configmap 用於配置環境變量的好處是可以將環境配置信息和容器鏡像解耦,便於應用配置的修改。

我們可以快速的創建出一個configmap如下:

#busybox-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: busybox-configmap
data:
  DEMO_VERSION: "demov2"

configmap使用 data(UTF-8位元組序列) 和 binaryData(二進制數據base64 編碼的字串) 字段創建鍵值對做數據存儲。

接着使用調整我們deployment中的envDEMO_VERSION的字段如下:

- name: DEMO_VERSION
  valueFrom:
    configMapKeyRef:
      name: busybox-configmap
      key: DEMO_VERSION

configMapKeyRef如API所說的選擇一個configmap

同樣創建後查看

# kubectl exec pod/busybox-deployment-64c678977f-zjnhb -- printenv

DEMO_VERSION=demov2
...

這樣我們只需要維護這個configmap即可,不過通過環境變量引用configmap時也是不支持熱更新,環境變量只在容器創建時加載,所以你需要觸發一次deployment的滾動更新。

2、掛載配置信息

顯然從名字上可以看出configmap並不是為環境變量而生。我們可以將configmap中key作文文件掛載到容器中,我們創建如下清單:

apiVersion: v1
kind: ConfigMap
metadata:
  name: busybox-configmap
data:
  DEMO_VERSION: "demov3"

  game.properties: |
    enemies=aliens
    lives=3
    enemies.cheat=true
    enemies.cheat.level=noGoodRotten
    secret.code.passphrase=UUDDLRLRBABAS
    secret.code.allowed=true
    secret.code.lives=30
  ui.properties: |
    color.good=purple
    color.bad=yellow
    allow.textmode=true
    how.nice.to.look=fairlyNice

相當於此時我們獲得三個key文件,接下來我們就可以通過volume掛載了。

...
volumeMounts:
- name: config-volume
  mountPath: /etc/config
volumes:
- name: config-volume
  configMap:
    name: busybox-configmap
...

在volume中configmap字段指定我們的busybox-configmap,創建後查看/etc/config

$ kubectl exec busybox-deployment-87b6c7bd7-ljcfr --  ls /etc/config/
DEMO_VERSION
game.properties
ui.properties

當卷中使用的 ConfigMap 被更新時,所投射的鍵最終也會被更新。 kubelet 組件會在每次周期性同步時檢查所掛載的 ConfigMap 是否為最新。即k8s的watch機制。

Secret


與ConfigMap類似,k8s提供了另一種API對象Secret用於存儲機密信息,我們可以使用Secret對象存儲敏感信息例如密碼、令牌或密鑰,這樣在應用程序代碼中解耦機密數據。

創建一個Sercet

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  password: cGFzc3dk
stringData:
  username: k8s

data 字段用來存儲 base64 編碼的任意數據,我們可以通過base64命令生成編碼。

stringData則允許 Secret 使用未編碼的字符串,只用於寫,無法直接讀取明文字段。

$ kubectl get secret mysecret -o yaml
apiVersion: v1
data:
  password: cGFzc3dk
  username: azhz
...
$ kubectl describe secret mysecret
...
Data
====
password:  6 bytes
username:  3 bytes

這樣在kubectl getkubectl describe 中默認不顯示 Secret 的內容。 這是為了防止 Secret 意外地暴露給旁觀者或者保存在終端日誌中。

Kubernetes 提供若干種內置的Secret類型,用於一些常見的使用場景。 針對這些類型,Kubernetes 所執行的合法性檢查操作以及對其所實施的限制各不相同。

內置類型 用法
Opaque 用戶定義的任意數據
kubernetes.io/service-account-token 服務賬號令牌
kubernetes.io/dockercfg ~/.dockercfg 文件的序列化形式
kubernetes.io/dockerconfigjson ~/.docker/config.json 文件的序列化形式
kubernetes.io/basic-auth 用於基本身份認證的憑據
kubernetes.io/ssh-auth 用於 SSH 身份認證的憑據
kubernetes.io/tls 用於 TLS 客戶端或者服務器端的數據
bootstrap.kubernetes.io/token 啟動引導令牌數據

類型說明可參考官方文檔:secret,當然也可以通過Opaque自定義的實現內置類型。

這裡我們以類型kubernetes.io/ssh-auth為例嘗試使用Secret,kubernetes.io/ssh-auth 用來存放 SSH 身份認證中 所需要的憑據。使用這種 Secret 類型時,我們必須在其 data (或 stringData) 字段中提供一個 ssh-privatekey 鍵值對,作為要使用的 SSH 憑據。

創建如下的yaml:

apiVersion: v1
kind: Secret
metadata:
  name: secret-ssh-auth
type: kubernetes.io/ssh-auth
data:
  ssh-privatekey: |
          PRIVATEKEY_STINGS..  #base64編碼數據

創建後可以查看到類型和key名稱。

$ kubectl describe secret/secret-ssh-auth
Name:         secret-ssh-auth
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  kubernetes.io/ssh-auth

Data
====
ssh-privatekey:  2626 bytes

接着創建用於加載secret的pod

apiVersion: v1
kind: Pod
metadata:
  name: pod-secret
spec:
  containers:
  - name: pod-secret
    image: nginx
    volumeMounts:
    - name: secret-volume
      mountPath: "/etc/ssh/"
      readOnly: true
  volumes:
  - name: secret-volume
    secret:
      secretName: secret-ssh-auth

此時容器中已加載到secretName中的ssh-privatekey

$ kubectl exec pod/pod-secret --  ls /etc/ssh
ssh-privatekey

這樣我們可以通過此key來做ssh相關的認證。

和configmap一樣,secret也可用於環境變量配置。通過secretRef字段引入secret

...
envFrom:
- secretRef:
    name: mysecret
...

以上secret使用僅做學習,生產中請排查以下安全問題,更多secret內容參考官方文檔:Secret

安全問題:

  • 當部署與 Secret API 交互的應用程序時,應使用 鑒權策略, 例如 RBAC,來限制訪問。

  • API 服務器上的 Secret 數據以純文本的方式存儲在 etcd 中,因此:

    • 管理員應該為集群數據開啟靜態加密(要求 v1.13 或者更高版本)。
    • 管理員應該限制只有 admin 用戶能訪問 etcd;
    • API 服務器中的 Secret 數據位於 etcd 使用的磁盤上,不再使用secret應該被刪除。
    • 如果 etcd 運行在集群內,管理員應該確保 etcd 之間的通信使用 SSL/TLS 進行加密。
  • 如果將 Secret 數據編碼為 base64 的清單(JSON 或 YAML)文件,共享該文件或將其檢入代碼庫,該密碼將會被泄露。 Base64 編碼不是一種加密方式,應該視同純文本。

  • 應用程序在從卷中讀取 Secret 後仍然需要保護 Secret 的值,例如不會意外將其寫入日誌或發送給不信任方。

  • 可以創建使用 Secret 的 Pod 的用戶也可以看到該 Secret 的值。即使 API 服務器策略不允許用戶讀取 Secret 對象,用戶也可以運行 Pod 導致 Secret 暴露。


希望小作文對你有些許幫助,如果內容有誤請指正。

您可以隨意轉載、修改、發佈本文,無需經過本人同意。 通過博客閱讀:iqsing.github.io

Tags: