参考文档:

  1. client-go官方库
  2. 从内部访问api-server
  3. 从外部访问api-server

集群配置管理

k8s的配置文件默认会存放在~/.kube/config中,其内容如下:
image.png

client-go中对于配置文件的管理可以简单概括为以下两点:

  • 加载配置文件
  • 合并配置文件(存疑。。。)

接下来分别从代码层面看一下。

加载配置文件

  1. func main() {
  2. var kubeconfig *string
  3. // 默认会从~/.kube/config路径下获取配置文件
  4. if home := homeDir(); home != "" {
  5. kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional)absolute path to the kubeconfig file")
  6. } else {
  7. kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
  8. }
  9. flag.Parse()
  10. // 使用k8s.io/client-go/tools/clientcmd加载配置文件并生成config的对象
  11. if config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig); err != nil {
  12. panic(err.Error())
  13. }
  14. }

clientcmd.BuildConfigFromFlags加载配置文件后, 会生成一个Config的对象(具体信息)
这个对象中会包含如:apiserver地址、用户名、密码、token等信息。


进入到clientcmd.BuildConfigFromFlags查看其进行配置加载相关的代码:

进入到tools/clientcmd/client_config.go

  1. // BuildConfigFromFlags is a helper function that builds configs from a master
  2. // url or a kubeconfig filepath. These are passed in as command line flags for cluster
  3. // components. Warnings should reflect this usage. If neither masterUrl or kubeconfigPath
  4. // are passed in we fallback to inClusterConfig. If inClusterConfig fails, we fallback
  5. // to the default config.
  6. func BuildConfigFromFlags(masterUrl, kubeconfigPath string) (*restclient.Config, error) {
  7. if kubeconfigPath == "" && masterUrl == "" {
  8. klog.Warning("Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work.")
  9. kubeconfig, err := restclient.InClusterConfig()
  10. if err == nil {
  11. return kubeconfig, nil
  12. }
  13. klog.Warning("error creating inClusterConfig, falling back to default config: ", err)
  14. }
  15. return NewNonInteractiveDeferredLoadingClientConfig(
  16. &ClientConfigLoadingRules{ExplicitPath: kubeconfigPath},
  17. &ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterUrl}}).ClientConfig()
  18. }

