K8s-kubectl(缓存机制)

基于1.25

kubectl的关键步骤是构造操作/查询资源的请求

kubectl为了减小kube-apiserver的压力,使用Client-go中的CacheDisoveryClient提供的本地磁盘能力。

缓存数据结构

kubectl使用servergroups.json文件缓存从kube-apiserver获取所有的资源信息

  • 缓存文件存在$KUBECACHEDIR/disocvery中

  • 没有设置环境变量KUBECACHEDIR,默认位置$HOME/.kube/cache

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    [root@hcss-ecs-5425 ~]# tree $HOME/.kube/cache 
    /root/.kube/cache
    ├── discovery
    │ └── 113.45.181.99_6443
    │ ├── admissionregistration.k8s.io
    │ │ ├── v1
    │ │ │ └── serverresources.json
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ ├── apiextensions.k8s.io
    │ │ ├── v1
    │ │ │ └── serverresources.json
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ ├── apiregistration.k8s.io
    │ │ ├── v1
    │ │ │ └── serverresources.json
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ ├── apps
    │ │ └── v1
    │ │ └── serverresources.json
    │ ├── authentication.k8s.io
    │ │ ├── v1
    │ │ │ └── serverresources.json
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ ├── authorization.k8s.io
    │ │ ├── v1
    │ │ │ └── serverresources.json
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ ├── autoscaling
    │ │ ├── v1
    │ │ │ └── serverresources.json
    │ │ ├── v2beta1
    │ │ │ └── serverresources.json
    │ │ └── v2beta2
    │ │ └── serverresources.json
    │ ├── batch
    │ │ ├── v1
    │ │ │ └── serverresources.json
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ ├── certificates.k8s.io
    │ │ ├── v1
    │ │ │ └── serverresources.json
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ ├── coordination.k8s.io
    │ │ ├── v1
    │ │ │ └── serverresources.json
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ ├── discovery.k8s.io
    │ │ ├── v1
    │ │ │ └── serverresources.json
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ ├── events.k8s.io
    │ │ ├── v1
    │ │ │ └── serverresources.json
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ ├── extensions
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ ├── flowcontrol.apiserver.k8s.io
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ ├── networking.k8s.io
    │ │ ├── v1
    │ │ │ └── serverresources.json
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ ├── node.k8s.io
    │ │ ├── v1
    │ │ │ └── serverresources.json
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ ├── policy
    │ │ ├── v1
    │ │ │ └── serverresources.json
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ ├── rbac.authorization.k8s.io
    │ │ ├── v1
    │ │ │ └── serverresources.json
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ ├── scheduling.k8s.io
    │ │ ├── v1
    │ │ │ └── serverresources.json
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ ├── servergroups.json
    │ ├── storage.k8s.io
    │ │ ├── v1
    │ │ │ └── serverresources.json
    │ │ └── v1beta1
    │ │ └── serverresources.json
    │ └── v1
    │ └── serverresources.json
    └── http
    ├── 0791299400facefaaa2474034997875c
    ├── 0e35cbc773d2d51c9496961c3c502cef
    ├── 120535426aaf11668aa5064327a29c72
    ├── 14897edf5fefeb7a00f130a4163529b1
    ├── 1f07d5c65af8db33754189bf453ef251
    ├── 1f72ffe7c48e778654c717e0e2d98d4a
    ├── 2ce60c705942f017d7f3897ddaad2b16
    ├── 2e653727288d8bf6086abeee7d9cba9f
    ├── 310cfc9031096250f5ed519fab1eca68
    ├── 3210f4404e6ed41e4aa404c03d883671
    ├── 379d6534b442c28ff98fea7e8764fa6f
    ├── 4f8f48d72307c73fa48587f57a4a14c5
    ├── 5b53da0dfab2deaa4c66763756720755
    ├── 5e36ca48c98de8feff8b357c3cd780fd
    ├── 60d88fccba5c8f144812f74831b9c538
    ├── 68198318799539777365ceef73afeed6
    ├── 6d12a199bb93348145719d2e96e51445
    ├── 7657e197b8075107ae7011a1fb6d8be3
    ├── 7e36901e60cf635390ea6c0895ad857f
    ├── 7f7f356d7a41af980b94f29ab7a146ac
    ├── 7fa1f5d50356c9344347dc02495e5b1e
    ├── 8308e632d6e42d86e7dc70539a8ca88f
    ├── 99f4f61eb966810f53bb47475d6fc4ff
    ├── 9a31dc2ad0e1b4169b12d32038519510
    ├── a4174ee3721458bb23e51469ab5e575f
    ├── bcdc40145d9b774da290858b1eec8a49
    ├── be5298f46ae94a7507a14db8bbd0fb76
    ├── bedc98239a8911859556606adec2eaaa
    ├── cbace2814af9a69c77aa4bd27f981979
    ├── d0ec27974d76a8256efa79a7842d4c8f
    ├── d4bbc2feee7f7c4258f79ff7f773970e
    ├── e0e3f313d74c0e4edcbcc741e5385a38
    ├── e3272e47b3ebc83b6debfbfad3ec7a02
    ├── e5eb3bb7d0146e4e6c7dbe97053f1481
    ├── e868f248d5b4f2465eeb78671e580577
    ├── e906bcc0ab35331fa26aa6aba87aae4c
    ├── ebf991e9e2062d0097a7d9f99a4487a1
    ├── ecce97bc885fb535212f7356c95adce4
    ├── f2b99bdca7666fc462c0ceeb0b7342cc
    ├── f76a226306794058338a5b817d9dcbda
    ├── fb57df2ff4ff6008c0cf59b0ef4be7e4
    └── fb9a70668b179122fb25d0440b218d04

    62 directories, 82 files
    [root@hcss-ecs-5425 ~]#

