Loading...
墨滴

舍得

2021/11/09  阅读:38  主题:绿意

Pod使用进阶

image-20211108144447899
image-20211108144447899

目录

实验环境

实验环境:
1、win10,vmwrokstation虚机;
2、k8s集群:3台centos7.6 1810虚机,1个master节点,2个node节点
   k8s version:v1.22.2
   containerd://1.5.5

实验软件(无)

深入理解 Pod 对象

1、Pod 资源配置

实际上上面几个步骤就是影响一个 Pod 生命周期的大的部分,但是还有一些细节也会在 Pod 的启动过程进行设置,比如在容器启动之前还会为当前的容器设置分配的 CPU、内存等资源,我们知道我们可以通过 CGroup 来对容器的资源进行限制,同样的,在 Pod 中我们也可以直接配置某个容器的使用的 CPU 或者内存的上限。那么 Pod 是如何来使用和控制这些资源的分配的呢?

首先对于 CPU,我们知道计算机里 CPU 的资源是按“时间片”的方式来进行分配的系统里的每一个操作都需要 CPU 的处理,所以,哪个任务要是申请的 CPU 时间片越多,那么它得到的 CPU 资源就越多,这个很容器理解。

然后还需要了解下 CGroup 里面对于 CPU 资源的单位换算:

1 CPU =  1000 millicpu(1 Core = 1000m)
0.5 CPU = 500 millicpu (0.5 Core = 500m)

这里的 m 就是毫、毫核的意思,**Kubernetes 集群中的每一个节点可以通过操作系统的命令来确认本节点的 CPU 内核数量,然后将这个数量乘以1000,得到的就是节点总 CPU 总毫数。**比如一个节点有四核,那么该节点的 CPU 总毫量为 4000m,如果你要使用0.5 core,则你要求的是 4000*0.5 = 2000m。在 Pod 里面我们可以通过下面的两个参数来限制和请求 CPU 资源:

  • spec.containers[].resources.limits.cpu:CPU 上限值,可以短暂超过,容器也不会被停止
  • spec.containers[].resources.requests.cpu:CPU请求值,Kubernetes 调度算法里的依据值,可以超过

这里需要明白的是,如果 resources.requests.cpu 设置的值大于集群里每个节点的最大 CPU 核心数,那么这个 Pod 将无法调度,因为没有节点能满足它

到这里应该明白了,requests 是用于集群调度使用的资源,而 limits 才是真正的用于资源限制的配置如果你需要保证的你应用优先级很高,也就是资源吃紧的情况下最后再杀掉你的 Pod,那么你就把你的 requests 和 limits 的值设置成一致,在后面应用的 Qos 中会具体讲解。


==:heart:实验测试:pod资源限制(测试成功)==

实验日期:2021年11月8日15:05:46

比如,现在我们定义一个 Pod,给容器的配置如下的资源:

# pod-resource-demo1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: resource-demo1
spec:
  containers:
  - name: resource-demo1
    image: nginx
    ports:
    - containerPort: 80
    resources: #这个是给调度器使用的;
      requests:
        memory: 50Mi
        cpu: 50m
      limits:
        memory: 100Mi
        cpu: 100m

这里,CPU 我们给的是 50m,也就是 0.05core,这 0.05core 也就是占了 1 CPU 里的 5% 的资源时间。而限制资源是给的是 100m,但是需要注意的是 CPU 资源是可压缩资源,也就是容器达到了这个设定的上限后,容器性能会下降,但是不会终止或退出

比如我们直接创建上面这个 Pod:

[root@master1 ~]#kubectl apply -f resource-demo1.yaml
pod/resource-demo1 created

创建完成后,我们可以看到 Pod 被调度到 node2 这个节点上:

[root@master1 ~]#kubectl get po -owide
NAME             READY   STATUS    RESTARTS   AGE   IP           NODE    NOMINATED NODE   READINESS GATES
resource-demo1   1/1     Running   0          42s   10.244.2.9   node2   <none>           <none>
[root@master1 ~]#

然后我们到 node2 节点上去查看 Pod 里面启动的 resource-demo1 这个容器:

[root@node2 ~]#crictl ps #查看当前节点pod信息
CONTAINER           IMAGE               CREATED             STATE               NAME                   ATTEMPT             POD ID
bcbbf88a9ac29       87a94228f133e       3 minutes ago       Running             resource-demo1         0                   0f2511f4b7567

