Kubernetes Initializer功能的使用方法:在Pod等Resource落地前进行修改

作者:李佶澳  更新时间:2019-01-12 14:38:18 +0800

  技巧    kubernetes    刷新

目录

说明

在研究通过LXCFS,在容器内显示容器的CPU、内存状态的时候,遇到了Kubernetes Initializers,学习一下。

注意Kubernetes InitializersKubernetes Init Containers是不同的,前者可以修改Pod的定义,后者是在Pod中正式容器启动前,进行一些准备工作。两者发生作用的时机也不一样。

用途

Kubernetes Initializers可以在pod/的pending阶段对pod进行修改,譬如注入新的容器、挂载volume等。

例如通过LXCFS,在容器内显示容器的CPU、内存状态中,就是用Initializer的方式,为每个pod自动挂载了lxcfs维护的/proc文件。

Initializer功能开启

在Kubernetes 1.13中initializers还是一个alpha特性,需要在Kube-apiserver中添加参数开启。

这里使用的是kubernets 1.12,设置方法是一样的:

--enable-admission-plugins="Initializers,NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota"
--runtime-config=admissionregistration.k8s.io/v1alpha1

--enable-admission-plugins--admission-control互斥,如果同时设置,kube-apiserver启动报错:

error: [admission-control and enable-admission-plugins/disable-admission-plugins flags are mutually exclusive, 
enable-admission-plugins plugin "--runtime-config=admissionregistration.k8s.io/v1alpha1" is unknown]

InitializerConfiguration

InitializerConfiguration资源中定义了一组的initializers

每个initializer有一个名字和多个规则,规则中是它要作用的资源,例如下面的initializers中只有一个initializer,名称为podimage.example.com,作用于v1版本的pods。


apiVersion: admissionregistration.k8s.io/v1alpha1
kind: InitializerConfiguration
metadata:
  name: example-config
initializers:
  # the name needs to be fully qualified, i.e., containing at least two "."
  - name: podimage.example.com
    rules:
      # apiGroups, apiVersion, resources all support wildcard "*".
      # "*" cannot be mixed with non-wildcard.
      - apiGroups:
          - ""
        apiVersions:
          - v1
        resources:
          - pods

在kubernets中创建了上面的initializers之后,新建的pod在pending阶段,metadata中会添加一个initializer列表:

  metadata:
    creationTimestamp: 2019-01-09T08:56:36Z
    generateName: echo-7cfbbd7d49-
    initializers:
      pending:
      - name: podimage.example.com

注意需要加上参数--include-uninitialized=true才能看到处于这个阶段的Pod:

 ./kubectl.sh -n demo-echo get pod --include-uninitialized=true -o yaml

metadata中initializers列表不为空的Pod,处于正在等待初始化状态,需要部署一个initializer controller对处于这个阶段中的pod完成初始化后, pod才能退出pending状态。。

initializer controller需要自己根据需要实现。

Initializer Controller

initializer controller监听指定类型的resource,当发现有新创建的resouce创建时,通过检查resource的metadata中的initializer名单,决定是否要对resource进行初始化设置,并且在完成设置之后,需要将对应的initializer名单从resource的metadata中删除,否则resource就一直处于等待初始化设置的状态。

具体实现可以参考lxcfs-initializer

如果有多个InitializerConfiguration和多个Initializer Controller,会怎样?

没有在文档中找到具体的说明,k8s的文档中Initializer章节的内容很少,这里通过实验,判断一下。

创建了两个不同名的但是包含相同rule的InitializerConfiguration:

apiVersion: admissionregistration.k8s.io/v1alpha1
kind: InitializerConfiguration
metadata:
  name: example-config
initializers:
  # the name needs to be fully qualified, i.e., containing at least two "."
  - name: podimage.example.com
    rules:
      # apiGroups, apiVersion, resources all support wildcard "*".
      # "*" cannot be mixed with non-wildcard.
      - apiGroups:
          - ""
        apiVersions:
          - v1
        resources:
          - pods

apiVersion: admissionregistration.k8s.io/v1alpha1
kind: InitializerConfiguration
metadata:
  name: example-config-2
initializers:
  # the name needs to be fully qualified, i.e., containing at least two "."
  - name: podimage-2.example.com rules:
      # apiGroups, apiVersion, resources all support wildcard "*".
      # "*" cannot be mixed with non-wildcard.
      - apiGroups:
          - ""
        apiVersions:
          - v1
        resources:
          - pods
  - name: podimage.example.com
    rules:
      # apiGroups, apiVersion, resources all support wildcard "*".
      # "*" cannot be mixed with non-wildcard.
      - apiGroups:
          - ""
        apiVersions:
          - v1
        resources:
          - pods

Pod中的metadata是这样的:

  metadata:
    creationTimestamp: 2019-01-10T04:03:12Z
    generateName: echo-7cfbbd7d49-
    initializers:
      pending:
      - name: podimage.example.com
      - name: podimage-2.example.com
      - name: podimage.example.com

之后又通过调整InitializerConfiguration的名称排序、创建的先后顺序、内部的rules的顺序,多次试验之后发现,多个InitializerConfiguration的在metadata中是按照它们的名称排序的,和创建时间无关。

每个InitializerConfiguration中的rules在metadata中顺序与它们定义的顺序一致。

根据lxcfs-initializer的实现以及k8s的文档,Initializer Controller对目标Resource完成设置之后,需要从metadata中移除对应的Initializer。

如果定义了多个Initializer,并且有多个Initializer Controller各自负责不同的Initializer,这时候需要小心设计,既要防止“漏掉”应当处理的Resource,导致Resource长期不落地,又要防止已经被删除的Initializer又被重新写上了,重复处理时出现错误。

根据现在掌握的信息,目前比较稳妥的做法是,将多个Initializer设计为顺序无关,谁先执行都可以,否则只有创建一个InitializerConfiguration,rules的顺序就是Initiliazer的顺序。只设计一个Initializer Controller,或者将多个Initializer Controller设计成串行执行,让它们监测Resource的创建和变化,不仅仅是刚创建,否则一些Initializer可能被漏掉。

lxcfs-initializer这个Initializer只关心ADD事件,如果同时有其它的Initializer Controller存在,可能会漏掉一些Resource。

_, controller := cache.NewInformer(includeUninitializedWatchlist, &v1.Deployment{}, resyncPeriod,
	cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			err := initializeDeployment(obj.(*v1.Deployment), c, clientset)
			if err != nil {
				log.Println(err)
			}
		},
	},
)

参考

  1. Kubernetes之路 2 - 利用LXCFS提升容器资源可见性
  2. Kubernetes Initializers
  3. 通过LXCFS,在容器内显示容器的CPU、内存状态
  4. Kubernetes Init Containers
  5. lxcfs-initializer

站长微信(朋友圈有精华,一般不闲聊)

推荐阅读

Copyright @2011-2019 All rights reserved. 转载请添加原文连接,合作请加微信lijiaocn或者发送邮件: [email protected],备注网站合作

友情链接:  李佶澳的博客  小鸟笔记  软件手册  编程手册  运营手册  爱马影视  网络课程  奇技淫巧  课程文档  精选文章  发现知识星球  百度搜索 谷歌搜索