系統整理K8S的設定管理實戰-建議收藏系列

2022-11-07 12:01:07

原文公眾號連結:https://mp.weixin.qq.com/s/gZx-IIW1g9-Kl7yXw7tsEA
原文公眾號連結:https://mp.weixin.qq.com/s/gZx-IIW1g9-Kl7yXw7tsEA

一、ConfigMap

應用部署的最佳實踐都趨向於將應用所需要的設定資訊和應用程式本身離開,以便實現通過不同的設定實現更靈活的功能。

我們都知道,K8S中執行的是容器,若不將組態檔抽離,每一次組態檔的變動,都需要重新制作映象,這其實挺麻煩挺沒必要的。

在K8S中提供了ConfigMap資源物件作為設定管理的統一管理方案,可以通過環境變數或者檔案的方式,在建立容器的時候將設定資訊動態注入到容器中~

下文開始對ConfigMap的實戰

官網檔案:https://kubernetes.io/zh/docs/concepts/configuration/configmap/

1.1、建立

1.1.1、from-file

準備目錄和檔案

# 建立目錄及組態檔
[root@master01 yamls]# ls conf/
nginx.conf  redis.conf

[root@master01 yamls]# cat conf/nginx.conf
app.name=nginx
location.prefix=/app

[root@master01 yamls]# cat conf/redis.conf
ip=10.10.10.101
port=2379

建立cm

[root@master01 yamls]# kubectl create cm -h
# --from-file引數既可以指定檔案又可以指定目錄
[root@master01 yamls]# kubectl create cm cm-from-file --from-file=conf/
configmap/cm-from-file created

檢視

[root@master01 yamls]# kubectl get cm
NAME               DATA   AGE
cm-from-file       2      38s
kube-root-ca.crt   1      17d

[root@master01 yamls]# kubectl get cm cm-from-file -oyaml
apiVersion: v1
data:
  # 預設的data的key值就是檔名
  # 可以在建立時通過引數 --from-file=abc=nginx.conf的方式將data.key改成abc
  nginx.conf: |
    app.name=nginx
    location.prefix=/app
  redis.conf: |
    ip=10.10.10.101
    port=2379
kind: ConfigMap
metadata:
  creationTimestamp: "2022-03-31T00:52:21Z"
  name: cm-from-file
  namespace: default
  resourceVersion: "759788"
  uid: 5a41bdbe-66d0-45fa-8a5e-b6f6b005d671
1.1.2、from-env-file

env環境變數的格式為:key=value

指定引數:--from-env-file而不是--from-file

[root@master01 yamls]# kubectl create cm cm-env-file --from-env-file=conf/nginx.conf
configmap/cm-env-file created

[root@master01 yamls]# kubectl get  cm cm-env-file -oyaml
apiVersion: v1
data:
  app.name: nginx
  location.prefix: /app
kind: ConfigMap
metadata:
  creationTimestamp: "2022-03-31T01:04:12Z"
  name: cm-env-file
  namespace: default
  resourceVersion: "761496"
  uid: 8e885d31-0a83-423c-a59f-6ea8b0473103
1.1.3、from-literal

literal(翻譯為:字面意義的)直接在命令列上指定好key和value

引數:--from-literal

[root@master01 ~]# kubectl create cm env-from-literal --from-literal=Level=INFO --from-literal=Name=Mac
configmap/env-from-literal created

[root@master01 ~]# kubectl get cm env-from-literal -oyaml
apiVersion: v1
data:
  Level: INFO
  Name: Mac
kind: ConfigMap
metadata:
  creationTimestamp: "2022-04-01T00:31:13Z"
  name: env-from-literal
  namespace: default
  resourceVersion: "762641"
  uid: da2f8922-8385-46ba-82e9-b0dc197a1eb2
[root@master01 ~]#
1.1.4、基於yaml檔案建立
apiVersion: v1
kind: ConfigMap
metadata:
  name: game-demo
