Please enable Javascript to view the contents

Kubevela 下的多集群应用

 ·  ☕ 6 分钟

Kubevela 目前处于 1.1 版本。通常,我们认为 1.x 的版本是相对稳定的,可以尝试引入生产。在不断地跟踪和学习过程中,也感受到 Kubevela 的一些好的地方,这是一篇小结性的文档。

1. Kubevela 能解决什么问题

  • 面向平台开发者

需要区分几个角色: 开发、运维、运维开发。开发面向的是业务需求,运维面向的是业务稳定,运维开发面向的是效率。运维开发提供各种各样的工具,打通开发和运维之间的壁垒,既要快速满足业务上线。又要保障业务稳定。

Kubevela 对开发和运维并没有太大吸引力,却能让运维开发耳目一新。因为,Kubevela 能显著提升团队的平台水平,直达主流梯队。

  • 应用生命周期的管理

Kubevela 提供了管理应用生命周期的解决方案,应用的定义 applications,部署 appdeployments ,版本管理 applicationrevisions,回滚 approllouts,灰度 traits、approllouts。利用这些 CRD 对象,能够覆盖很大一部分业务需求。

  • 应用负载和特性的组件化

Component 提供的是负载的定义,比如 Deployment、CloneSet。Trait 提供的是特征的定义,比如 Ingress、Istio。通过这两种抽象,Kubevela 允许平台的开发者能够组装、定制适合自己业务的平台。

而 Workflow 提供的编排能力,给集成各种云原生组件增添了更多可能,甚至能延展到 CICD 领域。

2. 多集群下应用面临的挑战

  • 统一的视角

在面向应用的平台上,切换集群是一个非常糟糕的用户体验。我们需要的不是在每个集群上部署一套管理服务,然后通过修改数据源,查看不同集群上的数据。

我们应该以应用为中心,集群只是应用的一个属性,而不能将应用归属于某个集群。统一视角就是希望能够提供给用户一个 UI,包含完整的应用描述、所在运行时、实时服务画像等信息。

  • 应用的定义

世界上,没有两个平台团队对应用的定义是一样的。

一个应用应该包含哪些属性,哪些特征,对哪些字段进行哪些限制,很多的细节需要推敲和考虑。当然你也可以选择背负技术债务,将问题延后解决,快速交付几个版本。但却也是道阻且长,越来越难。

每个团队在定义应用时,都会附带一些业务属性。自救是不可能的,繁杂的业务需求不会给平台的开发者喘息之机。

因此,OAM 的出现是个机会,有机会统一应用生命周期管理 (ALM)。虽前有 Kubernetes Applications 死在了沙滩,但 Kubevela 犹如黑夜星光,给人无限希望。

  • 分批发布

分批发布有两个维度,单个集群中的多副本应用,多个集群中的同一个应用。

单个集群上的多副本,不会一次性更新,而是需要分批发布。这个过程,称之为 rollout,是一个逐步放量的过程。

多个集群或者多个区域的服务,在更新时,也需要观察时间,而不能一把就 show hand。

3. AppDeployment 下的多集群应用

这里主要是以 AppDeployment 作为主要对象,将应用在多个集群上进行发布。

  • 在主集群上添加多个子集群

需要在同一个 kubeconfig 配置多个集群的 context,然后按照官方文档操作即可。这里添加了两个集群 prod-cluster-1 和 prod-cluster-2 。下面是查看集群的命令:

1
2
3
4
5
kubectl get clusters.core.oam.dev

NAME             AGE
prod-cluster-1   57d
prod-cluster-2   57d
  • 定义 Application 应用

需要提前定义 components 和 traits,下面是应用的定义:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: cluster-test-app-cloneset
  namespace: default
  annotations:
    app.oam.dev/revision-only: "true"
spec:
  components:
    - name: helloworld-cloneset
      type: cloneset
      properties:
        image: oamdev/helloworld-python:v1
        env:
          - name: "TARGET"
            value: "KubeVela-v1"
        port: 8080
      traits:
        - type: expose-nodeport
          properties:
            ports:
              - protocol: "TCP"
                port: 80

