searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享

KubeVela 的集群是如何管理的

2023-12-05 06:32:18
22
0

KubeVela 是多集群应用管理组件,所以在使用之前需要将集群纳管到 KubeVela 中,让 KubeVela 能感知并维护集群信息。在应用下发到指定集群时,KubeVela 能知道如何连接到目标集群并进行操作。

KubeVela 使用的是 Secret 来保存集群信息的,和 Cluster Gateway 共享的同一套 Secret 进行集群管理。当进行集群纳管时,KubeVela 会创建名字和集群名相同的 Secret,用于存储集群的连接信息。

当请求从 APIServer 转发到 Cluster Gateway 时,使用路径中提供的集群名去查询 Secret 并获取到纳管集群的连接信息。

Cluster Gateway 处理流程如下:

Cluster Gateway 处理流程图

集群信息 Secret

Secret 数据类似下面这样:

apiVersion: v1
kind: Secret
metadata:
  name: managed1
  labels:
    cluster.core.oam.dev/cluster-credential-type: ServiceAccountToken
type: Opaque # <--- Has to be opaque
data:
  endpoint: "..." # Should NOT be 127.0.0.1
  ca.crt: "..." # ca cert for cluster "managed1"
  token: "..." # working jwt token

纳管集群实现

纳管集群时,KubeVela 有两套非常相似的处理逻辑,VelaUX 和 vela-cli:

  • VelaUX 业务逻辑入口在 clusterServiceImpl.createKubeCluster,在进行一些判断后通过 joinClusterByKubeConfigString() 函数注册纳管集群,最终调用 multicluster.JoinClusterByKubeConfig() 函数进行集群纳管处理;
  • vela-cli 处理入口在 NewClusterJoinCommand 中,直接调用 multicluster.JoinClusterByKubeConfig() 函数进行集群纳管处理。

JoinClusterByKubeConfig() 函数通过 Secret 来管理集群,而在些之上 VelaUX 更进一步。

VelaUX 的 createKubeCluster() 方法还会在 Store 创建 model.Cluster{} 结构的数据,保存集群信息。Store 如果是 kubeapi,则是存储到 ConfigMap 中,否则存储到 MongoDB。

JoinClusterByKubeConfig

multicluster.JoinClusterByKubeConfig() 函数会创建前面提到的 Secret 用于管理集群,但是在创建后会做一些判断,如果条件不满足会删除创建的数据。

pkg/multicluster/cluster_management.go:389
// JoinClusterByKubeConfig add child cluster by kubeconfig path, return cluster info and error
func JoinClusterByKubeConfig(ctx context.Context, cli client.Client, kubeconfigPath string, clusterName string, options ...JoinClusterOption) (*KubeClusterConfig, error) {
	args := newJoinClusterArgs(options...)
	// 读取纳管集群的 kubeconfig 文件
	clusterConfig, err := LoadKubeClusterConfigFromFile(kubeconfigPath)
	if err != nil {
		return nil, err
	}
	if err := clusterConfig.SetClusterName(clusterName).SetCreateNamespace(args.createNamespace).Validate(); err != nil {
		return nil, err
	}
	// 纳管处理
	switch args.engine {
	case ClusterGateWayEngine:
		if err = clusterConfig.RegisterByVelaSecret(ctx, cli); err != nil {
			return nil, err
		}
	case OCMEngine:
		if args.inClusterBootstrap == nil {
			return nil, errors.Wrapf(err, "failed to determine the registration endpoint for the hub cluster "+
				"when parsing --in-cluster-bootstrap flag")
		}
		if err = clusterConfig.RegisterClusterManagedByOCM(ctx, cli, args); err != nil {
			return clusterConfig, err
		}
	}
	if cfg, ok := ctx.Value(KubeConfigContext).(*rest.Config); ok {
		if err = SetClusterVersionInfo(ctx, cfg, clusterConfig.ClusterName); err != nil {
			return nil, err
		}
	}
	return clusterConfig, nil
}

