kubernetes-ConfigMap、secret-9

配置管理

兩種特殊類型存儲卷,其多數情況下目的不是給pod提供存儲空間來用的,而是給管理員或用戶提供了從 集羣外部向 pod內部的應用注入配置信息的方式, 理論來源

配置容器應用方法

  1. 自定義命令行兩種參數: command, args:['xx','xx']
  2. 事先將配置文件直接寫死鏡像
  3. 環境變量: 應用程序應當支持環境變量,entrypoint(預處理腳本) 方式提供
    • 如果程序鏡像是雲原生,或是entrypoint腳本通過傳遞環境變量接受參數完成配置,這是一種輕量化的配置方式,在容器啓動時傳遞N個環境變量,分別就能代表N個重要的配置參數,從而完成應用程序配置;
    • 當以nginx爲例,當啓動nginx時需要加載自定義的配置文件模塊,或使用存儲卷的方式進行配置文件的傳遞,將外部配置文件加載至容器內部;
    • 但上述的配置方式是有缺陷的,當使用環境變量配置,env是在容器啓動時被裝入的,意味着如果想要修改某個變量,只能重新啓動容器,如果使用存儲卷,存儲卷的內容也是在進程啓動時被裝入,後續就算是修改了存儲卷的配置,也得需要手動觸發進程 加載新的配置
  4. 存儲卷
  5. dockerConfig (不是常用的方式)

使用場景

​ 當我們在一個Pod控制器下,有多個Pod時,這些Pod的配置信息應該都是一樣的,意味着它們會共享一個存儲卷,當存儲卷內容被修改,這些Pod都能加載到新的內容,但這些Pod都會被重載,尤其是當我們使用Hpa控制器時,它會根據用戶訪問量來自定義伸縮Pod副本,那此時就會不知道重載哪些pod,所以在這種環境下最好能提供一種機制,當我們修改配置信息後能自動關連相關的Pod重載,最好只需要改一次,所有加載該配置文件的Pod都能被自動重載;

​ k8s中用於實現配置自動重載功能的組件,它們分別是 ConfigMap、Secret,它們都是用於將配置文件配置爲k8s資源

  1. ConfigMap用於提供非敏感配置

  2. Secre用於提供敏感配置信息(密碼、密鑰等)進行編碼存放

    它們在內部都是對鍵值對的方式存在,鍵做爲配置參數,值可以是整個文件,比如說 可以將配置文件文件名做爲鍵,整個文件的配置做爲值

configMap

​ 特殊類型的存儲卷,configMap | secret也是存儲卷,但它們目的不是爲給pod提供存儲空間,而是給管理員或用戶提供從集羣外部向pod內部的應用注入配置信息的方式,集羣配置管理資源, 信息明文存放

configMap也屬於名稱空間級別的資源, 字段查看 kubectl explain cm

​ ConfigMap做爲一個鍵值存儲系統,我們的配置文件幾乎都可以被實例爲ConfigMap的鍵值對象,在k8s中pod的ConfigMap調用有兩種方式:

  1. 在k8s的容器中,將每個key的value映射爲這個容器內部環境變量的值,比如在Pod中某個環境變量名是MYSQL_USER它的值引用於ConfigMap的值,我們可以向ConfigMap賦值,而不是直接給容器的MYSQL_USER賦值,從而由ConfigMap替換,然後由我們的應用程序所引用;
  2. k8s的ConfigMap和Pod作爲標準的k8s資源,當我們定義一個ConfigMap,其第一個參數鍵叫redis_host,值爲10.1.1.100,第二個鍵爲redis_port,值爲6379,隨後在配置一個filebeat的Pod,這個Pod通過環境變量引用redis主機和端口的配置,對應環境變量名是host和port,那麼我就可以這樣定義Pod,“host:redis-cfg.redis_host,port:redis-cfg.redis_port”,後續修改配置也只需要配置ConfigMap即可,但這種引用也有一種缺陷,當Pod啓動之後就不會再獲取值了,這也就意味着後續如果修改了ConfigMap裏的數據也不會被Pod加載,這時就需要重建來重新加載新配置了,這也是環境變量的缺陷

配置文件引入方式

  • 啓動pod時可以將configMap資源關連至當前pod資源, 從中讀一個配置以變量注入的方式傳遞配置
  • 將configMap當成一個存儲卷掛載至容器的某一個目錄,該目錄爲項目的配置目錄