data:
  # 類屬性鍵;每一個鍵都對映到一個簡單的值
  player_initial_lives: "3"
  ui_properties_file_name: "user-interface.properties"

  # 類檔案鍵
  game.properties: |
    enemy.types=aliens,monsters
    player.maximum-lives=5    
  user-interface.properties: |
    color.good=purple
    color.bad=yellow
    allow.textmode=true    

1.2、Pod使用ConfigMap

1.2.1、valueFrom

推薦將下面這種kv格式的configMap注入為容器的組態檔

[root@master01 yamls]# kubectl get cm cm-env-file -oyaml
apiVersion: v1
data:
  app.name: nginx
  location.prefix: /app
kind: ConfigMap
metadata:
  creationTimestamp: "2022-03-31T01:04:12Z"
  name: cm-env-file
  namespace: default
  resourceVersion: "761496"
  uid: 8e885d31-0a83-423c-a59f-6ea8b0473103

建立dp,並將cm掛在進去

[root@master01 yamls]#  kubectl create deployment dp-test-cm --image=nginx --dry-run=client -oyaml > dp-test-cm.yaml

修改

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: dp-test-cm
  name: dp-test-cm
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dp-test-cm
  template:
    metadata:
      labels:
        app: dp-test-cm
    spec:
      containers:
      - image: nginx
        name: nginx
        env:
          # 直接定義ENV的kv
          - name: Level
            value: Pro
          # 將cm中的指定key的值作為AppName這個環境變數的值
          - name: AppName
            valueFrom:
              configMapKeyRef:
                name: cm-env-file
                key: app.name

驗證:

[root@master01 yamls]# kubectl get po
NAME                          READY   STATUS    RESTARTS         AGE
dp-test-cm-7c5666c5c4-wnhtk   1/1     Running   0                111s
[root@master01 yamls]# kubectl exec -ti dp-test-cm-7c5666c5c4-wnhtk -- sh
# echo $AppName
nginx
# echo $Level
Pro
1.2.2、envFrom

一次性設定多個環境變數

注意點:如果key不存在,不會影響pod的運用,但是也不會建立這個環境變數

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: dp-test-cm
  name: dp-test-cm
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dp-test-cm
  template:
    metadata:
      labels:
        app: dp-test-cm
    spec:
      containers:
      - image: nginx
        name: nginx
        # 和env同級,將redis-cm中的所有kv均作為環境變數注入到容器中
        envFrom:
        - configMapRef:
            name: redis-cm
        env:
          - name: Level
            value: Pro
          - name: AppName
            valueFrom:
              configMapKeyRef:
                name: cm-env-file
                key: app.name

驗證:

[root@master01 yamls]# kubectl exec -ti dp-test-cm-6b7d8dc675-wf2vm -- sh
# echo $ip
10.10.10.101
1.2.3、volumeMounts

將基於檔案建立的configMap以檔案的形式掛在Pod的指定目錄中

關鍵字:volume、volumeMounts

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: dp-test-cm
  name: dp-test-cm
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dp-test-cm
  template:
    metadata:
      labels:
        app: dp-test-cm
    spec:
      volumes:
        - name: brm-config
          configMap:
            name: cm-from-file
      containers:
      - image: nginx
        name: nginx
        volumeMounts:
        - name: brm-config
          mountPath: "/etc/foo"

驗證:可以看到它會將ConfigMap.data中的每一項,都作為一個單獨的檔案掛載進Pod中。

[root@master01 yamls]# kubectl get cm cm-from-file -oyaml
apiVersion: v1
data:
  nginx.conf: |
    app.name=nginx
    location.prefix=/app
  redis.conf: |
    ip=10.10.10.101
    port=2379
kind: ConfigMap
metadata:
  creationTimestamp: "2022-03-31T00:52:21Z"
  name: cm-from-file
  namespace: default
  resourceVersion: "759788"
  uid: 5a41bdbe-66d0-45fa-8a5e-b6f6b005d671
  
