zoukankan      html  css  js  c++  java
  • kubernetes中的Project Volume


    这kubernetes中,这类Volume不是为了存放数据,也不是用来做数据交换,而是为容器提供预先定义好的数据。所以从容器角度来看,这类Volume就像是被投射进容器一样。


    到目前为止,kubernetes支持4种这类Volume:
    (1)、Secret
    (2)、ConfigMap
    (3)、DownloadAPI
    (4)、ServiceAccountToken

    3.1.1、Secret

    Secret的作用是把Pod想要访问的加密数据存放到Etcd中,然后可以在Pod容器中通过挂载的方式访问Secret里保存的信息。


    一旦Secret被创建,就可以通过下面三种方式使用它:
    (1)在创建Pod时,通过为Pod指定Service Account来自动使用该Secret。
    (2)通过挂载该Secret到Pod来使用它。
    (3)在Docker镜像下载时使用,通过指定Pod的spc.ImagePullSecrets来引用它。


    例如,我们定义下面这个Pod:

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-volume-test
      labels:
        app: pod-volume-test
    spec:
      containers:
      - name: volume-secret-test
        image: busybox
        command:
        - "/bin/sh"
        - "-c"
        - "sleep 3600"
        volumeMounts:
        - name: my-secret
          mountPath: "/project-volume"
          readOnly: true
      volumes:
      - name: my-secret
        projected:
          sources:
          - secret:
              name: my-secret-volume
    


    从上面的yaml文件中可以看到定义了一个简单的容器volume-secret-test,它里面挂载了一个my-secret的volume,这个volume是project类型,而这个数据来源是叫user和password得secret对象。


    这里的secret对象,可以直接通过文件生成,也可以通过定义YAML文件的方式来创建。
    (1)、通过文件生成

    cat ./username.txt
    admin
    $ cat ./password.txt
    c1oudc0w!
    
    $ kubectl create secret generic user --from-file=./username.txt
    $ kubectl create secret generic pass --from-file=./password.txt
    


    (2)、通过YAML方式生成

    
    apiVersion: v1
    kind: Secret
    metadata:
      name: my-secret-volume
    type: Opaque
    data:
      user: cm9vdA==
      password: UEBzc1cwcmQ=
    


    其中user和password的值是需要经过base64转码,如下:

    [root@master ~]# echo -n "root" | base64 
    cm9vdA==
    [root@master ~]# echo -n "P@ssW0rd" | base64 
    UEBzc1cwcmQ=
    


    这个转码未经过加密,在实际生产中是需要添加一个secret的插件,用来做加密操作。
    然后我们来创建这个两个pod:

    # kubectl apply -f creat-volume-secret.yaml
    # kubectl apply -f pod-volume-test.yaml
    


    然后通过如下命令查看创建的secret:
    image.png


    然后通过kubectl exec进去容器查看是否挂载上:

    [root@master volume]# kubectl exec -it pod-volume-test -- /bin/sh
    / # cd project-volume/
    /project-volume # ls
    password  user
    /project-volume # cat password 
    P@ssW0rd
    /project-volume # cat user 
    root
    


    通过这种方式挂载的Secret,如果某个数据被更新,这些Volume里的内容不会被更新,如果要更新,我们需要重新apply一下或者删除重建。


    比如,我们修改password的值:

    apiVersion: v1
    kind: Secret
    metadata:
      name: my-secret-volume
    type: Opaque
    data:
      user: cm9vdA==
      password: cGFzc3dvcmQxMjM0NTY=
    


    然后重新执行一下:

    # kubectl apply -f creat-volume-secret.yaml
    


    然后我们进入容器查看password变化(大概等了2分钟):

    [root@master volume]# kubectl exec -it pod-volume-test -- /bin/sh
    / # cd project-volume/
    /project-volume # cat password 
    password123456
    

    说明:
    每个单独的Secret大小不能超过1MB,Kubernetes不鼓励创建大的Secret,因为如果使用大的Secret,则将大量占用API Server和kubelet的内存。当然,创建许多小的Secret也能耗尽APIServer和kubelet的内存。


    综上,我们可以通过Secret保管其他系统的敏感信息(比如数据库的用户名和密码),并以Mount的方式将Secret挂载到Container中,然后通过访问目录中文件的方式获取该敏感信息。当Pod被API Server创建时,API Server不会校验该Pod引用的Secret是否存在。一旦这个Pod被调度,则kubelet将试着获取Secret的值。如果Secret不存在或暂时无法连接到API Server,则kubelet按一定的时间间隔定期重试获取该Secret,并发送一个Event来解释Pod没有启动的原因。一旦Secret被Pod获取,则kubelet将创建并挂载包含Secret的Volume。只有所有Volume都挂载成功,Pod中的Container才会被启动。在kubelet启动Pod中的Container后,Container中和Secret相关的Volume将不会被改变,即使Secret本身被修改。为了使用更新后的Secret,必须删除旧Pod,并重新创建一个新Pod。

    3.1.2、ConfigMap

    ConfigMap和Serect类似,不同之处在于ConfigMap保存的数据信息是不需要加密的,比如一些应用的配置信息,其他的用法和Secret一样。同样,我们可以使用两种方式来创建ConfigMap:

    • 通过命令行方式,也就是kubectl create configmap;
    • 通过YAML文件方式;

    (1)、通过命令方式创建

    如果我们不知道ConfigMap的命令方式,可以使用kubectl create configmap -h查看使用方法,如下:

    Examples:
      # Create a new configmap named my-config based on folder bar
      kubectl create configmap my-config --from-file=path/to/bar
      
      # Create a new configmap named my-config with specified keys instead of file basenames on disk
      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
      
      # Create a new configmap named my-config from the key=value pairs in the file
      kubectl create configmap my-config --from-file=path/to/bar
      
      # Create a new configmap named my-config from an env file
      kubectl create configmap my-config --from-env-file=path/to/bar.env
    


    从上面可以看出,创建ConfigMap可以从给定一个目录来创建。例如,我们定义了如下一些配置文件:

    [root@master volume]# cd configmap-daemo/
    [root@master configmap-daemo]# ll
    total 8
    -rw-r--r-- 1 root root 25 Sep  6 17:07 mysqld.conf
    -rw-r--r-- 1 root root 25 Sep  6 17:07 redis.conf
    [root@master configmap-daemo]# cat mysqld.conf 
    host=127.0.0.1
    port=3306
    [root@master configmap-daemo]# cat redis.conf 
    host=127.0.0.1
    port=6379
    


    然后使用一下命令来进行创建:

    # kubectl create configmap my-configmap --from-file=configmap-daemo/
    


    然后通过一下命令查看创建完的configmap:

    [root@master volume]# kubectl get configmap
    NAME           DATA   AGE
    my-configmap   2      19s
    [root@master volume]# kubectl describe configmap my-configmap
    Name:         my-configmap
    Namespace:    default
    Labels:       <none>
    Annotations:  <none>
    
    Data
    ====
    mysqld.conf:
    ----
    host=127.0.0.1
    port=3306
    
    redis.conf:
    ----
    host=127.0.0.1
    port=6379
    
    Events:  <none>
    


    我们可以看到两个key对应的是文件的名字,value对应的是文件的内容。如果要看键值的话可以通过如下命令查看:

    [root@master volume]# kubectl get configmap my-configmap -o yaml
    apiVersion: v1
    data:
      mysqld.conf: |
        host=127.0.0.1
        port=3306
      redis.conf: |
        host=127.0.0.1
        port=6379
    kind: ConfigMap
    metadata:
      creationTimestamp: "2019-09-06T09:10:49Z"
      name: my-configmap
      namespace: default
      resourceVersion: "252070"
      selfLink: /api/v1/namespaces/default/configmaps/my-configmap
      uid: cd8d3752-c1c4-48e0-b523-bafa20f1ba1f
    


    当然,我们还可以通过文件来创建一个configmap,比如我们定义一个如下的配置文件:

    [root@master configmap-daemo]# cat nginx.conf 
    user  nobody;
    worker_processes  1;
    error_log  logs/error.log;
    error_log  logs/error.log  notice;
    error_log  logs/error.log  info;
    pid        logs/nginx.pid;
    events {
        worker_connections  1024;
    }
    http {
        include       mime.types;
        default_type  application/octet-stream;
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';
        access_log  logs/access.log  main;
        sendfile        on;
        tcp_nopush     on;
        keepalive_timeout  65;
        gzip  on;
        server {
            listen       80;
            server_name  localhost;
            location / {
                root   html;
                index  index.html index.htm;
            }
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
        }
    }
    


    然后启动如下命令创建一个nginx的configmap:

    # kubectl create configmap nginx-configmap --from-file=nginx.conf
    


    然后查看创建后的信息:

    [root@master configmap-daemo]# kubectl get configmap nginx-configmap -o yaml
    apiVersion: v1
    data:
      nginx.conf: |
        user  nobody;
        worker_processes  1;
        error_log  logs/error.log;
        error_log  logs/error.log  notice;
        error_log  logs/error.log  info;
        pid        logs/nginx.pid;
        events {
            worker_connections  1024;
        }
        http {
            include       mime.types;
            default_type  application/octet-stream;
            log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                              '$status $body_bytes_sent "$http_referer" '
                              '"$http_user_agent" "$http_x_forwarded_for"';
            access_log  logs/access.log  main;
            sendfile        on;
            tcp_nopush     on;
            keepalive_timeout  65;
            gzip  on;
            server {
                listen       80;
                server_name  localhost;
                location / {
                    root   html;
                    index  index.html index.htm;
                }
                error_page   500 502 503 504  /50x.html;
                location = /50x.html {
                    root   html;
                }
            }
        }
    kind: ConfigMap
    metadata:
      creationTimestamp: "2019-09-06T09:25:42Z"
      name: nginx-configmap
      namespace: default
      resourceVersion: "253356"
      selfLink: /api/v1/namespaces/default/configmaps/nginx-configmap
      uid: c4804bb0-dec3-461e-8fc4-0b0bb516815c
    


    注:在一条命令中--from-file可以指定多次。
    另外,通过帮助文档我们可以看到我们还可以直接使用字符串进行创建,通过--from-literal参数传递配置信息,同样的,这个参数可以使用多次,格式如下:

    [root@master configmap-daemo]# kubectl create configmap my-cm-daemo --from-literal=db.host=localhost --from-literal=db.port=3306
    configmap/my-cm-daemo created
    [root@master configmap-daemo]# kubectl get configmap my-cm-daemo -o yaml
    apiVersion: v1
    data:
      db.host: localhosy
      db.port: "3306"
    kind: ConfigMap
    metadata:
      creationTimestamp: "2019-09-06T09:29:49Z"
      name: my-cm-daemo
      namespace: default
      resourceVersion: "253713"
      selfLink: /api/v1/namespaces/default/configmaps/my-cm-daemo
      uid: ee8823e7-f2b3-46bf-ba6c-2f32303622c4
    

    (2)、通过YAML文件创建

    通过YAML文件创建就比较简单,我们可以参考上面输出的yaml信息,比如定义如下一个YAML文件:

    [root@master configmap-daemo]# cat my-cm-daemo2.yaml 
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: my-cm-daemon2
      labels:
        app: cm-daemon
    data:
      redis.conf: |
        host=127.0.0.1
        port=6379
    


    查看结果信息:

    [root@master configmap-daemo]# kubectl apply -f my-cm-daemo2.yaml 
    configmap/my-cm-daemon2 created
    [root@master configmap-daemo]# kubectl describe configmap my-cm-daemon2
    Name:         my-cm-daemon2
    Namespace:    default
    Labels:       app=cm-daemon
    Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                    {"apiVersion":"v1","data":{"redis.conf":"host=127.0.0.1
    port=6379
    "},"kind":"ConfigMap","metadata":{"annotations":{},"labels":{"app":"cm...
    
    Data
    ====
    redis.conf:
    ----
    host=127.0.0.1
    port=6379
    
    Events:  <none>
    

    (3)、使用ConfigMap

    ConfigMap中的配置数据可以通过如下方式进行使用:

    • 设置环境变量值
    • 在容器里设置命令行参数
    • 在数据卷中创建config文件


    1、通过设置环境变量值来使用ConfigMap
    定义如下YAML文件:

    [root@master configmap-daemo]# cat env-configmap.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: env-configmap
      labels:
        app: env-configmap-mysql
    spec:
      containers:
      - name: test-configmap
        image: busybox
        command:
        - "/bin/sh"
        - "-c"
        - "env"
        env:
          - name: DB_HOST
            valueFrom:
              configMapKeyRef:
                name: my-cm-daemo
                key: db.host
          - name: DB_PORT
            valueFrom:
              configMapKeyRef:
                name: my-cm-daemo
                key: db.port
        envFrom:
          - configMapRef:
              name: my-cm-daemo
    


    查看配置结果:

    [root@master configmap-daemo]# kubectl apply -f env-configmap.yaml 
    pod/env-configmap created
    [root@master configmap-daemo]# kubectl logs env-configmap
    KUBERNETES_PORT=tcp://10.68.0.1:443
    KUBERNETES_SERVICE_PORT=443
    HOSTNAME=env-configmap
    DB_PORT=3306
    DB_HOST=localhost
    ......
    


    我们可以看到我们期望得到的变量信息已经从ConfigMap中得到了。


    2、在容器中设置命令行参数来获取ConfigMap配置信息
    定义YAML问价如下:

    [root@master configmap-daemo]# cat command-configmap.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: command-configmap
    spec:
      containers:
      - name: command-configmap-test
        image: busybox
        command:
        - "/bin/sh"
        - "-c"
        - "echo $(DB_HOST) $(DB_PORT)"
        env:
          - name: DB_HOST
            valueFrom:
              configMapKeyRef:
                name: my-cm-daemo
                key: db.host
          - name: DB_PORT
            valueFrom:
               configMapKeyRef:
                 name: my-cm-daemo
                 key: db.port
    


    查看结果

    [root@master configmap-daemo]# kubectl logs command-configmap
    localhosy 3306
    
    


    3、在数据卷中使用ConfigMap
    定义YAML文件如下:

    [root@master configmap-daemo]# cat volume-configmap.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: volume-configmap-test
    spec:
      containers:
        - name: volume-configmap-test
          image: busybox
          command: [ "/bin/sh", "-c", "cat /etc/config/redis.conf" ]
          volumeMounts:
          - name: config-volume
            mountPath: /etc/config
      volumes:
        - name: config-volume
          configMap:
            name: my-configmap 
    


    运行Pod,查看结果

    [root@master configmap-daemo]# kubectl logs volume-configmap-test
    host=127.0.0.1
    port=6379
    


    我们也可以在ConfigMap值被映射的数据卷里去控制路径,如下Pod定义:

    [root@master configmap-daemo]# cat volume-path-configmap.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: volume-path-configmap
    spec:
      containers:
        - name: volume-path-configmap-test
          image: busybox
          command: [ "/bin/sh","-c","cat /etc/config/path/to/msyqld.conf" ]
          volumeMounts:
          - name: config-volume
            mountPath: /etc/config
      volumes:
        - name: config-volume
          configMap:
            name: my-configmap
            items:
            - key: mysqld.conf
              path: path/to/msyqld.conf
    


    然后运行Pod,查看执行结果:

    [root@master configmap-daemo]# kubectl logs volume-path-configmap
    host=127.0.0.1
    port=3306
    


    另外需要注意的是,当ConfigMap以数据卷的形式挂载进Pod的时,这时更新ConfigMap(或删掉重建ConfigMap),Pod内挂载的配置信息会热更新。这时可以增加一些监测配置文件变更的脚本,然后reload对应服务。

    3.1.3、DownloadAPI

    让这个Pod里的容器可以直接获取这个Pod API对象本身的信息。
    比如:

    apiVersion: v1
    kind: Pod
    metadata:
      name: test-downwardapi-volume
      labels:
        zone: us-est-coast
        cluster: test-cluster1
        rack: rack-22
    spec:
      containers:
        - name: client-container
          image: k8s.gcr.io/busybox
          command: ["sh", "-c"]
          args:
          - while true; do
              if [[ -e /etc/podinfo/labels ]]; then
                echo -en '
    
    '; cat /etc/podinfo/labels; fi;
              sleep 5;
            done;
          volumeMounts:
            - name: podinfo
              mountPath: /etc/podinfo
              readOnly: false
      volumes:
        - name: podinfo
          projected:
            sources:
            - downwardAPI:
                items:
                  - path: "labels"
                    fieldRef:
                      fieldPath: metadata.labels
    


    通过这样的声明方式,就可以把Pod的labels字段值挂载成kubernetes容器中/etc/podinfo/labels文件。


    当前DownloadAPI支持的字段如下:

    1. 使用 fieldRef 可以声明使用:
    spec.nodeName - 宿主机名字
    status.hostIP - 宿主机 IP
    metadata.name - Pod 的名字
    metadata.namespace - Pod 的 Namespace
    status.podIP - Pod 的 IP
    spec.serviceAccountName - Pod 的 Service Account 的名字
    metadata.uid - Pod 的 UID
    metadata.labels['<KEY>'] - 指定 <KEY> 的 Label 值
    metadata.annotations['<KEY>'] - 指定 <KEY> 的 Annotation 值
    metadata.labels - Pod 的所有 Label
    metadata.annotations - Pod 的所有 Annotation
    
    2. 使用 resourceFieldRef 可以声明使用:
    容器的 CPU limit
    容器的 CPU request
    容器的 memory limit
    容器的 memory request
    


    注意:DownloadAPI能够获取到的信息一定是Pod里的容器进程启动之前就能够确定下来的信息。

    3.1.4、ServiceAccountToken

    ServiceAccountToken是kubernetes内置的一种"服务账户",它是Kubernetes进行权限分配的对象。ServiceAccount的 授权信息和文件实际上是保存在Secret对象中,它是一个特殊的Secret对象。任何运行在Kubernetes集群上的应用,都必须使用ServiceAccountToken里保存的授权信息,也就是Token,这样才能合法的访问API Server。


    目前,Kubernetes已经提供了一个默认的"服务账户"(Default Service Account),任何一个运行在Kubernetes里的Pod,都可以无显示声明的挂载这个ServiceAccount并使用它。


    我们随意找一个Pod查看其详细信息,就可以看到一个default-token-xxxx的Volume自动挂载到容器的/var/run/secrets/kubernetes.io/serviceaccount目录上。如下:

    [root@master k8s]# kubectl describe pod nginx-deployment-6f655f5d99-q4fhk
    ......
    Containers:
      nginx:
    .......
        Mounts:
          /var/run/secrets/kubernetes.io/serviceaccount from default-token-gmdbb (ro)
    Conditions:
    ......
    Volumes:
      default-token-gmdbb:
        Type:        Secret (a volume populated by a Secret)
        SecretName:  default-token-gmdbb
        Optional:    false
    QoS Class:       BestEffort
    


    我们可以看到这个Volume是Secret类型,正式默认Service Account对应的ServiceAccountToken,所以说,Kubernetes在每个Pod创建的时候,自动为其添加默认的ServiceAccountToken的定义,然后自动为每个容器加上对应的VolumeMounts字段,这个过程对应用户来说是透明的,一旦这个Pod创建完成,容器里的应用可以直接从这个默认的ServiceAccountToken挂载的目录里访问到授权信息和文件,这个路径在Kubernetes里是固定的。


    我们进入Pod会看到挂载的目录下的文件信息如下:

    [root@master k8s]# kubectl exec -it nginx-deployment-6f655f5d99-q4fhk -- /bin/sh
    # ls /var/run/secrets/kubernetes.io/serviceaccount    
    ca.crt	namespace  token
    # 
    


    所以,应用程序只要加载这些授权文件,就可以直接访问Kubernetes API了,而且,如果是直接使用Kubernetes官方的包(k8s.io/client-go),是可以直接加载这些授权文件的。


    这种把Kubernetes的配置信息以容器的方式运行在集群中,然后使用ServiceAccountToken方式自动授权,被称为"InClusterConfig"。

  • 相关阅读:
    42. Trapping Rain Water
    223. Rectangle Area
    645. Set Mismatch
    541. Reverse String II
    675. Cut Off Trees for Golf Event
    安装 VsCode 插件安装以及配置
    向上取整 向下取整 四舍五入 产生100以内随机数
    JS 判断是否为数字 数字型特殊值
    移动端初始配置,兼容不同浏览器的渲染内核
    Flex移动布局中单行和双行布局的区别以及使用
  • 原文地址:https://www.cnblogs.com/coolops/p/12975029.html
Copyright © 2011-2022 走看看