核心作用

​ 爲了將配置文件從鏡像中解耦,從而增強應用的可移植性以及可複用性,一個configMap就是一系列配置數據的集合,而這些數據將來可以注入到pod對象容器中所使用,而注入方式有兩種

  1. 直接將configMap當存儲卷;
  2. 使用env的valueFrom方式來引用configMap, 在configMap中所有的配置都保存爲鍵值對的格式(kv),鍵值對中的值長度無限制

configMap臨時使用

Aliases:
configmap, cm

Examples:
  # --from-file=path/to/bar   文件名當鍵, 文件當值
  kubectl create configmap my-config --from-file=path/to/bar
  
  # --from-file=key1=/path/to/bar/file1.txt 指定鍵是key, 值是某個文件
  kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt
  
  # Create a new configmap named my-config with key1=config1 and key2=config2
  kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2

獲取環境變量

  1. 在pod容器上使用env或volueFrom來獲取

    ~]# kubectl explain pods.spec.containers
      env
        name: 變量名
        value: 數據是什麼
        valueFrom: 數據引用另一個變量
          configMapKeyRef: configMap資源
          fieldRef: 引用pod資源的字段
          resourceFieldRef: 資源需求 | 資源限制
          secretKeyRef: 引用secretKey配置資源
    

以鍵值對方式創建

  1. 創建

    # 創建一個臨時的鍵值對
    ~]# kubectl create cm nginx-test --from-literal=NGINX_NAME=t1.xiong.com --from-literal=NGINX_PORT=80
    
  2. 查看

    ~]# kubectl get cm
    NAME         DATA   AGE
    nginx-test   2      6s
    
    # 查看詳細內容
     ~]# kubectl describe cm nginx-test 
    Name:         nginx-test
    Namespace:    default
    Labels:       <none>
    Annotations:  <none>
    
    Data
    ====
    NGINX_NAME:
    ----
    t1.xiong.com
    NGINX_PORT:
    ----
    80
    Events:  <none>
    
  3. 創建pod

    ]# cat nginx_cm.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      annotations:
        configMap/test: "nginx"
      name: nginx-cm-test
      labels:
        app: nginx-cm
        release: qa
    spec:
      containers:
      - name: nginx-cm
        image: ikubernetes/myapp:v1
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80
        env:
        - name: NGINX_PORT
          valueFrom:
            configMapKeyRef:
              name: nginx-test
              key: NGINX_PORT
        - name: NGINX_NAME
          valueFrom:
            configMapKeyRef:    # 來源
              name: nginx-test
              key: NGINX_NAME
              
    ]# kubectl apply -f nginx_cm.yaml
    
    ]# kubectl exec -it  nginx-cm-test -- /bin/sh
        / # env
        NGINX_PORT=80
        NGINX_NAME=t1.xiong.com
    
  4. 編輯configMap

    ]# kubectl edit cm nginx-test  # 將port修改爲8080
    
    # 在查看pod, env
    	NGINX_PORT=80  # 當使用環境變量注入時,只在系統啓動時有效
    

以存儲卷創建

  1. 創建

    ]# cat t2.xiong.conf 
    server {
        listen       80;
        server_name  localhost;
    
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
    }
    
    ]# kubectl create cm nginx-test --from-file=t2.xiong.conf 
    
  2. 查看

    ]# kubectl describe cm nginx-test
    Name:         t2-xiong
    Namespace:    default
    
    Data
    ====
    t2.xiong.conf:   # key就是文件名
    ----      # 值是文本中的全部內容
    server {
        listen       80;
        server_name  localhost;
    
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
    }
    
  3. 以存儲卷方式掛載

    ]# cat t3_cm.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      annotations:
        configMap/test: "nginx"
      name: t3-xiong
      labels:
        app: t3-xiong
        release: qa
    spec:
      containers:
      - name: nginx-cm
        image: ikubernetes/myapp:v1
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80
        volumeMounts:
        - name: nginx
          mountPath: /etc/nginx/conf.d/
          readOnly: true
      volumes:
      - name: nginx
        configMap:
          name: nginx-test
    
    # 或掛載多個
      volumes:
      - name: conf # 該volumes的名字
        configMap:
          name: nginx-conf # 要使用configMap的名字
          items:
          - key: server1 # 要使用指定configMap裏面的鍵名
            path: s1.conf # 掛載之後的文件名
          - key: server2 # 要使用指定configMap裏面的鍵名
            path: s2.conf # 掛載之後的文件名
    
  4. 測試

    ~]# kubectl exec -it t3-xiong -- /bin/sh
        /etc/nginx/conf.d # ls -lh
        lrwxrwxrwx    1 root     root      20 May  7 06:02 t2.xiong.conf -> ..data/t2.xiong.conf
    
    # root目錄下創建xx.html  內容 hello world
    ]# kubectl get pods -o wide
    NAME       READY   STATUS    RESTARTS   AGE   IP           NODE  
    t3-xiong   1/1     Running   0          69s   10.244.1.2   slave1
    
    ]# curl 10.244.1.2/xx.html
    hello world
    
  • 使用該 ConfigMap 掛載的 Env 不會同步更新
  • 使用該 ConfigMap 掛載的 Volume 中的數據需要一段時間(實測大概10秒)才能同步更新