JoinClusterByKubeConfig() 函数在纳管集群时需要从本地文件读取 kubeconfig 配置,所以在 VelaUX 的 joinClusterByKubeConfigString() 中会先创建临时文件再调用 JoinClusterByKubeConfig() 函数处理。

上面代码中有两个分支的处理逻辑。这里主要关注直接通过 Cluster Gateway 管理的集群,OCM 集群先跳过。ClusterGateway 纳管集群通过 clusterConfig.RegisterByVelaSecret() 方法进行:

func (clusterConfig *KubeClusterConfig) RegisterByVelaSecret(ctx context.Context, cli client.Client) error {
	// 检查集群是否已经存在
	if err := ensureClusterNotExists(ctx, cli, clusterConfig.ClusterName); err != nil {
		return errors.Wrapf(err, "cannot use cluster name %s", clusterConfig.ClusterName)
	}
	// 不存在,创建集群 Secret
	if err := clusterConfig.createClusterSecret(ctx, cli, true); err != nil {
		return errors.Wrapf(err, "failed to add cluster to kubernetes")
	}
	// 后置检查
	return clusterConfig.PostRegistration(ctx, cli)
}
 

纳管逻辑很重要部分在后置检查这里,后置检查会保证配置的 clusterConfig.CreateNamespace 命名空间在纳管集群创建,此时会发起请求通过 Cluster Gateway 连接纳管集群进行操作。

[!warning]
这里请求会直接从本地向 APIServer 发起,而且请求 URL 是以下格式: /apis/cluster.core.oam.dev/v1alpha1/clustergateways/{clusterName}/proxy/{api}

Namespace 操作失败会回退纳管操作,删除 Secret,返回纳管失败错误。

Cluster Gateway 获取集群信息

当代理请求通过 Cluster Gateway 时,就需要去查询集群的信息。

在 Cluster Gateway 代码中,创建代理连接时的处理方法 Connect() 里会去获取集群信息。这个方法会通过 parentStorage.Get() 调用的父资源 ClusterGateway 的 Get() 方法:

pkg/apis/cluster/v1alpha1/clustergateway_types_secret.go:46
func (in *ClusterGateway) Get(ctx context.Context, name string, _ *metav1.GetOptions) (runtime.Object, error) {
	if singleton.GetSecretControl() == nil {
		return nil, fmt.Errorf("loopback secret client are not inited")
	}

	clusterSecret, err := singleton.GetSecretControl().Get(ctx, name)
	if err != nil {
		klog.Warningf("Failed getting secret %q/%q: %v", config.SecretNamespace, name, err)
		return nil, err
	}

	if options.OCMIntegration {
		if singleton.GetClusterControl() == nil {
			return nil, fmt.Errorf("loopback cluster client are not inited")
		}
		managedCluster, err := singleton.GetClusterControl().Get(ctx, name)
		if err != nil {
			return convertFromSecret(clusterSecret)
		}
		return convertFromManagedClusterAndSecret(managedCluster, clusterSecret)
	}

	return convertFromSecret(clusterSecret)
}
 

这个方法内部是通过 SecretControl 获取集群同名的 Secret,并转换成 ClusterGateway 对象,最终传给 proxyHandler 使用。

 

总结

KubeVela 这样使用 Secret 管理集群也是有好处的:

  1. Secret 能进行权限管理,保证安全;
  2. 支持通过 Label 设置集群元信息,用于调度时基于 Label 进行应用分发。

在代码中我们可以看到,如果使用的 vela-cli 进行纳管,请求会从当前主机向 API Server 发出,而很多时候 Kubernetes 的 API Server 是不开放到外面访问的。

所以在生产环境中,更多的是使用 vela-cli in pod 的方式进行管理。

0条评论
0 / 1000
lorland
10文章数
0粉丝数
lorland
10 文章 | 0 粉丝