[root@master01 yamls]# kubectl exec -ti dp-test-cm-68d77c6c6-4jtqr -- sh
# cd /etc/foo
# ls
nginx.conf  redis.conf
# cat nginx.conf
app.name=nginx
location.prefix=/app
1.2.4、自定義檔名稱

自定義掛載進Pod容器的檔名關鍵字:spec.spec.volumes.configMap.items

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: dp-test-cm
  name: dp-test-cm
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dp-test-cm
  template:
    metadata:
      labels:
        app: dp-test-cm
    spec:
      volumes:
        - name: brm-config
          configMap:
            name: cm-from-file
            items:
            - key: redis.conf
              path: redis.conf.cus
      containers:
      - image: nginx
        name: nginx
        volumeMounts:
        - name: brm-config
          mountPath: "/etc/foo"
1.2.5、控制檔案許可權

關鍵字:spec.template.spec.vulumes.configMap.defaultModespec.template.spec.vulumes.configMap.items.mode

用在控制掛載進Pod的檔案的許可權,---分別對應421(八進位制)

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: dp-test-cm
  name: dp-test-cm
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dp-test-cm
  template:
    metadata:
      labels:
        app: dp-test-cm
    spec:
      volumes:
        - name: brm-config
          configMap:
            name: cm-from-file
            items:
            - key: redis.conf
              path: redis.conf.cus
              mode: 0111
            defaultMode: 0666  
      containers:
      - image: nginx
        name: nginx
        volumeMounts:
        - name: brm-config
          mountPath: "/etc/foo"
1.2.6、子目錄-subPath

關鍵字:subPath

subpath的作用是解決spec.template.spec.containers.volumeMounts.mountPath的掛載覆蓋問題

意思就是說,如果mountPath指定的是一個目錄,那麼k8s會用我們期望掛載進該目錄的檔案覆蓋掉該目錄中已存在的檔案,從而導致意外的結果。

解決方式如下的subPath,就是將cm 掛載成指定目錄+指定檔案,覆蓋也是對指定目錄中的指定檔案進行覆蓋,也就是下例中:將brm-config這個cm掛載進容器的/etc/foo/nginx.conf檔案(覆蓋也不會影響其他檔案)。

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: dp-test-cm
  name: dp-test-cm
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dp-test-cm
  template:
    metadata:
      labels:
        app: dp-test-cm
    spec:
      volumes:
        - name: brm-config
          configMap:
            name: cm-from-file
            items:
            - key: redis.conf
              path: redis.conf.cus
              mode: 0111
            defaultMode: 0666  
      containers:
      - image: nginx
        name: nginx
        volumeMounts:
        - name: brm-config
          mountPath: "/etc/foo/nginx.conf"
          subPath: "nginx.conf"

這裡可以做一個實驗,比如在掛在之前先搞一個/etc/foo/1.txt,然後分別用subpath和不用subpath兩種方式做掛載,對比/etc/foo/1.txt的是否被覆蓋的差異~

1.2.7、熱更新

cm中的值被編輯修改後,Pod中對應的掛載檔案的值也會保持同步。

特殊情況:

env-fromvalue-from這種以環境變數的形式掛載進pod的cm,無法做到熱更新

subPath也無法熱更新

1.2.8、不可變的cm

與Kind同級,設定引數immutable=true即可

1.3、限制條件

  • cm收NameSpace限制,只有在同一個NameSpace中的Pod才能參照她
  • cm必須先於使用它的pod前建立
  • 只有被apiserver管理的Pod的才能使用cm,靜態pod無法使用cm

二、Secret

Secret主要使用者保管私密資料,比如密碼、token、ssh keys等資訊。這些資訊直接放在映象中一是不方便動態變動,而是資料比較敏感,不安全。

可以通過三種方式使用Secret

  • 通過掛在方式掛在Secret到Pod中使用它
  • 通過

2.1、建立