缓存机制详解

缓存对象初始化

kubectl创建Builder实例的过程中,会创建CacheDicoveryClient

  • 环境文件有效时间6h

  • Ref:https://github.com/kubernetes/cli-runtime/blob/777f84f55a05fe0cf98a21badfe6a0e39bf74553/pkg/genericclioptions/config_flags.go#L244

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    // ToDiscoveryClient implements RESTClientGetter.
    // Expects the AddFlags method to have been called.
    // Returns a CachedDiscoveryInterface using a computed RESTConfig.
    func (f *ConfigFlags) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
    if f.usePersistentConfig {
    return f.toPersistentDiscoveryClient()
    }
    return f.toDiscoveryClient()
    }

    func (f *ConfigFlags) toDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
    config, err := f.ToRESTConfig()
    if err != nil {
    return nil, err
    }

    config.Burst = f.discoveryBurst
    config.QPS = f.discoveryQPS

    cacheDir := getDefaultCacheDir()

    // retrieve a user-provided value for the "cache-dir"
    // override httpCacheDir and discoveryCacheDir if user-value is given.
    // user-provided value has higher precedence than default
    // and KUBECACHEDIR environment variable.
    if f.CacheDir != nil && *f.CacheDir != "" && *f.CacheDir != getDefaultCacheDir() {
    cacheDir = *f.CacheDir
    }

    httpCacheDir := filepath.Join(cacheDir, "http")
    discoveryCacheDir := computeDiscoverCacheDir(filepath.Join(cacheDir, "discovery"), config.Host)

    return diskcached.NewCachedDiscoveryClientForConfig(config, discoveryCacheDir, httpCacheDir, time.Duration(6*time.Hour))
    }

缓存填充和更新

