Downward API

本文详细介绍了Kubernetes的Downward API,包括如何通过环境变量和volume挂载将pod信息注入容器,以及如何获取pod的元数据如labels和annotations。此外,还提到了podpreset功能,用于自动填充pod字段,以及时间同步的方法。

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

downwardAPI提供了两种方式用于将pod的信息注入到容器内部:

环境变量: 用于单个变量,可以将pod信息和容器信息直接注入容器内部

volume挂载:将pod信息生成为文件,直接挂载到容器内部中去

环境变量

我们通过downwardAPI来讲pod的ip,名称以及所对应的namespace注入到容器的环境变量中去,然后再容器中打印全部的环境变量来进行验证

[root@master1 ~]# cat  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"]
      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创建之前就已经定下来的,所以我们可以使用metadata就可获取到,但是对于pod的IP则不一样,因为我们知道pod ip是不固定的,pod重建了就变了,它属于状态数据,所以我们使用status这个属性去获取,另外出了使用fieldRef获取pod的基本信息,还通过resourceFieldRef去获取容器的资源请求和资源限制信息。

 kubectl  create -f   env-pod.yaml

kubectl  logs  env-pod  -n  kube-system | grep  POD

kubectl  logs  -f  env-pod  -n  kube-system

[root@master1 ~]# kubectl    logs env-pod -n  kube-system 
POD_IP=10.244.2.38
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT=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
KUBE_DNS_PORT_53_TCP_ADDR=10.96.0.10
KUBERNETES_PORT_443_TCP_PORT=443
KUBE_DNS_SERVICE_PORT_METRICS=9153
KUBE_DNS_PORT_9153_TCP=tcp://10.96.0.10:9153
KUBERNETES_PORT_443_TCP_PROTO=tcp
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

我们可以看到pod 的ip ,name,namespace都通过环境变量打印出来的

kubectl  get svc  -n kube-system

 volume挂载

downward API除了提供环境变量方式外,还提供通过volume挂载的方式去获取pod的基本信息,接下来通过 downward API将pod的label,annotation等信息通过volume挂载到容器的某个文件中去,然后在容器中打印机出的值来验证的,对应的资源清单

apiVersion: v1
kind: Pod
metadata:
  name: volume-pod
  namespace: kube-system
  labels:
    k8s-app: test-volume
    node-env: test
  annotations:
    own: wangmuniangniang
    bulid: test
spec:
  volumes:
  - name: podinfo
    downwardAPI:
        items:
        - path: labels
          fieldRef:
            fieldPath: metadata.annotations
        - path: anntations
          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   exec  -it  volume-pod   /bin/sh  -n  kube-system
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # ls  /etc/podinfo/
anntations  labels
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var
/ # cat  /etc/podinfo/labels 
bulid="test"
kubernetes.io/config.seen="2022-04-27T03:23:02.840574876-04:00"
kubernetes.io/config.source="api"
own="wangmuniangniang"/ # ^C
/ # 

可以看到pod的labels和annotations信息都被挂载到/etc/podinfo目录下面lables和annotations文件了  目前downwardAPI支持的字段已经非常丰富了

DownwardAPI支持的字段已经非常丰富了,比如
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的label值
metadata.annotations 指定key的annotation值
metadata.labels pod的所有label
mwetadata.annotations pod的所有的annotation
使用 resourceFieldRef可以声明使用
 容器cpu  limit  cpu  requesr  memory  limit   memory  request

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

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

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

podpreset

我们已经学些了很多pod的知识点,但是可能有部分同学还觉得pod的字段属性太多了。kubernetes能提供一个功能为pod自动填充一些字段呢,这个需求还是很实际的,

kubernetes版本后提供了一个叫做podpreset的功能可以解决

 kubernetes提供了一个podpreset准入控制器,当启用后,podpreset会将应用创建请求传入到该控制器上,当有pod创建请求时,系统将执行一下操作。

检索所有可用的podpreset

检查有podpreset的标签选择器上的标签与正在创建的pod的标签是否匹配

尝试将有podpreset定义的各种资源合并到正在创建的pod中

出现错误时,该pod上引发记录合并错误的时间,podPreset不会注入任何资源到创建的pod中

注释刚生成的修改过的pod  spec以表明她已被podprese修改过,

每个pod可以匹配podPres、et并且每个podpreset可以应用于多个pod,podpreset应用于kubernetes会修改pod spec,对于env,envfrom和volumeMounts的修改,kubernetes修改pod中所有容器的spec,对于volume的更改,kubernetes修改pod spec

启用podpreset

要启用podpreset功能,需要确保你使用的是kubernetes1.8以上版本,然后需要准入控制中加入podpreset