ENV 是在容器啓動的時候注入的,啓動之後 kubernetes 就不會再改變環境變量的值,且同一個 namespace 中的 pod 的環境變量是不斷累加的,爲了更新容器中使用 ConfigMap 掛載的配置,可以通過滾動更新 pod 的方式來強制重新掛載 ConfigMap,也可以在更新了 ConfigMap 後,先將副本數設置爲 0,然後再擴容。

配置中心

    Kubernetes用來配置分佈式或者負載均衡集羣化的配置中心,比如如果在nginx後面維護有20個tomcat,需要改修tomcat配置文件的一些配置信息,比如在修改tomcat連接redis的賬號密碼,那如何讓20個tomcat都應用到新配置,此前的做法就是使用ansible,然後分批推,推的時候還需要以灰度的方式進行,如果一下全部推送那在某一時刻服務都無法訪問了,所以即使藉助了ansible來編排,也得一個一個來,但這種才20個,但是如果有30個或者更多這就比較麻煩了,所以很多規模非常大的網站都不會通過這種方式來配置應用程序,而是讓應用程序所有配置都不通過本地配置文件加載,而是通過聯繫一個配置中心的服務去加載配置,所以稱之爲配置中心;
    啓動多個應用程序時,拋棄了傳統從本地文件加載配置的方法,而是通過一箇中心服務器來加載配置,這個服務叫做配置中心,隨後我們在這個配置中心修改了配置以後,會通知給每一個進程,讓進程自動進行重載,就能完成所有的進程進行重載,還可以以灰度的方式通知,那麼他們就可以以灰度的方式去更新自己的配置信息;
    國內有兩個項目,爲非容器化應用程序提供配置中心,協程的Apollo、百度的Distconf,所以在非容器化模式中,也可以使用配置中心,要使用配置中心還需要我們的程序支持從配置中心加載配置纔行;

secret

功能與configMap一樣,信息以 base64編碼存放 (相當於加密)

​ ConfigMap和Secret都作爲k8s的標準資源,用於實現爲Pod中容器提供配置信息,而這個配置信息它還扮演着K8s系統之上一組類似應用的配置中心,當配置發生變量時,我們只需要修改配置中心的配置,而後配置中心應用程序會自動更新配置信息並讓其重載應用;

​ 配置中心都需要存儲大量的配置數據,那麼這些配置數據可以存儲在各式各樣的存儲系統當中,KV存儲最爲常見,比如zookepper、etcd這些配置工具,ConfigMap提供的配置信息,一般而言可以被我們的Pod容器以兩種方式進行加載,所以Pod中的容器加載ConfigMap資源中的信息

  1. 第一種爲環境變量爲容器提供環境變量實現;

  2. 第二種方式就是通過volumes存儲卷的方式配置;

    而因爲ConfigMap和Pod都是名稱空間級別的資源,因此而者必須在同一名稱空間下面引用;

​ ConfigMap允許我們在必要時進行修改,修改存儲卷中內容在過一段隨機時間之後會同步到Pod的容器中,但如果容器本身不支持自動重載,我們可以在外部發送重載命令,讓其進行重載,也可以以灰度的方式進行,從這個角度上來說它的發佈可能會有一定的問題,有一部分建構在k8s之上的高級工具也能夠幫助我們完成k8s所不支持的各式各樣的功能;

