Kubernetes 配置管理

Posted by Vito on January 22, 2024

ConfigMap

  • 补充知识点:将 kubectl create 命令输出到 yaml 文件
    • kubectl create ...... --dry-run=client -o yaml > xxx.yaml
    • --dry-run=client : 预览而不真正提交到 apiserver
    • -o yaml :以 yaml 格式输出
  • 补充知识点:获取已存在资源的规范
    • kubectl get TYPE NAME -o yaml > xxx.yaml
  • 补充知识点:资源更新/替换
    • kubectl replace -f File
    • kubectl edit TYPE NAME
文件准备
1
2
3
4
5
6
7
8
9
[root@k8s-master1 ~]# cat config/db.properties 
datasource.url=jdbc:postgresql://192.168.23.11:5432/ims-devnft-v1
datasource.username=postgres
datasource.password=Admin123456

[root@k8s-master1 ~]# cat config/redis.yml 
redis:
  host: 192.168.23.11
  password: 123456
创建 ConfigMap
  • 通过命令 kubectl create cm -h 查看创建 configmap 的语法

  • 将指定目录下所有文件创建为 configmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[root@k8s-master1 ~]# kubectl create cm cm-dir-config --from-file=/root/config
configmap/cm-dir-config created

[root@k8s-master1 ~]# kubectl describe cm cm-dir-config
Name:         cm-dir-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
db.properties:
----
datasource.url=jdbc:postgresql://192.168.23.11:5432/ims-devnft-v1
datasource.username=postgres
datasource.password=Admin123456

redis.yml:
----
redis:
  host: 192.168.23.11
  password: 123456


BinaryData
====

Events:  <none>

# 注意:`----`上面的是 key , 下面是 value
# 所以上面创建的 configmap 仅有两组 key/value ,千万不要把 datasource.url、redis.host 等当作 key 来使用
  • 指定具体文件来创建 configmap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[root@k8s-master1 ~]# kubectl create cm cm-file-config \
                      --from-file=postgres.properties=/root/config/db.properties \
                      --from-file=/root/config/redis.yml
configmap/cm-file-config created

[root@k8s-master1 ~]# kubectl describe cm cm-file-config
Name:         cm-file-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
postgres.properties:
----
datasource.url=jdbc:postgresql://192.168.23.11:5432/ims-devnft-v1
datasource.username=postgres
datasource.password=Admin123456

redis.yml:
----
redis:
  host: 192.168.23.11
  password: 123456


BinaryData
====

Events:  <none>
  • 指定具体的 key-value 来创建 configmap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@k8s-master1 ~]# kubectl create cm cm-literal-config --from-literal=uname=vito --from-literal=pwd=123456
configmap/cm-literal-config created

[root@k8s-master1 ~]# kubectl describe cm cm-literal-config
Name:         cm-literal-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
pwd:
----
123456
uname:
----
vito

BinaryData
====

Events:  <none>
  • 通过 yaml 文件来创建 configMap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
[root@k8s-master1 ~]# cat config/cm-spring-k8s.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: cm-spring-k8s
data:
  server.port: '8080'
  spring.application.name: tensquare-main-tensquare_eureka_server
  eureka.client.service-url.defaultZone: 'http://127.0.0.1:10086/eureka'

[root@k8s-master1 ~]# kubectl create -f config/cm-spring-k8s.yaml 
configmap/cm-spring-k8s created

[root@k8s-master1 ~]# kubectl describe configmap/cm-spring-k8s
Name:         cm-spring-k8s
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
eureka.client.service-url.defaultZone:
----
http://127.0.0.1:10086/eureka
server.port:
----
8080
spring.application.name:
----
tensquare-main-tensquare_eureka_server

BinaryData
====

Events:  <none>

Secret

文件准备

1
2
3
4
5
6
7
8
9
[root@k8s-master1 ~]# cat secret/activemq.properties 
activemq.user=admin
activemq.password=MQ12345678

[root@k8s-master1 ~]# cat secret/s3.yml 
file:
  amazon-s3:
    access-key: NUFVTEMOKWDZMWFJLFOI
    secret-key: tvGr6wcMbMStCi/+kLSdV6CABTGfxpgKRgB3wZyE

