目 录CONTENT

文章目录

配置管理

简中仙
2022-05-10 / 0 评论 / 0 点赞 / 63 阅读 / 0 字 / 正在检测是否收录...
温馨提示:
本文最后更新于2024-01-14,若内容或图片失效,请留言反馈。 本文如有错误或者侵权的地方,欢迎您批评指正!

这篇学习笔记是基于杜宽老师在51CTO上发布的视频课程制作的。在此,感谢杜宽老师的分享和教学。如有侵权,请及时联系我。版权归原作者所有,未经允许不得转载或使用。

一、ConfigMap

1、什么是configmap

一般用 ConfigMap 去管理一些配置文件,或者一些大量的环境变量信息。

ConfigMap 将配置和 Pod分开,有一个nginx, nginx.conf-> configmap, nginx 去读取configmap的信息。更易于配置文件的更新和管理。

Secret: Secret更倾向于存储和共享敏感、加密的配置信息。

配置文档:https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-pod-configmap/

2、创建 ConfigMap

创建configmap的几种形式

kubectl create configmap -h			#查看帮助文档

1、通过yaml / json文件创建

apiVersion: v1
kind: ConfigMap
metadata: 
  name: test-conf
  namespace: test
data:
  test-conf: |+
    SESSION_LIFETIME: 3600
    URL: "http://test-server:8080"

执行命令:

kubectl create -f configmap.yaml

若报错:"namespace 'test' not found",则需要先创建namespace:

kubectl create namespace test

2、通过--from-file创建

分别指定单个文件和目录,指定目录可以创建一个包含该目录中所有文件的configmap:

kubectl create cm cmfromdir --from-file=conf/			#基于文件夹的形式创建

将--from-file指定为单个文件就可以从单个文件中创建:

kubectl create cm cmfromfile --from-file=conf/redis.conf 			#基于文件创建

其中,--from-file可以使用多次,比如:

kubectl create configmap *** --from-file=file1 --from-file=file2

自定义名称创建

kubectl create cm cmspecialname --from-file=game-conf=game.conf			#基于文件创建并自定义名称(game-conf)

可以指定多个

kubectl create cm cmspecialname2 --from-file=game-conf=game.conf  --from-file=redis-conf=redis.conf			#基于文件创建并自定义名称(多个文件)

3、通过key-value字符串创建

kubectl create cm envfromliteral --from-literal=level=INFO --from-literal=PASSWORD=redis123			#直接创建

4、通过env文件创建

通过环境文件创建:

kubectl create cm gameenvcm --from-env-file=game.conf			#基于环境变量创建

其中,env.txt的文件格式为:

lives=3
secrect.code=true
test_env=xxx

当使用多个--from-env-file从多个数据源创建configmap时,仅最后一个env文件有效。

3、查看configmap创建情况

可以使用以下命令查看创建成功的configmap:

命令说明
kubectl get configmaps查看所有configmap
kubectl get configmaps -n namespace1查看命名空间为namespace1的所有configmap
kubectl describe configmaps configmap1查看configmap1的详细信息
kubectl get configmaps configmap1 -o yaml以yaml文件形式展现configmap详细信息

4、使用configmap

configmap创建成功之后,如何在pod中使用呢?有以下几种方法:

注意

使用ConfigMap有以下几个限制条件:

  1. ConfigMap必须在pod之前创建
  2. configmap受namespace的限制,只能相同namespace的pod才可以引用

1、使用valueFrom定义环境变量

首先创建configmap:

# 导出development配置文件
kubectl create deploy dp-cm \ 
--image=registry.cn-beijing.aliyuncs.com/dotbalo/nginx \
--dry-run=client -oyaml > dp-cm.yaml

接下来用作环境变量,创建dp-cm.yaml

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  namespace: test
spec:
  containers:
    - name: test-container
      image: test:v0.1
      env:
        - name: TEST_ENV
          value: testenv
        - name: LIVES
          valueFrom:
            configMapKeyRef:
              name: gameenvcm
              key: lives
        - name: test_env
          valueFrom:
            configMapKeyRef:
              name: gameenvcm
              key: test_env