生成一个结构体:ClientConfigLoadingRules,这里面记录了当前传入的kubeconfig文件的位置。另外,在这个结构体中有一个变量load ClientConfigLoader,对于kubeconfig文件的管理,就是通过其中定义的[ClientConfigLoadingRules.Load()](https://github.com/kubernetes/client-go/blob/becbabb360023e1825a48b4db85f454e452ae249/tools/clientcmd/loader.go#L76)实现的。

  1. // ClientConfigLoadingRules is an ExplicitPath and string slice of specific locations that are used for merging together a Config
  2. // Callers can put the chain together however they want, but we'd recommend:
  3. // EnvVarPathFiles if set (a list of files if set) OR the HomeDirectoryPath
  4. // ExplicitPath is special, because if a user specifically requests a certain file be used and error is reported if this file is not present
  5. type ClientConfigLoadingRules struct {
  6. ExplicitPath string
  7. Precedence []string
  8. // MigrationRules is a map of destination files to source files. If a destination file is not present, then the source file is checked.
  9. // If the source file is present, then it is copied to the destination file BEFORE any further loading happens.
  10. MigrationRules map[string]string
  11. // DoNotResolvePaths indicates whether or not to resolve paths with respect to the originating files. This is phrased as a negative so
  12. // that a default object that doesn't set this will usually get the behavior it wants.
  13. DoNotResolvePaths bool
  14. // DefaultClientConfig is an optional field indicating what rules to use to calculate a default configuration.
  15. // This should match the overrides passed in to ClientConfig loader.
  16. DefaultClientConfig ClientConfig
  17. // WarnIfAllMissing indicates whether the configuration files pointed by KUBECONFIG environment variable are present or not.
  18. // In case of missing files, it warns the user about the missing files.
  19. WarnIfAllMissing bool
  20. }

函数:

  1. // Load starts by running the MigrationRules and then
  2. // takes the loading rules and returns a Config object based on following rules.
  3. // if the ExplicitPath, return the unmerged explicit file
  4. // Otherwise, return a merged config based on the Precedence slice
  5. // A missing ExplicitPath file produces an error. Empty filenames or other missing files are ignored.
  6. // Read errors or files with non-deserializable content produce errors.
  7. // The first file to set a particular map key wins and map key's value is never changed.
  8. // BUT, if you set a struct value that is NOT contained inside of map, the value WILL be changed.
  9. // This results in some odd looking logic to merge in one direction, merge in the other, and then merge the two.
  10. // It also means that if two files specify a "red-user", only values from the first file's red-user are used. Even
  11. // non-conflicting entries from the second file's "red-user" are discarded.
  12. // Relative paths inside of the .kubeconfig files are resolved against the .kubeconfig file's parent folder
  13. // and only absolute file paths are returned.
  14. func (rules *ClientConfigLoadingRules) Load() (*clientcmdapi.Config, error) {
  15. if err := rules.Migrate(); err != nil {
  16. return nil, err
  17. }
  18. errlist := []error{}
  19. missingList := []string{}
  20. kubeConfigFiles := []string{}
  21. // Make sure a file we were explicitly told to use exists
  22. if len(rules.ExplicitPath) > 0 {
  23. if _, err := os.Stat(rules.ExplicitPath); os.IsNotExist(err) {
  24. return nil, err
  25. }
  26. kubeConfigFiles = append(kubeConfigFiles, rules.ExplicitPath)
  27. } else {
  28. kubeConfigFiles = append(kubeConfigFiles, rules.Precedence...)
  29. }
  30. kubeconfigs := []*clientcmdapi.Config{}
  31. // read and cache the config files so that we only look at them once
  32. for _, filename := range kubeConfigFiles {
  33. if len(filename) == 0 {
  34. // no work to do
  35. continue
  36. }
  37. config, err := LoadFromFile(filename)
  38. if os.IsNotExist(err) {
  39. // skip missing files
  40. // Add to the missing list to produce a warning
  41. missingList = append(missingList, filename)
  42. continue
  43. }
  44. if err != nil {
  45. errlist = append(errlist, fmt.Errorf("error loading config file \"%s\": %v", filename, err))
  46. continue
  47. }
  48. kubeconfigs = append(kubeconfigs, config)
  49. }
  50. if rules.WarnIfAllMissing && len(missingList) > 0 && len(kubeconfigs) == 0 {
  51. klog.Warningf("Config not found: %s", strings.Join(missingList, ", "))
  52. }
  53. // first merge all of our maps
  54. mapConfig := clientcmdapi.NewConfig()
  55. for _, kubeconfig := range kubeconfigs {
  56. mergo.MergeWithOverwrite(mapConfig, kubeconfig)
  57. }
  58. // merge all of the struct values in the reverse order so that priority is given correctly
  59. // errors are not added to the list the second time
  60. nonMapConfig := clientcmdapi.NewConfig()
  61. for i := len(kubeconfigs) - 1; i >= 0; i-- {
  62. kubeconfig := kubeconfigs[i]
  63. mergo.MergeWithOverwrite(nonMapConfig, kubeconfig)
  64. }
  65. // since values are overwritten, but maps values are not, we can merge the non-map config on top of the map config and
  66. // get the values we expect.
  67. config := clientcmdapi.NewConfig()
  68. mergo.MergeWithOverwrite(config, mapConfig)
  69. mergo.MergeWithOverwrite(config, nonMapConfig)
  70. if rules.ResolvePaths() {
  71. if err := ResolveLocalPaths(config); err != nil {
  72. errlist = append(errlist, err)
  73. }
  74. }
  75. return config, utilerrors.NewAggregate(errlist)
  76. }

合并配置文件

上面对kubeconfig完成加载后,下一步就需要对kubeconfig做合并处理。


代码位置:tools/clientcmd/loader.go

  1. // since values are overwritten, but maps values are not, we can merge the non-map config on top of the map config and
  2. // get the values we expect.
  3. config := clientcmdapi.NewConfig()
  4. mergo.Merge(config, mapConfig, mergo.WithOverride)
  5. mergo.Merge(config, nonMapConfig, mergo.WithOverride)