创建 Secret

  • 查看帮助文档
1
2
3
4
5
6
7
[root@k8s-master1 ~]# kubectl create secret -h
Create a secret using specified subcommand.

Available Commands:
  docker-registry   创建一个给 Docker registry 使用的 Secret
  generic           Create a secret from a local file, directory, or literal value
  tls               创建一个 TLS secret
  • tls
1
2
3
[root@k8s-master1 ~]# kubectl create secret tls zhch.lan \
                      --cert=/home/zc/cert/zhch.lan.crt \
                      --key=/home/zc/cert/zhch.lan.key
  • docker-registry
1
2
3
4
5
# kubectl create secret docker-registry -h
[root@k8s-master1 ~]# kubectl create secret docker-registry secret-harbor \
                      --docker-server='harbor.zhch.lan' \
                      --docker-username='vito' \
                      --docker-password='Harbor12345'
  • generic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# kubectl create secret generic -h
# secret generic 的创建方式与 configmap 的创建方式基本一样

[root@k8s-master1 ~]# kubectl create secret generic secret-dir-config --from-file=/root/secret
secret/secret-dir-config created

[root@k8s-master1 ~]# kubectl create secret generic secret-file-config \
                      --from-file=mq.properties=/root/secret/activemq.properties \
                      --from-file=/root/secret/s3.yml
secret/secret-file-config created

[root@k8s-master1 ~]# kubectl create secret generic secret-literal-config --from-literal=uname=zhch --from-literal=pwd=666666
secret/secret-literal-config created


[root@k8s-master1 ~]# cat secret/secret-spring-k8s.yaml 
apiVersion: v1
kind: Secret
metadata:
  name: secret-spring-k8s
type: Opaque
stringData: # 注意这里应该使用 stringData ,而不是 data
  spring.datasource.username: root
  spring.datasource.password: 'Root@123'

[root@k8s-master1 ~]# kubectl create -f secret/secret-spring-k8s.yaml
secret/secret-spring-k8s created
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[root@k8s-master1 ~]# kubectl describe secret secret-file-config
Name:         secret-file-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
mq.properties:  49 bytes
s3.yml:         113 bytes

[root@k8s-master1 ~]# kubectl edit secret secret-file-config
apiVersion: v1
data:
  mq.properties: YWN0aXZlbXEudXNlcj1hZG1pbgphY3RpdmVtcS5wYXNzd29yZD1NUTEyMzQ1Njc4Cg==
  s3.yml: ZmlsZToKICBhbWF6b24tczM6CiAgICBhY2Nlc3Mta2V5OiBOVUZWVEVNT0tXRFpNV0ZKTEZPSQogICAgc2VjcmV0LWtleTogdHZHcjZ3Y01iTVN0Q2kvK2tMU2RWNkNBQlRHZnhwZ0tSZ0Izd1p5RQo=
kind: Secret
metadata:
  creationTimestamp: "2023-12-21T05:35:06Z"
  name: secret-file-config
  namespace: default
  resourceVersion: "283089"
  uid: 00716022-8192-48cb-84de-e53f9051699f
type: Opaque

[root@k8s-master1 ~]# echo 'YWN0aXZlbXEudXNlcj1hZG1pbgphY3RpdmVtcS5wYXNzd29yZD1NUTEyMzQ1Njc4Cg==' | base64 --decode
activemq.user=admin
activemq.password=MQ12345678

配置文件的使用

环境变量、docker-registry

1
2
3
4
5
6
7
8
9
# 客户端要使用 tls 与 Harbor 通信,使用的还是自签证书,那么必须建立一个目录:/etc/docker/certs.d
# 然后在这个目录下创建签名的域名目录,并把证书拷贝到这个目录中
[root@k8s-node1 ~]# mkdir -p /etc/docker/certs.d
[root@k8s-node1 ~]# cd /etc/docker/certs.d/
[root@k8s-node1 certs.d]# mkdir harbor.zhch.lan