由于有 app.oam.dev/revision-only: "true" 的 Annotations,因此相关的资源并不会被创建。我们在此只是定义应用,并不需要创建相应的负载。

  • 修改应用的版本,产生不同的应用版本

为了更加逼近生产环境,我们修改上面 Application 的参数,比如:环境变量、镜像版本等,产生不同的应用版本。

1
2
3
4
5
6
kubectl get applicationrevisions.core.oam.dev

NAME                  AGE
cluster-test-app-v1   57d
cluster-test-app-v2   57d
cluster-test-app-v3   57d

最终,分发到各个集群上的应用版本,由此产生。这些版本,大致相同而有细微差异,类似日常应用更新。

  • AppDeployment 多集群分发应用

AppDeployment 提供了一个更加贴近用户对应用理解的视角。应用不仅包含的是对应用的定义,还有对运行时的选择。这里将 cluster-test-app-v1 部署到 prod-cluster-1 集群,设置 3 个副本数量;而将 cluster-test-app-v2 部署到 prod-cluster-2 集群,设置 4 个副本数量。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: core.oam.dev/v1beta1
kind: AppDeployment
metadata:
  name: cross-cluster-app
  namespace: default
spec:
  appRevisions:
    - revisionName: cluster-test-app-v1
      placement:
        - clusterSelector:
            labels:
              env: stage
            name: prod-cluster-1
          distribution:
            replicas: 3

    - revisionName: cluster-test-app-v2
      placement:
        - clusterSelector:
            labels:
              env: production
            name: prod-cluster-2
          distribution:
            replicas: 4

4 Workflow 下的多集群应用

Workflow 是 Kubevela 近期版本新增的一个特性,在这里主要用来生成 OCM 需要的跨集群资源对象。

4.1 配置 Open Cluster Management (OCM)

  • 使用 vela 命令安装 Open Cluster Management
1
vela addon enable ocm-cluster-manager
  • 在主集群上添加多个子集群

需要在同一个 kubeconfig 配置多个集群的 context。在 dev1 集群上,添加 dev2 集群的 kubeconfig。

1
2
3
4
5
kubectl config get-contexts

CURRENT   NAME           CLUSTER              AUTHINFO                NAMESPACE
*         dev1-context   dev1.cluster.local   dev1-kubernetes-admin
          dev2-context   dev2.cluster.local   dev2-kubernetes-admin
  • 配置环境变量

使用 dev1(主集群) 管理 dev2(子集群) 。在主集群上,执行命令:

1
2
3
4
export HUB_CLUSTER_NAME=dev1
export MANAGED_CLUSTER_NAME=dev2
export CTX_HUB_CLUSTER=dev1-context
export CTX_MANAGED_CLUSTER=dev2-context
  • 查找添加子集群的 Token

在主集群上,执行命令:

1
2
3
clusteradm get token

xxxxxxxxxxxxxx

取出其中的 token 值,Base64 反解码,可以得到一个有效的 hub-token 值。

  • 添加子集群

这里的 hub-apiserver 就是主集群的 kube-apiserver 的访问地址。在主集群上,执行命令:

1
clusteradm join --context ${CTX_MANAGED_CLUSTER} --hub-token xxxxxxxxxxxxxx --hub-apiserver https://1.1.1.1:6443 --cluster-name ${MANAGED_CLUSTER_NAME}
  • 接受新的集群添加请求

在主集群上,执行命令:

1
clusteradm accept --clusters dev2
  • 查看被管理的集群

在主集群上,执行命令:

1
2
3
4
kubectl get managedcluster

NAME   HUB ACCEPTED   MANAGED CLUSTER URLS                JOINED   AVAILABLE   AGE
dev2   true           https://dev1.chenshaowen.com:6443   True     True        3m38s
  • 在被管理的集群上安装 Kubevela rollout

在子集群上,执行命令:

helm repo add kubevela https://charts.kubevela.net/core
helm install vela-rollout  --create-namespace -n vela-system kubevela/vela-rollout

4.2 新建 WorkflowStepDefinition 描述跨集群资源

在主集群使用 Workflow 将跨集群的资源定义在 WorkflowStepDefinition 中。下面是需要用到的资源之一:

 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
