實務上比較好的作法是盡可能將映像檔設計成可以重複使用,相同的映像檔應該設計成能夠用在不同執行環境,像是開發、測試和生產環境等,若是可以跨越不同的服務及應用程式更好。 * ConfigMap :用來提供應用程式或服務執行時所需要的設定組態。他的內容可以是很短的設定參數(字串、數字),也可以是一個複雜的檔案格式(YAML或JSON)組成的參數。 * Secret:功能類似於ConfigMap,但更著重於存放程式或服務所需的敏感資訊。他們可能是密碼或是TLS憑證等等。 ## ConfigMap 可以把ConfigMap想像成透過Kubernetes物件定義的小型檔案系統,或是將他視為在容器中執行應用程式或命令列所需要的一組變數。 關鍵在於Pod執行前會將ConfigMap的資訊合併,也就是說我們可以透過修改ConfigMap的方式,讓應用程式或服務重複使用相同的容器映像檔及Pod的定義。 ### 建立ConfigMap 可以透過命令列指令或利用manifest檔建立 ```txt #my-config.txt parameter1 = value1 parameter2 = value2 ``` ```shell # create config $ kubectl create configmap my-config \ --from-literal=extra-param=extra-value \ --from-literal=another-param=another-value \ --from-file=my-config.txt configmap/my-config created ``` ```shell # get configmap kubectl get configMaps my-config -o yaml ``` ```yaml apiVersion: v1 data: another-param: another-value extra-param: extra-value my-config.txt: | parameter1 = value1 parameter2 = value2 kind: ConfigMap metadata: creationTimestamp: "2023-07-11T15:21:03Z" name: my-config namespace: default resourceVersion: "76808050" uid: a54b8e59-5b94-4fb0-8eda-296b0f9bc1d7 ``` ### 使用ConfigMap 有三種不同的方式: * 檔案系統 - 可以將ConfigMap當作目錄掛載到Pod中,每個主鍵會以名稱建立一個檔案,而值為檔案內容。 * 環境變數 - 可以動態地設定環境變數。 * 命令列參數 - 容器運行時,使用來自於configmap的環境變數。 ```yaml # kuard-config.yaml apiVersion: v1 kind: Pod metadata: name: kuard-config spec: containers: - name: test-container image: gcr.io/kuar-demo/kuard-amd64:blue imagePullPolicy: Always command: - "/kuard" - "$(EXTRA_PARAM)" env: # An example of an environment variable used inside the container - name: ANOTHER_PARAM valueFrom: configMapKeyRef: name: my-config key: another-param # An example of an environment variable passed to the command to start # the container (above). - name: EXTRA_PARAM valueFrom: configMapKeyRef: name: my-config key: extra-param volumeMounts: # Mounting the ConfigMap as a set of files - name: config-volume mountPath: /config volumes: - name: config-volume configMap: name: my-config restartPolicy: Never ``` ```shell $ kubectl apply -f kuard-config.yaml pod/kuard-config created ``` ```shell!! # enter pod's container $kubectl exec -i -t kuard-config -- sh $ls /config another-param extra-param my-config.txt $cat /config/another-param another-value ``` ```shell # port forwarding kubectl port-forward kuard-config 8080 ``` Now point your browser to http://localhost:8080/ ![](https://hackmd.io/_uploads/rJhmTesth.png) ![](https://hackmd.io/_uploads/rJ8dTxoKh.png) ## Secret 有些敏感的資料,像是密碼、token或其他類型的私鑰,我們統稱這種類型的資料為Secret。 Kubernetes原生就具有儲存以及處理這類敏感資料的能力。 Secret讓建立容器映像檔時不需要將敏感資料直接儲存在映像檔中。這允許容器在不同的環境間保持可移植性。 :::info :bulb: Kubernetes預設使用純文字將敏感資訊儲存在從集中的etcd儲存區。 新版本中開始支援使用雲端加密儲存區(cloud key store)存放敏感資訊, 除此之外,大多數的雲端加密儲存區也支援整合Kubernetes彈性磁碟區,可以完全不使用Kubernetes內建的Secret機制改用雲供應商所提供的雲端加密儲存區取代。 ::: ### 建立Secret Secret可以透過Kubernetes API或kubectl命令列工具建立,可以儲存一組或多組資料元件並儲存為key/value的集合。 ```shell!! # download Kuard's key pairs by curl $ curl -o kuard.crt https://storage.googleapis.com/kuar-demo/kuard.crt $ curl -o kuard.key https://storage.googleapis.com/kuar-demo/kuard.key ``` ```shell $ kubectl create secret generic kuard-tls \ --from-file=kuard.crt \ --from-file=kuard.key secret/kuard-tls created ``` ```shell $kubectl describe secrets kuard-tls ``` ```yaml Name: kuard-tls Namespace: default Labels: <none> Annotations: <none> Type: Opaque Data ==== kuard.crt: 1050 bytes #base64 encode kuard.key: 1679 bytes #base64 encode ``` ### 使用Secret ### Secret磁碟區 在Pod中可以透過Secret磁碟區存取Secret。 Kubelet會負責管理這些Secret磁碟區,並在Pod產生時一併建立。 Secret是儲存在tmpfs磁碟區(RAM磁碟)中,所以他們並不會真正被寫到node的硬碟。 每一個Secret資料元件都會儲存成獨立檔案,並將這些檔案掛載在目標掛載點下。 ```yaml apiVersion: v1 kind: Pod metadata: name: kuard-tls spec: containers: - name: kuard-tls image: gcr.io/kuar-demo/kuard-amd64:blue imagePullPolicy: Always volumeMounts: - name: tls-certs mountPath: "/tls" readOnly: true volumes: - name: tls-certs secret: secretName: kuard-tls ``` ```shell $ kubectl apply -f kuard-secret.yaml pod/kuard-tls created ``` Connect to the Pod by running: ```shell $ kubectl port-forward kuard-tls 8443:8443 ``` See the kuard server hosted via HTTPS ![](https://hackmd.io/_uploads/r1kbzZoKn.png) ### 私有Docker儲存庫 使用Secret的另一種情境是儲存私有Docker儲存庫的存取憑證。 ```shell!! # replace generic with docker-registry for private docker registry's secret $ kubectl create secret docker-registry my-image-pull-secret \ --docker-username=<username> \ --docker-password=<password> \ --docker-email=<email-address> ``` Enable access to the private repository by referencing the "image pull secret" ```yaml apiVersion: v1 kind: Pod metadata: name: kuard-tls spec: containers: - name: kuard-tls image: gcr.io/kuar-demo/kuard-amd64:blue imagePullPolicy: Always volumeMounts: - name: tls-certs mountPath: "/tls" readOnly: true imagePullSecrets: - name: my-image-pull-secret volumes: - name: tls-certs secret: secretName: kuard-tls ``` ### 命名限制 在Secret或ConfigMap中定義各資料的主鍵名稱後,這些名稱會用來當作實際環境變數的名稱。 ``` 命名規則必須符合正則表示式 ^[.]?[a-zAZ0-9]([.]?[a-zA-Z0-9]+[-_a-zA-Z0-9]?)*$ ``` 有效和無效名稱範例 | 有效名稱 | 無效名稱 | | -------- | -------- | | .auth_token| Token..properties | | Key.pem| auth file.json | | config_file|_password.txt | :::info :bulb:在選擇主鍵的名稱時,請考慮到這些鍵將會透過磁碟區掛載的方式給Pod使用。 挑選一個在命令列或是配置檔中使用時具有意義的名稱。 ::: * ConfigMap:以UTF-8文字格式直接明文儲存於manifest中。從Kubernetes1.6版之後就無法儲存binary格式的資料了。 * Secret:皆以base64加密儲存。可以儲存binary格式的資料。每一個ConfigMap或Secret最大不得超過1MB。 ### 管理ConfigMap和Secret 我們可以透過Kubernetes API管理ConfigMap和Secret 常用:create、delete、get、describe #### 列表 可看見原始資料(包括Secret的值) ```shell!! $kubectl get secret kuard-tls -o yaml ``` ```shell!! $ kubectl get secrets NAME TYPE DATA AGE default-token-f5jq2 kubernetes.io/service-account-token 3 1h kuard-tls Opaque 2 20m $ kubectl get configmaps NAME DATA AGE my-config 3 1m ``` ```shell kubectl describe configmap my-config Name: my-config Namespace: default Labels: <none> Annotations: <none> Data ==== another-param: 13 bytes extra-param: 11 bytes my-config.txt: 116 bytes ``` #### 建立 ``` --from-file=<filename> Load from the file with the Secret data key that’s the same as the filename. --from-file=<key>=<filename> Load from the file with the Secret data key explicitly specified. --from-file=<directory> Load all the files in the specified directory where the filename is an acceptable key name. --from-literal=<key>=<value> Use the specified key/value pair directly ``` #### 更新 * 從檔案更新 ``` $ kubectl replace -f <filename> $ kubectl apply -f <filename> ``` * 重建和更新 ```shell!! # dry-run 不會透過api 直接寫入只會顯示結果 $ kubectl create secret generic kuard-tls \ --from-file=kuard.crt --from-file=kuard.key \ --dry-run -o yaml | kubectl replace -f - ``` * 編輯目前的版本 ```shell!! $ kubectl edit configmap my-config configmap/my-config edited ``` * 即時更新 自動更新 - 額外下載Reloader plugin,再透過annotation定義後,當ConfigMap或Secret更新時,pod會自動restart存取最新的value https://github.com/stakater/Reloader