本文基于《Kubernetes in Action》第8章整理。

虽然k8s作为云基础设施,部署在其上的应用不应该感知到k8s的存在。但是业务场景千千万,总会碰到需要获取k8s元数据的情况。特此记录几种获取方式

Downward API

Downward API是通过环境变量或者文件的方式,将pod的元数据暴露给pod中的应用。可以传递给容器的数据包括

  • pod的名称
  • pod的IP
  • pod所在的命名空间
  • pod运行的节点名称
  • pod归属的服务账户的名称
  • 每个容器请求的CPU和内存的使用量
  • 每个容器请求的CPU和内存的限制
  • pod的标签
  • pod的注解

环境变量的方式示例

apiVersion:v1
kind: Pod
metadata:
  name: example
spec:
  containers:
  - name: my-container
    image: test-image
    command: ["sleep", "999999"]
    resources:
      requests:
        cpu: 250m
        memory: 520Mi
      limits:
        cpu: 1
        memory: 1Gi
    env:
    - name: POD_NAME
      valueFrom:
        fieldRef:
          fieldPath: metadata.name
    - name: CPU_REQUEST
      valueFrom:
        resourceFieldRef:  # CPU和内存使用量是引用resourceFieldRef
          resource: requests.cpu
          divisor: 1m

在配置CPU和memory相关的环境变量时,需要设置divisor,即基数单位。实际的环境变量的值是资源请求值除以这个基数单位。因此CPU_REQUEST的值,在这个例子中的值是250m / 1m = 250。对于cpu而言,请求量可以设置成1(表示1核),或者1m(表示千分之一核);内存可以设置成1(表示1字节),1K或1Ki,1M或者1Mi。

基于卷的方式示例

apiVersion:v1
kind: Pod
metadata:
  name: example
  labels:
    my-labels: test
spec:
  containers:
  - name: my-container
    image: test-image
    command: ["sleep", "999999"]
    resources:
      requests:
        cpu: 250m
        memory: 520Mi
      limits:
        cpu: 1
        memory: 1Gi
    volumeMounts:
    - name: downward
      mountPath: /etc/downward
  volumes:
  - name: downward
    downwardAPI:
      items:
      - path: "podName"
        fieldRef:
          fieldPath: metadata.name
      - path: CPU_REQUEST
    - name: CPU_REQUEST
        resourceFieldRef:  # CPU和内存使用量是引用resourceFieldRef
          resource: requests.cpu
          divisor: 1m
          containerName: my-container

downward卷是pod级别的,因此当要暴露容器级别的元数据时,需要指定容器名称。

基于卷和环境变量暴露元数据的区别

  1. 标签和注解只可以通过卷暴露。因为可以在pod运行时修改标签和注解,当更新后,k8s会更新存有相关信息的文件,从而让pod可以获取最新的数据,而环境变量的方式,新的值无法被暴露。
  2. 通过卷的方式,可以传递一个容器的资源字段到另一个容器。而环境变量方式,只能传递它自身资源的请求和限制信息。

与k8s API服务器交互

在节点上与API服务器交互

首先需要知道API服务器的地址,可以执行下面命令获取

kubectl cluster-info

从执行结果看,服务器使用的是HTTPS协议,因此需要对API服务器进行认证。当然在测试的时候可以通过curl的--insecure选项跳过对API服务器的认证,因此可以通过以下命令尝试访问API服务器

curl https://<K8S-API-HOST>:<K8S-API-PORT> -k # 注意替换变量

但是服务器会返回Unauthorized,因为服务器需要对我们进行认证和鉴权

不过,我们可以启动一个代理服务器,封装所有这些安全认证操作,我们只需要和代理服务器交互即可。启动代理服务的方式如下

$ kubectl proxy
Starting to serve on 127.0.0.1:8001

可以通过以下命令访问API服务器

curl localhost:8001

此时,服务器会返回一组路径的清单。当尝试请求这些路径时,会发现返回体一般有两种kind,分别是APIGroup和APIResourceList。但返回的kind=APIGroup时,返回的信息主要是PAI版本信息;当返回的kind=APIResourceList时,返回的是这个API版本下包含的资源信息,以及REST请求的相关信息。

在pod内部访问API服务器

如上面说到的,要想和API服务器交互,需要双向认证。因此我们需要一个可信任的CA证书认证API服务器,我们也需要提供一个TOKEN,让API服务器进行认证和鉴权。

k8s中有一个name=kubernetes的服务,指向的就是API服务器。

对于每个pod而言,都有一个ServiceAccount,其本身就是用于和k8s API服务器进行交互的。ServiceAccount会关联一个secret,这个secret包含ca.crt,namespace,token三项内容,并挂载到
/var/run/secrets/kubernetes.io/serviceaccount目录下。

ca.crt包含了CA的证书,用于对API服务器证书进行认证。token是用来获取API服务器的授权。因此可以通过下面的形式和API服务器进行交互

TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -H "Authorization: Bearer $TOKEN" https://kubernetes

其他优化方法

可以在pod中多部署一个容器,在这个容器中运行kubectl proxy命令,通过它来实现与API服务器的交互。因此,主容器中就可以直接和这个proxy容器交互,免去了繁琐的安全认证操作

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