kubectl使用CacheDiscoveryClient查询资源组和资源信息。如果缓存目录中不存在对应的缓存文件,或者缓存文件失效,CacheDiscoveryClient会拉取或更新缓存文件

  1. 获取API版本信息
    • 通过访问kube-apiserver的/api获取到API版本信息
  2. 获取资源组列表
    • 通过访问kube-apiserver的/apis获取到资源组列表
  3. 获取各个资源组下个各个版本的资源列表
    • CacheDiscoveryClient访问kube-apiserver的/apis/{groupname}/{version}获取资源组个各个资源版本的资源列表
    • 为了加速,使用了并发策略访问kube-apiserver
  • Ref:https://github.com/kubernetes/client-go/blob/4f1c2e7b9711846cf31255fd709616c66cb3cfea/discovery/discovery_client.go#L338

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    // fetchServerResourcesForGroupVersions uses the discovery client to fetch the resources for the specified groups in parallel.
    func fetchGroupVersionResources(d DiscoveryInterface, apiGroups *metav1.APIGroupList) (map[schema.GroupVersion]*metav1.APIResourceList, map[schema.GroupVersion]error) {
    groupVersionResources := make(map[schema.GroupVersion]*metav1.APIResourceList)
    failedGroups := make(map[schema.GroupVersion]error)

    wg := &sync.WaitGroup{}
    resultLock := &sync.Mutex{}
    for _, apiGroup := range apiGroups.Groups {
    for _, version := range apiGroup.Versions {
    groupVersion := schema.GroupVersion{Group: apiGroup.Name, Version: version.Version}
    wg.Add(1)
    go func() {
    defer wg.Done()
    defer utilruntime.HandleCrash()

    apiResourceList, err := d.ServerResourcesForGroupVersion(groupVersion.String())

    // lock to record results
    resultLock.Lock()
    defer resultLock.Unlock()

    if err != nil {
    // TODO: maybe restrict this to NotFound errors
    failedGroups[groupVersion] = err
    }
    if apiResourceList != nil {
    // even in case of error, some fallback might have been returned
    groupVersionResources[groupVersion] = apiResourceList
    }
    }()
    }
    }
    wg.Wait()

    return groupVersionResources, failedGroups
    }

缓存失效机制

kubectl使用缓存减少压力,但是依旧有存在失效的情况

缓存过期失效

kubectl初始化缓存对象的时候,默认指定失效时间6h,所以过期之后会再次请求kube-apiserver

  • Ref:https://github.com/kubernetes/client-go/blob/4f1c2e7b9711846cf31255fd709616c66cb3cfea/discovery/cached/disk/cached_discovery.go#L134

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    func (d *CachedDiscoveryClient) getCachedFile(filename string) ([]byte, error) {
    // after invalidation ignore cache files not created by this process
    d.mutex.Lock()
    _, ourFile := d.ourFiles[filename]
    if d.invalidated && !ourFile {
    d.mutex.Unlock()
    return nil, errors.New("cache invalidated")
    }
    d.mutex.Unlock()

    file, err := os.Open(filename)
    if err != nil {
    return nil, err
    }
    defer file.Close()

    fileInfo, err := file.Stat()
    if err != nil {
    return nil, err
    }
    // 设置过期时间
    if time.Now().After(fileInfo.ModTime().Add(d.ttl)) {
    return nil, errors.New("cache expired")
    }

    // the cache is present and its valid. Try to read and use it.
    cachedBytes, err := ioutil.ReadAll(file)
    if err != nil {
    return nil, err
    }

    d.mutex.Lock()
    defer d.mutex.Unlock()
    d.fresh = d.fresh && ourFile

    return cachedBytes, nil
    }

使用新的缓存目录

使用KUBECACHEDIR可以指定/更新本地缓存目录。更新缓存目录后,之前的目录中的缓存文件不可爱使用。再调用CachedDiscoveryClient获取资源组列表会重新拉取对应的资源对象

主动让缓存失效

  • Ref:https://github.com/kubernetes/client-go/blob/4f1c2e7b9711846cf31255fd709616c66cb3cfea/discovery/cached/disk/cached_discovery.go#L266

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // Invalidate enforces that no cached data is used in the future that is older than the current time.
    // 清空CachedDiscoveryClient 记录的所有缓存文件名ourFiles
    // 将Cached DiscoveryClient重的invalidated 失效状态设置为true,这回将之前的缓存内容全部标记为失效
    func (d *CachedDiscoveryClient) Invalidate() {
    ...
    d.ourFiles = map[string]struct{}{}
    d.fresh = true
    d.invalidated = true
    ...
    }

    下面这些特殊的命令,会主动让缓存失效:

    命令 用途 缓存失效场景
    kubectl version 查询当前客户端和服务端的版本信息 为了获取最新的,让缓存失效
    kubectl api-resources 查询kube-apiserver支持的资源列表 在未显式指定缓存,–cached=true,默认访问kube-apiserver获取资源对象,并且主动让缓存失效
    kubectl api-versions 打印支持API版本列表 为了获取最新的API版本列表,主动强制让缓存失效

