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的方式挂在到指定的目录下(可以挂载单个文件),覆盖原有文件;

猜你喜欢

转载自blog.csdn.net/u010304195/article/details/106937852