KubeVela 的集群是如何管理的

2023-12-05 06:32:18
22
0

KubeVela 是多集群应用管理组件,所以在使用之前需要将集群纳管到 KubeVela 中,让 KubeVela 能感知并维护集群信息。在应用下发到指定集群时,KubeVela 能知道如何连接到目标集群并进行操作。

KubeVela 使用的是 Secret 来保存集群信息的,和 Cluster Gateway 共享的同一套 Secret 进行集群管理。当进行集群纳管时,KubeVela 会创建名字和集群名相同的 Secret,用于存储集群的连接信息。

当请求从 APIServer 转发到 Cluster Gateway 时,使用路径中提供的集群名去查询 Secret 并获取到纳管集群的连接信息。

Cluster Gateway 处理流程如下:

Cluster Gateway 处理流程图

集群信息 Secret

Secret 数据类似下面这样:

apiVersion: v1
kind: Secret
metadata:
  name: managed1
  labels:
    cluster.core.oam.dev/cluster-credential-type: ServiceAccountToken
type: Opaque # <--- Has to be opaque
data:
  endpoint: "..." # Should NOT be 127.0.0.1
  ca.crt: "..." # ca cert for cluster "managed1"
  token: "..." # working jwt token

纳管集群实现

纳管集群时,KubeVela 有两套非常相似的处理逻辑,VelaUX 和 vela-cli:

  • VelaUX 业务逻辑入口在 clusterServiceImpl.createKubeCluster,在进行一些判断后通过 joinClusterByKubeConfigString() 函数注册纳管集群,最终调用 multicluster.JoinClusterByKubeConfig() 函数进行集群纳管处理;
  • vela-cli 处理入口在 NewClusterJoinCommand 中,直接调用 multicluster.JoinClusterByKubeConfig() 函数进行集群纳管处理。

JoinClusterByKubeConfig() 函数通过 Secret 来管理集群,而在些之上 VelaUX 更进一步。

VelaUX 的 createKubeCluster() 方法还会在 Store 创建 model.Cluster{} 结构的数据,保存集群信息。Store 如果是 kubeapi,则是存储到 ConfigMap 中,否则存储到 MongoDB。

JoinClusterByKubeConfig

multicluster.JoinClusterByKubeConfig() 函数会创建前面提到的 Secret 用于管理集群,但是在创建后会做一些判断,如果条件不满足会删除创建的数据。

pkg/multicluster/cluster_management.go:389
// JoinClusterByKubeConfig add child cluster by kubeconfig path, return cluster info and error
func JoinClusterByKubeConfig(ctx context.Context, cli client.Client, kubeconfigPath string, clusterName string, options ...JoinClusterOption) (*KubeClusterConfig, error) {
	args := newJoinClusterArgs(options...)
	// 读取纳管集群的 kubeconfig 文件
	clusterConfig, err := LoadKubeClusterConfigFromFile(kubeconfigPath)
	if err != nil {
		return nil, err
	}
	if err := clusterConfig.SetClusterName(clusterName).SetCreateNamespace(args.createNamespace).Validate(); err != nil {
		return nil, err
	}
	// 纳管处理
	switch args.engine {
	case ClusterGateWayEngine:
		if err = clusterConfig.RegisterByVelaSecret(ctx, cli); err != nil {
			return nil, err
		}
	case OCMEngine:
		if args.inClusterBootstrap == nil {
			return nil, errors.Wrapf(err, "failed to determine the registration endpoint for the hub cluster "+
				"when parsing --in-cluster-bootstrap flag")
		}
		if err = clusterConfig.RegisterClusterManagedByOCM(ctx, cli, args); err != nil {
			return clusterConfig, err
		}
	}
	if cfg, ok := ctx.Value(KubeConfigContext).(*rest.Config); ok {
		if err = SetClusterVersionInfo(ctx, cfg, clusterConfig.ClusterName); err != nil {
			return nil, err
		}
	}
	return clusterConfig, nil
}