apiVersion: core.oam.dev/v1beta1
kind: WorkflowStepDefinition
metadata:
  name: dispatch-traits
  namespace: vela-system
spec:
  schematic:
    cue:
      template: |
        import ("vela/op")

        comp: op.#Load & {
           component: parameter.component
        }

        apply: op.#Apply & {
            value: {
                apiVersion: "work.open-cluster-management.io/v1"
                kind: "ManifestWork"
                metadata: {
                   namespace: parameter.cluster
                   name: parameter.component + "-traits"
                }
                spec: {
                   workload: manifests : comp.value.auxiliaries
                }
            }
        }


        parameter: {
          component: string
          cluster: string
        }        

其中 ManifestWork 定义了分发到某个集群的配置和资源信息。这里只定义了 dispatch-traits,相应的我们还需要定义 dispatch-comp-rev。

分发资源的过程可以理解为,将待分发的资源打包成主集群上的 ManifestWork 对象,通过 OCM 分发到子集群的 AppliedManifestworks 对象,然后由子集群提取资源进行创建。

4.3 创建应用进行分发

这里使用 Application 在主集群 dev1 上定义一个应用,分发到子集群 dev2 上。

 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
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: workflow-rollout-demo
  namespace: default
spec:
  components:
    - name: nginx-server
      externalRevision: nginx-server-v1
      type: webservice
      properties:
        image: nginx:1.20.0
        port: 80
      traits:
        - type: rollout
          properties:
            targetRevision: nginx-server-v1
            targetSize: 2
            rolloutBatches:
              - replicas: 1
              - replicas: 1

  workflow:
    steps:
      - name: dispatch-comp-rev-v1
        type: dispatch-comp-rev
        properties:
           compRev: nginx-server-v1
           cluster: dev2

      - name: dispatchRollout
        type: dispatch-traits
        properties:
          component: nginx-server
          cluster: dev2

在 OCM 多集群应用的场景下,子集群需要部署 Kubevela rollout 组件。因此,Kubevela 能够更精细地控制子集群 rollout 过程,比如滚动过程中每个批次的比例和数量等。

4.4 可能会碰到的问题

  • OCM 在子集群创建资源时报错
E0905 14:36:23.461052       1 base_controller.go:270] "ManifestWorkAgent" controller failed to sync "nginx-server-traits", err: rollouts.standard.oam.dev "nginx-server" is forbidden: User "system:serviceaccount:open-cluster-management-agent:klusterlet-work-sa" cannot get resource "rollouts" in API group "standard.oam.dev" in the namespace "default"

提示是权限不够,在子集群上,直接给 klusterlet-work-sa 绑定了一个 admin 权限。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: admin-ocm
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
subjects:
  - kind: ServiceAccount
    name: klusterlet-work-sa
    namespace: open-cluster-management-agent

5. 总结

本篇主要讨论的是 Kubevela 在多集群下的应用,主要内容如下:

  • 多集群下的应用,不同于单集群,不能简单地切换数据源实现,其对交互设计有更高的要求。多集群应用平台需要有统一的视角,查看应用在多集群下的服务画像,以应用为中心,将集群当做属性,分清主次。
  • AppDeployment 是一个很好的抽象,也能给平台设计一些启发,还能看到一些 KubeFed 的身影。AppDeployment 是以用户视角呈现的多集群应用,但目前对 Workload 的处理粒度太大,面向的是整个 Application,也就是全量删除、更新、创建 Workload。如果用于生产,还需要配合 rollout 进行更新。
  • 借助 Workflow 集成 OCM 下的 Kubevela 多集群应用,更具扩展性,后续也可以换成其他多集群组件,比如 Karmada。利用 OCM 的分发能力,加上子集群上的 Kubevela rollout 组件,我们可以实现分批发布、滚动更新。

实际上,多集群下的应用,不仅仅需要考虑的是对应用描述的分发,更重要的还有负载的滚动更新、资源的统一分配、应用的智能调度、应用的自动扩缩容、服务的状态画像等。Kubevela 针对的是看得见的应用,但支撑起整个应用平台还需要更多底层组件。

6. 参考


微信公众号
作者
微信公众号