执行命令创建Pod:

kubectl create -f dp-cm.yaml

创建成功之后,执行命令查看pod的详细信息,可以看到已经将configmap中的配置添加到环境变量:

kubectl exec dp-cm-7sadas454-dasf -- env

同时,也支持多个configmap共同创建环境变量。

2、使用envFrom定义环境变量

将所有configmap的数据定义为容器环境变量, configmap中的键成为pod中的环境变量名称。

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  namespace: test
spec:
  containers:
  - image: registry.cn-beijing.aliyuncs.com/dotbalo/nginx 
    name: nginx
    envFrom:
    - configMapRef:
        name: gameenvcm
      prefix: fromCm_		#标识文件生成的环境变量前缀

3、以文件的形式挂载ConfigMap

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  namespace: test
spec:
  containers:
    - image: registry.cn-beijing.aliyuncs.com/dotbalo/nginx 
      name: nginx
      volumeMounts:
        - name: redisconf	#对应volumes中name
          mountPath: /etc/config
        - name: cmfromfile 
          mountPath: /etc/config2
  volumes:
    - name: redisconf
      configMap:
        name: redis-conf
    - name: cmfromfile
      configMap:
        name: cmfromfile

4、自定义挂载权限及名称

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  namespace: test
spec:
  containers:
    - image: registry.cn-beijing.aliyuncs.com/dotbalo/nginx 
      name: nginx
      volumeMounts:
        - name: redisconf
          mountPath: /etc/config
        - name: cmfromfile 
          mountPath: /etc/config2
  volumes:
      - name: redisconf
        configMap:
          name: redis-conf
      - name: cmfromfile
        configMap:
          name: cmfromfile
          items:
            - key: redis.conf
              path: redis.conf.bak
            - key: redis.conf
              path: redis.conf.bak2
              mode: 0644 # 优先级高
          defaultMode: 0666  # 328

二、Secret

1、什么是secret

文档:https://kubernetes.io/zh/docs/concepts/configuration/secret/

用于存储和管理一些敏感数据,比如密码,token,密钥等敏感信息。它把 Pod 想要访问的加密数据存放到 Etcd 中。然后用户就可以通过在 Pod 的容器里挂载 Volume 的方式或者环境变量的方式访问到这些 Secret 里保存的信息了。

Secret常用类型

  • uOpaque:通用型Secret,默认类型;
  • ukubernetes.io/service-account-token:作用于ServiceAccount,包含一个令牌,用于标识API服务账户;
  • ukubernetes.io/dockerconfigjson:下载私有仓库镜像使用的Secret,和宿主机的/root/.docker/config.json一致,宿主机登录后即可产生该文件;
  • ukubernetes.io/basic-auth:用于使用基本认证(账号密码)的Secret,可以使用Opaque取代;
  • ukubernetes.io/ssh-auth:用于存储ssh密钥的Secret;
  • ukubernetes.io/tls:用于存储HTTPS域名证书文件的Secret,可以被Ingress使用;
  • ubootstrap.kubernetes.io/token:一种简单的 bearer token,用于创建新集群或将新节点添加到现有集群,在集群安装时可用于自动颁发集群的证书。

2、使用 kubectl 管理 Secret

1、创建Secret

一个 Secret 可以包含 Pod 访问数据库所需的用户凭证。 例如,由用户名和密码组成的数据库连接字符串。 你可以在本地计算机上,将用户名存储在文件 ./username.txt 中,将密码存储在文件 ./password.txt 中。

echo -n 'admin' > ./username.txt
echo -n '1f2d1e2e67df' > ./password.txt

在这些命令中,-n 标志确保生成的文件在文本末尾不包含额外的换行符。 这一点很重要,因为当 kubectl 读取文件并将内容编码为 base64 字符串时,多余的换行符也会被编码。

kubectl create secret 命令将这些文件打包成一个 Secret 并在 API 服务器上创建对象。

kubectl create secret generic(类型) db-user-pass(名称) \
  --from-file=./username.txt \
  --from-file=./password.txt

输出类似于:

secret/db-user-pass created