我们可以去查看下主容器的信息:

➜  ~ crictl inspect bcbbf88a9ac29 #我淦,这个crictl命令也可以直接来看容器的详细信息的……
  "status": {
    "id""bcbbf88a9ac29d84700525b4c898171889510b372b45a77f1c9757fdef3793a2",
    "metadata": {
      "attempt": 0,
      "name""resource-demo1"
    },
    "state""CONTAINER_RUNNING",
    "createdAt""2021-11-07T16:46:37.069325484+08:00",
    "startedAt""2021-11-07T16:46:37.412557847+08:00",
    "finishedAt""0001-01-01T00:00:00Z",
    "exitCode": 0,
    "image": {
      "annotations": {},
      "image""docker.io/library/nginx:latest"
    },
......
      "linux": {
        "resources": {
          "devices": [
            {
              "allow"false,
              "access""rwm"
            }
          ],
          "memory": {
            "limit": 104857600 #注意
          },
          "cpu": {
            "shares": 51,
            "quota": 10000, #注意
            "period": 100000
          }
        },
        "cgroupsPath""kubepods-burstable-pod7e80487d_24d7_44af_bf38_c43b6dfe4045.slice:cri-containerd:bcbbf88a9ac29d84700525b4c898171889510b372b45a77f1c9757fdef3793a2",

     ......

实际上我们就可以看到这个容器的一些资源情况,Pod 上的资源配置最终也还是通过底层的容器运行时去控制 CGroup 来实现的,我们可以进入如下目录查看 CGroup 的配置,该目录就是 CGroup 父级目录,而 CGroup 是通过文件系统来进行资源限制的,所以我们上面限制容器的资源就可以在该目录下面反映出来:

image-20211107171358662
image-20211107171358662
[root@node2 ~]#cd /sys/fs/cgroup/cpu/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod7e80487d_24d7_44af_bf38_c43b6dfe4045.slice/
[root@node2 kubepods-burstable-pod7e80487d_24d7_44af_bf38_c43b6dfe4045.slice]#ls
cgroup.clone_children  cpuacct.usage         cpu.rt_period_us   cri-containerd-0f2511f4b75676145584aa6379a933d65d0e531a500e6697a1998bfb1b0b7d9d.scope
cgroup.event_control   cpuacct.usage_percpu  cpu.rt_runtime_us  cri-containerd-bcbbf88a9ac29d84700525b4c898171889510b372b45a77f1c9757fdef3793a2.scope
cgroup.procs           cpu.cfs_period_us     cpu.shares         notify_on_release
cpuacct.stat           cpu.cfs_quota_us      cpu.stat           tasks
[root@node2 kubepods-burstable-pod7e80487d_24d7_44af_bf38_c43b6dfe4045.slice]#cat cpu.cfs_quota_us
10000 #1/10的比例;
[root@node2 kubepods-burstable-pod7e80487d_24d7_44af_bf38_c43b6dfe4045.slice]#cat cpu.cfs_period_us
100000
[root@node2 kubepods-burstable-pod7e80487d_24d7_44af_bf38_c43b6dfe4045.slice]#

注意这里的比值计算:

1.yaml文件里给的spec.containers.resources.requests.cpu=50m(50毫核=0.05c,即1c里面的0.05c,0.05/1的比值,5/100=1/20的比值)

2.而cgroups里面的比值为:10000/100000=1/10的比值

这里自己比较有些模糊…………

其中 cpu.cfs_quota_us 就是 CPU 的限制值,如果要查看具体的容器的内存资源,我们也可以进入到容器目录下面去查看即可。

[root@node2 ~]#cat /sys/fs/cgroup/memory/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod7e80487d_24d7_44af_bf38_c43b6dfe4045.slice/memory.limit_in_bytes #limits
104857600
[root@node2 ~]#
  • 注意:单位换算问题

最后我们了解下内存这块的资源控制,内存的单位换算比较简单:

1 MiB = 1024 KiB,内存这块在 Kubernetes 里一般用的是Mi单位,当然你也可以使用Ki、Gi甚至Pi,看具体的业务需求和资源容量。

单位换算:

这里注意的是MiB ≠ MB,MB 是十进制单位,MiB 是二进制,平时我们以为 MB 等于 1024KB,其实1MB=1000KB1MiB才等于1024KiB。中间带字母 i 的是国际电工协会(IEC)定的,走1024乘积;KB、MB、GB 是国际单位制,走1000乘积。

这里要注意的是,内存是不可压缩性资源,如果容器使用内存资源到达了上限,那么会OOM,造成内存溢出,容器就会终止和退出。我们也可以通过上面的方式去通过查看 CGroup 文件的值来验证资源限制。

2、静态 Pod(static pod)

在 Kubernetes 集群中除了我们经常使用到的普通的 Pod 外,还有一种特殊的 Pod,叫做Static Pod,也就是我们说的静态 Pod,静态 Pod 有什么特殊的地方呢?

静态 Pod 直接由节点上的 kubelet 进程来管理,不通过 master 节点上的 apiserver。无法与我们常用的控制器 Deployment 或者 DaemonSet 进行关联,它由 kubelet 进程自己来监控,当 pod 崩溃时会重启该 pod,kubelet 也无法对他们进行健康检查静态 pod 始终绑定在某一个 kubelet 上,并且始终运行在同一个节点上kubelet 会自动为每一个静态 pod 在 Kubernetes 的 apiserver 上创建一个镜像 Pod,因此我们可以在 apiserver 中查询到该 pod,但是不能通过 apiserver 进行控制(例如不能删除)

创建静态 Pod 有两种方式:配置文件HTTP 两种方式

方法1:通过配置文件创建静态Pods

配置文件就是放在特定目录下的标准的 JSON 或 YAML 格式的 pod 定义文件。kubelet --pod-manifest-path=<the directory>来启动 kubelet 进程,kubelet 定期的去扫描这个目录,根据这个目录下出现或消失的 YAML/JSON 文件来创建或删除静态 pod。

[root@master1 ~]#kubelet --help|grep manifest
manifest can be provided to the Kubelet.
(underspec'd currently) to submit a new manifest.
      --manifest-url string                                      URL for accessing additional Pod specifications to run (DEPRECATED: This parameter should be set via the config file specified by the Kubelet'
s --config flag. See https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/ for more information.)
      --manifest-url-header colonSeparatedMultimapStringString   Comma-separated list of HTTP headers to use when accessing the url provided to --manifest-url. Multiple headers with the same name will be added in the same order provided. This flag can be repeatedly invoked. For example: --manifest-url-header 'a:hello,b:again,c:world' --manifest-url-header 'b:beautiful' (DEPRECATED: This parameter should be set via the config file specified by the Kubelet's --config flag. See https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/ for more information.)
      --pod-manifest-path string                                 Path to the directory containing static pod files to run, or the path to a single static pod file. Files starting with dots will be ignored. (DEPRECATED: This parameter should be set via the config file specified by the Kubelet'
s --config flag. See https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/ for more information.)
[root@master1 ~]#

比如我们在 node1 这个节点上用静态 pod 的方式来启动一个 nginx 的服务,配置文件路径为:

[root@master1 ~]#cat /var/lib/kubelet/config.yaml
......
staticPodPath: /etc/kubernetes/manifests  # 和命令行的 pod-manifest-path 参数一致
......

打开这个文件我们可以看到其中有一个属性为 staticPodPath 的配置,其实和命令行的 --pod-manifest-path 配置是一致的,所以如果我们通过 kubeadm 的方式来安装的集群环境,对应的 kubelet 已经配置了我们的静态 Pod 文件的路径,默认地址为 /etc/kubernetes/manifests,所以我们只需要在该目录下面创建一个标准的 Pod 的 JSON 或者 YAML 文件即可,如果你的 kubelet 启动参数中没有配置上面的--pod-manifest-path 参数的话,那么添加上这个参数然后重启 kubelet 即可

这边创建一个静态pod用于测试实验:

  ~ cat <<EOF >/etc/kubernetes/manifests/static-web.yaml
apiVersion: v1
kind: Pod
metadata:
  name: static-web
  labels:
    app: static
spec:
  containers:
    - name: web
      image: nginx
      ports:
        - name: web #我淦,这个容器端口也是可以指定name的,因为一个容器可以有不同的端口来提供不同的服务;
          containerPort: 80
EOF
#注意
[root@master1 ~]#kubectl explain pod.spec.containers.ports
……
   name <string>
     If specified, this must be an IANA_SVC_NAME and unique within the pod. Each
     named port in a pod must have a unique name. Name for the port that can be
     referred to by services.
……


方法2:通过 HTTP 创建静态 Pods

kubelet 周期地从 –manifest-url= 参数指定的地址下载文件,并且把它翻译成 JSON/YAML 格式的 pod 定义。此后的操作方式与–pod-manifest-path= 相同,kubelet 会不时地重新下载该文件,当文件变化时对应地终止或启动静态 pod。

kubelet 启动时,由 --pod-manifest-path=--manifest-url= 参数指定的目录下定义的所有 pod 都会自动创建,例如,我们示例中的 static-web

➜  ~ nerdctl -n k8s.io ps
CONTAINER ID    IMAGE                                              COMMAND                   CREATED           STATUS    PORTS    NAMES
6add7aa53969    docker.io/library/nginx:latest                     "/docker-entrypoint.…"    43 seconds ago    Up
......

现在我们通过kubectl工具可以看到这里创建了一个新的镜像 Pod:

[root@master1 ~]#kubectl get pod
NAME                 READY   STATUS    RESTARTS   AGE
resource-demo1       1/1     Running   0          67m
static-web-master1   1/1     Running   0          2m29s
[root@master1 ~]#

静态 pod 的标签会传递给镜像 Pod,可以用来过滤或筛选

需要注意的是,我们不能通过 API 服务器来删除静态 pod(例如,通过kubectl命令),kubelet 不会删除它。

[root@master1 ~]#kubectl get pod
NAME                 READY   STATUS    RESTARTS   AGE
resource-demo1       1/1     Running   0          72m
static-web-master1   1/1     Running   0          7m20s

[root@master1 ~]#kubectl delete pod static-web-master1
pod "static-web-master1" deleted
[root@master1 ~]#kubectl get pod
NAME                 READY   STATUS    RESTARTS   AGE
resource-demo1       1/1     Running   0          72m
static-web-master1   0/1     Pending   0          1s
[root@master1 ~]#kubectl get pod
NAME                 READY   STATUS    RESTARTS   AGE
resource-demo1       1/1     Running   0          73m
static-web-master1   1/1     Running   0          5s
[root@master1 ~]#

静态 Pod 的动态增加和删除

运行中的 kubelet 周期扫描配置的目录(我们这个例子中就是 /etc/kubernetes/manifests)下文件的变化,当这个目录中有文件出现或消失时创建或删除 pods:

[root@master1 ~]#kubectl get pod
NAME                 READY   STATUS    RESTARTS   AGE
resource-demo1       1/1     Running   0          73m
static-web-master1   1/1     Running   0          48s
[root@master1 ~]#mv /etc/kubernetes/manifests/static-web.yaml /tmp/
[root@master1 ~]#kubectl get pod
NAME             READY   STATUS    RESTARTS   AGE
resource-demo1   1/1     Running   0          73m
[root@master1 ~]#mv /tmp/static-web.yaml /etc/kubernetes/manifests/
[root@master1 ~]#kubectl get pod
NAME                 READY   STATUS    RESTARTS   AGE
resource-demo1       1/1     Running   0          74m
static-web-master1   0/1     Pending   0          2s
[root@master1 ~]#kubectl get pod
NAME                 READY   STATUS    RESTARTS      AGE
resource-demo1       1/1     Running   0             74m
static-web-master1   1/1     Running   1 (28s ago)   5s
[root@master1 ~]#

其实我们用 kubeadm 安装的集群,master 节点上面的几个重要组件都是用静态 Pod 的方式运行的,我们登录到 master 节点上查看/etc/kubernetes/manifests目录:

➜  ~ ls /etc/kubernetes/manifests/
etcd.yaml  kube-apiserver.yaml  kube-controller-manager.yaml  kube-scheduler.yaml

现在明白了吧,这种方式也为我们将集群的一些组件容器化提供了可能,因为这些 Pod 都不会受到 apiserver 的控制,不然我们这里kube-apiserver怎么自己去控制自己呢?万一不小心把这个 Pod 删掉了呢?所以只能有kubelet自己来进行控制,这就是我们所说的静态 Pod。

注意:静态pod作用

静态pod本身就是用来去管理我们的k8s集群,例如用静态pod去跑一个nginx,然后去管理我们的k8s集群;

3、Downward API

前面我们从 Pod 的原理到生命周期介绍了 Pod 的一些使用,作为 Kubernetes 中最核心的资源对象、最基本的调度单元,我们可以发现 Pod 中的属性还是非常繁多的,前面我们使用过一个 volumes 的属性,表示声明一个数据卷,我们可以通过命令kubectl explain pod.spec.volumes去查看该对象下面的属性非常多,前面我们只是简单使用了 hostPathemptyDir{} 这两种模式,其中还有一种模式叫做downwardAPI这个模式和其他模式不一样的地方在于它不是为了存放容器的数据,也不是用来进行容器和宿主机的数据交换的,而是让 Pod 里的容器能够直接获取到这个 Pod 对象本身的一些信息。

目前 Downward API 提供了两种方式用于将 Pod 的信息注入到容器内部:

  • 环境变量:用于单个变量,可以将 Pod 信息和容器信息直接注入容器内部
  • Volume 挂载:将 Pod 信息生成为文件,直接挂载到容器内部中去

1.环境变量

我们通过 Downward API 来将 Pod 的 IP、名称以及所对应的 namespace 注入到容器的环境变量中去,然后在容器中打印全部的环境变量来进行验证,对应资源清单文件如下:


==:heart:实验测试:==

[root@master1 ~]#vim env-pod.yaml

# env-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: env-pod
  namespace: kube-system
spec:
  containers:
  - name: env-pod
    image: busybox
    command: ["/bin/sh", "-c", "env"]  #注意,这个pod执行完这个命令就退出了,没有进程可以hold住容器,可以通过查看日志来确认一些信息了;
    env:
    - name: POD_NAME
      valueFrom:
        fieldRef:
          fieldPath: metadata.name
    - name: POD_NAMESPACE
      valueFrom:
        fieldRef:
          fieldPath: metadata.namespace
    - name: POD_IP
      valueFrom:
        fieldRef:
          fieldPath: status.podIP

我们可以看到上面我们使用了一种新的方式来设置 env 的值:valueFrom,由于 Pod 的 name 和 namespace 属于元数据,是在 Pod 创建之前就已经定下来了的,所以我们可以使用 metata 就可以获取到了,但是对于 Pod 的 IP 则不一样,因为我们知道 Pod IP 是不固定的,Pod 重建了就变了,它属于状态数据,所以我们使用 status 这个属性去获取。另外除了使用 fieldRef获取 Pod 的基本信息外,还可以通过 resourceFieldRef 去获取容器的资源请求和资源限制信息。

我们直接创建上面的 Pod:

[root@master1 ~]#kubectl apply -f env-pod.yaml
pod/env-pod created
[root@master1 ~]#

Pod 创建成功后,我们可以查看日志:

[root@master1 ~]# kubectl logs env-pod -nkube-system
POD_IP=10.244.2.10
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBE_DNS_SERVICE_PORT_DNS_TCP=53
HOSTNAME=env-pod
SHLVL=1
HOME=/root
KUBE_DNS_SERVICE_HOST=10.96.0.10
KUBE_DNS_PORT_9153_TCP_ADDR=10.96.0.10
KUBE_DNS_PORT_9153_TCP_PORT=9153
KUBE_DNS_PORT_9153_TCP_PROTO=tcp
KUBE_DNS_SERVICE_PORT=53
KUBE_DNS_PORT=udp://10.96.0.10:53
POD_NAME=env-pod
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBE_DNS_SERVICE_PORT_METRICS=9153
KUBE_DNS_PORT_53_TCP_ADDR=10.96.0.10
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBE_DNS_PORT_9153_TCP=tcp://10.96.0.10:9153
KUBE_DNS_PORT_53_UDP_ADDR=10.96.0.10
KUBE_DNS_PORT_53_TCP_PORT=53
KUBE_DNS_PORT_53_TCP_PROTO=tcp
KUBE_DNS_PORT_53_UDP_PORT=53
KUBE_DNS_SERVICE_PORT_DNS=53
KUBE_DNS_PORT_53_UDP_PROTO=udp
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
POD_NAMESPACE=kube-system
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
KUBE_DNS_PORT_53_TCP=tcp://10.96.0.10:53
KUBE_DNS_PORT_53_UDP=udp://10.96.0.10:53
[root@master1 ~]#

[root@master1 ~]# kubectl logs env-pod -nkube-system|grep POD
POD_IP=10.244.2.10
POD_NAME=env-pod
POD_NAMESPACE=kube-system
[root@master1 ~]#


[root@master1 ~]# kubectl logs -f  env-pod -nkube-system #我淦,这个-f参数有什么区别吗?
POD_IP=10.244.2.10
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBE_DNS_SERVICE_PORT_DNS_TCP=53
HOSTNAME=env-pod
SHLVL=1
HOME=/root
KUBE_DNS_SERVICE_HOST=10.96.0.10
KUBE_DNS_PORT_9153_TCP_ADDR=10.96.0.10
KUBE_DNS_PORT_9153_TCP_PORT=9153
KUBE_DNS_PORT_9153_TCP_PROTO=tcp
KUBE_DNS_SERVICE_PORT=53
KUBE_DNS_PORT=udp://10.96.0.10:53
POD_NAME=env-pod
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBE_DNS_SERVICE_PORT_METRICS=9153
KUBE_DNS_PORT_53_TCP_ADDR=10.96.0.10
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBE_DNS_PORT_9153_TCP=tcp://10.96.0.10:9153
KUBE_DNS_PORT_53_UDP_ADDR=10.96.0.10
KUBE_DNS_PORT_53_TCP_PORT=53
KUBE_DNS_PORT_53_TCP_PROTO=tcp
KUBE_DNS_PORT_53_UDP_PORT=53
KUBE_DNS_SERVICE_PORT_DNS=53
KUBE_DNS_PORT_53_UDP_PROTO=udp
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
POD_NAMESPACE=kube-system
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
KUBE_DNS_PORT_53_TCP=tcp://10.96.0.10:53
KUBE_DNS_PORT_53_UDP=udp://10.96.0.10:53
[root@master1 ~]#
image-20211107222147427
image-20211107222147427

我们可以看到 Pod 的 IP、NAME、NAMESPACE 都通过环境变量打印出来了。

这里需要注意下:pod的状态变化

这一片估计是健康检查在其作用。。。。

image-20211107222253044
image-20211107222253044
image-20211107222341606
image-20211107222341606

环境变量

上面打印 Pod 的环境变量可以看到有很多内置的变量,其中大部分是系统自动为我们添加的,Kubernetes 会把当前命名空间下面的 Service 信息通过环境变量的形式注入到 Pod 中去

[root@master1 ~]#kubectl get svc -nkube-system
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   7d14h
[root@master1 ~]#

2.Volume 挂载

Downward API除了提供环境变量的方式外,还提供了通过 Volume 挂载的方式去获取 Pod 的基本信息。接下来我们通过Downward API将 Pod 的 Label、Annotation 等信息通过 Volume 挂载到容器的某个文件中去,然后在容器中打印出该文件的值来验证,对应的资源清单文件如下所示:


==:heart:实验测试:==

[root@master1 ~]#vim volume-pod.yaml

# volume-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: volume-pod
  namespace: kube-system
  labels:
    k8s-app: test-volume
    node-env: test
  annotations:
    own: youdianzhishi
    build: test
spec:
  volumes:
  - name: podinfo
    downwardAPI:
      items:
      - path: labels
        fieldRef:
          fieldPath: metadata.labels
      - path: annotations
        fieldRef:
          fieldPath: metadata.annotations
  containers:
  - name: volume-pod
    image: busybox
    args:
    - sleep
    - "3600"
    volumeMounts:
    - name: podinfo
      mountPath: /etc/podinfo

我们将元数据 labels 和 annotaions 以文件的形式挂载到了 /etc/podinfo 目录下,创建上面的 Pod:

[root@master1 ~]#kubectl apply -f volume-pod.yaml
pod/volume-pod created
[root@master1 ~]#

创建成功后,我们可以进入到容器中查看元信息是不是已经存入到文件中了:

[root@master1 ~]#kubectl exec -it volume-pod   -nkube-system  -- sh
# cd /etc/podinfo/
/etc/podinfo # ls -l
total 0
lrwxrwxrwx    1 root     root            18 Nov  7 14:41 annotations -> ..data/annotations
lrwxrwxrwx    1 root     root            13 Nov  7 14:41 labels -> ..data/labels
/etc/podinfo # cat labels
k8s-app="test-volume"
node-env="test"/etc/podinfo #
/etc/podinfo # cat annotations
build="test"
kubectl.kubernetes.io/last-applied-configuration="{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{\"build\":\"test\",\"own\":\"youdianzhishi\"},\"labels\":{\"k8s-app\":\"test-volume\",\"node-env\":\"test\"},\"name\":\"volume-pod\",\"namespace\":\"kube-system\"},\"spec\":{\"containers\":[{\"args\":[\"sleep\",\"3600\"],\"image\":\"busybox\",\"name\":\"volume-pod\",\"volumeMounts\":[{\"mountPath\":\"/etc/podinfo\",\"name\":\"podinfo\"}]}],\"volumes\":[{\"downwardAPI\":{\"items\":[{\"fieldRef\":{\"fieldPath\":\"metadata.labels\"},\"path\":\"labels\"},{\"fieldRef\":{\"fieldPath\":\"metadata.annotations\"},\"path\":\"annotations\"}]},\"name\":\"podinfo\"}]}}\n"
kubernetes.io/config.seen="2021-11-07T22:41:51.934064864+08:00"
kubernetes.io/config.source="api"
own="youdianzhishi"/etc/podinfo #

我们可以看到 Pod 的 Labels 和 Annotations 信息都被挂载到 /etc/podinfo 目录下面的 lables 和 annotations 文件了。

注意:

我们可以看到annotations里面还有一些其他的信息,这个是pod启动自动生成的一些信息;

目前,Downward API 支持的字段已经非常丰富了,比如:

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

注意

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

在实际应用中,如果你的应用有获取 Pod 的基本信息的需求,一般我们就可以利用Downward API来获取基本信息,然后编写一个启动脚本或者利用initContainer将 Pod 的信息注入到我们容器中去,然后在我们自己的应用中就可以正常的处理相关逻辑了。

除了通过 Downward API 可以获取到 Pod 本身的信息之外,其实我们还可以通过映射其他资源对象来获取对应的信息比如 Secret、ConfigMap 资源对象,同样我们可以通过环境变量和挂载 Volume 的方式来获取他们的信息,但是,通过环境变量获取这些信息的方式,不具备自动更新的能力所以,一般情况下,都建议使用 Volume 文件的方式获取这些信息,因为通过 Volume 的方式挂载的文件在 Pod 中会进行热更新。

  • 注意:downwars API的应用场景

阳总说的:

比如说你的一个pod,把你的日志输出到一个文件中去,然后你要去采集日志的时候,如果你的多个pod都给他输出,都给他挂载到同一个地方的话,那么它挂载的同样一个日志是不是有可能冲突啊。

这个时候,最好的方式,是不是就是把每一个pod给他输出到不同的文件或文件夹当中去,那么这个时候,我们就可以获取到pod本身的名称,然后根据pod名称去创建一个日志文件,给他们区分开,这个方式是不是很可以的。

注意事项

1.注意:label和annotations的区别

# volume-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: volume-pod
  namespace: kube-system
  labels:
    k8s-app: test-volume
    node-env: test
  annotations:
    own: youdianzhishi
    build: test

annotations就是注解;

1.label更多用于开发 人员和我们运维人员,对使用k8s人员来说的,用于来标记的;

2.annotations更多是程序用来读取资源对象时来使用的;

关于我

我的博客主旨:我希望每一个人拿着我的博客都可以做出实验现象,先把实验做出来,然后再结合理论知识更深层次去理解技术点,这样学习起来才有乐趣和动力。并且,我的博客内容步骤是很完整的,也分享源码和实验用到的软件,希望能和大家一起共同进步!

各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人免费帮您解决问题:

  1. 个人微信二维码:x2675263825 (舍得), qq:2675263825。

    image-20211002091450217
    image-20211002091450217
  2. 个人博客地址:www.onlyonexl.cn

    image-20211002092057988
    image-20211002092057988
  3. 个人微信公众号:云原生架构师实战

    image-20211002141739664
    image-20211002141739664
  4. 个人csdn

    https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421

    image-20211002092344616
    image-20211002092344616

最后

​ 好了,关于pod使用进阶实验就到这里了,感谢大家阅读,最后贴上我女神的photo,祝大家生活快乐,每天都过的有意义哦,我们下期见!

image-20210922123505950
image-20210922123505950

舍得

2021/11/09  阅读:38  主题:绿意

作者介绍

舍得