zoukankan      html  css  js  c++  java
  • k8s (六) ConfigMap 和 Secret:配置应用程序

    一、向容器传递命令行参数

    1.1. 在 Docker 中定义命令与参数

    容器中运行的完整指令由两部分组成:命令与参数。

    ENTRYPOINT 与 CMD:

    • ENTRYPOINT:定义容器启动时被调用的可执行程序。
    • CMD:指定传递给 ENTRYPOINT 的参数。

    尽管可以直接使用 CMD 指令指定镜像运行时想要执行的命令,正确的做法依旧是借助 ENTRYPOINT 指令,仅仅用 CMD 指定所需的默认参数。这样,镜像可以直接运行,无须添加任何参数:

    docker run <image>

    或者是添加一些参数,覆盖 Dockerfile 中任何由 CMD 指定的默认参数值:

    docker run <image> <arguments>

    shell 与 exec 形式的区别:

    • shell 形式:如 ENTRYPOINT node app.js
    • exec 形式:如 ENTRYPOINT [“node”, “app.js”]

    两者的区别在于指定的命令是否是在 shell 中被调用。exec 形式的 ENTRYPOINT 指令是直接运行 node 进程;shell 形式的指令主进程(PID 1)是 shell 进程而非 node 进程,node 进程于 shell 中启动。shell 进程往往是多余的,因此通常可以直接采用 exec 形式的 ENTRYPOINT 指令。

    实例:

    luksa/fortune:args 镜像中的运行脚本:

    #!/bin/bash
    trap "exit" SIGINT
    
    INTERVAL=$1
    echo Configured to generate new fortune every $INTERVAL seconds
    
    mkdir -p /var/htdocs
    
    while :
    do
      echo $(date) Writing fortune to /var/htdocs/index.html
      /usr/games/fortune > /var/htdocs/index.html
      sleep $INTERVAL
    done
    

    luksa/fortune:args 的 Dockerfile 内容:

    FROM ubuntu:latest
    
    RUN apt-get update ; apt-get -y install fortune
    ADD fortuneloop.sh /bin/fortuneloop.sh
    
    ENTRYPOINT ["/bin/fortuneloop.sh"]
    CMD ["10"]
    

    测试:

    docker run -it luksa/fortune:args # 默认的 10 秒钟
    docker run -it luksa/fortune:args 15 # 传参修改为 15 秒钟
    

    1.2. 在 Kubernetes 中覆盖命令和参数

    在 Kubernetes 中定义容器时,镜像的 ENTRYPOINT 和 CMD 均可以被覆盖,仅需要在容器定义中设置 command 和 args 的值:

    kind: Pod
    spec:
      containers:
      - image: some/image
        command: ["/bin/command"] # 对应 ENTRYPOINT
        args: ["arg1", "arg2", "arg3"] # 对应 CMD,多参数值可以使用 "-" 数组的形式(字符串值无须用引号标记,数值需要)
    

    注意:command 和 args 字段在 pod 创建后无法被修改。绝大多数情况下,只需要设置自定义参数。命令一般很少被覆盖,除非针对一些未定义 ENTRYPOINT 的通用镜像。

    二、为容器设置环境变量

    在容器定义中指定环境变量:

    apiVersion: v1
    kind: Pod
    metadata:
      name: fortune-env
    spec:
      containers:
      - image: luksa/fortune:env
        env:
        - name: INTERVAL
          value: "30"
    

    在环境变量值中引用其他环境变量:

        env:
        - name: FIRST_VAR
          value: "foo"
        - name: SECOND_VAR
          value: "$(FIRST_VAR)bar"
    

    三、利用 ConfigMap 解耦配置

    Kubernetes 允许将配置选项分离到单独的资源对象 ConfigMap 中,本质上就是一个键/值对映射,值可以是短字面量,也可以是完整的配置文件。应用无须直接读取 ConfigMap,甚至根本不需要知道其是否存在。映射的内容通过环境变量或者卷文件的形式传递给容器,而并非直接传递给容器。

    3.1. 创建 ConfigMap

    3.1.1. 使用指令创建 ConfigMap

    kubectl create configmap fortune-config --from-literal=sleep-interval=25

    创建了一个叫 fortune-config 的 ConfigMap,只包含一个条目。也可以添加多个条目:

    kubectl create configmap myconfigmap --from-literal=foo=bar --from-literal=bar=baz --from-literal=one=two

    注意:ConfigMap 中的键名必须是一个合法的 DNS 子域,仅包含数字字母、破折号、下划线以及圆点。

    查看创建的 ConfigMap 的 YAML 格式的定义描述:

    kubectl get configmap fortune-config -o yaml

    3.1.2. 从文件内容创建 ConfigMap 目录

    kubectl create configmap my-config --from-file=config-file.conf

    默认使用文件名作为键名,也可以手动指定键名:

    kubectl create configmap my-config --from-file=customkey=config file.conf

    多次使用 —from-file 参数可增加多个文件条目。

    3.1.3. 从文件夹创建 ConfigMap

    kubectl create configmap my -config --from-file=/path/to/dir

    为文件夹中的每个文件单独创建条目,仅限于那些文件名可作为合法 ConfigMap 键名的文件

    3.1.4. 合并不同选项

    kubectl create configmap my -config
      --from-file=foo.json # 单独的文件
      --from-file=bar=foobar.conf # 自定义键名条目下的文件
      --from-file=config-opts/ # 完整的文件夹
      --from-file=some=thing # 字面量
    

    3.2. 给容器传递 ConfigMap 条目作为环境变量

    apiVersion: v1
    kind: Pod
    metadata:
      name: fortune-env-from-configmap
    spec:
      containers:
      - image: luksa/fortune:env
        env:
        - name: INTERVAL # 环境变量名为 INTERVAL
          valueFrom: 
            configMapKeyRef: # ConfigMap
              name: fortune-config # ConfigMap 名称
              key: sleep-interval # ConfigMap 对应键的值
    ... ...
    

    在 pod 中引用不存在的 ConfigMap,如果没有设置 configMapKeyRef.optional: true 则容器会启动失败,如果之后创建了这个缺失的 ConfigMap,失败容器会自动启动,无须重新创建 pod

    3.3. 一次性传递 ConfigMap 的所有条目作为环境变量

    spec:
      containers:
      - image: some-image
        envFrom:
        - prefix: CONFIG_ # 所有环境变量的前缀,可以不设置
          configMapRef: 
            name: my-config-map
    ... ...
    

    3.4. 传递 ConfigMap 条目作为命令行参数

    apiVersion: v1
    kind: Pod
    metadata:
      name: fortune-args-from-configmap
    spec:
      containers:
      - image: luksa/fortune:args
        env:
        - name: INTERVAL
          valueFrom: 
            configMapKeyRef:
              name: fortune-config
              key: sleep-interval
        args: ["$(INTERVAL)"] # 在参数设置中引用环境变量
    ... ...
    

    3.5. 使用 ConfigMap 卷将条目暴露为文件

    3.5.1. 创建 ConfigMap

    新建文件夹 configmap-files 并将 my-nginx-config.conf 和 sleep-interval 放置在文件夹下:

    # my-nginx-config.conf
    
    server {
        listen              80;
        server_name         www.kubia-example.com;
    
        gzip on;
        gzip_types text/plain application/xml;
    
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
    }
    
    # sleep-interval
    
    25
    

    先删除之前创建的 ConfigMap:

    kubectl delete configmap fortune-config

    新建 ConfigMap:

    kubectl create configmap fortune-config --from-file=configmap-files

    查看:

    kubectl get configmap fortune-config -o yaml

    3.5.2. 在卷内使用 ConfigMap 的条目

    # fortune-pod-configmap-volume.yaml
    # 详见:https://github.com/luksa/kubernetes-in-action/blob/master/Chapter07/fortune-pod-configmap-volume.yaml
    
    apiVersion: v1
    kind: Pod
    metadata:
      name: fortune-configmap-volume
    spec:
      containers:
      ... ...
      - image: nginx:alpine
        name: web-server
        volumeMounts:
        ... ...
        - name: config
          mountPath: /etc/nginx/conf.d # 挂载 configMap 卷至这个位置
          readOnly: true
        ... ...
      volumes:
      ... ...
      - name: config
        configMap:
          name: fortune-config # 卷引用 fortune-config
    

    创建:

    kubectl create -f fortune-pod-configmap-volume.yaml

    验证:

    kubectl port-forward fortune-configmap-volume 8080:80 &

    curl -H "Accept-Encoding: gzip" -I localhost:8080

    输出:

    ... ...
    Content-Encoding: gzip
    

    注意:挂载某一文件夹会隐藏该文件夹中已存在的文件

    3.5.3. 卷内暴露指定的 ConfigMap 条目

      volumes:
      - name: config
        configMap:
          name: fortune-config
          items: # 选择包含在卷中的条目
          - key: my-nginx-config.conf # 该键对应的条目被包含
            path: gzip.conf # 条目的值被存储在该文件中
    `
    

    3.5.4. ConfigMap 独立条目作为文件被挂载且不隐藏文件夹中的其他文件

    spec:
      containers:
      - image: some/image
        volumeMounts:
        - name: myvolume
          mountPath: /etc/someconfig.conf # 挂载至某一文件而不是文件夹
          subPath: myconfig.conf #仅挂载指定的条目 myconfig.conf 并非完整的卷
    

    3.5.5. 为 configMap 卷中的文件设置权限

    configMap 卷中所有文件的权限默认被设置为644 (-rw-r-r—)。可以通过卷规格定义中的 defaultMode 属性改变默认权限:

      volumes:
      - name: html
        emptyDir: {}
      - name: config
        configMap:
          name: fortune-config
          defaultMode: 0660 # 设置所有文件的权限为 -rw-rw------
    

    3.6. 更新应用配置且不重启应用程序

    使用环境变量或者命令行参数作为配置源的弊端在于无法在进程运行时更新配置。将 ConfigMap 暴露为卷可以达到配置热更新的效果,无须重新创建 pod 或者重启容器。ConfigMap 被更新之后,卷中引用它的所有文件也会相应更新,进程发现文件被改变之后进行重载。Kubernetes 同样支待文件更新之后手动通知容器。

    修改 ConfigMap:

    kubectl edit configmap fortune-config

    将 gzip on 改为 gzip off,ConfigMap 被更新不久之后会自动更新卷中的对应文件,查看:

    kubectl exec fortune-configmap-volume -c web-server -- cat /etc/nginx/conf.d/my-nginx-config.conf

    通知 Nginx 重载配置:

    kubectl exec fortune-configmap-volume -c web-server -- nginx -s reload

    四、使用 Secret 给容器传递敏感数据

    Secret 的使用方法也与ConfigMap 相同,可以:

    • 将 Secret 条目作为环境变量传递给容器
    • 将 Secret 条目暴露为卷中的文件

    Secret 只会存储在节点的内存中,永不写入物理存储,这样从节点上删除 Secret 时就不需要擦除磁盘

    创建 Secret:

    kubectl create secret generic fortune-https --from-file=https.key --from-file=https.cert --from-file=foo

    https.key, https.cert, foo 文件内容见 链接

    查看:

    kubectl get secret fortune-https -o yaml

    Secret 条目的内容会被以 Base64 格式编码,这种区别导致在处理 YAML 和 JSON 格式的 Secret 时会稍许有些麻烦,可以通过 stringData 字段设置条目的纯文本值。

    通过 secret 卷将 Secret 暴露给容器之后,Secret 条目的值会被解码并以真实形式(纯文本或二进制)写入对应的文件。通过环境变量暴露 Secret 条目亦是如此。在这两种情况下,应用程序均无须主动解码,可直接读取文件内容或者查找环境变量。

    修改 fortune-config ConfigMap 以开启 HTTPS:

    kubectl edit configmap fortune-config

    ... ...
    
    server {
        listen              80;
        listen              443 ssl;
        server_name         www.kubia-example.com;
        ssl_certificate     certs/https.cert; # /etc/nginx 的相对位置
        ssl_certificate_key certs/https.key; # /etc/nginx 的相对位置
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers         HIGH:!aNULL:!MD5;    
    ... ...
    

    挂载 fortune-secret 至 pod:

    # fortune-pod-https.yaml
    
    apiVersion: v1
    kind: Pod
    metadata:
      name: fortune-https
    spec:
      containers:
      - image: luksa/fortune:env
        name: html-generator
        env:
        - name: INTERVAL
          valueFrom: 
            configMapKeyRef:
              name: fortune-config
              key: sleep-interval
        volumeMounts:
        - name: html
          mountPath: /var/htdocs
      - image: nginx:alpine
        name: web-server
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html
          readOnly: true
        - name: config
          mountPath: /etc/nginx/conf.d
          readOnly: true
        - name: certs
          mountPath: /etc/nginx/certs/ # 配置 Nginx 从 /etc/nginx/certs 中读取证书和密钥文件
          readOnly: true
        ports:
        - containerPort: 80
        - containerPort: 443
      volumes:
      - name: html
        emptyDir: {}
      - name: config
        configMap:
          name: fortune-config
          items:
          - key: my-nginx-config.conf
            path: https.conf
      - name: certs
        secret:
          secretName: fortune-https # secret 卷
    

    kubectl create -f fortune-pod-https.yaml

    测试:

    kubectl port-forward fortune-https 8443:443 &

    curl https://localhost:8443 -k

  • 相关阅读:
    教你怎么做游戏运营数据分析
    经验|数据分析告诉我们的四个经验教训
    hdu 2074 叠筐 好有意思的绘图题
    asp 之 让实体中字段类型为DateTime的字段仅仅显示日期不显示时间
    将字符串中不同字符的个数打印出来
    Cocos2d-x 3.0final 终结者系列教程08-画图节点Node中的锚点和坐标系
    mysql数据库sql优化——子查询优化
    jQuery ajax 动态append创建表格出现不兼容ie8
    JavaScript关于闭包
    PatternSyntaxException:Syntax error in regexp pattern
  • 原文地址:https://www.cnblogs.com/victorbu/p/14324205.html
Copyright © 2011-2022 走看看