默认密钥名称是文件名。 你可以选择使用 --from-file=[key=]source 来设置密钥名称。例如:

kubectl create secret generic db-user-pass \
  --from-file=username=./username.txt \
  --from-file=password=./password.txt

你不需要对文件中包含的密码字符串中的特殊字符进行转义。

你还可以使用 --from-literal=<key>=<value> 标签提供 Secret 数据。 可以多次使用此标签,提供多个键值对。 请注意,特殊字符(例如:$\*=!)由你的 shell 解释执行,而且需要转义。

在大多数 shell 中,转义密码最简便的方法是用单引号括起来。 比如,如果你的密码是 S!B\*d$zDsb=, 可以像下面一样执行命令:

kubectl create secret generic dev-db-secret \
  --from-literal=username=devuser \
  --from-literal=password='S!B\*d$zDsb='

2、验证Secret

检查 secret 是否已创建:

kubectl get secrets

输出类似于:

NAME                  TYPE                                  DATA      AGE
db-user-pass          Opaque                                2         51s

你可以查看 Secret 的描述:

kubectl describe secrets/db-user-pass

输出类似于:

Name:            db-user-pass
Namespace:       default
Labels:          <none>
Annotations:     <none>

Type:            Opaque

Data
====
password:    12 bytes
username:    5 bytes

kubectl getkubectl describe 命令默认不显示 Secret 的内容。 这是为了防止 Secret 被意外暴露或存储在终端日志中。

3、解码Secret

要查看创建的 Secret 的内容,运行以下命令:

kubectl get secret db-user-pass -o jsonpath='{.data}'

输出类似于:

{"password":"MWYyZDFlMmU2N2Rm","username":"YWRtaW4="}

现在你可以解码 password 的数据:

echo 'MWYyZDFlMmU2N2Rm' | base64 --decode

输出类似于:

1f2d1e2e67df

4、清理

删除创建的 Secret:

kubectl delete secret db-user-pass

3、使用配置文件管理 Secret

1、创建配置文件

你可以先用 JSON 或 YAML 格式在文件中创建 Secret,然后创建该对象。 Secret 资源包含2个键值对: datastringDatadata 字段用来存储 base64 编码的任意数据。 提供 stringData 字段是为了方便,它允许 Secret 使用未编码的字符串。 datastringData 的键必须由字母、数字、-_. 组成。

例如,要使用 Secret 的 data 字段存储两个字符串,请将字符串转换为 base64 ,如下所示:

echo -n 'admin' | base64

输出类似于:

YWRtaW4=
echo -n '1f2d1e2e67df' | base64

输出类似于:

MWYyZDFlMmU2N2Rm

编写一个 Secret 配置文件,如下所示:

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm

注意,Secret 对象的名称必须是有效的 DNS 子域名.

说明:

Secret 数据的 JSON 和 YAML 序列化结果是以 base64 编码的。 换行符在这些字符串中无效,必须省略。 在 Darwin/macOS 上使用 base64 工具时,用户不应该使用 -b 选项分割长行。 相反地,Linux 用户 应该base64 地命令中添加 -w 0 选项, 或者在 -w 选项不可用的情况下,输入 base64 | tr -d '\n'

对于某些场景,你可能希望使用 stringData 字段。 这字段可以将一个非 base64 编码的字符串直接放入 Secret 中, 当创建或更新该 Secret 时,此字段将被编码。

上述用例的实际场景可能是这样:当你部署应用时,使用 Secret 存储配置文件, 你希望在部署过程中,填入部分内容到该配置文件。

例如,如果你的应用程序使用以下配置文件:

apiUrl: "https://my.api.com/api/v1"
username: "<user>"
password: "<password>"

你可以使用以下定义将其存储在 Secret 中:

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
stringData:
  config.yaml: |
    apiUrl: "https://my.api.com/api/v1"
    username: <user>
    password: <password>    

2、创建 Secret 对象

现在使用 kubectl apply 创建 Secret:

kubectl apply -f ./secret.yaml

输出类似于:

secret/mysecret created

3、检查 Secret

stringData 字段是只写的。获取 Secret 时,此字段永远不会输出。 例如,如果你运行以下命令:

