Kubernetes學習筆記(七):訪問Pod元數據與Kubernetes API

Downward API

我們已經了解到,使用ConfigMap和Secret嚮應用傳遞配置數據,這對於運行前預設的數據是可行的。但是對於那些不能預先知道的,就需要使用Downward API。

Downward API允許我們通過環境變量或者卷的方式嚮應用傳遞元數據。可傳遞的數據包括:Pod的IP、名稱、標籤、註解、所在命令空間、運行的節點名稱、運行所屬的ServiceAccountName,每個容器請求的CPU和內存使用量以及限制。

通過環境變量暴露元數據

env.valueFrom下引用Pod的字段使用fieldRef,引用容器的cpu和內存使用resourceFieldRef
對於暴露資源的請求和使用顯示的環境變量,我們通常會設置一個基數單位。實際的資源請求值和使用限制值除以這個基數單位,所得結果通過環境變量暴露出去。

# downward-env.yaml
apiVersion: v1
kind: Pod
metadata:
  name: downward-env
spec:
  containers:
    - name: alpine
      image: alpine
      command: ["sleep","999999"]
      resources:
        requests:
          cpu: 15m
          memory: 100Ki
        limits:
          cpu: 500m
          memory: 100Mi
      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
      - name: NODE_NAME
        valueFrom:
          fieldRef:
            fieldPath: spec.nodeName
      - name: SERVICE_ACCOUNT
        valueFrom:
          fieldRef:
            fieldPath: spec.serviceAccountName
      - name: CONTAINER_CPU_REQ_MILLICORES
        valueFrom:
          resourceFieldRef:
            resource: requests.cpu
            divisor: 1m
      - name: CONTAINER_MEMORY_LIMIT_KIBIBYTES
        valueFrom:
          resourceFieldRef:
            resource: limits.memory
            divisor: 1Ki

查看一下環境變量

-> [[email protected]] [~] k create -f downward-env.yaml
pod/downward-env created

-> [[email protected]] [~] k exec downward-env env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=downward-env
POD_NAME=downward-env
POD_NAMESPACE=default
POD_IP=10.244.1.24
NODE_NAME=kube1.vm
SERVICE_ACCOUNT=default
CONTAINER_CPU_REQ_MILLICORES=15
CONTAINER_MEMORY_LIMIT_KIBIBYTES=102400

通過Downward卷傳遞元數據

使用downward卷的方式傳遞元數據,當Pod的標籤和註解修改後,Kubernetes會更新存有相關信息的文件。而環境變量方式下,新值無法暴露。

該描述文件定義了一個downward類型的卷,掛載到容器的/tmp/downward。卷中包含的內容是用downwardAPI.items定義的。

# downward-volume.yaml
apiVersion: v1
kind: Pod
metadata:
  name: downward-volume
  labels:
    foo: bar
  annotations:
    key1: value1
    key2: |
      multi
      line
      value
spec:
  containers:
    - name: alpine
      image: alpine
      command: ["sleep","999999"]
      resources:
        requests:
          cpu: 15m
          memory: 100Ki
        limits:
          cpu: 500m
          memory: 100Mi
      volumeMounts:
      - name: downward
        mountPath: /tmp/downward
  volumes:
  - name: downward
    downwardAPI:
      items:
      - path: "podName"
        fieldRef:
            fieldPath: metadata.name
      - path: "podNamespace"
        fieldRef:
            fieldPath: metadata.namespace
      - path: "labels"
        fieldRef:
            fieldPath: metadata.labels
      - path: "annotations"
        fieldRef:
            fieldPath: metadata.annotations
      - path: "containerCpuReqMillicores"
        resourceFieldRef:
          containerName: alpine
          resource: requests.cpu
          divisor: 1m
      - path: "containerMemoryLimitBytes"
        resourceFieldRef:
          containerName: alpine
          resource: limits.memory
          divisor: 1

創建查看

-> [[email protected]] [~] k create -f downward-volume.yaml
pod/downward-volume created

-> [[email protected]] [~] k exec downward-volume ls /tmp/downward
annotations
containerCpuReqMillicores
containerMemoryLimitBytes
labels
podName
podNamespace

與Kubernetes API服務器交互

DownwardAPI可以獲得當前Pod的部分元數據,但是無法獲得到其他的Pod的,以及一些集群中的其他資源信息。

Kubernetes REST API

先來查看集群信息,找到API服務器地址。然後 curl -k //192.168.199.117:6443 ,當然結果也是訪問受限的。

-> [[email protected]] [~] k cluster-info
Kubernetes master is running at //192.168.199.117:6443
KubeDNS is running at //192.168.199.117:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

所以我們通過 kubectl proxy 訪問API服務器。kubectl proxy啟動一個代理,接收來自本機的HTTP請求並驗證身份,轉發到API服務器。

