1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        kube-apiserver 初始命名空間實(shí)現(xiàn)方式

        共 12078字,需瀏覽 25分鐘

         ·

        2023-08-19 09:29

        在我們第 1 回僅啟動(dòng)一個(gè) kube-apiserver 組件的情況下,Kubernetes 就創(chuàng)建了四個(gè)初始命名空間:

        • default:默認(rèn)命名空間
        • kube-node-lease:用于保存與各個(gè)節(jié)點(diǎn)關(guān)聯(lián)的 Lease(租約)對(duì)象
        • kube-public:所有(包括未經(jīng)身份驗(yàn)證)的客戶端都可以讀取,主要用于集群內(nèi)部共享資源
        • kube-system:用于 Kubernetes 系統(tǒng)創(chuàng)建資源,包括 Kubernetes 運(yùn)行所需的核心組件
        $ kubectl get ns
        NAME                 STATUS   AGE
        default              Active   2d22h
        kube-node-lease      Active   2d22h
        kube-public          Active   2d22h
        kube-system          Active   2d22h

        如果刪除這四個(gè)初始命名空間:

        $ kubectl delete ns default kube-node-lease kube-public kube-system
        namespace "kube-node-lease" deleted
        Error from server (Forbidden): namespaces "default" is forbidden: this namespace may not be deleted
        Error from server (Forbidden): namespaces "kube-public" is forbidden: this namespace may not be deleted
        Error from server (Forbidden): namespaces "kube-system" is forbidden: this namespace may not be deleted

        會(huì)發(fā)現(xiàn)只有 kube-node-lease 允許刪除,而且經(jīng)過觀察,刪除后 1 分鐘內(nèi),該命名空間也會(huì)自動(dòng)重新創(chuàng)建:

        $ kubectl get ns
        NAME                 STATUS   AGE
        default              Active   2d22h
        kube-node-lease      Active   10s
        kube-public          Active   2d22h
        kube-system          Active   2d22h

        這四個(gè)初始命名空間的維護(hù)工作,實(shí)際是由 GenericAPIServer 的 Hook 機(jī)制完成的。

        在第 5 回啟動(dòng) HTTP Server 的 NonBlockingRun 方法中:

        // k8s.io/apiserver/pkg/server/genericapiserver.go
        func (s preparedGenericAPIServer) NonBlockingRun(stopCh <-chan struct{}, shutdownTimeout time.Duration) (<-chan struct{}, <-chan struct{}, error) {
         // ...
         if s.SecureServingInfo != nil && s.Handler != nil {
          // 啟動(dòng) HTTP Server
          stoppedCh, listenerStoppedCh, err = s.SecureServingInfo.Serve(s.Handler, shutdownTimeout, internalStopCh)
          // ...
         }

          // HTTP Server 退出通知
         go func() {
          <-stopCh
          close(internalStopCh)
         }()

         // 運(yùn)行 Hook
         s.RunPostStartHooks(stopCh)
         // ...
        }

        當(dāng) HTTP Server 啟動(dòng)成功后,就會(huì)開始運(yùn)行所有的 Hook :

        // k8s.io/apiserver/pkg/server/hooks.go

        type PostStartHookFunc func(context PostStartHookContext) error

        // Hook 實(shí)體
        type postStartHookEntry struct {
         // hook 方法
         hook PostStartHookFunc
          // hook 方法的調(diào)用棧信息
         originatingStack string
         done chan struct{}
        }

        func (s *GenericAPIServer) RunPostStartHooks(stopCh <-chan struct{}) {
         s.postStartHookLock.Lock()
         defer s.postStartHookLock.Unlock()
         s.postStartHooksCalled = true

         context := PostStartHookContext{
          LoopbackClientConfig: s.LoopbackClientConfig,
          StopCh:               stopCh,
         }

         // postStartHooks 是一個(gè)保存所有 Hook 的 map[string]postStartHookEntry
          // 遍歷所有 Hook 并運(yùn)行其 hook 方法
         for hookName, hookEntry := range s.postStartHooks {
          go runPostStartHook(hookName, hookEntry, context)
         }
        }

        func runPostStartHook(name string, entry postStartHookEntry, context PostStartHookContext) {
         var err error
         func() {
          // don't let the hook *accidentally* panic and kill the server
          defer utilruntime.HandleCrash()
          // 運(yùn)行其 hook 方法
          err = entry.hook(context)
         }()
         // if the hook intentionally wants to kill server, let it.
         if err != nil {
          klog.Fatalf("PostStartHook %q failed: %v", name, err)
         }
         close(entry.done)
        }

        s.postStartHooks 位置斷點(diǎn)調(diào)試,可以看到當(dāng)前版本一共有 24 種不同功能的 Hook :

        其中 start-system-namespaces-controller 便是本文的主角。

        如果從 debug 的角度去找,可以看其對(duì)應(yīng)的 hook 的調(diào)用棧信息定位到該 Hook 的創(chuàng)建位置:

        或者繼續(xù)跟隨我的思路,來到第 3 回注冊(cè) /api/* 核心路由的 InstallLegacyAPI 方法:

        // pkg/controlplane/instance.go
        func (m *Instance) InstallLegacyAPI(c *completedConfig, restOptionsGetter generic.RESTOptionsGetter) error {
         // 創(chuàng)建 RESTStorage
         legacyRESTStorage, apiGroupInfo, err := legacyRESTStorageProvider.NewLegacyRESTStorage(c.ExtraConfig.APIResourceConfigSource, restOptionsGetter)


         controllerName := "bootstrap-controller"
         client := kubernetes.NewForConfigOrDie(c.GenericConfig.LoopbackClientConfig)
         // Kubernetes clusters contains the following system namespaces:
         // kube-system, kube-node-lease, kube-public, default
         // 注冊(cè) start-system-namespaces-controller Hook
         m.GenericAPIServer.AddPostStartHookOrDie("start-system-namespaces-controller"func(hookContext genericapiserver.PostStartHookContext) error {
          go systemnamespaces.NewController(client, c.ExtraConfig.VersionedInformers.Core().V1().Namespaces()).Run(hookContext.StopCh)
          return nil
         })

         bootstrapController, err := c.NewBootstrapController(legacyRESTStorage, client)
         if err != nil {
          return fmt.Errorf("error creating bootstrap controller: %v", err)
         }
         m.GenericAPIServer.AddPostStartHookOrDie(controllerName, bootstrapController.PostStartHook)
         m.GenericAPIServer.AddPreShutdownHookOrDie(controllerName, bootstrapController.PreShutdownHook)

         // 核心路由注冊(cè)
         if err := m.GenericAPIServer.InstallLegacyAPIGroup(genericapiserver.DefaultLegacyAPIPrefix, &apiGroupInfo); err != nil {
          return fmt.Errorf("error in registering group versions: %v", err)
         }
         return nil
        }

        在 RESTStorage 創(chuàng)建之后,核心路由注冊(cè)之前,注冊(cè)了兩個(gè) Hook :bootstrap-controllerstart-system-namespaces-controller 。

        Hook 注冊(cè)的 AddPostStartHookOrDie 方法實(shí)際就是將 Hook 添加到 postStartHooks 中:

        // k8s.io/apiserver/pkg/server/hooks.go
        func (s *GenericAPIServer) AddPostStartHookOrDie(name string, hook PostStartHookFunc) {
         if err := s.AddPostStartHook(name, hook); err != nil {
          klog.Fatalf("Error registering PostStartHook %q: %v", name, err)
         }
        }

        func (s *GenericAPIServer) AddPostStartHook(name string, hook PostStartHookFunc) error {
         // ...
          // 添加到 postStartHooks map 中
         s.postStartHooks[name] = postStartHookEntry{hook: hook, originatingStack: string(debug.Stack()), done: done}

         return nil
        }

        因?yàn)?Hook 運(yùn)行時(shí)實(shí)際是直接調(diào)用 hook 方法,所以重點(diǎn)還是各個(gè) Hook 注冊(cè)時(shí)自身所傳入的 hook PostStartHookFunc 參數(shù)。

        對(duì)于 start-system-namespaces-controller Hook 注冊(cè)的 PostStartHookFunc 方法:

        func(hookContext genericapiserver.PostStartHookContext) error {
          // 創(chuàng)建 start-system-namespaces-controller 并調(diào)用 Run 運(yùn)行
          go systemnamespaces.NewController(client, c.ExtraConfig.VersionedInformers.Core().V1().Namespaces()).Run(hookContext.StopCh)
          return nil
        }

        該 controller 的實(shí)現(xiàn)很簡(jiǎn)單,我直接全部貼出來:

        // pkg/controlplane/controller/systemnamespaces/system_namespaces_controller.go

        // 創(chuàng)建 start-system-namespaces-controller
        func NewController(clientset kubernetes.Interface, namespaceInformer coreinformers.NamespaceInformer) *Controller {
         // 需要維護(hù)的四個(gè)初始命名空間
         systemNamespaces := []string{metav1.NamespaceSystem, metav1.NamespacePublic, v1.NamespaceNodeLease, metav1.NamespaceDefault}
         // 定時(shí)周期為 1 分鐘
         interval := 1 * time.Minute

         return &Controller{
          client:           clientset,
          namespaceLister:  namespaceInformer.Lister(),
          namespaceSynced:  namespaceInformer.Informer().HasSynced,
          systemNamespaces: systemNamespaces,
          interval:         interval,
         }
        }

        // 運(yùn)行 start-system-namespaces-controller
        func (c *Controller) Run(stopCh <-chan struct{}) {
         defer utilruntime.HandleCrash()
         defer klog.Infof("Shutting down system namespaces controller")

         klog.Infof("Starting system namespaces controller")

         if !cache.WaitForCacheSync(stopCh, c.namespaceSynced) {
          utilruntime.HandleError(fmt.Errorf("timed out waiting for caches to sync"))
          return
         }

         // 定時(shí)執(zhí)行 c.sync 方法,定時(shí)周期為 1 分鐘
         go wait.Until(c.sync, c.interval, stopCh)

         <-stopCh
        }

        func (c *Controller) sync() {
         // Loop the system namespace list, and create them if they do not exist
          // 遍歷四個(gè)初始命名空間
         for _, ns := range c.systemNamespaces {
          // 如果需要?jiǎng)t創(chuàng)建
          if err := c.createNamespaceIfNeeded(ns); err != nil {
           utilruntime.HandleError(fmt.Errorf("unable to create required kubernetes system Namespace %s: %v", ns, err))
          }
         }
        }

        func (c *Controller) createNamespaceIfNeeded(ns string) error {
         if _, err := c.namespaceLister.Get(ns); err == nil {
          // the namespace already exists
            // 命名空間已存在
          return nil
         }
         // 命名空間不存在,就去創(chuàng)建命名空間
         newNs := &v1.Namespace{
          ObjectMeta: metav1.ObjectMeta{
           Name:      ns,
           Namespace: "",
          },
         }
         _, err := c.client.CoreV1().Namespaces().Create(context.TODO(), newNs, metav1.CreateOptions{})
         if err != nil && errors.IsAlreadyExists(err) {
          err = nil
         }
         return err
        }

        這就是為什么啟動(dòng)一個(gè) kube-apiserver 組件就創(chuàng)建了四個(gè)初始命名空間,并且 kube-node-lease 命名空間刪除后 1 分鐘內(nèi)會(huì)自動(dòng)重新創(chuàng)建的原因。

        對(duì)于其它 23 種 Hook ,感興趣也可以直接全局搜索 Hook name 快速定位到其注冊(cè)位置去看。


        瀏覽 1392
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            天天躁夜夜躁av 操逼2211 | 欧美有码视频 | 国产 浪潮AV一区 | 7777国产| www.豆花视频 | 日韩中文字幕视频在线 | 国产精品无码久久久 | 啪啪激情网 | 午夜久| 李思思一级婬片A片 |