kubectl get secret mysecret -o yaml

输出类似于:

apiVersion: v1
data:
  config.yaml: YXBpVXJsOiAiaHR0cHM6Ly9teS5hcGkuY29tL2FwaS92MSIKdXNlcm5hbWU6IHt7dXNlcm5hbWV9fQpwYXNzd29yZDoge3twYXNzd29yZH19
kind: Secret
metadata:
  creationTimestamp: 2018-11-15T20:40:59Z
  name: mysecret
  namespace: default
  resourceVersion: "7225"
  uid: c280ad2e-e916-11e8-98f2-025000000001
type: Opaque

命令 kubectl getkubectl describe 默认不显示 Secret 的内容。 这是为了防止 Secret 意外地暴露给旁观者或者保存在终端日志中。 检查编码数据的实际内容,请参考解码 secret.

如果在 datastringData 中都指定了一个字段,比如 username,字段值来自 stringData。 例如,下面的 Secret 定义:

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: YWRtaW4=
stringData:
  username: administrator

结果有以下 Secret:

apiVersion: v1
data:
  username: YWRtaW5pc3RyYXRvcg==
kind: Secret
metadata:
  creationTimestamp: 2018-11-15T20:46:46Z
  name: mysecret
  namespace: default
  resourceVersion: "7579"
  uid: 91460ecb-e917-11e8-98f2-025000000001
type: Opaque

其中 YWRtaW5pc3RyYXRvcg== 解码成 administrator

4、清理

删除你创建的 Secret:

kubectl delete secret mysecret

4、使用Secret拉取私有仓库镜像

kubectl create secret docker-registry myregistrykey \
--docker-server=DOCKER_REGISTRY_SERVER \
--docker-username=DOCKER_USER \
--docker-password=DOCKER_PASSWORD \
--docker-email=DOCKER_EMAIL

docker-registry:指定Secret的类型

myregistrykey: Secret名称

DOCKER_REGISTRY_SERVER:镜像仓库地址

DOCKER_USER:镜像仓库用户名,需要有拉取镜像的权限

DOCKER_PASSWORD:镜像仓库密码

DOCKER_EMAIL:邮箱信息,可以为空

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  namespace: test
spec:
  imagePullSecrets:
  - name: myregistry
  - name: xxxxxxx
  .......
  containers:
    - image: registry.cn-beijing.aliyuncs.com/dotbalo/nginx 
      name: nginx

5、使用Secret管理HTTPS证书

生成证书(测试)

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=test.com"

创建secret

kubectl -n default create secret tls nginx-test-tls --key=tls.key --cert=tls.crt

挂载证书

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: nginx-https-test
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - host: https-test.com
    http:
      paths:
      - backend:
          serviceName: nginx-svc
          servicePort: 80
  tls:
   - secretName: nginx-test-tls

三、ConfigMap&Secret使用SubPath解决挂载覆盖

挂载的时候,不覆盖其他文件

为了支持单一个pod多次使用同一个volume而设计,subpath翻译过来是子路径的意思,如果是数据卷挂载在容器,指的是存储卷目录的子路径,如果是配置项configMap/Secret,则指的是挂载在容器的子路径。

1、创建configMap

# cat conf-subpath.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: conf-subpath-zltest
  namespace: default
data:
  nginx.conf: hello      # key-value键值对
  example.property.2: world
  example.property.file: |-
    property.1=value-1
    property.2=value-2
    property.3=value-3

2、在Pod中使用configMap

# cat pod-conf-subpath.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    purpose: test-configmap-volume
  name: pod-conf-testvolume
spec:
  containers:
    - name: test-configmap-volume
      image: nginx
      volumeMounts:
        - name: config-volume
          mountPath: /etc/nginx/nginx.conf       # 以文件的形势挂载
          subPath: nginx.conf                    # 仅替换文件
  volumes:
    - name: config-volume
      configMap:
         name: conf-subpath-zltest      # 指定使用哪个CM
        