我们经常有一个需求是同步pod和宿主机的时间,一般情况下,我们是通过挂载宿主机的localtime来完成的

[root@master1 ~]# cat  time-demo.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: time-demo
  labels:
    app: time
spec:
   containers:
   - name: time-demo
     image: nginx
     ports: 
     - containerPort: 80

我们可以看到pod的时间和nodes时间是不一样的,这时候我们可以挂载主机的localtime文件到pod中去

[root@master1 ~]# cat  time-demo.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: time-demo
  labels:
    app: time
spec:
   volumes:
   - name: host-time
     hostPath:
       path: /etc/localtime
   containers:
   - name: time-demo
     image: nginx
     volumeMounts:
     - name: host-time
       mountPath: /etc/localtime
     ports: 
     - containerPort: 80

此时pod就和node的时间一样了。但是往往我们素有的pod都有时间同步的需要,如果所有pod都挂载太麻烦,这个时候可以使用PodPreset来预设模板


[root@master1 ~]# cat time-preset.yaml 
apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: time-preset
  namespace: default
spec: 
  selector:
    mathLables:
  volumeMounts:
  - name: localtime
    mountPath: /etc/localtime
  volumes:
  - name: localtime
    hostPath:
      path: /etc/localtime

在此之前我们需要修改apiVersion的参数 

/etc/kubernetes/manifests/kube-apiserver.yaml 修改完移动一下kube-apiversion.yaml文件,相当于强制启动

root@master1 ~]# cat  /etc/kubernetes/manifests/kube-apiserver.yaml 

apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 192.168.1.126:6443
  creationTimestamp: null
  labels:
    component: kube-apiserver
    tier: control-plane
  name: kube-apiserver
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-apiserver
    - --advertise-address=192.168.1.126
    - --allow-privileged=true
    - --authorization-mode=Node,RBAC
    - --client-ca-file=/etc/kubernetes/pki/ca.crt
    - --enable-admission-plugins=NodeRestriction
    - --enable-bootstrap-token-auth=true
    - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
    - --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
    - --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
    - --etcd-servers=https://127.0.0.1:2379
    - --insecure-port=0
    - --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
    - --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key
    - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
    - --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
    - --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
    - --requestheader-allowed-names=front-proxy-client
    - --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
    - --requestheader-extra-headers-prefix=X-Remote-Extra-
    - --requestheader-group-headers=X-Remote-Group
    - --requestheader-username-headers=X-Remote-User
    - --secure-port=6443
    - --service-account-key-file=/etc/kubernetes/pki/sa.pub
    - --service-cluster-ip-range=10.96.0.0/12
    - --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
    - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
    - --enable-admission-plugins=NodeRestriction,PodPreset  //新加的这两行
    - --runtime-config=settings.k8s.io/v1alpha1=true // 新加的这两行
    image: registry.aliyuncs.com/google_containers/kube-apiserver:v1.19.0
    imagePullPolicy: IfNotPresent
    livenessProbe:
      failureThreshold: 8
      httpGet:
        host: 192.168.1.126
        path: /livez
        port: 6443
        scheme: HTTPS
      initialDelaySeconds: 10
      periodSeconds: 10
      timeoutSeconds: 15
    name: kube-apiserver
    readinessProbe:
      failureThreshold: 3
      httpGet:
        host: 192.168.1.126
        path: /readyz
        port: 6443
        scheme: HTTPS
      periodSeconds: 1
      timeoutSeconds: 15
    resources:
      requests:
        cpu: 250m
    startupProbe:
      failureThreshold: 24
      httpGet:
        host: 192.168.1.126
        path: /livez
        port: 6443
        scheme: HTTPS
      initialDelaySeconds: 10
      periodSeconds: 10
      timeoutSeconds: 15
    volumeMounts:
    - mountPath: /etc/ssl/certs
      name: ca-certs
      readOnly: true
    - mountPath: /etc/pki
      name: etc-pki
      readOnly: true
    - mountPath: /etc/kubernetes/pki
      name: k8s-certs
      readOnly: true
  hostNetwork: true
  priorityClassName: system-node-critical
  volumes:
  - hostPath:
      path: /etc/ssl/certs
      type: DirectoryOrCreate
    name: ca-certs
  - hostPath:
      path: /etc/pki
      type: DirectoryOrCreate
    name: etc-pki
  - hostPath:
      path: /etc/kubernetes/pki
      type: DirectoryOrCreate
    name: k8s-certs
status: {}

 这种就是开启的

验证一下pod的状态

 kubectl  get  pods  -l  app=time  筛选一下podname

 可以看到pod和node的时间是一致的 