# 192.168.99.101 是 Nginx 服务器的 IP,其 SSH 端口已由默认的 22 改为 2222
# scp [可选参数] file_source file_target  
[root@k8s-node1 certs.d]# scp -P 2222 zc@192.168.99.101:/home/zc/cert/zhch.lan.crt /etc/docker/certs.d/harbor.zhch.lan/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[root@k8s-master1 test]# vim po-config-test.yaml 
apiVersion: v1
kind: Pod 
metadata:
  name: po-config-test
spec:
  imagePullSecrets: # 登录私有镜像仓库
    - name: secret-harbor
  containers:
  - name: po-config-test-c
    image: harbor.zhch.lan/tensquare/tensquare-main-tensquare_eureka_server:2023.1208.143152
    imagePullPolicy: IfNotPresent
    env: # 环境变量
    - name: SPRING_APPLICATION_NAME
      valueFrom:
        configMapKeyRef:
          name: cm-spring-k8s # ConfigMap 的名字
          key: spring.application.name # ConfigMap 中的 key
    - name: EUREKA_DEFAULT_ZONE
      valueFrom:
        configMapKeyRef:
          name: cm-spring-k8s
          key: eureka.client.service-url.defaultZone
    - name: SPRING_DATASOURCE_PASSWORD
      valueFrom:
        secretKeyRef:
          name: secret-spring-k8s
          key: spring.datasource.password
    - name: SPRING_AMAZON_S3
      valueFrom:
        secretKeyRef:
          name: secret-file-config   # Secret 的名字
          key: s3.yml # Secret 中的 key
  restartPolicy: Never
1
2
3
4
5
6
7
8
9
10
11
12
13
[root@k8s-master1 test]# kubectl create -f po-config-test.yaml 
pod/po-config-test created

[root@k8s-master1 test]# kubectl exec -it po-config-test -- sh
/ # env
SPRING_DATASOURCE_PASSWORD=Root@123
SPRING_APPLICATION_NAME=tensquare-main-tensquare_eureka_server
EUREKA_DEFAULT_ZONE=http://127.0.0.1:10086/eureka
SPRING_AMAZON_S3=file:
  amazon-s3:
    access-key: NUFVTEMOKWDZMWFJLFOI
    secret-key: tvGr6wcMbMStCi/+kLSdV6CABTGfxpgKRgB3wZyE
# 这里省略了其他环境变量

文件挂载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[root@k8s-master1 test]# vim po-configfile-test.yaml 
apiVersion: v1
kind: Pod 
metadata:
  name: po-configfile-test
spec:
  volumes:
  - name: db-config # 数据卷名称
    configMap: # configMap 类型的数据卷
      name: cm-dir-config # ConfigMap 资源的名字
      items: # 对 configMap 中的 key 进行映射,将 key 对应的 value 映射为文件。如果不配置 items,则默认将 configMap 中所有的 key/value 全部映射为文件
      - key: db.properties
        path: db.properties
  - name: secret-config # 数据卷名称
    secret: # secret 类型的数据卷
      secretName: secret-dir-config  # Secret 资源的名字
      # items:  # 含义与 configMap 类型数据卷中的 items 一致
  containers:
  - name: po-configfile-test-c
    image: alpine:3.16
    command: ["/bin/sh", "-c", "sleep 3600"]
    imagePullPolicy: IfNotPresent
    volumeMounts: # 在容器中挂载数据卷
    - name: db-config # 数据卷名字
      mountPath: /configMap # 挂载到容器中的路径
    - name: secret-config
      mountPath: /secret
      readOnly: true
  restartPolicy: Never

1
2
3
4
5
6
7
8
9
10
11
12
[root@k8s-master1 test]# kubectl create -f po-configfile-test.yaml
pod/po-configfile-test created

[root@k8s-master1 test]# kubectl exec -it po-configfile-test -- sh
/ # ls configMap
db.properties
/ # ls secret
activemq.properties  s3.yml
/ # cat secret/activemq.properties 
activemq.user=admin
activemq.password=MQ12345678
/ # 

配置文件热更新

  • 直接编辑
1
[root@k8s-master1 test]# kubectl edit configMap/cm-dir-config
  • kubectl replace
