跳到内容

工作原理

1) CLI

目前,kops 中的一切都由命令行界面驱动。我们使用 cobra 来定义我们所有的命令行 UX。

kOps 的所有 CLI 代码都可以在 /cmd/kops 链接 中找到。

例如,如果你想找到 kops create cluster 的入口点,可以查看 /cmd/kops/create_cluster.go。在那里你会找到一个名为 RunCreateCluster() 的函数。那就是该命令的入口点。

2) 存储

我们有一种与存储进行交互的抽象方式,称为 clientset。这是一种与 kops 的远程存储进行交互的抽象方式。这通常被称为 kops 的 **状态存储**。

我们可以通过 util.Factory 结构访问它,如下所示

func RunMyCommand(f *util.Factory, out io.Writer, c *MyCommandOptions) error {
        clientset, _ := f.Clientset()
        cluster, _ := clientset.Clusters().Get(clusterName)
        fmt.Println(cluster)
}

可用的 Clientset 函数是

Create()
Update()
Get()
List()

3) API

a) 集群规范

kops API 是 Go 代码中结构成员的定义,可以在 这里 找到。kops API **不**与命令行界面匹配(这是设计使然)。我们使用原生 Kubernetes API 机制来管理 kops API 的版本控制。

API 的基础级别结构是 api.Cluster{},它定义在 这里。顶级结构包含有关对象的一些元信息,例如类型和版本,而集群本身的主要数据可以在 cluster.Spec 中找到。

需要注意的是,API 成员是 Kubernetes 集群的表示。这些值存储在上面提到的 kops **状态存储** 中,以便以后使用。按照设计,kOps 不会在状态存储中存储有关云状态的信息,如果它可以从查看云的实际状态中推断出来,则会这样做。

有关 API 的更多信息,请查看 这里

b) 实例组

为了让 kops 创建任何服务器,我们需要定义实例组。这些是一系列指向 kops.InstanceGroup 结构的指针。

var instanceGroups []*kops.InstanceGroup

每个实例组代表云中的一组实例。每个实例组 (或 IG) 定义有关实例组的值,例如它们的大小、卷信息等。定义也可以在 /pkg/apis/kops/instancegroup.go 文件中找到,这里

4) Cloudup

a) ApplyClusterCmd

在用户构建出有效的 api.Cluster{} 和有效的 []*kops.InstanceGroup 之后,他们就可以开始与 kops 中的核心逻辑进行交互。

用户可以构建一个 cloudup.ApplyClusterCmd,定义在 这里,如下所示

applyCmd := &cloudup.ApplyClusterCmd{
    Cluster:         cluster,
    Clientset:       clientset,
    TargetName:      "target",                               // ${GOPATH}/src/k8s.io/kops/upup/pkg/fi/cloudup/target.go:19
    OutDir:          c.OutDir,
    DryRun:          isDryrun,
    MaxTaskDuration: 10 * time.Minute,                       // ${GOPATH}/src/k8s.io/kops/upup/pkg/fi/cloudup/apply_cluster.go
    InstanceGroups:  instanceGroups,
}

现在 ApplyClusterCmd 已经填充完毕,我们可以尝试运行应用。

err = applyCmd.Run()

这就是我们进入 kops 逻辑 **核心** 的地方。起点可以在 这里 找到。根据上面 ApplyClusterCmd 中定义的指令,应用操作将根据提供的输入以不同的方式进行。

b) 验证

ApplyClusterCmd.Run() 函数内部,我们首先尝试通过验证操作来清理我们的输入。在函数的开头有很多示例,我们会在其中验证输入。

c) 云

cluster.Spec.CloudProvider 应该在之前已经填充,并且可以用来切换到构建我们的云,如 这里 所示。如果你想实现新的云实现,该接口定义在 这里,AWS 示例在 这里

**注意** 就目前而言,FindVPCInfo() 函数是接口中定义的成员。这仅限于 AWS,最终会从接口中移除。现在,请将该函数实现为一个无操作函数。

d) 模型

模型是将模棱两可的集群规范(之前定义)映射到 **任务** 的东西。每个 **任务** 都是对云发起的 API 请求的表示。如果你打算实现新的云,一种选择是定义新的模型上下文类型,并为你的云对象构建自定义模型构建器。

现有的模型代码可以在 这里 找到。

一旦模型构建器定义好,如 这里 所示,代码就会自动调用。

在构建器内部,我们注意到每个构建器都有具体的逻辑。逻辑将决定需要调用哪些任务才能将资源应用到云。这些任务通过调用 AddTask() 函数添加,这里

一旦模型构建器被调用,所有任务都应该被设置。

e) 任务

任务通常是单个 API 调用的表示。任务接口定义在 这里

**注意** 对于像 AWS 这样的更高级的云,在执行定义在 这里 的任务的核心逻辑中,还有 Find()Render() 函数。

5) Nodeup

Nodeup 是一个独立的二进制文件,它负责引导 Kubernetes 集群。有一个 shell 脚本 这里 将引导 nodeup。AWS 实现使用 cloud-init 在实例上运行该脚本。所有新的云都需要找出在平台上引导 nodeup 的最佳实践。