zoukankan      html  css  js  c++  java
  • Kubernetes学习笔记(六):使用ConfigMap和Secret配置应用程序

    概述

    本文的核心是:如何处理应用程序的数据配置。
    配置应用程序可以使用以下几种途径:

    • 向容器传递命令行参数
    • 为每个容器配置环境变量
    • 通过特殊的卷将配置文件挂载到容器中

    向容器传递命令行参数

    在Kubernetes中定义容器时,镜像的ENTRYPOINT和CMD都可以被覆盖(但是在Docker中,镜像的ENTRYPOINT是不能覆盖的)。仅需在容器定义中设置command和args的值。

    构建一个镜像

    loopechodate.sh:接收一个时间间隔的参数,追加输出当前时间到 /tmp/a.txt

    #! /bin/sh
    trap "exit" SIGINT
    echo "interval is : $1"
    while :
    do
    	echo -e "$(date)" >> /tmp/a.txt
    	sleep $1
    done
    

    Dockerfile

    FROM alpine
    COPY loopechodate.sh /bin/
    ENTRYPOINT ["/bin/loopechodate.sh"]
    CMD ["5"]
    

    构建、推送

    -> [root@kube0.vm] [~] docker build -t registry.cn-hangzhou.aliyuncs.com/orzi/loopechodate .
    -> [root@kube0.vm] [~] docker push registry.cn-hangzhou.aliyuncs.com/orzi/loopechodate
    

    运行Pod

    # cat config-cli.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: config-cli
    spec:
      containers:
        - name: config-cli
          image: registry.cn-hangzhou.aliyuncs.com/orzi/loopechodate
          args: ["2"]	# 间隔时间2s
    

    创建这个pod,然后查看一下logs

    -> [root@kube0.vm] [~] k create -f config-cli.yaml
    pod/config-cli created
    -> [root@kube0.vm] [~] k exec -it config-cli cat /tmp/a.txt
    Sun May 24 15:49:37 UTC 2020
    Sun May 24 15:49:39 UTC 2020
    

    为容器设置环境变量

    Kubernetes中通过容器的env属性定义环境变量,采用$(VAR)语法在环境变量值中引用其他变量。

    定义了两个环境变量FIRST_VAR,和引用了FIRST_VAR的SECOND_VAR。

    # config-env.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: config-env
    spec:
      containers:
        - name: config-env
          image: nginx:alpine
          env:
          - name: FIRST_VAR
            value: "Hello"
          - name: SECOND_VAR
            value: "$(FIRST_VAR) World!"
    

    创建查看

    -> [root@kube0.vm] [~] k create -f config-env.yaml
    pod/config-env created
    
    -> [root@kube0.vm] [~] k exec config-env env
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    HOSTNAME=config-env
    FIRST_VAR=Hello
    SECOND_VAR=Hello World!
    .......
    

    ConfigMap

    ConfigMap本质上是一个键值对,值可以使短字面量,也可以是文件

    创建ConfigMap

    kubectl create configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run] [options]

    kubectl create命令支持从字面量(--from-literal),文件、目录(--from-file)、以及环境变量文件(--from-env-file)创建。而且不同选项可以合并,但是--from-env-file不能与--from-literal和--from-file一起指定。

    下面是使用字面量、文件、目录合并创建。

    -> [root@kube0.vm] [~] k create configmap mycm --from-literal=interval=3 --from-file=Dockerfile --from-file=/root/configdir
    configmap/mycm created
    
    -> [root@kube0.vm] [~] k describe cm mycm
    Name:         mycm
    Namespace:    default
    Labels:       <none>
    Annotations:  <none>
    
    Data
    ====
    Dockerfile:
    ----
    FROM alpine
    COPY loopechodate.sh /bin/
    ENTRYPOINT ["/bin/loopechodate.sh"]
    CMD ["5"]
    
    a.txt:
    ----
    this is configdir/a.txt
    
    b.txt:
    ----
    this is configdir/b.txt
    
    interval:
    ----
    3
    Events:  <none>
    

    使用环境变量文件创建

    -> [root@kube0.vm] [~] echo -e "env1=1111
    env2=2222" | tee test.env
    env1=1111
    env2=2222
    
    -> [root@kube0.vm] [~] k create cm envcm --from-env-file=test.env
    configmap/envcm created
    
    -> [root@kube0.vm] [~] k describe cm envcm
    Name:         envcm
    Namespace:    default
    Labels:       <none>
    Annotations:  <none>
    
    Data
    ====
    env1:
    ----
    1111
    env2:
    ----
    2222
    Events:  <none>
    

    传递ConfigMap条目作为环境变量

    定义一个Pod,引用了mycm中的两个key。

    # config-env-cm.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: config-env-cm
    spec:
      containers:
        - name: config-env-cm
          image: nginx:alpine
          env:
          - name: INTERVAL
            valueFrom:
              configMapKeyRef:	# 引用configMap中的内容
                name: mycm		# configMap的名字
                key: interval	# 引用哪个键
          - name: ATXT
            valueFrom:
              configMapKeyRef:
                name: mycm
                key: a.txt
    

    创建查看

    -> [root@kube0.vm] [~] k create -f config-env-cm.yaml
    pod/config-env-cm created
    
    -> [root@kube0.vm] [~] k exec config-env-cm env
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    HOSTNAME=config-env-cm
    INTERVAL=3
    ATXT=this is configdir/a.txt
    ....
    

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

    # config-env-cmall.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: config-env-cmall
    spec:
      containers:
        - name: config-env-cmall
          image: nginx:alpine
          envFrom:
          - prefix: CONFIG_
            configMapRef:
              name: mycm
    

    创建查看

    -> [root@kube0.vm] [~] k create -f config-env-cmall.yaml
    pod/config-env-cmall created
    
    -> [root@kube0.vm] [~] k exec config-env-cmall env
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    HOSTNAME=config-env-cmall
    CONFIG_interval=3
    CONFIG_Dockerfile=FROM alpine
    COPY loopechodate.sh /bin/
    ENTRYPOINT ["/bin/loopechodate.sh"]
    CMD ["5"]
    
    CONFIG_a.txt=this is configdir/a.txt
    
    CONFIG_b.txt=this is configdir/b.txt
    ........
    

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

    containers.args无法直接引用ConfigMap,但是可以通过$(ENV_VAR_NAME)引用环境变量,间接引用ConfigMap。

    # config-cli-cm.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: config-cli-cm
    spec:
      containers:
        - name: config-cli-cm
          image: registry.cn-hangzhou.aliyuncs.com/orzi/loopechodate
          env:
          - name: INTERVAL
            valueFrom:
              configMapKeyRef:
                name: mycm
                key: interval
          args: ["$(INTERVAL)"]
    

    创建查看

    -> [root@kube0.vm] [~] k create -f config-cli-cm.yaml
    pod/config-cli-cm created
    
    -> [root@kube0.vm] [~] k logs config-cli-cm
    interval is : 3
    
    -> [root@kube0.vm] [~] k exec config-cli-cm cat /tmp/a.txt
    Mon May 25 05:11:14 UTC 2020
    Mon May 25 05:11:17 UTC 2020
    Mon May 25 05:11:20 UTC 2020
    

    将ConfigMap条目暴露为卷

    环境变量和命令行参数作为配置值通常适用于变量值较短的场景。如果想暴露ConfigMap中配置文件,可以将ConfigMap或者其条目通过卷的形式挂载到容器。

    # config-volume-cm.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: config-volume-cm
    spec:
      containers:
        - name: config-volume-cm
          image: nginx:alpine
          volumeMounts:
          - name: config
            mountPath: /tmp/mycm
            readOnly: true
      volumes:
      - name: config
        configMap:
          name: mycm
    

    创建查看

    -> [root@kube0.vm] [~] k create -f config-volume-cm.yaml
    pod/config-volume-cm created
    
    -> [root@kube0.vm] [~] k exec config-volume-cm ls /tmp/mycm
    Dockerfile
    a.txt
    b.txt
    interval
    

    如果只想暴露指定的条目,可以指定volumes.configMap.items

      volumes:
      - name: config
        configMap:
          name: mycm
          items:
          - key: interval
            path: interval2
    

    输出结果是:

    -> [root@kube0.vm] [~] k exec config-volume-cm ls /tmp/mycm
    interval2
    

    configMap.defaultMode设置访问权限

    挂载文件夹会隐藏该文件夹中已存在的文件,挂载ConfigMap的单独条目不会隐藏其他文件

    Secret

    Secret与ConfigMap一样都是键值对,也可以作为环境变量传递给容器,条目也能暴露称为卷中的文件。但是为了安全起见,请始终使用Secret卷暴露Secret。Secret只会存储在内存中,永不写入物理存储。Secret条目的内容会被进行Base64编码。

    默认令牌

    每个pod默认都会挂载一个Secret,该Secret包含ca.crt、namespace、token,包含了从Pod内部安全访问Kubernetes Api服务器所需的全部信息。
    先随便找一个pod查看。

    -> [root@kube0.vm] [~] k describe pod config-volume-cm
    Name:         config-volume-cm
    Namespace:    default
    ......
        Mounts:
          /tmp/mycm from config (ro)
          /var/run/secrets/kubernetes.io/serviceaccount from default-token-5g447 (ro)
    ......
    Volumes:
    ......
      default-token-5g447:
        Type:        Secret (a volume populated by a Secret)
        SecretName:  default-token-5g447
        Optional:    false
    ......
    

    再查看一下详情

    -> [root@kube0.vm] [~] k describe secrets default-token-5g447
    Name:         default-token-5g447
    Namespace:    default
    Labels:       <none>
    Annotations:  kubernetes.io/service-account.name: default
                  kubernetes.io/service-account.uid: bd92a729-ed0a-491d-b600-0f86824ad588
    
    Type:  kubernetes.io/service-account-token
    
    Data
    ====
    ca.crt:     1025 bytes
    namespace:  7 bytes
    token:      eyJhbGciOiJSUzI1....
    

    使nginx支持https

    创建私钥和证书

    -> [root@kube0.vm] [~/cert] openssl genrsa -o https.key 2048
    -> [root@kube0.vm] [~/cert] openssl req -new -x509 -key https.key -out https.cert -days 3650 -subj /CN=www.mysecret.com
    

    创建Secret

    创建一个类型为generic的Secret,其他两个类型是docker-registry、tls。

    -> [root@kube0.vm] [~/cert] echo bar > foo # 后面会用到
    
    -> [root@kube0.vm] [~/cert] k create secret generic mysecret --from-file=./
    secret/mysecret created
    

    将ssl.conf放入ConfigMap中

    # ssl.conf
    server {
        listen              80;
        listen              443 ssl;
        server_name         www.mysecret.com;
        ssl_certificate     certs/https.cert;
        ssl_certificate_key certs/https.key;
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers         HIGH:!aNULL:!MD5;
    
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
    }
    
    -> [root@kube0.vm] [~] k create configmap sslcm --from-file=ssl.conf
    configmap/sslcm created
    

    创建查看

    先看一下描述文件

    # https-nginx.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: https-nginx
    spec:
      containers:
        - name: https-nginx
          image: nginx:alpine
          env:
            - name: FOO
              valueFrom:
                secretKeyRef:
                  name: mysecret
                  key: foo
          volumeMounts:
          - name: sslcm
            mountPath: /etc/nginx/conf.d/
            readOnly: true
          - name: mysecret
            mountPath: /etc/nginx/certs/
            readOnly: true
          ports:
          - containerPort: 80
          - containerPort: 443
      volumes:
      - name: sslcm
        configMap:
          name: sslcm
          items:
          - key: ssl.conf
            path: https.conf
      - name: mysecret
        secret:
          secretName: mysecret
    

    创建、设置端口转发

    -> [root@kube0.vm] [~] k create -f https-nginx.yaml
    pod/https-nginx created
    
    -> [root@kube0.vm] [~] k port-forward https-nginx 443:443
    Forwarding from 127.0.0.1:443 -> 443
    

    新开窗口,发送请求

    -> [root@kube0.vm] [~] curl -k https://localhost
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    .....
    

    查看Secret通过环境变量暴露的条目

    -> [root@kube0.vm] [~] k exec https-nginx env
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    HOSTNAME=https-nginx
    FOO=bar
    .......
    

    使用私有的镜像仓库

    使用方法:创建一个docker-registry类型的secret,然后

    创建一个docker-registry类型的secret。 --docker-server 用于指定仓库服务的地址。

    k create secret docker-registry dockerregsecret --docker-username=zhangsan --docker-password=123 --docker-email=zhangsan@163.com
    

    在Pod中的containers.imagePullSecrets.name中引用。

    apiVersion: v1
    kind: Pod
    metadata:
      name: private-pod
    spec:
      imagePullSecrets:
      - name: dockerregsecret
      containers:
      - image: username/private:tag
        name: main
    

    StringData与二进制数据

    采用Base64编码,使Secret也能存储二进制数据,而纯文本值可以在secret.StringData中定义,但StringData字段是只写的,kubectl get -o yaml查看时会被Base64编码显示在data下。

    注意事项

    • 在Kubernetes中定义容器时,镜像的ENTRYPOINT和CMD都可以被覆盖。但是在Docker中,镜像的ENTRYPOINT是不能覆盖的。
    • 可以将configMapKeyRef.optional设置为true,这样即使ConfigMap不存在,容器也能启动。

    小结

    • 对于环境变量:使用valueFrom.configMapKeyRef引用一个ConfigMap条目;使用envFrom.configMapRef引用全部,envFrom.prefix设置前缀。
    • 对于命令行参数:containers.args无法直接引用ConfigMap,但是可以通过$(ENV_VAR_NAME)引用环境变量,间接引用了ConfigMap。
    • 挂载文件夹会隐藏该文件夹中已存在的文件,挂载ConfigMap的单独条目不会隐藏其他文件
    • 将ConfigMap暴露为卷可以达到热更新的效果。
    • 每个pod默认都会挂载一个Secret,该Secret包含ca.crt、namespace、token,包含了从Pod内部安全访问Kubernetes Api服务器所需的全部信息。
    • 采用Base64编码,使Secret也能存储二进制数据,而纯文本值可以在secret.StringData中定义,但StringData字段是只写的,kubectl get -o yaml查看时会被Base64编码显示在data下。
  • 相关阅读:
    Hia~hia~
    细节与销售
    敛财术
    酒井法子
    买了新手机NOKIA E71
    观《拉贝日记》
    居然不配套
    2009上海最新“四金”及个人所得税计算(器)
    有好听点的新歌么?
    我家乌龟终于下蛋了!
  • 原文地址:https://www.cnblogs.com/flhs/p/12952683.html
Copyright © 2011-2022 走看看