前面我们从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"