1. 程式人生 > >Kubernetes學習筆記(六):使用ConfigMap和Secret配置應用程式

Kubernetes學習筆記(六):使用ConfigMap和Secret配置應用程式

## 概述 本文的核心是:如何處理應用程式的資料配置。 配置應用程式可以使用以下幾種途徑: - 向容器傳遞命令列引數 - 為每個容器配置環境變數 - 通過特殊的卷將配置檔案掛載到容器中 ## 向容器傳遞命令列引數 在Kubernetes中定義容器時,映象的ENTRYPOINT和CMD都可以被覆蓋(但是在Docker中,映象的ENTRYPOINT是不能覆蓋的)。僅需在容器定義中設定command和args的值。 ### 構建一個映象 loopechodate.sh:接收一個時間間隔的引數,追加輸出當前時間到 /tmp/a.txt ``` #! /bin/sh trap "exit" SIGINT echo "interval is : $1" while : do echo -e "$(date)" >> /tmp/a.txt sleep $1 done ``` Dockerfile ``` FROM alpine COPY loopechodate.sh /bin/ ENTRYPOINT ["/bin/loopechodate.sh"] CMD ["5"] ``` 構建、推送 ``` -> [[email protected]] [~] docker build -t registry.cn-hangzhou.aliyuncs.com/orzi/loopechodate . -> [[email protected]] [~] docker push registry.cn-hangzhou.aliyuncs.com/orzi/loopechodate ``` ### 執行Pod ``` # cat config-cli.yaml apiVersion: v1 kind: Pod metadata: name: config-cli spec: containers: - name: config-cli image: registry.cn-hangzhou.aliyuncs.com/orzi/loopechodate args: ["2"] # 間隔時間2s ``` 建立這個pod,然後檢視一下logs ``` -> [[email protected]] [~] k create -f config-cli.yaml pod/config-cli created -> [[email protected]] [~] k exec -it config-cli cat /tmp/a.txt Sun May 24 15:49:37 UTC 2020 Sun May 24 15:49:39 UTC 2020 ``` ## 為容器設定環境變數 Kubernetes中通過容器的env屬性定義環境變數,採用$(VAR)語法在環境變數值中引用其他變數。 定義了兩個環境變數FIRST_VAR,和引用了FIRST_VAR的SECOND_VAR。 ``` # config-env.yaml apiVersion: v1 kind: Pod metadata: name: config-env spec: containers: - name: config-env image: nginx:alpine env: - name: FIRST_VAR value: "Hello" - name: SECOND_VAR value: "$(FIRST_VAR) World!" ``` 建立檢視 ``` -> [[email protected]] [~] k create -f config-env.yaml pod/config-env created -> [[email protected]] [~] k exec config-env env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=config-env FIRST_VAR=Hello SECOND_VAR=Hello World! ....... ``` ## ConfigMap ConfigMap本質上是一個鍵值對,值可以使短字面量,也可以是檔案 ### 建立ConfigMap `kubectl create configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run] [options]` kubectl create命令支援從字面量(--from-literal),檔案、目錄(--from-file)、以及環境變數檔案(--from-env-file)建立。而且不同選項可以合併,但是--from-env-file不能與--from-literal和--from-file一起指定。 下面是使用字面量、檔案、目錄合併建立。 ``` -> [[email protected]] [~] k create configmap mycm --from-literal=interval=3 --from-file=Dockerfile --from-file=/root/configdir configmap/mycm created -> [[email protected]] [~] k describe cm mycm Name: mycm Namespace: default Labels: Annotations: Data ==== Dockerfile: ---- FROM alpine COPY loopechodate.sh /bin/ ENTRYPOINT ["/bin/loopechodate.sh"] CMD ["5"] a.txt: ---- this is configdir/a.txt b.txt: ---- this is configdir/b.txt interval: ---- 3 Events: ``` 使用環境變數檔案建立 ``` -> [[email protected]] [~] echo -e "env1=1111\nenv2=2222" | tee test.env env1=1111 env2=2222 -> [[email protected]] [~] k create cm envcm --from-env-file=test.env configmap/envcm created -> [[email protected]] [~] k describe cm envcm Name: envcm Namespace: default Labels: Annotations: Data ==== env1: ---- 1111 env2: ---- 2222 Events: ``` ### 傳遞ConfigMap條目作為環境變數 定義一個Pod,引用了mycm中的兩個key。 ``` # config-env-cm.yaml apiVersion: v1 kind: Pod metadata: name: config-env-cm spec: containers: - name: config-env-cm image: nginx:alpine env: - name: INTERVAL valueFrom: configMapKeyRef: # 引用configMap中的內容 name: mycm # configMap的名字 key: interval # 引用哪個鍵 - name: ATXT valueFrom: configMapKeyRef: name: mycm key: a.txt ``` 建立檢視 ``` -> [[email protected]] [~] k create -f config-env-cm.yaml pod/config-env-cm created -> [[email protected]] [~] k exec config-env-cm env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=config-env-cm INTERVAL=3 ATXT=this is configdir/a.txt .... ``` ### 一次性傳遞ConfigMap所有條目作為環境變數 ``` # config-env-cmall.yaml apiVersion: v1 kind: Pod metadata: name: config-env-cmall spec: containers: - name: config-env-cmall image: nginx:alpine envFrom: - prefix: CONFIG_ configMapRef: name: mycm ``` 建立檢視 ``` -> [[email protected]] [~] k create -f config-env-cmall.yaml pod/config-env-cmall created -> [[email protected]] [~] k exec config-env-cmall env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=config-env-cmall CONFIG_interval=3 CONFIG_Dockerfile=FROM alpine COPY loopechodate.sh /bin/ ENTRYPOINT ["/bin/loopechodate.sh"] CMD ["5"] CONFIG_a.txt=this is configdir/a.txt CONFIG_b.txt=this is configdir/b.txt ........ ``` ### 傳遞ConfigMap條目作為命令列引數 `containers.args`無法直接引用ConfigMap,但是可以通過$(ENV_VAR_NAME)引用環境變數,間接引用ConfigMap。 ``` # config-cli-cm.yaml apiVersion: v1 kind: Pod metadata: name: config-cli-cm spec: containers: - name: config-cli-cm image: registry.cn-hangzhou.aliyuncs.com/orzi/loopechodate env: - name: INTERVAL valueFrom: configMapKeyRef: name: mycm key: interval args: ["$(INTERVAL)"] ``` 建立檢視 ``` -> [[email protected]] [~] k create -f config-cli-cm.yaml pod/config-cli-cm created -> [[email protected]] [~] k logs config-cli-cm interval is : 3 -> [[email protected]] [~] k exec config-cli-cm cat /tmp/a.txt Mon May 25 05:11:14 UTC 2020 Mon May 25 05:11:17 UTC 2020 Mon May 25 05:11:20 UTC 2020 ``` ### 將ConfigMap條目暴露為卷 環境變數和命令列引數作為配置值通常適用於變數值較短的場景。如果想暴露ConfigMap中配置檔案,可以將ConfigMap或者其條目通過卷的形式掛載到容器。 ``` # config-volume-cm.yaml apiVersion: v1 kind: Pod metadata: name: config-volume-cm spec: containers: - name: config-volume-cm image: nginx:alpine volumeMounts: - name: config mountPath: /tmp/mycm readOnly: true volumes: - name: config configMap: name: mycm ``` 建立檢視 ``` -> [[email protected]] [~] k create -f config-volume-cm.yaml pod/config-volume-cm created -> [[email protected]] [~] k exec config-volume-cm ls /tmp/mycm Dockerfile a.txt b.txt interval ``` 如果只想暴露指定的條目,可以指定`volumes.configMap.items`。 ``` volumes: - name: config configMap: name: mycm items: - key: interval path: interval2 ``` 輸出結果是: ``` -> [[email protected]] [~] k exec config-volume-cm ls /tmp/mycm interval2 ``` `configMap.defaultMode`設定訪問許可權 **掛載資料夾會隱藏該資料夾中已存在的檔案,掛載ConfigMap的單獨條目不會隱藏其他檔案** ## Secret Secret與ConfigMap一樣都是鍵值對,也可以作為環境變數傳遞給容器,條目也能暴露稱為卷中的檔案。但是為了安全起見,請始終使用Secret卷暴露Secret。Secret只會儲存在記憶體中,永不寫入物理儲存。Secret條目的內容會被進行Base64編碼。 ### 預設令牌 每個pod預設都會掛載一個Secret,該Secret包含ca.crt、namespace、token,包含了從Pod內部安全訪問Kubernetes Api伺服器所需的全部資訊。 先隨便找一個pod檢視。 ``` -> [[email protected]] [~] k describe pod config-volume-cm Name: config-volume-cm Namespace: default ...... Mounts: /tmp/mycm from config (ro) /var/run/secrets/kubernetes.io/serviceaccount from default-token-5g447 (ro) ...... Volumes: ...... default-token-5g447: Type: Secret (a volume populated by a Secret) SecretName: default-token-5g447 Optional: false ...... ``` 再檢視一下詳情 ``` -> [[email protected]] [~] k describe secrets default-token-5g447 Name: default-token-5g447 Namespace: default Labels: Annotations: kubernetes.io/service-account.name: default kubernetes.io/service-account.uid: bd92a729-ed0a-491d-b600-0f86824ad588 Type: kubernetes.io/service-account-token Data ==== ca.crt: 1025 bytes namespace: 7 bytes token: eyJhbGciOiJSUzI1.... ``` ### 使nginx支援https #### 建立私鑰和證書 ``` -> [[email protected]] [~/cert] openssl genrsa -o https.key 2048 -> [[email protected]] [~/cert] openssl req -new -x509 -key https.key -out https.cert -days 3650 -subj /CN=www.mysecret.com ``` #### 建立Secret 建立一個型別為generic的Secret,其他兩個型別是docker-registry、tls。 ``` -> [[email protected]] [~/cert] echo bar > foo # 後面會用到 -> [[email protected]] [~/cert] k create secret generic mysecret --from-file=./ secret/mysecret created ``` #### 將ssl.conf放入ConfigMap中 ``` # ssl.conf server { listen 80; listen 443 ssl; server_name www.mysecret.com; ssl_certificate certs/https.cert; ssl_certificate_key certs/https.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers HIGH:!aNULL:!MD5; location / { root /usr/share/nginx/html; index index.html index.htm; } } ``` ``` -> [[email protected]] [~] k create configmap sslcm --from-file=ssl.conf configmap/sslcm created ``` #### 建立檢視 先看一下描述檔案 ``` # https-nginx.yaml apiVersion: v1 kind: Pod metadata: name: https-nginx spec: containers: - name: https-nginx image: nginx:alpine env: - name: FOO valueFrom: secretKeyRef: name: mysecret key: foo volumeMounts: - name: sslcm mountPath: /etc/nginx/conf.d/ readOnly: true - name: mysecret mountPath: /etc/nginx/certs/ readOnly: true ports: - containerPort: 80 - containerPort: 443 volumes: - name: sslcm configMap: name: sslcm items: - key: ssl.conf path: https.conf - name: mysecret secret: secretName: mysecret ``` 建立、設定埠轉發 ``` -> [[email protected]] [~] k create -f https-nginx.yaml pod/https-nginx created -> [[email protected]] [~] k port-forward https-nginx 443:443 Forwarding from 127.0.0.1:443 -> 443 ``` 新開視窗,傳送請求 ``` -> [[email protected]] [~] curl -k https://localhost Welcome to nginx!
..... ``` 檢視Secret通過環境變數暴露的條目 ``` -> [[email protected]] [~] k exec https-nginx env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=https-nginx FOO=bar ....... ``` ### 使用私有的映象倉庫 使用方法:建立一個docker-registry型別的secret,然後 建立一個docker-registry型別的secret。 --docker-server 用於指定倉庫服務的地址。 ``` k create secret docker-registry dockerregsecret --docker-username=zhangsan --docker-password=123 [email protected] ``` 在Pod中的`containers.imagePullSecrets.name`中引用。 ``` apiVersion: v1 kind: Pod metadata: name: private-pod spec: imagePullSecrets: - name: dockerregsecret containers: - image: username/private:tag name: main ``` ### StringData與二進位制資料 採用Base64編碼,使Secret也能儲存二進位制資料,而純文字值可以在`secret.StringData`中定義,但StringData欄位是隻寫的,`kubectl get -o yaml`檢視時會被Base64編碼顯示在data下。 ## 注意事項 - 在Kubernetes中定義容器時,映象的ENTRYPOINT和CMD都可以被覆蓋。但是在Docker中,映象的ENTRYPOINT是不能覆蓋的。 - 可以將`configMapKeyRef.optional`設定為true,這樣即使ConfigMap不存在,容器也能啟動。 ## 小結 - 對於環境變數:使用`valueFrom.configMapKeyRef`引用一個ConfigMap條目;使用`envFrom.configMapRef`引用全部,`envFrom.prefix`設定字首。 - 對於命令列引數:`containers.args`無法直接引用ConfigMap,但是可以通過$(ENV_VAR_NAME)引用環境變數,間接引用了ConfigMap。 - 掛載資料夾會隱藏該資料夾中已存在的檔案,掛載ConfigMap的單獨條目不會隱藏其他檔案 - 將ConfigMap暴露為卷可以達到熱更新的效果。 - 每個pod預設都會掛載一個Secret,該Secret包含ca.crt、namespace、token,包含了從Pod內部安全訪問Kubernetes Api伺服器所需的全部資訊。 - 採用Base64編碼,使Secret也能儲存二進位制資料,而純文字值可以在`secret.StringData`中定義,但StringData欄位是隻寫的,`kubectl get -o yaml`檢視時會被Base64編碼顯示在dat