1
2
3
[root@k8s-master1 test]# vim /root/secret/activemq.properties

[root@k8s-master1 test]# kubectl create secret generic secret-dir-config --from-file=/root/secret --dry-run=client -o yaml | kubectl replace -f-
  • 进入容器内查看挂载的文件内容是否有变化
1
[root@k8s-master1 test]# kubectl exec -it po-configfile-test -- sh
  • 注意:
    • 默认方式:会更新,更新周期是更新时间 + 缓存时间
    • subPath:不会更新
    • 变量形式:如果 pod 中的一个变量是从 configmap 或 secret 中得到,同样也是不会更新的
    • 对于 subPath 的方式,我们可以取消 subPath 的使用,将配置文件挂载到一个不存在的目录,避免目录的覆盖,然后再利用软连接的形式,将该文件链接到目标位置

subPath

  • 有时,在单个 Pod 中共享卷以供多个容器使用是很有用的。 volumeMounts.subPath 属性可用于指定所引用的卷内的子路径,而不是其根路径。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    [root@k8s-master1 test]# vim po-subpath-test.yaml 
    apiVersion: v1
    kind: Pod 
    metadata:
      name: po-subpath-test
    spec:
      volumes:
      - name: dir-config
        configMap:
          name: cm-dir-config # cm-dir-config 内有两个配置文件
      containers:
      - name: po-subpath-test-c1
        image: nginx:1.7.9
        command: ["/bin/sh", "-c", "sleep 3600"]
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - name: dir-config
          mountPath: /etc/nginx/db.properties
          subPath: db.properties
      - name: po-subpath-test-c2
        image: nginx:1.7.9
        command: ["/bin/sh", "-c", "sleep 3600"]
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - name: dir-config
          mountPath: /etc/nginx/redis.yml
          subPath: redis.yml
      restartPolicy: Never
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    [root@k8s-master1 test]# kubectl create -f po-subpath-test.yaml 
    pod/po-subpath-test created
      
    [root@k8s-master1 test]# kubectl exec -it po-subpath-test -c po-subpath-test-c1 -- bash
    root@po-subpath-test:/# ls /etc/nginx/
    conf.d	db.properties  fastcgi_params  koi-utf	koi-win  mime.types  nginx.conf  scgi_params  uwsgi_params  win-utf
    root@po-subpath-test:/# cat /etc/nginx/db.properties 
    datasource.url=jdbc:postgresql://192.168.23.11:5432/ims-devnft-v1
    datasource.username=root
    datasource.password=Admin888888
      
    [root@k8s-master1 test]# kubectl exec -it po-subpath-test -c po-subpath-test-c2 -- bash
    root@po-subpath-test:/# ls /etc/nginx/
    conf.d	fastcgi_params	koi-utf  koi-win  mime.types  nginx.conf  redis.yml  scgi_params  uwsgi_params	win-utf
    root@po-subpath-test:/# cat /etc/nginx/redis.yml 
    redis:
      host: 192.168.23.11
      password: 123456
    

挂载时目录被覆盖的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: v1
kind: Pod 
metadata:
  name: po-dir-overwrite-test
spec:
  volumes:
  - name: db-config
    configMap:
      name: cm-dir-config
      items:
      - key: db.properties
        path: db.properties
  containers:
  - name: po-dir-overwrite-test-c
    image: nginx:1.7.9
    command: ["/bin/sh", "-c", "sleep 3600"]
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: db-config
      mountPath: /etc/nginx
  restartPolicy: Never

# 容器内 /etc/nginx 中将只存在 db.properties 文件,其他文件均被覆盖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: v1
kind: Pod 
metadata:
  name: po-dir-overwrite-test
spec:
  volumes:
  - name: db-config
    configMap:
      name: cm-dir-config
      items:
      - key: db.properties
        path: db.properties
  containers:
  - name: po-dir-overwrite-test-c
    image: nginx:1.7.9
    command: ["/bin/sh", "-c", "sleep 3600"]
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: db-config
      mountPath: /etc/nginx/db.properties
  restartPolicy: Never
  
  # 此时,容器内`/etc/nginx`中的其他文件不会被覆盖