JoinClusterByKubeConfig() 函数在纳管集群时需要从本地文件读取 kubeconfig 配置,所以在 VelaUX 的 joinClusterByKubeConfigString() 中会先创建临时文件再调用 JoinClusterByKubeConfig() 函数处理。

上面代码中有两个分支的处理逻辑。这里主要关注直接通过 Cluster Gateway 管理的集群,OCM 集群先跳过。ClusterGateway 纳管集群通过 clusterConfig.RegisterByVelaSecret() 方法进行:

func (clusterConfig *KubeClusterConfig) RegisterByVelaSecret(ctx context.Context, cli client.Client) error {
	// 检查集群是否已经存在
	if err := ensureClusterNotExists(ctx, cli, clusterConfig.ClusterName); err != nil {
		return errors.Wrapf(err, "cannot use cluster name %s", clusterConfig.ClusterName)
	}
	// 不存在,创建集群 Secret
	if err := clusterConfig.createClusterSecret(ctx, cli, true); err != nil {
		return errors.Wrapf(err, "failed to add cluster to kubernetes")
	}
	// 后置检查
	return clusterConfig.PostRegistration(ctx, cli)
}
 

纳管逻辑很重要部分在后置检查这里,后置检查会保证配置的 clusterConfig.CreateNamespace 命名空间在纳管集群创建,此时会发起请求通过 Cluster Gateway 连接纳管集群进行操作。

[!warning]
这里请求会直接从本地向 APIServer 发起,而且请求 URL 是以下格式: /apis/cluster.core.oam.dev/v1alpha1/clustergateways/{clusterName}/proxy/{api}

Namespace 操作失败会回退纳管操作,删除 Secret,返回纳管失败错误。

Cluster Gateway 获取集群信息

当代理请求通过 Cluster Gateway 时,就需要去查询集群的信息。

在 Cluster Gateway 代码中,创建代理连接时的处理方法 Connect() 里会去获取集群信息。这个方法会通过 parentStorage.Get() 调用的父资源 ClusterGateway 的 Get() 方法:

pkg/apis/cluster/v1alpha1/clustergateway_types_secret.go:46
func (in *ClusterGateway) Get(ctx context.Context, name string, _ *metav1.GetOptions) (runtime.Object, error) {
	if singleton.GetSecretControl() == nil {
		return nil, fmt.Errorf("loopback secret client are not inited")
	}

	clusterSecret, err := singleton.GetSecretControl().Get(ctx, name)
	if err != nil {
		klog.Warningf("Failed getting secret %q/%q: %v", config.SecretNamespace, name, err)
		return nil, err
	}

	if options.OCMIntegration {
		if singleton.GetClusterControl() == nil {
			return nil, fmt.Errorf("loopback cluster client are not inited")
		}
		managedCluster, err := singleton.GetClusterControl().Get(ctx, name)
		if err != nil {
			return convertFromSecret(clusterSecret)
		}
		return convertFromManagedClusterAndSecret(managedCluster, clusterSecret)
	}

	return convertFromSecret(clusterSecret)
}
 

这个方法内部是通过 SecretControl 获取集群同名的 Secret,并转换成 ClusterGateway 对象,最终传给 proxyHandler 使用。

 

总结

KubeVela 这样使用 Secret 管理集群也是有好处的:

  1. Secret 能进行权限管理,保证安全;
  2. 支持通过 Label 设置集群元信息,用于调度时基于 Label 进行应用分发。

在代码中我们可以看到,如果使用的 vela-cli 进行纳管,请求会从当前主机向 API Server 发出,而很多时候 Kubernetes 的 API Server 是不开放到外面访问的。

所以在生产环境中,更多的是使用 vela-cli in pod 的方式进行管理。

文章来自个人专栏
kubernetes
10 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0