2.1.1、from-file
# 建立檔案
[root@master01 echo -n 'admin' > ./username.txt
[root@master01 echo -n 'qwerqwer123123' > ./password.txt

# 檢視幫助檔案
[root@master01 secret-file]# kubectl create secret --help

# 基於file建立secret,使用generic建立出的Secret型別為Opaque
[root@master01 secret-file]# kubectl create secret generic db-user-info --from-file=./username.txt --from-file=./password.txt
secret/db-user-info created

檢視

[root@master01 secret-file]# kubectl get secrets db-user-info -oyaml
apiVersion: v1
data:
  password.txt: cXdlcnF3ZXIxMjMxMjM=
  username.txt: YWRtaW4=
kind: Secret
metadata:
  creationTimestamp: "2022-04-05T23:08:11Z"
  name: db-user-info
  namespace: default
  resourceVersion: "837054"
  uid: eabe607c-27fc-4611-92c6-fce4cc24f030
type: Opaque

data中的資料經base64加密儲存,可直接解密

[root@master01 secret-file]# echo "cXdlcnF3ZXIxMjMxMjM=" | base64  -d
qwerqwer123123
2.1.2、from-literal

基於字面意思上的命令列中指定好key和value建立Secret

[root@master01 secret-file]# kubectl create secret generic secret-from-literal --from-literal=username=admin --from-literal=passsword=123456
secret/secret-from-literal created

檢視

[root@master01 secret-file]# kubectl get secrets secret-from-literal -oyaml
apiVersion: v1
data:
  passsword: MTIzNDU2
  username: YWRtaW4=
kind: Secret
metadata:
  creationTimestamp: "2022-04-05T23:19:02Z"
  name: secret-from-literal
  namespace: default
  resourceVersion: "838616"
  uid: ebb95a99-8cbf-48fd-a651-60e12cd30110
type: Opaque
2.1.3、基於yaml檔案建立
  • 需要將data使用base64提前加密好,必須基於祕文建立
  • 也可以使用stringData基於明文建立secret
apiVersion: v1
kind: Secret
metadata:
  name: my-secret-from-yaml
  namespace: default
type: Opaque
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm

建立

[root@master01 secret-file]# kubectl apply -f secret-user-info.yaml
secret/my-secret-from-yaml created

檢視

[root@master01 secret-file]# kubectl get secrets my-secret-from-yaml -o yaml
apiVersion: v1
data:
  password: MWYyZDFlMmU2N2Rm
  username: YWRtaW4=
kind: Secret
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","data":{"password":"MWYyZDFlMmU2NRm","username":"YWRW4="},"kind":"Secret","metadata":{"annotations":{},"name":"my-secret-from-yaml","namespace":"default"},"type":"Opaque"}
  creationTimestamp: "2022-04-05T23:28:27Z"
  name: my-secret-from-yaml
  namespace: default
  resourceVersion: "839971"
  uid: eb3acb4d-edf2-4ac0-9373-e7a931a1a559
type: Opaque

基於明文建立

使用stringData關鍵字可以基於明文建立,因為不安全所以不推薦。

apiVersion: v1
kind: Secret
metadata:
  name: secret-basic-auth
type: kubernetes.io/basic-auth
stringData:
  username: admin      #  kubernetes.io/basic-auth 型別的必需欄位
  password: t0p-Secret # kubernetes.io/basic-auth 型別的必需欄位
2.1.4、from-env-file

用法和cm的from-env-file類似

[root@master01 secret-file]# cat ./secret-env-file.txt
username=admin
password=123456

[root@master01 secret-file]# kubectl get secrets secret-from-env -oyaml
apiVersion: v1
data:
  password: MTIzNDU2
  username: YWRtaW4=
kind: Secret
metadata:
  creationTimestamp: "2022-04-05T23:39:47Z"
  name: secret-from-env
  namespace: default
  resourceVersion: "841608"
  uid: efaf7ad6-2ded-4544-93f8-5efabd2ca449
type: Opaque

2.2、實戰

2.2.1、設定阿里雲私有倉庫金鑰

給kubelet設定私有云下載Docker映象的賬號密碼

# 檢視幫助檔案
[root@master01 secret-file]# kubectl create secret docker-registry -h

# 將username、password、email修改成自己的
[root@master01 secret-file]# kubectl create secret docker-registry brm-alicloud-docker-secret --docker-username=xxxx --docker-password=xxx [email protected]  --docker-server=registry.cn-hangzhou.aliyuncs.com

檢視(data中的dockerconfigjson) 同樣可以使用base64解碼看到一個json串

[root@master01 secret-file]# kubectl get secrets brm-alicloud-docker-secret -oyaml
apiVersion: v1
data:
  .dockerconfigjson: eyJhdXRocyI6eyJyZWdpc3RyeS5jbi1oYW5nemhvdS5hbGl5dW5jcy5jb20iOnsidXNlcm5hbWUiOiLmnLHmmIzmraYyMjMzIiwicGFzc3dvcmQiOiJxd2VyMTAxMC4uIiwiZW1haWwiOiI2NDY0NTAzMDhAcXEuY29tIiwiYXV0aCI6IjVweXg1cGlNNXEybU1qSXpNenB4ZDJWeU1UQXhNQzR1In19fQ==
kind: Secret
metadata:
  creationTimestamp: "2022-04-06T00:04:17Z"
  name: brm-alicloud-docker-secret
  namespace: default
  resourceVersion: "845134"
  uid: 6e7bd04e-621c-4da8-8649-99c0ebffcee9
type: kubernetes.io/dockerconfigjson

掛載,先搞一個模版dp

[root@master01 secret-file]# kubectl create deployment alicloud-private-nginx --image=registry.cn-hangzhou.aliyuncs.com/changwu/nginx:1.7.9-nettools --dry-run=client -oyaml

修改新增imagePullSecrets設定

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: alicloud-private-nginx
  name: alicloud-private-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: alicloud-private-nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: alicloud-private-nginx
    spec:
      imagePullSecrets:
      - name: brm-alicloud-docker-secret
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/changwu/nginx:1.7.9-nettools
        name: nginx
        resources: {}
status: {}

驗證的話就去 kubectl get pod -owide即可

2.2.2、管理https證書

生成私鑰和crt

[root@master01 https]# openssl req -x509 -nodes -days 3650 \
> -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=test.com"
Generating a 2048 bit RSA private key
....................................................................+++
...........+++
writing new private key to 'tls.key'
-----
[root@master01 https]# ls
tls.crt  tls.key

將key和cry託管進secret

[root@master01 https]# kubectl create secret tls https-nginx-tls-test-secret -n default --key=tls.key --cert=tls.crt
secret/https-nginx-tls-test-secret created

檢視

[root@master01 https]# kubectl get secrets https-nginx-tls-test-secret -oyaml
apiVersion: v1
data:
  tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1R1lrWTJRCjN4VUpQV1hVR0lqM2VVYnhTc0hFZ2lyZDlJalBZL1pwZEsxWittbmNHTWMyNW41aVhoUEs1UG1ZcjYrcAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
  tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1V3AzbUtRNHJkZG1CZGplMjJpMjR1bU5IUGd2STJBRGlEalAKNXBTb2hRYWRkZVZYRDJFZWdlWFRTTHY3Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K
kind: Secret
metadata:
  creationTimestamp: "2022-04-06T00:25:33Z"
  name: https-nginx-tls-test-secret
  namespace: default
  resourceVersion: "848213"
  uid: afa127bb-4a3a-4eb9-9d55-8cd50af5b3f4
type: kubernetes.io/tls

設定到ingress中(不是很推薦直接在ingress中設定https,通常會將https設定在ingress的上一層的SLB代理中)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: simple-tls-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: https-test.com # 設定域名,可以不寫,匹配*,或者寫 *.bar.com
    http:
      paths: # 相當於nginx的location,同一個host可以設定多個path
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-svc
            port:
              number: 80
  tls:
   - secretName: https-nginx-tls-test-secret

驗證

2.2.3、不可變的secret

與Kind同級,設定引數immutable=true即可