参考文档:
集群配置管理
k8s的配置文件默认会存放在~/.kube/config中,其内容如下:
client-go中对于配置文件的管理可以简单概括为以下两点:
- 加载配置文件
 - 合并配置文件(存疑。。。)
 
接下来分别从代码层面看一下。
加载配置文件
func main() {var kubeconfig *string// 默认会从~/.kube/config路径下获取配置文件if home := homeDir(); home != "" {kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional)absolute path to the kubeconfig file")} else {kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")}flag.Parse()// 使用k8s.io/client-go/tools/clientcmd加载配置文件并生成config的对象if config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig); err != nil {panic(err.Error())}}
clientcmd.BuildConfigFromFlags加载配置文件后, 会生成一个Config的对象(具体信息)
这个对象中会包含如:apiserver地址、用户名、密码、token等信息。
进入到clientcmd.BuildConfigFromFlags查看其进行配置加载相关的代码:
进入到tools/clientcmd/client_config.go
// BuildConfigFromFlags is a helper function that builds configs from a master// url or a kubeconfig filepath. These are passed in as command line flags for cluster// components. Warnings should reflect this usage. If neither masterUrl or kubeconfigPath// are passed in we fallback to inClusterConfig. If inClusterConfig fails, we fallback// to the default config.func BuildConfigFromFlags(masterUrl, kubeconfigPath string) (*restclient.Config, error) {if kubeconfigPath == "" && masterUrl == "" {klog.Warning("Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work.")kubeconfig, err := restclient.InClusterConfig()if err == nil {return kubeconfig, nil}klog.Warning("error creating inClusterConfig, falling back to default config: ", err)}return NewNonInteractiveDeferredLoadingClientConfig(&ClientConfigLoadingRules{ExplicitPath: kubeconfigPath},&ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterUrl}}).ClientConfig()}
生成一个结构体:ClientConfigLoadingRules,这里面记录了当前传入的kubeconfig文件的位置。另外,在这个结构体中有一个变量load ClientConfigLoader,对于kubeconfig文件的管理,就是通过其中定义的[ClientConfigLoadingRules.Load()](https://github.com/kubernetes/client-go/blob/becbabb360023e1825a48b4db85f454e452ae249/tools/clientcmd/loader.go#L76)实现的。
// ClientConfigLoadingRules is an ExplicitPath and string slice of specific locations that are used for merging together a Config// Callers can put the chain together however they want, but we'd recommend:// EnvVarPathFiles if set (a list of files if set) OR the HomeDirectoryPath// ExplicitPath is special, because if a user specifically requests a certain file be used and error is reported if this file is not presenttype ClientConfigLoadingRules struct {ExplicitPath stringPrecedence []string// MigrationRules is a map of destination files to source files. If a destination file is not present, then the source file is checked.// If the source file is present, then it is copied to the destination file BEFORE any further loading happens.MigrationRules map[string]string// DoNotResolvePaths indicates whether or not to resolve paths with respect to the originating files. This is phrased as a negative so// that a default object that doesn't set this will usually get the behavior it wants.DoNotResolvePaths bool// DefaultClientConfig is an optional field indicating what rules to use to calculate a default configuration.// This should match the overrides passed in to ClientConfig loader.DefaultClientConfig ClientConfig// WarnIfAllMissing indicates whether the configuration files pointed by KUBECONFIG environment variable are present or not.// In case of missing files, it warns the user about the missing files.WarnIfAllMissing bool}
函数:
// Load starts by running the MigrationRules and then// takes the loading rules and returns a Config object based on following rules.// if the ExplicitPath, return the unmerged explicit file// Otherwise, return a merged config based on the Precedence slice// A missing ExplicitPath file produces an error. Empty filenames or other missing files are ignored.// Read errors or files with non-deserializable content produce errors.// The first file to set a particular map key wins and map key's value is never changed.// BUT, if you set a struct value that is NOT contained inside of map, the value WILL be changed.// This results in some odd looking logic to merge in one direction, merge in the other, and then merge the two.// It also means that if two files specify a "red-user", only values from the first file's red-user are used. Even// non-conflicting entries from the second file's "red-user" are discarded.// Relative paths inside of the .kubeconfig files are resolved against the .kubeconfig file's parent folder// and only absolute file paths are returned.func (rules *ClientConfigLoadingRules) Load() (*clientcmdapi.Config, error) {if err := rules.Migrate(); err != nil {return nil, err}errlist := []error{}missingList := []string{}kubeConfigFiles := []string{}// Make sure a file we were explicitly told to use existsif len(rules.ExplicitPath) > 0 {if _, err := os.Stat(rules.ExplicitPath); os.IsNotExist(err) {return nil, err}kubeConfigFiles = append(kubeConfigFiles, rules.ExplicitPath)} else {kubeConfigFiles = append(kubeConfigFiles, rules.Precedence...)}kubeconfigs := []*clientcmdapi.Config{}// read and cache the config files so that we only look at them oncefor _, filename := range kubeConfigFiles {if len(filename) == 0 {// no work to docontinue}config, err := LoadFromFile(filename)if os.IsNotExist(err) {// skip missing files// Add to the missing list to produce a warningmissingList = append(missingList, filename)continue}if err != nil {errlist = append(errlist, fmt.Errorf("error loading config file \"%s\": %v", filename, err))continue}kubeconfigs = append(kubeconfigs, config)}if rules.WarnIfAllMissing && len(missingList) > 0 && len(kubeconfigs) == 0 {klog.Warningf("Config not found: %s", strings.Join(missingList, ", "))}// first merge all of our mapsmapConfig := clientcmdapi.NewConfig()for _, kubeconfig := range kubeconfigs {mergo.MergeWithOverwrite(mapConfig, kubeconfig)}// merge all of the struct values in the reverse order so that priority is given correctly// errors are not added to the list the second timenonMapConfig := clientcmdapi.NewConfig()for i := len(kubeconfigs) - 1; i >= 0; i-- {kubeconfig := kubeconfigs[i]mergo.MergeWithOverwrite(nonMapConfig, kubeconfig)}// since values are overwritten, but maps values are not, we can merge the non-map config on top of the map config and// get the values we expect.config := clientcmdapi.NewConfig()mergo.MergeWithOverwrite(config, mapConfig)mergo.MergeWithOverwrite(config, nonMapConfig)if rules.ResolvePaths() {if err := ResolveLocalPaths(config); err != nil {errlist = append(errlist, err)}}return config, utilerrors.NewAggregate(errlist)}
合并配置文件
上面对kubeconfig完成加载后,下一步就需要对kubeconfig做合并处理。
代码位置:tools/clientcmd/loader.go
// since values are overwritten, but maps values are not, we can merge the non-map config on top of the map config and// get the values we expect.config := clientcmdapi.NewConfig()mergo.Merge(config, mapConfig, mergo.WithOverride)mergo.Merge(config, nonMapConfig, mergo.WithOverride)
