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"。

  • 相关阅读:
    微信小程序demo理解
    HTML 和 JavaScript 编写简单的 404 界面
    阿里云实现简单的运行 Django 项目
    AJAX 与 Python 后台通信
    django session 使用案例
    PHP 基础知识
    Django 搭建后台 favicon.ico 文件操作
    Win10 Ubuntu 双系统 卸载 Ubuntu
    JavaScript 表单验证 案例
    JavaScript Image对象 / Tabel对象 / Select对象 / Form对象
  • 原文地址:https://www.cnblogs.com/coolops/p/12975029.html
Copyright © 2011-2022 走看看