访问/操作本地缓存中未识别的资源

K8s支持CustomResource定义更多的资源类型,以满足拓展资源和场景的使用需求

  • 出现未识别资源的,先尝试获取资源的R 45estMapping
  • 如果本地缓存查找不到对应的资源信息,调用RESTMapper的Reset重置方法
    • Reset:调用CachedDiscoveryClient.Invalidate主动让CachedDiscoveryClient缓存失效
  • kuebctl尝试获取资源的RestMapping信息,让CachedDiscoveryClient从kube-apiserver获取资源组中最新的资源列表

缓存使用场景

资源访问

kubectl在使用RESTful对资源操作之前,需要根据资源信息找到访问资源的客户端对象。

类目展开

通过kubectl查询所有的资源对象

1
kubectl get all -n kube-system
资源类目 展开后的资源列表
all pods\replicationscontrollers\services\daemonsets.apps\deployment.apps\replcasets.apps\statefulsets.apps\horizontalpodautoscalers.autoscaling\horizontalpodautoscalers\cronjobs.batch\jobs.batch\cronjobs.batch
api-extensions apiservice.apiregistration.k8s.io/v1. apiservice.apiregistration.k8s.io/v1.admissionregistration.k8s.io apiservice.apiregistration.k8s.io/v1.apiextensions.k8s.io apiservice.apiregistration.k8s.io/v1.apps apiservice.apiregistration.k8s.io/v1.authentication.k8s.io apiservice.apiregistration.k8s.io/v1.authorization.k8s.io apiservice.apiregistration.k8s.io/v1.autoscaling apiservice.apiregistration.k8s.io/v1.batch apiservice.apiregistration.k8s.io/v1.certificates.k8s.io apiservice.apiregistration.k8s.io/v1.coordination.k8s.io apiservice.apiregistration.k8s.io/v1.discovery.k8s.io apiservice.apiregistration.k8s.io/v1.events.k8s.io apiservice.apiregistration.k8s.io/v1.networking.k8s.io apiservice.apiregistration.k8s.io/v1.node.k8s.io apiservice.apiregistration.k8s.io/v1.policy apiservice.apiregistration.k8s.io/v1.rbac.authorization.k8s.io apiservice.apiregistration.k8s.io/v1.scheduling.k8s.io apiservice.apiregistration.k8s.io/v1.storage.k8s.io apiservice.apiregistration.k8s.io/v1beta1.admissionregistration.k8s.io apiservice.apiregistration.k8s.io/v1beta1.apiextensions.k8s.io apiservice.apiregistration.k8s.io/v1beta1.authentication.k8s.io apiservice.apiregistration.k8s.io/v1beta1.authorization.k8s.io apiservice.apiregistration.k8s.io/v1beta1.batch apiservice.apiregistration.k8s.io/v1beta1.certificates.k8s.io apiservice.apiregistration.k8s.io/v1beta1.coordination.k8s.io apiservice.apiregistration.k8s.io/v1beta1.discovery.k8s.io apiservice.apiregistration.k8s.io/v1beta1.events.k8s.io apiservice.apiregistration.k8s.io/v1beta1.extensions apiservice.apiregistration.k8s.io/v1beta1.flowcontrol.apiserver.k8s.io apiservice.apiregistration.k8s.io/v1beta1.networking.k8s.io apiservice.apiregistration.k8s.io/v1beta1.node.k8s.io apiservice.apiregistration.k8s.io/v1beta1.policy apiservice.apiregistration.k8s.io/v1beta1.rbac.authorization.k8s.io apiservice.apiregistration.k8s.io/v1beta1.scheduling.k8s.io apiservice.apiregistration.k8s.io/v1beta1.storage.k8s.io apiservice.apiregistration.k8s.io/v2beta1.autoscaling apiservice.apiregistration.k8s.io/v2beta2.autoscaling

缩写替换

kubetcl可以使用缩写来实现对一些资源的,比如deploy和deployment