# kubectl create -f pod-conf-subpath.yaml 
# kubectl describe pod  pod-conf-testvolume 
Name:         pod-conf-testvolume
Namespace:    default
Priority:     0
Node:         k8s-master/192.168.126.129
Start Time:   Wed, 03 Jun 2020 11:46:36 +0800
Labels:       purpose=test-configmap-volume
Annotations:  cni.projectcalico.org/podIP: 10.122.235.249/32
              cni.projectcalico.org/podIPs: 10.122.235.249/32
Status:       Running
IP:           10.122.235.249
IPs:
  IP:  10.122.235.249
Containers:
  test-configmap-volume:
    Container ID:   docker://e2cf37cb24af32023eb5d22389545c3468104a4344c47363b5330addc40cb914
    Image:          nginx
    Image ID:       docker-pullable://nginx@sha256:883874c218a6c71640579ae54e6952398757ec65702f4c8ba7675655156fcca6
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Wed, 03 Jun 2020 11:46:53 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /etc/nginx/nginx.conf from config-volume (rw,path="nginx.conf")  
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-74s86 (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  config-volume:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      conf-subpath-zltest
    Optional:  false
  default-token-74s86:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-74s86
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:          <none>

在容器挂载路径验证下是否将configMap中nginx.conf挂载在容器中,且是否会覆盖掉原有的目录

root@pod-conf-testvolume:/# cd  /etc/nginx 
root@pod-conf-testvolume:/etc/nginx# ls
conf.d            fastcgi_params  koi-win    modules     scgi_params   win-utf
nginx.conf  koi-utf        mime.types    nginx.conf  uwsgi_params

从上可以看到nginx.conf已经挂载到容器中,且未对目录原有的文件进行覆盖

root@pod-conf-testvolume:/etc/nginx# cd nginx.conf 
bash: cd: nginx.conf: Not a directory
root@pod-conf-testvolume:/etc/nginx# cat nginx.conf 
helloroot@pod-conf-testvolume:/etc/nginx# 

从上可以验证configMap的subpath用法支持将configMap中的每对key-value以key名称作为文件名,value作为文件内容挂载到容器的目录中。

四、ConfigMap&Secret 热更新

ConfigMap 和 Secret 如果是以 subPath 的形式挂载的,那么 Pod 是不会感知到ConfigMap 和Secret 的更新。

如果 Pod 的变量来自于 ConfigMap 和 Secret 中定义的变量,那么 ConfigMap 和 Secret更新后,也不会更新Pod中的变量

Kubernetes中提供configmap,用来管理应用的配置,configmap具备热更新的能力,但只有通过目录挂载的configmap才具备热更新能力,其余通过环境变量,通过subPath挂载的文件都不能动态更新。

使用volume的方式挂载configmap之后,当configmap更新之后,变量的值会发生变化

kubectl replace -f

但是中间会存在一定的时间间隔,大约是10左右,这主要是因为kubelet 对pod的同步间隔是10秒,另外需要注意的是当使用subpath将configmap中的某个文件单独挂载到目录下,那这个文件是无法热更新的,这是configmap本身的逻辑决定的。

参考:https://blog.csdn.net/qingyafan/article/details/102848860

postStart: 容器启动之前执行的命令

preStrop: 容器停止之前执行的命令

热更新ConfigMap 和 Secert

kubectl create cm nginx-conf --from-file=nginx.conf --dry-run -oyaml | kubectl replace -f

五、ConfigMap&Secret使用限制

提前场景ConfigMap和Secret

引用Key必须存在

envFrom、valueFrom无法热更新环境变量

envFrom配置环境变量,如果key是无效的,它会忽略掉无效的key

ConfigMap和Secret必须要和Pod或者是引用它资源在同一个命名空间

subPath也是无法热更新的

ConfigMap和Secret最好不要太大

六、ConfigMap&Secret使用限制不可变

比如秒杀系统中,设置了某个值是100,只能100个人秒杀成功,这个值不可变

kubectl create cm test-immutable --from-file=/etc/kubernetes/admin.kubeconfig
kubectl edit cm test-immutable
# 在配置文件最后加上
immutable: true
# 再去修改 kubectl edit cm test-immutable, 发现无法修改
0

评论区