【探索 Kubernetes|作业管理篇 系列 9】Pod 的服务对象

  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

    前言

    大家好我是秋意零。

    在上一篇中我们介绍了 Pod 的生命周期以及区分 Pod 字段的层次级别相信你对此有了充分的认识。

    今天我们还会接着以 Pod 展开说说它的 “服务对象”一听就知道是对 Pod 提供服务的对象接下来就一起来看看 “服务对象” 是否有趣吧

    哦对了最近搞了一个扣扣群旨在技术交流、博客互助希望各位大佬多多支持在我主页推广区域如图

    • 在这里插入图片描述

    文章底部推广区域如图

    • 在这里插入图片描述

    简介

    • 个人主页 秋意零
    • 个人介绍在校期间参与众多云计算相关比赛如 “省赛”、“国赛”并斩获多项奖项荣誉证书
    • 目前状况24 届毕业生拿到一家私有云IAAS公司 offer暑假开始实习
    • 账号各个平台 秋意零 账号创作者、 云社区 创建者
    • 欢迎大家欢迎大家一起学习云计算走向年薪 30 万

    在这里插入图片描述

    系列文章目录


    【探索Kubernetes|容器基础进阶篇 系列1】容器的本质是进程
    【探索 Kubernetes|容器基础进阶篇 系列 2】容器资源限制利器
    【探索 Kubernetes|容器基础进阶篇 系列 3】容器进程的文件系统
    【探索 Kubernetes|容器基础进阶篇 系列 4】理解现代云原生时代的引擎
    【探索 Kubernetes|集群搭建篇 系列 5】简化 Kubernetes 的部署深入解析其工作流程



    更多点击专栏查看深入探索 Kubernetes

    文章目录

    正文开始

    • 快速上船马上开始掌舵了Kubernetes距离开船还有 3s2s1s…

    在这里插入图片描述

    一、Pod 服务对象

    早在 【探索 Kubernetes|容器基础进阶篇 系列 4】理解现代云原生时代的引擎 (七、Kubernetes 全景图) 这篇中就简单介绍过 “服务对象” 而下图中所说的 “编排对象” 将在后面详细展开。如下图所示

    在这里插入图片描述

    首先需要声明的是目前介绍的 “服务对象”仅仅是通过 Pod 的 Volume 字段来展开说明的。为什么呢

    • Secret、ConfigMap、Downward API、ServiceAccountToken 这四种 Projected Volume 是今天主角也就是通过 Volume 字段挂载投射进 Pod 从而进行服务的。这种 Volume存在的意义不是为了存放容器里的数据也不是用来进行容器和宿主机之间的数据交换。这些特殊 Volume 的作用是为容器提供预先定义好的数据。所以从容器的角度来看这些 Volume 里的信息就是仿佛是被 Kubernetes“投射”Project进入容器当中的。这正是 Projected Volume 的含义。
    • 而像 Service、Horizontal Pod Autoscaler 就是通过其它指标字段对 Pod 进行服务的

    二、Secret

    Sercret 是将 Pod 要访问的加密数据存在在 Etcd 数据库中。之后Pod 通过挂载 Volume 卷的方式访问到这些 Secret 里存放的信息。

    Secret 使用方法

    想象一个这样的场景使用 Kubernetes 部署一个 Mysql 服务Mysql 容器初始化时需要指定 root 密码因为我们一般使用 YAML 方式部署这样方便管理容器服务对象。这时我们需要在 YAML 文件中通过环境变量的方式初始化 Mysql 用户和密码但是这样就容易暴露这样的明文用户和密码信息。这时就需要使用 Secret 映射给这个 Mysql 使用对应的认证信息

    1.首先需要给明文用户和密码加密

    因为我们 Secret 也是 YAML 方式部署不过在企业中这种信息一般是管理人员为运维人员创建。运维人员使用这样一个 Secret 即可。

    这里使用 base64 方式转码并不安全因为 base64 仅仅是经过了转码而并没有被加密。在真正的生产环境中你需要在 Kubernetes 中开启 Secret 的加密插件增强数据的安全性

    # 加密方式
    [root@master01 ~]#  echo -n "root" | base64
    cm9vdA==
    [root@master01 ~]# echo -n "000000" | base64
    MDAwMDAw
    
    # 解密方式
    [root@master01 ~]# echo -n "cm9vdA==" | base64 -d
    admin
    [root@master01 ~]# echo -n "MDAwMDAw" | base64 -d
    000000
    

    2.创建 Secret

    将加密过后的用户和密码信息填写到 Secret 中。data 字段下以 Key-Value 的格式保存了两份 Secret 数据。其中“user” 就是第一份数据的 Key“pass” 是第二份数据的 Key。

    • user 是用户 key 而 cm9vdA== 是用户 value用户名
    • pass 是用户 key 而 MDAwMDAw 是用户 value用户密码
    [root@master01 yaml]# cat > secret-my.yaml << EOF
    apiVersion: v1
    kind: Secret
    metadata:
      name: mysecret
    type: Opaque # 默认类型
    data:
      user: cm9vdA==
      pass: MDAwMDAw
    EOF
    
    # 部署 Secret
    [root@master01 yaml]# kubectl apply -f secret-my.yaml
    secret/mysecret created
    
    # 记住 Secret 的名称这里叫mysecret待会会使用。
    [root@master01 yaml]# kubectl get secret
    NAME       TYPE     DATA   AGE
    mysecret   Opaque   2      9s
    

    3.创建 PodMysql

    可以使用 kubectl create secret generic 命令创建或者 YAML 文件创建。

    • 3.1.将 Secret 导入到环境变量中
    apiVersion: v1
    kind: Pod
    metadata:
      name: mysql-pod
    spec:
      containers:
        - name: mysql-container
          image: mysql:5.7
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 3306
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysecret
                  key: pass
    

    进入容器验证环境变量是否和 Secret 中保存的值一致。

    [root@master01 yaml]# kubectl exec -it  mysql-pod -- /bin/bash
    root@mysql-pod:/# env |grep MYSQL_ROOT_PASSWORD
    MYSQL_ROOT_PASSWORD=000000
    

    在这里插入图片描述

    • 3.2.将 Secret 挂载到 projected Voluem 中
    apiVersion: v1
    kind: Pod
    metadata:
      name: busybox-pod
    spec:
      containers:
        - name: busybox-container
          image: busybox
          imagePullPolicy: IfNotPresent
    	  args:
    	  - sleep
    	  - "3600"
          volumeMounts:
            - name: busybox-secrets
              mountPath: /var/secrets/busybox
              readOnly: true
      volumes:
        - name: busybox-secrets
          projected:
            sources:
             - secret:
                 name: mysecret
    

    进入容器验证挂载的目录的值是否和 Secret 中保存的值一致。

    • 注意使用 Voluem 挂载方式时是将 Secret 中的 key 作为目录名称value 作为目录中的值
    [root@master01 yaml]# kubectl exec -it busybox-pod -- /bin/sh
    # 查看使用 Secret 挂载进容器中的目录
    / # ls  /var/secrets/busybox
    pass  user
    # 查看值
    / # cat /var/secrets/busybox/user
    admin
    / # cat /var/secrets/busybox/pass
    000000/ #
    

    在这里插入图片描述

    小结

    通过挂载方式进入到容器里的 Secret一旦其对应的 Etcd 里的数据被更新这些 Volume 里的文件内容同样也会被更新。其实这是 kubelet 组件在定时维护这些 Volume。

    不过这个更新会有一定延时。所以在编写应用程序时在发起数据库连接的代码处写好重试和超时的逻辑绝对是个好习惯

    三、ConfigMap

    ConfigMap 与 Secret 类似区别就是 ConfigMap 保存的是不需要加密的、应用所需的配置文件信息。

    ConfigMap 的用法几乎与 Secret 完全相同可以使用 kubectl create configmap 从文件或者目录创建 ConfigMap也可以直接编写 ConfigMap 对象的 YAML 文件。

    [root@master01 yaml]# cat test-db.text
    database.host=localhost
    database.port=3306
    database.username=admin
    database.password=secret
    
    # 从 test-db.text 文件中创建 configmap。
    [root@master01 yaml]# kubectl create configmap my-config --from-file=test-db.text
    configmap/my-config created
    

    查看 configmap 中 data 数据信息可以看到是和 test-db.text 配置文件中一致的后期也是可以通过环境变量和 Voluem 卷的方式使用同上述 Secret。

    [root@master01 yaml]# kubectl get configmap my-config -o yaml
    

    在这里插入图片描述

    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    spec:
      containers:
        - name: my-container
          image: my-image
          env:
            - name: DATABASE_HOST
              valueFrom:
                configMapKeyRef:
                  name: my-config
                  key: database.host
            - name: DATABASE_PORT
              valueFrom:
                configMapKeyRef:
                  name: my-config
                  key: database.port
            - name: DATABASE_USERNAME
              valueFrom:
                configMapKeyRef:
                  name: my-config
                  key: database.username
            - name: DATABASE_PASSWORD
              valueFrom:
                configMapKeyRef:
                  name: my-config
                  key: database.password
    
    

    四、Downward API

    Downward API 是一种特性它允许容器在运行时获取关于自身和它所在 Pod 的一些元数据信息。这些信息可以作为环境变量或卷挂载提供给容器使用。

    如果按照 Downward下载这个单词意思理解就是 将 Pod 或容器自身的元数据信息下载到是运行状态的容器中使用。

    Downward API 提供了以下作用

    在这里插入图片描述

    总的来说Downward API 提供了一种在容器运行时获取 Pod 和容器自身元数据的机制使容器能够动态获取并使用这些信息。这对于编写灵活且适应性强的应用程序非常有用并能够在 Kubernetes 环境中提供更多的自动化和配置选项。

    可用字段

    只有部分 Kubernetes API 字段可以通过 Downward API 使用。

    • fieldRef传递 Pod 级字段的信息
    • resourceFieldRef传递 Container 级字段的信息

    1.可通过 fieldRef 获得的信息

    • metadata.namePod 的名称
    • metadata.namespacePod 的命名空间
    • metadata.uidPod 的唯一 ID

    2.可通过 resourceFieldRef 获得的信息

    • limits.cpu容器的 CPU 限制值
    • requests.cpu容器的 CPU 请求值
    • requests.memory容器的内存请求值
    • limits.memory容器的内存限制值

    Kubernetes 官网更多可用字段信息

    举个例子

    我们定义了一个 Pod 名为 projected-buxybox并创建了一个名为 app 的容器。我们使用了一个 Projected Volume并将其挂载到了 /etc/config 目录下。 并使用 fieldRef 来获取 Pod 的元数据信息使用 resourceFieldRef 来获取容器的元数据信息。

    • items.path定义元数据信息的目录是什么。
    • fieldRef.fieldPath定义 Pod 元数据信息的值是什么。
    • resourceFieldRef.resource定义 容器 元数据信息的值是什么。
    apiVersion: v1
    kind: Pod
    metadata:
      name: projected-buxybox
    spec:
      containers:
        - name: app
          image: busybox
          imagePullPolicy: IfNotPresent
          args:
          - sleep
          - "3600"
          resources:
            limits:
              cpu: "2"
            requests:
              cpu: "1"
          volumeMounts:
            - name: config-volume
              mountPath: /etc/config
      volumes:
        - name: config-volume
          projected:
            sources:
              - downwardAPI:
                  items:
                    - path: "pod_name"
                      fieldRef:
                        fieldPath: metadata.name
                    - path: "pod_namespace"
                      fieldRef:
                        fieldPath: metadata.namespace
                    - path: "cpu_limits"
                      resourceFieldRef:
                        containerName: app
                        resource: limits.cpu
                    - path: "cpu_request"
                      resourceFieldRef:
                        containerName: app
                        resource: requests.cpu
    

    验证部署 Pod 并查看 /etc/config 目录下获取的值是否正确。

    [root@master01 yaml]# kubectl apply -f projected-buxybox-pod.yaml
    [root@master01 yaml]# kubectl get -f projected-buxybox-pod.yaml
    NAME                READY   STATUS    RESTARTS   AGE
    projected-buxybox   1/1     Running   0          3m11s
    
    [root@master01 yaml]# kubectl exec -it projected-buxybox -- /bin/sh
    / # ls /etc/config/
    cpu_limits     cpu_request    pod_name       pod_namespace
    / # cat /etc/config/cpu_limits
    2
    / # cat /etc/config/cpu_request
    1
    / # cat /etc/config/pod_name
    projected-buxybox
    / # cat /etc/config/pod_namespace
    default
    

    在这里插入图片描述

    小结

    注意Downward API 能够获取到的信息一定是 Pod 里的容器进程启动之前就能够确定下来的信息。而如果你想要获取 Pod 容器运行后才会出现的信息比如容器进程的 PID那就肯定不能使用 Downward API 了而应该考虑在 Pod 里定义一个 sidecar 容器。

    Secret、ConfigMap以及 Downward API 这三种 Projected Volume 定义的信息大多还可以通过环境变量的方式出现在容器里。但是通过环境变量获取这些信息的方式不具备自动更新的能力。所以一般情况下我都建议你使用 Volume 文件的方式获取这些信息

    五、ServiceAccountToken

    如果我有一个 Pod而且在 Pod 中安装 Kubernetes 的 Clinet想实现可以从容器里直接访问并且操作这个 Kubernetes 的 API 这种方式是可行的不过你首先要解决 API Server 的授权问题这就需要 ServiceAccount 服务对象了。

    1.Service Account 是什么

    • Service Account服务账号是 Kubernetes 中用于身份验证和授权的实体进行权限分配的对象。它是为 Pod 提供访问 Kubernetes API 的身份凭据。每个 Service Account 都有一个唯一的名称和对应的身份令牌Token。
    • Service Account 可以与 Pod 关联使 Pod 具有与 Kubernetes API 进行交互的权限。它允许 Pod 在运行时进行身份验证并根据其配置的权限来执行操作例如创建、更新或删除资源。

    比如Service Account A可以只被允许对 Kubernetes API 进行 GET 操作而 Service Account B则可以有 Kubernetes API 的所有操作权限。

    2.ServiceAccountToken 是什么

    像上述这样的权限分配操作实际上是通过一种它所绑定的一个 ServiceAccountToken。任何运行在 Kubernetes 集群上的应用都必须使用这个 ServiceAccountToken 里保存的授权信息也就是 Token才能访问 kube-apiserver

    在这里插入图片描述

    另外为了方便使用Kubernetes 已经为你提供了一个默认“服务账户”default Service Account。如图

    在这里插入图片描述

    并且任何一个运行在 Kubernetes 里的 Pod都可以直接使用这个默认的 Service Account而无需显示地声明挂载它因为是默认自动挂载可以设置不挂载默认挂载靠 Projected Volume 机制实现。

    你可以查看任意一个运行中的 Pod你会发现一个 类型为 Projected 并且包含来自多个源的注入数据的卷Service Account 的身份令牌然后自动挂载在每个容器的一个固定目录上 /var/run/secrets/kubernetes.io/serviceaccount容器可以通过该路径访问令牌并将其用于与 Kubernetes API 的安全通信。

    这里提供了两种查看方式如下图

    kubectl describe pod mysql-pod
    

    在这里插入图片描述

    下图我们可以看到这个 Projected 包含来自多个源的注入数据的卷使用了 ServiceAccountToken、ConfigMap、DownwardAPI。

    kubectl get pod -o yaml mysql-pod
    

    在这里插入图片描述

    所以 Pod 中的容器应用就可以直接使用这个目录下的授权信息和文件与 kube-apiserver 访问 Projected 目录下的内容如图所示
    在这里插入图片描述
    这种把 Kubernetes 客户端以容器的方式运行在集群里然后使用 default Service Account 自动授权的方式被称作 “InClusterConfig”内部集群配置也是我最推荐的进行 Kubernetes API 编程的授权方式。

    除了默认的 ServiceAccount 还可以自定义 ServiceAccount 来对应不同的权限设置。这样 Pod 在使用这个 Service Account 对应的 ServiceAccountToken 时权限就更加灵活。

    总结

    今天介绍了 Pod 的 Volume 的 Projected 服务对象。

    你还应该认真体会一下 Kubernetes “一切皆对象” 的设计思想比如应用是 Pod 对象应用的配置是 ConfigMap 对象应用要访问的密码则是 Secret 对象。

    最后技术交流、博客互助点击下方或主页推广加入哦
    在这里插入图片描述

  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
    标签: k8s