-> [[email protected]] [~] k proxy
Starting to serve on 127.0.0.1:8001

新開一個窗口,訪問根路徑實時

-> [[email protected]] [~] curl //localhost:8001/
{
  "paths": [
    "/api",
    "/api/v1",
    "/apis",
    "/apis/",
............

從pod內部與API服務器交互

確定API服務器的地址

-> [[email protected]] [~] k get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   2d1h

或者從任意Pod查找服務的環境變量

-> [[email protected]] [~] k exec myalpine env|grep KUBERNETES_SERVICE
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_HOST=10.96.0.1

用一個有curl的鏡像啟動一個Pod

首先驗證服務器身份,定義CURL_CA_BUNDLE環境變量,省去每次都要 curl –cacert 指定證書

export CURL_CA_BUNDLE=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

其次獲得服務器授權:定義TOKEN

export TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)

繞過RBAC,賦予所有服務賬戶(也可以說所有pod)的集群管理員權限。

-> [[email protected]] [~] k create clusterrolebinding permissive-binding --clusterrole=cluster-admin --group=system:serviceaccounts
clusterrolebinding.rbac.authorization.k8s.io/permissive-binding created

訪問API服務器

$ curl -H "Authorization: Bearer $TOKEN" //kubernetes/
{
  "paths": [
    "/api",
    "/api/v1",
...........

獲取當前運行Pod所在的命名空間

export NS=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)

列出當前命名空間的Pods

$ curl -H "Authorization: Bearer $TOKEN" //kubernetes/api/v1/namespaces/$NS/pods
{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {
    "selfLink": "/api/v1/namespaces/default/pods",
    "resourceVersion": "454829"
..........

簡化與API服務器的交互

在Pod中,除了主容器外另起一個運行kubectl proxy的容器,這樣主容器就可以通過//127.0.0.1:8001/訪問API服務器了。

先構建鏡像,準備kubectl-proxy.sh和Dockerfile。

# kubectl-proxy.sh

#!/bin/sh

API_SERVER="//$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT"
CA_CRT="/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
TOKEN="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"

/kubectl proxy --server="$API_SERVER" --certificate-authority="$CA_CRT" --token="$TOKEN" --accept-paths='^.*'

myalpine就是一個安裝了curl的自製鏡像

# Dockerfile
FROM registry.cn-hangzhou.aliyuncs.com/orzi/myalpine
RUN curl -LO //storage.googleapis.com/kubernetes-release/release/v1.18.0/bin/linux/amd64/kubectl && chmod +x ./kubectl && mv ./kubectl /
COPY kubectl-proxy.sh /kubectl-proxy.sh
ENTRYPOINT ["/kubectl-proxy.sh"]

構建、推送

docker build -t registry.cn-hangzhou.aliyuncs.com/orzi/myalpine:kubeproxy .

docker push registry.cn-hangzhou.aliyuncs.com/orzi/myalpine:kubeproxy

描述文件

# mykubeproxy.yaml
apiVersion: v1
kind: Pod
metadata:
  name: mykubeproxy
spec:
  containers:
    - name: myalpine
      image: registry.cn-hangzhou.aliyuncs.com/orzi/myalpine
      command: ["sleep","999999"]
    - name: mykubeproxy
      image: registry.cn-hangzhou.aliyuncs.com/orzi/myalpine:kubeproxy

創建、查看

-> [[email protected]] [~] k create -f mykubeproxy.yaml
pod/mykubeproxy created

-> [[email protected]] [~] k exec -it mykubeproxy -c myalpine sh

$ curl //127.0.0.1:8001
{
  "paths": [
    "/api",
    "/api/v1",
    "/apis",
.......

小結

  • Downward API允許我們將不能預先知道的Pod元數據通過環境變量或者卷的方式傳遞給應用。
  • Downward API可傳遞的數據包括:Pod的IP、名稱、標籤、註解、所在命名空間、運行的節點名稱、運行所屬的ServiceAccountName,每個容器請求的CPU和內存的使用量和限制。
  • env.valueFrom下引用Pod的字段使用fieldRef,引用容器的cpu和內存使用resourceFieldRef
  • 對於暴露資源的請求和使用顯示的環境變量,我們通常會設置一個基數單位。實際的資源請求值和使用限制值除以這個基數單位,所得結果通過環境變量暴露出去。
  • 使用downward卷的方式傳遞元數據,當Pod的標籤和註解修改後,Kubernetes會更新存有相關信息的文件。而環境變量方式下,新值無法暴露。
  • 可以通過運行kubectl proxy後,在節點上訪問API服務器。也可以在Pod中另起一個專門運行kubectl proxy的容器,在主容器中訪問。