[root@master1 ~]# kubectl   get pod  time-demo  -o yaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{"app":"time"},"name":"time-demo","namespace":"default"},"spec":{"containers":[{"image":"nginx","name":"time-demo","ports":[{"containerPort":80}],"volumeMounts":[{"mountPath":"/etc/localtime","name":"host-time"}]}],"volumes":[{"hostPath":{"path":"/etc/localtime"},"name":"host-time"}]}}
  creationTimestamp: "2022-04-28T09:19:55Z"
  labels:
    app: time
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .: {}
          f:kubectl.kubernetes.io/last-applied-configuration: {}
        f:labels:
          .: {}
          f:app: {}
      f:spec:
        f:containers:
          k:{"name":"time-demo"}:
            .: {}
            f:image: {}
            f:imagePullPolicy: {}
            f:name: {}
            f:ports:
              .: {}
              k:{"containerPort":80,"protocol":"TCP"}:
                .: {}
                f:containerPort: {}
                f:protocol: {}
            f:resources: {}
            f:terminationMessagePath: {}
            f:terminationMessagePolicy: {}
            f:volumeMounts:
              .: {}
              k:{"mountPath":"/etc/localtime"}:
                .: {}
                f:mountPath: {}
                f:name: {}
        f:dnsPolicy: {}
        f:enableServiceLinks: {}
        f:restartPolicy: {}
        f:schedulerName: {}
        f:securityContext: {}
        f:terminationGracePeriodSeconds: {}
        f:volumes:
          .: {}
          k:{"name":"host-time"}:
            .: {}
            f:hostPath:
              .: {}
              f:path: {}
              f:type: {}
            f:name: {}
    manager: kubectl-client-side-apply
    operation: Update
    time: "2022-04-28T09:19:55Z"
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:status:
        f:conditions:
          k:{"type":"ContainersReady"}:
            .: {}
            f:lastProbeTime: {}
            f:lastTransitionTime: {}
            f:status: {}
            f:type: {}
          k:{"type":"Initialized"}:
            .: {}
            f:lastProbeTime: {}
            f:lastTransitionTime: {}
            f:status: {}
            f:type: {}
          k:{"type":"Ready"}:
            .: {}
            f:lastProbeTime: {}
            f:lastTransitionTime: {}
            f:status: {}
            f:type: {}
        f:containerStatuses: {}
        f:hostIP: {}
        f:phase: {}
        f:podIP: {}
        f:podIPs:
          .: {}
          k:{"ip":"10.244.1.43"}:
            .: {}
            f:ip: {}
        f:startTime: {}
    manager: kubelet
    operation: Update
    time: "2022-04-28T09:20:14Z"
  name: time-demo
  namespace: default
  resourceVersion: "239546"
  selfLink: /api/v1/namespaces/default/pods/time-demo
  uid: c0f154d6-e20f-48b9-a787-bdaadcec6249
spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: time-demo
    ports:
    - containerPort: 80
      protocol: TCP
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /etc/localtime
      name: host-time
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: default-token-sbhsk
      readOnly: true
  dnsPolicy: ClusterFirst
  enableServiceLinks: true
  nodeName: node1
  preemptionPolicy: PreemptLowerPriority
  priority: 0
  restartPolicy: Always
  schedulerName: default-scheduler
  securityContext: {}
  serviceAccount: default
  serviceAccountName: default
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  volumes:
  - hostPath:
      path: /etc/localtime
      type: ""
    name: host-time
  - name: default-token-sbhsk
    secret:
      defaultMode: 420
      secretName: default-token-sbhsk
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: "2022-04-28T09:19:55Z"
    status: "True"
    type: Initialized
  - lastProbeTime: null
    lastTransitionTime: "2022-04-28T09:20:14Z"
    status: "True"
    type: Ready
  - lastProbeTime: null
    lastTransitionTime: "2022-04-28T09:20:14Z"
    status: "True"
    type: ContainersReady
  - lastProbeTime: null
    lastTransitionTime: "2022-04-28T09:19:55Z"
    status: "True"
    type: PodScheduled
  containerStatuses:
  - containerID: docker://c92926918312220c9dc2360244d8b72a1e3452c54f36179b775c8b46f6dab73f
    image: nginx:latest
    imageID: docker-pullable://nginx@sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
    lastState: {}
    name: time-demo
    ready: true
    restartCount: 0
    started: true
    state:
      running:
        startedAt: "2022-04-28T09:20:14Z"
  hostIP: 192.168.1.127
  phase: Running
  podIP: 10.244.1.43
  podIPs:
  - ip: 10.244.1.43
  qosClass: BestEffort
  startTime: "2022-04-28T09:19:55Z"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值