深入剖析Kubernetes--第五章:声明式API与Kubernetes编程范式

声明式API与Kubernetes编程范式

Istio项目

Dynamic Admission Control

在 Kubernetes 项目中,当一个 Pod 或者任何一个 API 对象被提交给 APIServer 之后,在K8S项目正式处理之前会通过 项目里一组被称为 Admission Controller 的代码实现 Admission 的功能 来 进行一些初始化工作(如自动为所有 Pod 加上某些标签(Labels)。)

如果想要添加一些自己的规则到 Admission Controller(需要重新编译并重启 APIServer)。

所以,k8s提供了一种**“热插拔”**式的 Admission 机制,它就是 Dynamic Admission Control,也叫作:Initializer

用户提交的Pod中只有一个容器:myapp-pod

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']

Istio 项目要做的,就是在这个 Pod YAML 被提交给 Kubernetes 之后,在它对应的 API 对象里自动加上 Envoy 容器的配置,使这个对象变成如下所示的样子:

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
  - name: envoy
    image: lyft/envoy:845747b88f102c0fd262ab234308e9e22f693a1
    command: ["/usr/local/bin/envoy"]
    ...

如何做到呢

Istio 编写一个用来为 Pod“自动注入”Envoy 容器的 Initializer。

Istio 会将这个 Envoy 容器本身的定义,以 ConfigMap 的方式保存在 Kubernetes 当中。

apiVersion: v1
kind: ConfigMap
metadata:
  name: envoy-initializer
data:
  config: |
    containers:
      - name: envoy
        image: lyft/envoy:845747db88f102c0fd262ab234308e9e22f693a1
        command: ["/usr/local/bin/envoy"]
        args:
          - "--concurrency 4"
          - "--config-path /etc/envoy/envoy.json"
          - "--mode serve"
        ports:
          - containerPort: 80
            protocol: TCP
        resources:
          limits:
            cpu: "1000m"
            memory: "512Mi"
          requests:
            cpu: "100m"
            memory: "64Mi"
        volumeMounts:
          - name: envoy-conf
            mountPath: /etc/envoy
    volumes:
      - name: envoy-conf
        configMap:
          name: envoy

Initializer 需要把envoy的相关字段merge到用户提交的Pod内容中,(使用PATCH API实现,时声明式API的主要能力)

Istio 将一个编写好的 Initializer,作为一个 Pod 部署在 Kubernetes 中

apiVersion: v1
kind: Pod
metadata:
  labels:
    app: envoy-initializer
  name: envoy-initializer
spec:
  containers:
    - name: envoy-initializer
      image: envoy-initializer:0.0.1
      imagePullPolicy: Always

envoy-initializer:0.0.1 镜像,就是一个事先编写好的“自定义控制器”(Custom Controller)

功能:

for {
  // 获取新创建的 Pod
  pod := client.GetLatestPod()
  // Diff 一下,检查是否已经初始化过
  if !isInitialized(pod) {
    // 没有?那就来初始化一下
    doSomething(pod)
  }
}
//在 Initializer 控制器的工作逻辑里,它首先会从 APIServer 中拿到这个 ConfigMap
//把这个 ConfigMap 里存储的 containers 和 volumes 字段,直接添加进一个空的 Pod 对象里:
//Kubernetes 的 API 库,为我们提供了一个方法,使得我们可以直接使用新旧两个 Pod 对象,生成一个 TwoWayMergePatch
func doSomething(pod) {
  cm := client.Get(ConfigMap, "envoy-initializer")
 
  newPod := Pod{}
  newPod.Spec.Containers = cm.Containers
  newPod.Spec.Volumes = cm.Volumes
 
  // 生成 patch 数据
  patchBytes := strategicpatch.CreateTwoWayMergePatch(pod, newPod)
 
  // 发起 PATCH 请求,修改这个 pod 对象
  client.Patch(pod.Name, patchBytes)
}

Kubernetes 还允许你通过配置,来指定要对什么样的资源进行这个 Initialize 操作

apiVersion: admissionregistration.k8s.io/v1alpha1
kind: InitializerConfiguration
metadata:
  name: envoy-config
initializers:
  // 这个名字必须至少包括两个 "."
  - name: envoy.initializer.kubernetes.io
    rules:
      - apiGroups:
          - "" // 前面说过, "" 就是 core API Group 的意思
        apiVersions:
          - v1
        resources:
          - pods

一旦这个 InitializerConfiguration 被创建,Kubernetes 就会把这个 Initializer 的名字,加在所有新创建的 Pod 的 Metadata 上

apiVersion: v1
kind: Pod
metadata:
  initializers:
    pending:
      - name: envoy.initializer.kubernetes.io
  name: myapp-pod
  labels:
    app: myapp
...

每一个新创建的 Pod,都会自动携带了 metadata.initializers.pending 的 Metadata 信息

这个 Metadata,正是接下来 Initializer 的控制器判断这个 Pod 有没有执行过自己所负责的初始化操作的重要依据

当在 Initializer 里完成了要做的操作后,一定要metadata.initializers.pending 标志清除掉。

声明式API的工作原理

总结

K8s中,一个API对象在etcd中完整的路径是由Group(API组)、Version(API版本)、Resource(API资源类型)3个部分决定的。

核心 API 对象

对于 Kubernetes 里的核心 API 对象,比如:Pod、Node 等,是不需要 Group 的(即:它们

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值