構建ConfigMap資源有如下幾種方式

  1. 命令行: 但使用命令行去維護的資源是沒辦法被k8s跟蹤的,所以最好使用配置清單進行創建,使用命令行創建也有幾種方式
    • 第一種: --from-literal=key=value 可以定義多個, 同時寫一行即可
    • 第二種: --from-file=key=file_name 可以不指定key, 一般就是直接以文件名做爲鍵名
  2. 配置清單: 如果嵌套的是一個文件內容,稍微複雜一點,如下示例

secret資源類型

kubectl create secret -h

  1. docker-registry: 創建一個給docker register使用的私有倉庫帳號密碼, 在docker-register創建pod時,在spec當中有一個imagePullSecrets,對象列表,可以給出多個Secret,一個Secret就是一組帳號密碼,如果當第一個認證成功,那就繼續往下,自上而下依次進行檢索
  2. generic: 專用於存儲非tls類型的敏感信息,比如MySQL密碼
  3. tls: 專用於ssl或者tls的x509格式的證書和私鑰打包進Secret,證書和私鑰本身就是base64編碼,因此需要特有的邏輯來組織,不管文件名叫做什麼,在tls這種格式來組織的證書通通統一爲tls.cert,私鑰名爲tls.key;

generic

generic的方式主要是存儲一些用戶自定義的密碼,非tls類型的,比如MySQL密碼等,示例如下

通過環境變量

  1. 可選參數

    ]# kubectl create secret generic -h
    Examples:
      # 可以指定文件,key爲文件名
      kubectl create secret generic my-secret --from-file=path/to/bar
      
      # 指定key名,value爲文件內容
      kubectl create secret generic my-secret --from-file=ssh-privatekey=path/to/id_rsa --from-file=ssh-publickey=path/to/id_rsa.pub
      
      # 手動指定kv
      kubectl create secret generic my-secret --from-literal=key1=supersecret --from-literal=key2=topsecret
    
  2. 創建一個 generic 資源

    ]# kubectl create secret generic mysql-pass --from-literal=password=xiong@123
        secret/mysql-pass created
    
  3. 查看

    ]# kubectl get secret
    NAME                  TYPE                                  DATA   AGE
    mysql-pass            Opaque                                1      7s
    
    ]# kubectl describe secrets mysql-pass 
    Data
    ====
    password:  9 bytes   # key爲password, 其值就是一個隱藏結果只顯示字符串長度
    
    # 查看更詳細結果
    ]# kubectl get secrets mysql-pass -o yaml
    apiVersion: v1
    data:
      password: eGlvbmdAMTIz    # 通過-o yaml可以查看到其結果爲base64編碼
    kind: Secret
    metadata:
      creationTimestamp: "2020-05-07T06:34:29Z"
      managedFields:
      - apiVersion: v1
        fieldsType: FieldsV1
        fieldsV1:
          f:data:
            .: {}
            f:password: {}
          f:type: {}
        manager: kubectl
        operation: Update
        time: "2020-05-07T06:34:29Z"
      name: mysql-pass
      namespace: default
      resourceVersion: "25605"
      selfLink: /api/v1/namespaces/default/secrets/mysql-pass
      uid: 4075a4d2-f81d-4e26-8d98-61df0f8eab51
    type: Opaque
    
    # 解碼 base64
    ]# echo eGlvbmdAMTIz | base64 -d  # 相對的來說如果有心加密的值也能被顯示出來
        xiong@123
    
  4. 通過環境變量方式注入

    ]# cat s1_secret.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: s1-secret
      namespace: default
      labels:
        app: s1-secret
        release: qa
    spec:
      containers:
      - name: s1-secret
        image: ikubernetes/myapp:v1
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 80
        env:
        - name: mysql_pass
          valueFrom: 
            secretKeyRef:
              name: mysql-pass  # 指定secret定義的名稱
              key: password     # 指定secret定義的key,注意這個key需要存在對應的資源中
    
  5. 驗證

    ~]# kubectl exec s1-secret -- env
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    HOSTNAME=s1-secret
    mysql_pass=xiong@123
    

通過volume

​ volume是通過文件的方式載入配置,比如tomcat的默認配置有指定一個管理的user,那麼這個時候我們就可以把這個文件提取出來,載入Kubernetes作爲Secret,而後通過volume的方式掛在到指定的目錄下(可以掛載單個文件),覆蓋原有文件;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章