k8s env、configmap、secret外部數據載入配置
K8s提供了多種外部數據注入容器的方式,今天我們主要學習環境變數、ConfigMap以及Secret的使用和配置。
環境變數
在docker項目中,對一個容器添加環境變數可以在容器創建時通過-e ENV=name
方式載入。而k8s在創建 Pod 時,也提供了其下容器環境變數配置的能力。
我們可以通過配置清單中的 env
及 envFrom(來自外部配置)
欄位來設置環境變數。
比如如下的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
注意: 環境變數將覆蓋容器鏡像中指定的所有環境變數。
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中的env
DEMO_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 get
和 kubectl 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