diff --git a/kosmos/docs/i18n/zh/v0.2.0/application-migration_zh.md b/kosmos/docs/i18n/zh/v0.2.0/application-migration_zh.md new file mode 100644 index 0000000..a9f4f95 --- /dev/null +++ b/kosmos/docs/i18n/zh/v0.2.0/application-migration_zh.md @@ -0,0 +1,230 @@ +--- +id: application-migration_zh +title: '应用迁移' +--- + +# 应用迁移 +Kosmos 提供应用迁移功能,帮助用户将现有应用程序从子集群迁移到 Kosmos 控制平面集群。 + +## 应用迁移解决方案 + +### 简介 +在 Kosmos 多集群设计架构中,用户可以使用 kubectl、client-go 等工具与控制平面集群的 kube-apiserver 交互,创建部署或有状态的应用程序等。 +实际的 Pod 实例在子集群中运行。 + +然而,对于在子集群中未通过 Kosmos 控制平面创建的现有应用程序,这些应用程序无法在控制平面集群中查看和管理。 + +Kosmos 提供应用迁移功能,支持将命名空间中的应用程序迁移到控制平面集群。 +整个过程无需重新启动应用程序 Pod 实例,确保对业务运营的最小影响。 + +### 设计细节 +应用迁移主要包括三个过程:应用备份 -> 删除所有者对象 -> 在控制平面中重建应用程序。 + +#### 应用备份 +Kosmos 首先备份目标命名空间中的所有命名空间级别资源,以及依赖的集群级别资源,如集群角色、集群角色绑定、持久卷等。 +备份文件存储在 Kosmos 的 PVC 中。 + +#### 删除所有者对象 +Kosmos 子集群仅运行 Pod,它们的所有者 StatefulSet 或 ReplicaSet 需要在 Kosmos 控制平面中删除并重建。 +类似地,ReplicaSet 的所有者 Deployment,以及 StatefulSet 和 Deployment 的所有者,需要在 Kosmos 控制平面中删除并重建。 + +通过使用自上而下的级联删除所有者对象(例如,首先删除 Deployment,然后删除 ReplicaSet),Pod 不受影响并保持运行状态。 + +#### 在控制平面中重建应用程序 +基于备份资源,控制平面集群创建所有迁移后的资源,包括命名空间、Pod、部署、配置映射、服务账户等。 +为了与子集群中的 Pod 保持一致并保持其运行状态,应用程序使用自下而上的方法进行重建(例如,首先创建 Pod,然后创建 ReplicaSet)。 + +#### CRD API +提供 PromotePolicy CRD API 用于配置迁移策略。 +PromotePolicy 是一个集群范围的 CRD API。以下是如何使用它的示例: +```shell script +apiVersion: kosmos.io/v1alpha1 +kind: PromotePolicy +metadata: + name: promote-policy-sample +spec: + includedNamespaces: + - namespace1 + - namespace2 + excludedNamespaceScopedResources: + - events + - events.events.k8s.io + - endpoints + - endpointslices.discovery.k8s.io + clusterName: member-cluster1 +``` +其中: +- includedNamespaces: 要迁移的命名空间。 +- excludedNamespaceScopedResources: 不应迁移的命名空间级资源。 + 建议保留示例配置,并根据实际需求添加其他配置。 +- clusterName: Kosmos 子集群的名称。 + +#### 回滚 +Kosmos 支持迁移的回滚功能。 +成功迁移后,可以将子集群中现有的应用程序恢复到其初始状态。 +只需编辑 PromotePolicy YAML 文件,并添加配置 'rollback'=true。 +```shell script +apiVersion: kosmos.io/v1alpha1 +kind: PromotePolicy +metadata: + name: promote-policy-sample +spec: + rollback: "true" + includedNamespaces: + - namespace1 + - namespace2 + excludedNamespaceScopedResources: + - events + - events.events.k8s.io + - endpoints + - endpointslices.discovery.k8s.io + clusterName: member-cluster1 +``` + +### 测试计划 + +#### 准备工作 +首先,需要部署 [Kosmos](https://github.com/kosmos-io/kosmos)(必须安装 clustertree 模块)并添加一个子集群。 + +#### 在子集群中创建现有应用程序 +以在子集群中部署 nginx 应用程序为例。 +```shell script +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx + namespace: nginx-test +spec: + selector: + matchLabels: + app: nginx + replicas: 1 + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14-alpine + ports: + - containerPort: 80 + +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx-service + namespace: nginx-test +spec: + selector: + app: nginx + ports: + - protocol: TCP + port: 80 + targetPort: 80 + type: ClusterIP +``` + +#### 创建迁移策略 +```shell script +# kubectl apply -f promote-nginx.yaml +apiVersion: kosmos.io/v1alpha1 +kind: PromotePolicy +metadata: + name: promote-policy-example +spec: + includedNamespaces: + - nginx-test + excludedNamespaceScopedResources: + - events + - events.events.k8s.io + - endpoints + - endpointslices.discovery.k8s.io + clusterName: cluster-36-28 +``` + +#### 检查迁移结果 +检查迁移进度: +```shell script +# kubectl describe promotepolicy promote-policy-example +Name: promote-policy-example +Namespace: default +Labels: +Annotations: +API Version: kosmos.io/v1alpha1 +Kind: PromotePolicy +Metadata: + Creation Timestamp: 2024-03-11T10:57:47Z + Generation: 3 + Resource Version: 405947183 + UID: 0e32dd93-c370-4874-b9a7-37a6894cd373 +Spec: + Cluster Name: cluster-36-28 + Excluded Namespace Scoped Resources: + events + events.events.k8s.io + endpoints + endpointslices.discovery.k8s.io + controllerrevisions.apps + Included Namespaces: + nginx-test +Status: + Backedup File: /data/backup/promote-policy-sample20240311-104907 + Phase: Completed +Events: +``` +当 Status.Phase 为 'Completed' 时,表示迁移成功。 +此时,可以在控制平面集群中查看和管理 nginx-test 命名空间中的所有应用程序。 + +#### 回滚 +编辑 promote-nginx.yml 文件,并添加配置 'rollback'=true: +```shell script +# kubectl apply -f promote-nginx.yaml +apiVersion: kosmos.io/v1alpha1 +kind: PromotePolicy +metadata: + name: promote-policy-example +spec: + rollback: "true" + includedNamespaces: + - nginx-test + excludedNamespaceScopedResources: + - events + - events.events.k8s.io + - endpoints + - endpointslices.discovery.k8s.io + clusterName: cluster-36-28 +``` + +回滚结果检查: +```shell script +# kubectl describe promotepolicy promote-policy-example +Name: promote-policy-example +Namespace: default +Labels: +Annotations: +API Version: kosmos.io/v1alpha1 +Kind: PromotePolicy +Metadata: + Creation Timestamp: 2024-03-11T10:57:47Z + Generation: 5 + Resource Version: 405953692 + UID: 0e32dd93-c370-4874-b9a7-37a6894cd373 +Spec: + Cluster Name: cluster-36-28 + Excluded Namespace Scoped Resources: + events + events.events.k8s.io + endpoints + endpointslices.discovery.k8s.io + controllerrevisions.apps + Included Namespaces: + nginx-test +Status: + Backedup File: /data/backup/promote-policy-sample20240311-104907 + Phase: RolledBack +Events: +``` +当 `Status.Phase` 为 'RolledBack' 时,表示回滚成功。 +此时,nginx-test 命名空间中的应用程序在控制平面集群中无法查询到。 diff --git a/kosmos/docs/i18n/zh/v0.2.0/ccn-ipsec-tunnel_zh.md b/kosmos/docs/i18n/zh/v0.2.0/ccn-ipsec-tunnel_zh.md new file mode 100644 index 0000000..9961ff2 --- /dev/null +++ b/kosmos/docs/i18n/zh/v0.2.0/ccn-ipsec-tunnel_zh.md @@ -0,0 +1,136 @@ +--- +id: ipsec-network_zh +title: 'IPsec跨集群网络' +--- + +# IPsec跨集群容器网络解决方案 + +## 使用IPsec隧道在公共IP上进行跨集群容器网络通信 + +### 简介 +Kosmos是一个多集群解决方案,网络是其重要组成部分。 +有时候,需要在不同网络的Kubernetes集群之间进行通信。 +在某些情况下,两个或多个集群只能通过公共互联网进行通信。 +为了解决这个问题,Kosmos实现了基于IPsec隧道的跨集群容器网络通信解决方案。 + +### 动机 +出于灾难恢复的考虑,应用部署可能需要在多云多集群环境的不同区域(跨VPC)之间进行通信。 +在这种情况下,由于机器的内部IP地址通常无法直接访问而没有专用网络连接,容器通信变得具有挑战性。 +常见的CNI隧道技术如VxLAN或IPIP在公共互联网环境下可能无法有效工作。 +为解决此问题,Kosmos实现了基于IPsec隧道的容器网络通信解决方案,用于通过公共互联网进行跨云通信。 +该解决方案旨在满足在公共网络中进行通信的需求,并考虑数据传输的安全性。 + +### 目标 +目标是使用弹性公共IP地址使两个集群中的Pod能够通信。下图展示了流量的流向: + +![IPsec_Tunnel](img/IPsec_Tunnel.jpeg) + +:::info NOTE +此解决方案不涉及集群内主机网络模式下的容器网络通信。 +仅关注IPv4容器网络通信,并不涵盖IPv6容器网络。 +::: + +## 设计细节 + +### API变更 + +#### Cluster API变更 +此解决方案向 `.spec.ClusterLinkOptions` 添加了三个字段:`NodeElasticIPMap`、`ClusterPodCIDRs` 和 `UseExternalApiserver`。 +````shell script +type ClusterLinkOptions struct { + ... + // NodeElasticIPMap表示Kubernetes中节点名称与挂载在节点上的弹性IP之间的映射关系 + // +optional + NodeElasticIPMap map[string]string `json:"nodeElasticIPMap,omitempty"` + // +optional + ClusterPodCIDRs []string `json:"clusterpodCIDRs,omitempty"` + // +optional + UseExternalApiserver bool `json:"useexternalapiserver,omitempty"` +} +```` +- `NodeElasticIPMap` 字段表示Kubernetes中节点名称与挂载在节点上的弹性公共IP之间的映射关系。 +- `ClusterPodCIDRs` 字段用于输入Pod CIDR,因为对于某些CNI插件来说获取Pod CIDR并不总是容易的。 + +通常情况下,Kosmos通过kube-apiserver参数获取服务CIDR。 +然而,在某些情况下,kube-apiserver不是集群内的一个Pod。 +因此,添加了 `UseExternalApiserver` 字段以处理这种情况。 + +#### Clusternode API变更 +此解决方案向 `.spec` 添加了一个新字段 `ElasticIP`,并向 `.status` 添加了一个新字段 `NodeStatus`。 +````shell script +type ClusterNodeSpec struct { + ... + // +optional + ElasticIP string `json:"elasticip,omitempty"` +} + +type ClusterNodeStatus struct { + // +optional + NodeStatus string `json:"nodeStatus,omitempty"` +} +```` +- `ElasticIP` 字段描述了挂载在节点上的弹性公共IP。 +- `NodeStatus` 字段描述了节点的状态,可以是 "Ready" 或 "NotReady"。 + +#### Nodeconfig API变更 +此解决方案向 `.spec` 添加了两个新字段 `XfrmPoliciesXfrmStates` 和 `IPsetsAvoidMasqs`。 +````shell script +type NodeConfigSpec struct { + XfrmPolicies []XfrmPolicy `json:"xfrmpolicies,omitempty"` + XfrmStates []XfrmState `json:"xfrmstates,omitempty"` + IPsetsAvoidMasqs []IPset `json:"ipsetsavoidmasq,omitempty"` +} + +type XfrmPolicy struct { + LeftIP string `json:"leftip"` + LeftNet string `json:"leftnet"` + RightIP string `json:"rightip"` + RightNet string `json:"rightnet"` + ReqID int `json:"reqid"` + Dir int `json:"dir"` +} + +type XfrmState struct { + LeftIP string `json:"leftip"` + RightIP string `json:"rightip"` + ReqID int `json:"reqid"` + SPI uint32 `json:"spi"` + PSK string `json:"PSK"` +} + +type IPset struct { + CIDR string `json:"cidr"` + Name string `json:"name"` +} +```` +新的 `XfrmPolicies` 和 `XfrmStates` 字段定义了Kosmos创建的与IPsec相关的规则。 + +`IPsetsAvoidMasqs` 字段描述了需要避免伪装的网络段,允许容器的出站流量保留其容器IP地址。 + +### 组件修改 + +#### Clusterlink-controller-manager +处理kube-apiserver不在集群内的情况: +- 集群控制器通过 `GetSvcByCreateInvalidSvc` 函数优化服务CIDR的获取。 + +节点状态同步: +- 节点控制器基于 `Cluster` 对象的 `NodeElasticIPMap` 字段值,同步 `clusternode` 对象的 `ElasticIP` 字段。 +- 节点控制器现在根据节点的状态("Ready" 或 "NotReady")更新 `clusternode` 对象的 `.Status.NodeStatus` 字段。 + +#### Clusterlink-elector +选举模块用于在网关模式中选择网关。现在,它可以从处于 "Ready" 状态的节点中选择一个网关。 + +#### Clusterlink-network-manager +1. 添加对某些CNI插件的支持 + 对于某些CNI插件,添加了iptables规则以避免伪装,允许容器的出站流量保留其容器IP地址。 + +2. 构建IPsec规则 + 通常情况下,Kosmos创建路由以实现容器通信。在IPsec隧道模式下,如果 `clusternode` 的 `ElasticIP` 字段不为空,Kosmos会创建 `ip xfrm state` 和 `ip xfrm policy` 规则。 + +#### clusterlink-agent +添加了执行特定操作的函数,相当于在操作系统上执行 `ip xfrm state add/del` 和 `ip xfrm policy add/del` 命令。 + +为了避免伪装,添加了执行 `ipset` 命令和创建iptables规则的函数。 + +#### kosmosctl +添加了 `NodeElasticIP`、`UseExternalApiserver` 和 `ClusterPodCIDRs` 输入参数,用于填充 `Cluster` CRD 中的新字段 `NodeElasticIPMap`、`UseExternalApiserver` 和 `ClusterPodCIDRs`。 diff --git a/kosmos/docs/i18n/zh/v0.2.0/design-of-exec-and-log_zh.md b/kosmos/docs/i18n/zh/v0.2.0/design-of-exec-and-log_zh.md new file mode 100644 index 0000000..c28e1cb --- /dev/null +++ b/kosmos/docs/i18n/zh/v0.2.0/design-of-exec-and-log_zh.md @@ -0,0 +1,250 @@ +--- +id: exe-and-log_zh +title: 'Kosmos 中的 EXEC 和 Log 设计' +--- + +# Kosmos 中的 EXEC 和 Log 设计 + +## Kosmos 的 EXEC 和 Log 解决方案 + +### 简介 +在 Kosmos 中,调度到 kosmos-node 的 pod 也支持 `kubectl exec` 和 `kubectl log` 功能。 +由于 `kubectl exec` 和 `kubectl log` 的整体架构是相同的,我们将使用 `kubectl exec` 作为示例来介绍整体架构。 +下图展示了整体设计架构。 + +![EXE Log_Arch.png](img/EXEC_Log_Arch.png) + +### 背景知识 +首先,让我们探讨在 Kubernetes 中如何实现 `kubectl exec`。 +架构图中的 _**leaf-cluster**_ 部分是原生集群的 `kubectl exec` 功能的代表。 +用户发起的 kubectl exec 请求由 apiserver 处理。 +apiserver 在接收到 exec 请求后,需要将请求转发到 pod 所在的节点,因此需要查询分配了 pod 的节点信息。 +在 Kubernetes 源代码中,apiserver 会调用 `ExecLocation` 方法以获取 pod 的 exec url。 +代码如下: +````shell script +// ExecLocation 返回 pod 容器的 exec URL +// 如果 opts.Container 为空且 pod 中只有一个容器, 则使用该容器 +func ExecLocation( + ctx context.Context, + getter ResourceGetter, + connInfo client.ConnectionInfoGetter, + name string, + opts *api.PodExecOptions, +) (*url.URL, http.RoundTripper, error) { + return streamLocation(ctx, getter, connInfo, name, opts, opts.Container, "exec") +} +```` + +`ExecLocation` 调用了 `streamLocation` 方法,streamLocation 通过 pod 名称获取 pod 信息。 +````shell script +func streamLocation( + ctx context.Context, + getter ResourceGetter, + connInfo client.ConnectionInfoGetter, + name string, + opts runtime.Object, + container, + path string, +) (*url.URL, http.RoundTripper, error) { + pod, err := getPod(ctx, getter, name) + if err != nil { + return nil, nil, err + } + + // 尝试确定一个容器 + // 如果提供了一个容器, 则它必须是有效的 + container, err = validateContainer(container, pod) + if err != nil { + return nil, nil, err + } + + nodeName := types.NodeName(pod.Spec.NodeName) + if len(nodeName) == 0 { + // 如果 pod 尚未分配主机, 则返回空位置 + return nil, nil, errors.NewBadRequest(fmt.Sprintf("pod %s 尚未分配主机", name)) + } + nodeInfo, err := connInfo.GetConnectionInfo(ctx, nodeName) + if err != nil { + return nil, nil, err + } + params := url.Values{} + if err := streamParams(params, opts); err != nil { + return nil, nil, err + } + loc := &url.URL{ + Scheme: nodeInfo.Scheme, + Host: net.JoinHostPort(nodeInfo.Hostname, nodeInfo.Port), + Path: fmt.Sprintf("/%s/%s/%s/%s", path, pod.Namespace, pod.Name, container), + RawQuery: params.Encode(), + } + return loc, nodeInfo.Transport, nil +} +```` + +然后通过 `pod.Spec.NodeName` 获取分配 pod 的节点名称,再调用一个关键方法 `GetConnectionInfo`。 +代码如下: +````shell script +// GetConnectionInfo 从 Node API 对象的状态中检索连接信息 +func (k *NodeConnectionInfoGetter) GetConnectionInfo(ctx context.Context, nodeName types.NodeName) (*ConnectionInfo, error) { + node, err := k.nodes.Get(ctx, string(nodeName), metav1.GetOptions{}) + if err != nil { + return nil, err + } + + // 查找 kubelet 报告的地址, 使用首选地址类型 + host, err := nodeutil.GetPreferredNodeAddress(node, k.preferredAddressTypes) + if err != nil { + return nil, err + } + + // 使用 kubelet 报告的端口, 如果存在 + port := int(node.Status.DaemonEndpoints.KubeletEndpoint.Port) + if port <= 0 { + port = k.defaultPort + } + + return &ConnectionInfo{ + Scheme: k.scheme, + Hostname: host, + Port: strconv.Itoa(port), + Transport: k.transport, + InsecureSkipTLSVerifyTransport: k.insecureSkipTLSVerifyTransport, + }, nil +} +```` + +`GetConnectionInfo` 通过节点名称获取节点信息,然后使用 `GetPreferredNodeAddress` 选择一个合适的主机,通过 `streamLocation` 处理后,拼接一个 exec 请求 URL。 +apiserver 将知道应将 exec 请求转发到哪个节点。 +运行在节点上的 kubelet 服务将捕获 exec 请求,然后与 pod 建立链接。 + +以上简要介绍了建立 kubectl exec 的过程。 + +### 在 Kosmos 中的实现 +接下来,让我们看看整体架构图中的 _**root-cluster**_。 +为了将 exec 请求传递到 leaf 集群,需要对 exec 请求进行转发。 + +首先,我们需要告诉 apiserver,kosmos-node 的 IP 地址是 _**clustertree-cluster-manager**_ 的 podIP,这将导致 apiserver 将 exec 请求转发到 _**clustertree-cluster-manager**_。 +当我们同步 kosmos-node 的节点信息时,我们从环境变量 `LEAF_NODE_IP` 中读取该信息。 +启动 _**clustertree-cluster-manager**_ 服务时配置了此环境变量。 +关键配置片段如下: +````shell script +spec: + serviceAccountName: clustertree + containers: + - name: clustertree-cluster-manager + image: ghcr.io/kosmos-io/clustertree-cluster-manager:__VERSION__ + imagePullPolicy: IfNotPresent + env: + - name: APISERVER_CERT_LOCATION + value: /etc/cluster-tree/cert/cert.pem + - name: APISERVER_KEY_LOCATION + value: /etc/cluster-tree/cert/key.pem + - name: LEAF_NODE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: PREFERRED-ADDRESS-TYPE + value: InternalDNS +```` + +然后我们需要启动一个类似于 kubelet 的服务来监听 exec。 +在 _**clustertree-cluster-manager**_ 服务中,我们启动了一个 nodeserver 服务。 +代码片段如下: +````shell script +nodeServer := nodeserver.NodeServer{ + RootClient: mgr.GetClient(), + GlobalLeafManager: globalleafManager, +} +go func() { + if err := nodeServer.Start(ctx, opts); err != nil { + klog.Errorf("failed to start node server: %v", err) + } +}() +```` + +此服务监视 exec 和 log 请求,并将监视到的请求代理转发到相应的 leaf 集群。 +源代码如下: +````shell script +func (s *NodeServer) AttachRoutes(m *http.ServeMux) { + r := mux.NewRouter() + r.StrictSlash(true) + + r.HandleFunc( + "/containerLogs/{namespace}/{pod}/{container}", + api.ContainerLogsHandler(s.getClient), + ).Methods("GET") + + r.HandleFunc( + "/exec/{namespace}/{pod}/{container}", + api.ContainerExecHandler( + api.ContainerExecOptions{ + StreamIdleTimeout: 30 * time.Second, + StreamCreationTimeout: 30 * time.Second, + }, + s.getClient, + ), + ).Methods("POST", "GET") + + r.NotFoundHandler = http.HandlerFunc(api.NotFound) + + m.Handle("/", r) +} +```` + +完成转发部分后,我们需要让根集群中的 API server 识别 kosmos-node 的通信地址为 _**clustertree-cluster-manager**_ 服务的地址。 +因此,在维护 kosmos-node 的状态时,我们将 _**clustertree-cluster-manager**_ 的 podIP 同步到 kosmos-node。 +完整的过程如下: +- 用户发起 exec 请求。 +- 根集群中的 API server 接收到 exec 请求,并根据 pod 信息查询节点信息。 +- 查询到的节点主机是 _**clustertree-cluster-manager**_ 的 podIP。 +- 根集群中的 API server 与 _**clustertree-cluster-manager**_ 建立 exec 连接。 +- _**clustertree-cluster-manager**_ 接收到 exec 连接请求,查询 pod 信息,并将 exec 请求代理到 leaf 集群。 + 通过这个过程,Kosmos 实现了 exec 功能,log 功能的工作方式也是相同的。 + +### 定制化 +在与 es 产品对接时,有一个定制化需求。 +上述设计将导致所有 kosmos-node 的 IP 都是 _**clustertree-cluster-manager**_ 的 podIP。 +在 es 的产品设计中,nodeIP 用作主键,这会导致产品无法存储到仓库中。为此,kosmos 进行了特殊设计。 +在通过 kubectl get node -owide 获取的节点信息中,ip 地址属于 InternalIP 类型。 +```shell +sudo kubectl get nodes -owide +NAME STATUS ROLES AGE VERSION INTERNAL-IP + + EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME +kosmos-control-1 Ready control-plane,master,node 65d v1.21.5 192.xx.xx.1 BigCloud Enterprise Linux For Euler 21.10 LTS 4.19.90-2107.6.0.0192.8.oe1.bclinux.x86_64 containerd://1.5.7 +kosmos-control-2 Ready node 65d v1.21.5 192.xx.xx.2 BigCloud Enterprise Linux For Euler 21.10 LTS 4.19.90-2107.6.0.0192.8.oe1.bclinux.x86_64 containerd://1.5.7 +kosmos-cluster1 Ready agent 20d v1.21.5 192.xx.xx.3 +``` + +在查询节点主机时,上文提到的 GetPreferredNodeAddress 函数将根据优先级从 Address 列表中选择一个,因此在 es 中,我们将 _**clustertree-cluster-manager**_ 的 podIP 设置为比 InternalIP 类别地址更高的优先级,如下所示,可以指定 ip 的类型和值。 +````shell script +func GetAddress(ctx context.Context, rootClient kubernetes.Interface, originAddress []corev1.NodeAddress) ([]corev1.NodeAddress, error) { + preferredAddressType := corev1.NodeAddressType(os.Getenv("PREFERRED-ADDRESS-TYPE")) + + if len(preferredAddressType) == 0 { + preferredAddressType = corev1.NodeInternalDNS + } + + prefixAddress := []corev1.NodeAddress{ + {Type: preferredAddressType, Address: os.Getenv("LEAF_NODE_IP")}, + } + + address, err := SortAddress(ctx, rootClient, originAddress) + + if err != nil { + return nil, err + } + + return append(prefixAddress, address...), nil +} +```` + +如何查看地址优先级?通过查看 api-server 的启动参数 - kubelet-preferred-address-types,此处设置了 GetPreferredNodeAddress 函数以获取主机的优先级。 +默认情况下,InternalDNS 具有最高优先级。 +```shell script +- --kubelet-preferred-address-types=InternalDNS,InternalIP,Hostname,ExternaLDNS,ExternalIP +``` + +### 结论 +在 Kosmos 中,`kubectl exec` 和 `kubectl log` 都通过 API server 被“欺骗”并重定向到我们自己的 _**clustertree-cluster-manager**_ 服务。 +这使得我们可以在后续步骤中实现定制化功能。 \ No newline at end of file diff --git a/kosmos/docs/i18n/zh/v0.2.0/img/ClusterLink_Architecture.png b/kosmos/docs/i18n/zh/v0.2.0/img/ClusterLink_Architecture.png new file mode 100644 index 0000000..cf6180e Binary files /dev/null and b/kosmos/docs/i18n/zh/v0.2.0/img/ClusterLink_Architecture.png differ diff --git a/kosmos/docs/i18n/zh/v0.2.0/img/ClusterTree_Architecture.png b/kosmos/docs/i18n/zh/v0.2.0/img/ClusterTree_Architecture.png new file mode 100644 index 0000000..add8339 Binary files /dev/null and b/kosmos/docs/i18n/zh/v0.2.0/img/ClusterTree_Architecture.png differ diff --git a/kosmos/docs/i18n/zh/v0.2.0/introduction_zh.md b/kosmos/docs/i18n/zh/v0.2.0/introduction_zh.md new file mode 100644 index 0000000..ae82c3d --- /dev/null +++ b/kosmos/docs/i18n/zh/v0.2.0/introduction_zh.md @@ -0,0 +1,73 @@ +--- +id: introduction_zh +title: '简介' +--- + +# 简介 + +## 什么是 Kosmos? + +Kosmos 是一个开源的、一体化的分布式云原生解决方案。 +名称“kosmos”结合了代表 Kubernetes 的 'k' 和在希腊语中意为宇宙的 'cosmos',象征着 Kubernetes 的无限扩展。 + +目前,Kosmos 主要包括三个主要模块:`ClusterLink`、`ClusterTree` 和 `Scheduler`。 + +## ClusterLink + +ClusterLink 的目标是建立多个 Kubernetes 集群之间的连接。 +此模块可以独立部署和使用。 +ClusterLink 使 `Pods` 能够访问跨集群的 `Pods` 和 `Services`,就像它们在同一个集群中一样。 +目前,此模块主要提供以下功能: +1. **跨集群 PodIP 和 ServiceIP 通信**:基于 VxLAN 和 IPsec 等隧道技术的多 Kubernetes 集群之间的 L3 网络连接。 +这使用户能够在全球集群范围内进行 `Pod-to-Pod` 和 `Pod-to-Service` 通信。 +2. **多模式支持**:在加入集群时,可以选择 `P2P` 或 `Gateway` 模式。 +P2P 模式在覆盖层提供第二层网络互连,提供更短的网络路径和更优的性能。 +选择 `Gateway` 模式时,它表现出更好的兼容性,非常适合混合和多云场景。 +3. **支持全局 IP 分配**:ClusterLink 允许全局集群中存在两个或多个集群使用相同的 `Pod/Service` 网络段,方便用户管理子网。 +ClusterLink 支持配置 `PodCIDR/ServiceCIDR` 和 `GlobalCIDR` 之间的映射关系。 +`GlobalIP` 是全球唯一的,通过 `GlobalIP` 使冲突网络段的服务进行跨集群通信。 +4. **支持 IPv6/IPv4 双栈** + +### 网络架构 + +目前,Kosmos ClusterLink 模块包括以下关键组件: +![ClusterLink_Architecture.png](img/ClusterLink_Architecture.png) + +- `Controller-Manager`:收集当前集群的网络信息并监控网络设置的变化。 +- `Network-manager`:计算每个节点所需的网络配置。 +- `Agent`:一个 DaemonSet 用于配置主机网络,包括隧道创建、路由、NAT 等任务。 +- `Multi-Cluster-Coredns`:实现多集群服务发现。 +- `Elector`:选举网关节点。 + +## ClusterTree + +Kosmos clustertree 模块实现了 Kubernetes 的树状扩展,并实现了跨集群的应用编排。 +这是 Kosmos 实现 Kubernetes 无限扩展的技术基础。 +![ClusterTree_Architecture.png](img/ClusterTree_Architecture.png) + +目前,它主要支持以下功能: +1. **完全兼容 k8s API**:用户可以像平常一样使用 `kubectl`、`client-go` 等工具与主集群的 `kube-apiserver` 进行交互。然而,`Pods` 实际上分布在整个多云、多集群环境中。 +2. **支持有状态和 k8s 原生应用程序**:除了无状态应用程序外,Kosmos 还促进了有状态应用程序和 k8s 原生应用程序(与 `kube-apiserver` 交互)的编排。 +Kosmos 将自动检测 `Pods` 所依赖的存储和权限资源,如 pv/pvc、sa 等,并在控制平面集群和数据平面集群之间进行双向同步。 +3. **多样的 Pod 拓扑约束**:用户可以轻松控制全球集群内 Pods 的分布,如按地区、可用区、集群或节点。 +这有助于实现高可用性并提高资源利用率。 + +## Scheduler + +Kosmos 调度模块是在 Kubernetes 调度框架之上开发的扩展,旨在满足混合节点和子集群环境中的容器管理需求。 +它提供以下核心功能,以提高容器管理的灵活性和效率: + +1. **灵活的节点和集群混合调度**:Kosmos 调度模块允许用户根据自定义配置在真实节点和子集群之间智能调度工作负载。 +这使用户能够最佳利用不同节点上的资源,确保工作负载的最佳性能和可用性。 +基于此功能,Kosmos 使工作负载能够实现灵活的跨云和跨集群部署。 +2. **细粒度的容器分布策略**:通过引入自定义资源定义 (CRD),用户可以对工作负载的分布进行精确控制。 +CRD 的配置允许用户明确指定不同集群中工作负载的 pod 数量,并根据需要调整分布比例。 +3. **细粒度的碎片化资源处理**:Kosmos 调度模块智能检测子集群内的碎片化资源,有效避免 pod 部署遇到子集群内资源不足的情况。 +这有助于在不同节点间实现更均衡的资源分配,增强系统稳定性和性能。 + +无论是构建混合云环境还是需要灵活地跨集群部署工作负载,Kosmos 调度模块都是一个可靠的解决方案,帮助用户更高效地管理容器化应用。 + +## 下一步是什么 +- 开始 [安装 Kosmos](https://kosmos-io.github.io/website/v0.2.0/quick-start)。 +- 学习 Kosmos 的 [教程](https://kosmos-io.github.io/website/v0.2.0/tutorials/mcs-discovery)。 +- 学习 Kosmos 的 [提案](https://kosmos-io.github.io/website/v0.2.0/proposals/k8s-in-k8s)。 \ No newline at end of file diff --git a/kosmos/docs/i18n/zh/v0.2.0/multi-cluster-network_zh.md b/kosmos/docs/i18n/zh/v0.2.0/multi-cluster-network_zh.md new file mode 100644 index 0000000..d42da00 --- /dev/null +++ b/kosmos/docs/i18n/zh/v0.2.0/multi-cluster-network_zh.md @@ -0,0 +1,276 @@ +--- +id: mcn-connectivity_zh +title: '多集群网络联通' +--- + +# 多集群网络联通 + +Kosmos 多集群解决方案的 Clusterlink 设计旨在互连多个 Kubernetes 集群的节点和资源,形成统一的资源池。 +实现这一目标的基础之一是构建多集群网络架构,以满足不同集群之间的通信需求。 + +## 多集群容器网络解决方案 + +### 介绍 +Clusterlink 包含两种网络模式:Gateway 和 P2P。 +在 Gateway 模式下,当 Pod 发送数据包时,首先通过集群内的 vx-local 隧道到达该集群的 Gateway 节点,然后穿过跨集群隧道到达对端集群。 +一旦数据包到达对端集群,由 CNI 处理并通过单集群网络到达目标 Pod。 +这种模式的优点是每个集群只需要一个节点(或两个用于高可用性)提供外部访问,适用于多云和混合云场景。 +缺点是由于较长的网络路径,存在一定的性能损失。为了应对这一问题,Clusterlink 提供了 P2P 模式,适用于对网络性能要求较高的场景。 +在此模式下,数据包直接发送到目标 Pod 所在的节点。 +此外,P2P 和 Gateway 模式可以组合使用。 + +### 设计 +Kosmos 多集群网络 Gateway 解决方案的架构如下: + +![MCN GW_Architecture.png](img/MCN_GW_Architecture.png) + +:::info 注意 +提供了很强的兼容性,每个集群只需要一个节点(或两个用于高可用性)提供外部访问,适用于跨云场景。 +::: + +Kosmos 多集群网络 P2P 解决方案的架构如下: + +![MCN P2P_Architecture.png](img/MCN_P2P_Architecture.png) + +:::info 注意 +具有较短的网络路径和更好的性能,适用于完全互联的 Underlay 场景。 +::: + +### 先决条件 + +#### 安装 Kosmos +参考 Kosmos 快速入门文档 https://github.com/kosmos-io/kosmos 并启用 ClusterLink 模块以进行多集群网络配置。 +使用 kosmosctl 工具: +```shell script +kosmosctl install --cni calico --default-nic eth0 // 我们根据参数 default-nic 传递的网络接口值建立网络隧道 +``` + +#### 加入叶子集群 +```shell script +kosmosctl join cluster --name cluster1 --kubeconfig ~/kubeconfig/cluster1-kubeconfig --cni calico --default-nic eth0 --enable-link +``` + +### 跨集群 L3 网络连接性 +为了实现 Kosmos 中的跨集群 L3 网络连接性,需要至少两个不同集群的节点在主机网络层能够相互通信,并且集群必须正确部署并支持 VXLAN 或 IPSec 技术。 + +#### Gateway 模式 +在 Kosmos 联邦中的每个 Kubernetes 集群中,使用 Elector 模块选举一个节点作为 Gateway(GW)节点。 +两个集群的 GW 节点通过 vx-bridge 隧道(由 Kosmos 创建)进行通信以建立连接。 +在每个集群内,路由由 GW 节点处理。 +相比 P2P 模式,GW 模式由于 GW 节点的额外数据包封装和解封装,网络性能略低。 +然而,其优势在于集群节点的路由表和 FDB 表几乎可以保持不变。 +因此,GW 模式适用于对网络性能要求不高的更大规模多集群场景。 + +#### P2P 模式 +在 P2P 模式下,不需要使用 Elector 模块。 +Kosmos 在每个集群的所有节点上创建 vx-bridge 接口,实现不同集群节点之间的直接容器网络通信。 +此模式下的网络性能几乎与单个 Kubernetes 集群相同。 +然而,在 P2P 模式下,每个集群的每个节点需要为 Kosmos 联邦中的所有节点配置访问规则,导致较大的路由和 FDB 表大小。 +因此,P2P 模式适用于对网络性能要求较高但每个集群节点数量较少的场景。 + +### 启动 ClusterLink + +#### 使用 P2P 模式 +```shell script +# 完成“安装 Kosmos”和“加入叶子集群”部分的步骤 +# 检查集群资源是否正确创建 +[root@kosmos-control-cluster yaml]# kubectl --kubeconfig config-14 get clusters.kosmos.io +NAME NETWORK_TYPE IP_FAMILY +cluster38 p2p all +kosmos-control-cluster p2p all + +# 检查 clusternodes 资源是否正确创建 +[root@kosmos-control-cluster yaml]# kubectl get clusternodes.kosmos.io +NAME ROLES INTERFACE IP +cluster38-001 bond0.1820 10.*.*.38 +cluster38-002 bond0.1820 10.*.*.39 +cluster38-003 bond0.1830 10.*.*.94 +cluster38-004 ["gateway"] bond0.1830 10.*.*.95 +kosmos-control-cluster-001 bond0.1820 10.*.*.14 +kosmos-control-cluster-002 bond0.1820 10.*.*.15 +kosmos-control-cluster-003 ["gateway"] bond0.1565 10.*.*.38 +kosmos-control-cluster-004 bond0.1565 10.*.*.31 +kosmos-control-cluster-005 bond0.1565 10.*.*.32 +kosmos-control-cluster-006 bond0.1565 10.*.*.33 +kosmos-control-cluster-007 bond0.1565 10.*.*.37 + +# 检查 nodeconfigs 资源是否正确创建 +[root@kosmos-control-cluster yaml]# kubectl get nodeconfigs.kosmos.io +NAME AGE +cluster38-001 14d +cluster38-002 14d +cluster38-003 14d +cluster38-004 14d +kosmos-control-cluster-001 48d +kosmos-control-cluster-002 48d +kosmos-control-cluster-003 49d +kosmos-control-cluster-004 49d +kosmos-control-cluster-005 45d +kosmos-control-cluster-006 45d +kosmos-control-cluster-007 45d +``` + +#### 创建测试 Pods +通过在 kosmos-control-cluster 和 cluster38 集群中创建 Pod 验证跨集群容器网络连接性。 +为了确保容器具有常见的网络工具(如 Ping 和 Curl),使用 clusterlink-floater 镜像。 +以下是创建 Pods 的示例 YAML: +```yaml +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: clusterlink-floater + namespace: kosmos-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: clusterlink-floater +rules: + - apiGroups: ['*'] + resources: ['*'] + verbs: ["*"] + - nonResourceURLs: ['*'] + verbs: ["get"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: clusterlink-floater +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: clusterlink-floater +subjects: + - kind: ServiceAccount + name: clusterlink-floater + namespace: kosmos-system +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: clusterlink-floater + namespace: kosmos-system +spec: + replicas: 1 + selector: + matchLabels: + app: clusterlink-floater + template: + metadata: + labels: + app: clusterlink-floater + spec: + hostNetwork: false + serviceAccountName: clusterlink-floater + containers: + - name: floater + image: ghcr.io/kosmos-io/clusterlink-floater:v0.2.0-lts + imagePullPolicy: IfNotPresent + command: + - clusterlink-floater + securityContext: + privileged: true + env: + - name: "PORT" + value: "8889" + - name: "ENABLE_ANALYSIS" + value: "false" + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kosmos.io/exclude + operator: DoesNotExist + tolerations: + - effect: NoSchedule + operator: Exists + - key: CriticalAddonsOnly + operator: Exists + - effect: NoExecute + operator: Exists +``` + +:::info NOTE +本节提供的测试用例只能检查两个集群中节点之间的容器网络连接性。 +要快速测试集群中的所有节点,请参阅第 5 节。 +::: + +确保 Pods 在 kosmos-control-cluster 和 cluster38 集群中成功运行: +````shell script +[root@kosmos-control-cluster yaml]# kubectl -n kosmos-system get pod +NAME READY STATUS RESTARTS AGE +clusterlink-agent-6qq4v 1/1 Running 0 15d +clusterlink-agent-6v9jm 1/1 Running 0 15d +clusterlink-agent-7zpf5 1/1 Running 0 15d +clusterlink-agent-84d68 1/1 Running 0 15d +clusterlink-agent-dj9q2 1/1 Running 0 26h +clusterlink-agent-r2zj4 1/1 Running 0 15d +clusterlink-agent-vlh2x 1/1 Running 0 3d3h +clusterlink-controller-manager-6774ddd58b-bcn7s 1/1 Running 0 15d +clusterlink-elector-6b597b44f7-jrbg6 1/1 Running 0 15d +clusterlink-elector-6b597b44f7-mj882 1/1 Running 0 15d +clusterlink-floater-7dcb47579-lddgc 1/1 Running 0 77s +clusterlink-network-manager-6489597986-h74m4 1/1 Running 0 15d +clustertree-cluster-manager-6778bd7b6c-mwhpj 1/1 Running 0 5h45m +kosmos-operator-c88898f66-b8mjl 1/1 Running 0 15d +kosmos-scheduler-7dcfd94bf7-2km8m 1/1 Running 0 8d + +[root@cluster38 yaml]# kubectl -n kosmos-system get pod +NAME READY STATUS RESTARTS AGE +clusterlink-agent-jsv2b 1/1 Running 0 14d +clusterlink-agent-qncxt 1/1 Running 0 14d +clusterlink-agent-rzngm 1/1 Running 0 14d +clusterlink-agent-s252r 1/1 Running 0 14d +clusterlink-controller-manager-77fbbd9f78-bz47t 1/1 Running 0 14d +clusterlink-elector-86b49775b5-x4gsp 1/1 Running 0 14d +clusterlink-elector-86b49775b5-z4lb5 1/1 Running 0 14d +clusterlink-floater-7dcb47579-jx85c 1/1 Running 0 16s +```` + +获取两个 Pod 的 IP 地址,并进入其中一个 Pod 的容器执行 Ping 命令,以验证跨集群的容器网络连接。示例如下: +````shell script +[root@cluster38 yaml]# kubectl -n kosmos-system get pod clusterlink-floater-7dcb47579-jx85c -oyaml |grep ip + - ip: 10.*.*.253 + - ip: fd11:1111:*:*:*:*:4573:f17d + +[root@kosmos-control-cluster yaml]# kubectl -n kosmos-system exec -it clusterlink-floater-7dcb47579-lddgc -- sh +/ # ping 10.*.*.253 +PING 10.*.*.253 (10.*.*.253): 56 data bytes +64 bytes from 10.*.*.253: seq=0 ttl=62 time=0.592 ms +64 bytes from 10.*.*.253: seq=1 ttl=62 time=0.362 ms +64 bytes from 10.*.*.253: seq=2 ttl=62 time=0.388 ms +64 bytes from 10.*.*.253: seq=3 ttl=62 time=0.373 ms +^C +--- 10.*.*.253 ping statistics --- +4 packets transmitted, 4 packets received, 0% packet loss +round-trip min/avg/max = 0.362/0.428/0.592 ms +/ # ping -6 fd11:1111:*:*:*:*:4573:f17d +PING fd11:1111:*:*:*:*:4573:f17d (fd11:1111:*:*:*:*:4573:f17d): 56 data bytes +64 bytes from fd11:1111:*:*:*:*:4573:f17d: seq=0 ttl=62 time=0.679 ms +64 bytes from fd11:1111:*:*:*:*:4573:f17d: seq=1 ttl=62 time=0.492 ms +64 bytes from fd11:1111:*:*:*:*:4573:f17d: seq=2 ttl=62 time=0.406 ms +64 bytes from fd11:1111:*:*:*:*:4573:f17d: seq=3 ttl=62 time=1.488 ms +^C +--- fd11:1111:*:*:*:*:4573:f17d ping statistics --- +4 packets transmitted, 4 packets received, 0% packet loss +round-trip min/avg/max = 0.406/0.766/1.488 ms +```` + +### 一键诊断集群连接 +集群连接诊断 (Floater) 功能旨在解决使用 Kosmos 时持续检查多个 Kubernetes 集群之间网络连接的挑战。当集群数量较少时,例如只有两个集群,这项任务可能并不困难。然而,当集群数量达到 5000 或更多时,即使是最热情的运维人员也会发现几乎不可能完成这项任务。 + +为了解决这个问题,我们设计了 Floater 功能,它可以在集群中的每个节点上漂浮。通过 kosmosctl 工具,您可以使用一个命令诊断多个 Kubernetes 集群之间的网络连接。 +ClusterLink Floater 的架构如下: + +![MCN Floater_Flow.png](img/MCN_Floater_Flow.png) + +kosmosctl 命令行工具提供了一键诊断命令 "dr",可以轻松验证多个 Kubernetes 集群之间的网络连接,包括但不限于主机网络、容器网络和原生集群网络。示例如下: +````shell script +# 验证跨集群的主机网络 +kosmosctl dr -r ghcr.io/kosmos-io/komos --src-kubeconfig root-config --dst-kubeconfig cluster38-config --host-network + +# 验证跨集群的容器网络 +kosmosctl dr -r ghcr.io/kosmos-io/komos --src-kubeconfig root-config --dst-kubeconfig cluster38-config +```` \ No newline at end of file diff --git a/kosmos/docs/i18n/zh/v0.2.0/multi-cluster-scheduler_zh.md b/kosmos/docs/i18n/zh/v0.2.0/multi-cluster-scheduler_zh.md new file mode 100644 index 0000000..598e2fd --- /dev/null +++ b/kosmos/docs/i18n/zh/v0.2.0/multi-cluster-scheduler_zh.md @@ -0,0 +1,243 @@ +--- +id: mc-scheduler_zh +title: '多集群调度器' +--- + +# 多集群调度器 + +当 Kosmos 加入一个成员集群后,它会映射一个带有 `kosmos.io/node=true:Noschedule` 污点的虚拟节点,因此 Kubernetes 默认调度器无法将 Pod 调度到该虚拟节点(即成员集群)上。 +部署 kosmos-scheduler 后,用户可以通过 kosmos-scheduler 中的 `LeafNodeTaintToleration` 调度插件容忍 `kosmos.io/node=true:Noschedule` 污点,从而实现成员集群和主机集群节点之间的混合调度效果。 + +对于带有 PV/PVC 的 Pod,还需在 kosmos-scheduler 中配置 `LeafNodeVolumeBinding` 调度插件,以在存储卷绑定过程中直接使用带有 `kosmos.io/node=true:Noschedule` 污点的虚拟节点。 + +需要注意的是,对于不同版本的 Kubernetes,发布的默认调度器所依赖的调度模块(调度框架)也会随版本变化而变化。目前,Kosmos 已适配了两个版本(`release-1.21.5` 和 `release-1.26.3`)。以下验证部分将使用 `release-1.21.5` 进行部署和测试。 + +## 多集群调度器解决方案 + +### 简介 +调度器框架最初通过 Kubernetes 增强提案中的 [624-scheduling-framework](https://link.zhihu.com/?target=https%3A//github.com/kubernetes/enhancements/tree/master/keps/sig-scheduling/624-scheduling-framework) 提案引入,主要实现以下目标: +- 使调度器更加可扩展。 +- 通过将一些功能移至插件,使调度器核心更简单。 +- 在框架中提出扩展点。 +- 提出根据收到的结果继续或中止的插件结果接收机制。 +- 提出处理错误并将其与插件通信的机制。 + +为此,调度器框架定义了多个扩展点,如下图所示: +![MC_Scheduler.png](img/MC_Scheduler.png) + +kosmos-scheduler 中的 `LeafNodeTaintToleration` 和 `LeafNodeVolumeBinding` 调度插件主要是基于 Kubernetes 默认调度器的 `NodeTaintToleration` 和 `NodeVolumeBinding` 调度插件进行优化的。 +`LeafNodeTaintToleration` 插件主要在 `Filter` 扩展点中为虚拟节点上的 `kosmos.io/node=true:Noschedule` 污点添加容忍。 +`LeafNodeVolumeBinding` 插件主要在 `Filter`、`Reserve`、`Unreserved` 和 `PreBind` 扩展点上起作用,并直接传递带有 `kosmos.io/node=true:Noschedule` 污点的虚拟节点。 + +### 先决条件 + +#### 安装 Kosmos +参考 Kosmos 快速入门文档 https://github.com/kosmos-io/kosmos 并为多集群网络启用 ClusterLink 模块。使用 kosmosctl 工具: +````shell script +kosmosctl install --cni calico --default-nic eth0 // 我们基于传递的网络接口值构建网络隧道 +```` +:::info 提示 +至少部署 clustertree 模块并正确加入叶子集群。 +::: + +#### 加入叶子集群 +````shell script +kosmosctl join cluster --name cluster1 --kubeconfig ~/kubeconfig/cluster1-kubeconfig --cni calico --default-nic eth0 --enable-link +```` + +### 部署 Kosmos-scheduler +1. 配置调度器和调度策略: +````shell script +--- +# kosmos-scheduler 调度策略 +apiVersion: v1 +kind: ConfigMap +metadata: + name: scheduler-config + namespace: kosmos-system +data: + scheduler-config.yaml: | + apiVersion: kubescheduler.config.k8s.io/v1beta1 + kind: KubeSchedulerConfiguration + leaderElection: + leaderElect: true + resourceName: kosmos-scheduler + resourceNamespace: kosmos-system + profiles: + - schedulerName: kosmos-scheduler + plugins: + preFilter: + disabled: + - name: "VolumeBinding" + enabled: + - name: "LeafNodeVolumeBinding" + filter: + disabled: + - name: "VolumeBinding" + - name: "TaintToleration" + enabled: + - name: "LeafNodeTaintToleration" + - name: "LeafNodeVolumeBinding" + score: + disabled: + - name: "VolumeBinding" + reserve: + disabled: + - name: "VolumeBinding" + enabled: + - name: "LeafNodeVolumeBinding" + preBind: + disabled: + - name: "VolumeBinding" + enabled: + - name: "LeafNodeVolumeBinding" + pluginConfig: + - name: LeafNodeVolumeBinding + args: + bindTimeoutSeconds: 5 +--- +# 调度器配置 +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kosmos-scheduler + namespace: kosmos-system + labels: + component: scheduler +spec: + replicas: 1 + selector: + matchLabels: + component: scheduler + template: + metadata: + labels: + component: scheduler + spec: + volumes: + - name: scheduler-config + configMap: + name: scheduler-config + defaultMode: 420 + containers: + - name: kosmos-scheduler + image: ghcr.io/kosmos-io/scheduler:0.0.2 + command: + - scheduler + - --config=/etc/kubernetes/kube-scheduler/scheduler-config.yaml + resources: + requests: + cpu: 200m + volumeMounts: + - name: scheduler-config + readOnly: true + mountPath: /etc/kubernetes/kube-scheduler + livenessProbe: + httpGet: + path: /healthz + port: 10259 + scheme: HTTPS + initialDelaySeconds: 15 + periodSeconds: 10 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /healthz + port: 10259 + scheme: HTTPS + restartPolicy: Always + dnsPolicy: ClusterFirst + serviceAccountName: kosmos-scheduler + serviceAccount: kosmos-scheduler +```` + +2. 验证 kosmos-scheduler 服务: +````shell script +# 创建 kosmos-scheduler +kubectl -n kosmos-system get pod +NAME READY STATUS RESTARTS AGE +kosmos-scheduler-8f96d87d7-ssxrx 1/1 Running 0 24s +```` + +#### 示例 +1. 在测试集群上部署 openebs + +2. 使用案例 yaml(mysql-cluster.yaml) +````shell script +apiVersion: v1 +kind: Secret +metadata: + namespace: test-mysql + name: my-secret +type: Opaque +data: + # 需要指定 root 密码 + ROOT_PASSWORD: ${your_password} + ## 在集群启动时创建的应用凭据 + # DATABASE: + # USER: + # PASSWORD: +--- +kind: MysqlCluster +metadata: + name: test-mysql-cluster + namespace: test-mysql +spec: + replicas: 2 + secretName: my-secret + image: docker.io/percona:5.7 + mysqlVersion: "5.7" + podSpec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + mysql.presslabs.org/cluster: test-mysql-cluster + topologyKey: kubernetes.io/hostname + volumeSpec: + persistentVolumeClaim: + storageClassName: openebs-hostpath + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +```` + +3. 操作说明 +````shell script +# 显示主机集群中的所有节点 +kubectl get node +NAME STATUS ROLES AGE VERSION +kosmoscluster1-1 Ready control-plane,master,node 21d v1.21.5-eki.0 +kosmoscluster1-2 Ready node + + 21d v1.21.5-eki.0 +kosmos-member2-cluster-1 Ready agent 24m v1.21.5-eki.0 +kosmos-member2-cluster-2 Ready agent 24m v1.21.5-eki.0 + +# 显示虚拟节点上的污点信息 +kubectl describe node kosmos-member2-cluster-1 |grep Tai +Taints: node.kubernetes.io/unreachable:NoExecute + +kubectl describe node kosmos-member2-cluster-2 |grep Tai +Taints: node.kubernetes.io/unreachable:NoExecute + +# 使用 kosmos-scheduler 进行(混合)调度 +kubectl apply -f mysql-cluster.yaml + +# 在主机集群中显示实例(混合)调度结果 +kubectl get pod -owide -n test-mysql +NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES +test-mysql-cluster-mysql-0 4/4 Running 0 3m 2409:xxxxx:8ac kosmoscluster1-2 +test-mysql-cluster-mysql-1 4/4 Running 0 2m 2409:xxxxx:8ae kosmos-member2-cluster-1 + +# 在成员集群中显示实例(混合)调度结果 +kubectl get pod -owide -n test-mysql +NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES +test-mysql-cluster-mysql-1 4/4 Running 0 2m 2409:xxxxx:8ae kosmos-member2-cluster-1 +```` + +### 结论 +可以看到,kosmos-scheduler 成功将用户实例的 Pod 调度到了主机集群和成员集群中。 diff --git a/kosmos/docs/i18n/zh/v0.2.0/node-not-ready_zh.md b/kosmos/docs/i18n/zh/v0.2.0/node-not-ready_zh.md new file mode 100644 index 0000000..62aba3e --- /dev/null +++ b/kosmos/docs/i18n/zh/v0.2.0/node-not-ready_zh.md @@ -0,0 +1,133 @@ +--- +id: node-not-ready_zh +title: 'Kosmos 节点 NotReady' +--- + +# Kosmos 节点 NotReady + +## Kosmos 节点 NotReady 解决方案 + +### 简介 +假设我们已经在主集群上注册了集群 `cluster7`: +````shell script +$ kubectl get node +NAME STATUS ROLES AGE VERSION +ecs-54004033-001 Ready worker 50d v1.21.5 +ecs-54004033-002 Ready control-plane,master,worker 50d v1.21.5 +kosmos-cluster7 Ready agent 5d22h v1.21.5 +```` + +Kosmos 的 clustertree-cluster-manager 将持续监视 `cluster7` 集群的资源使用情况和集群状态,并将其更新到主集群上的叶节点 `kosmos-cluster7`。 +````shell script +$ kubectl get deploy -nkosmos-system +NAME READY UP-TO-DATE AVAILABLE AGE +clusterlink-controller-manager 1/1 1 1 5d22h +clusterlink-elector 2/2 2 2 5d22h +clusterlink-network-manager 1/1 1 1 5d22h +clustertree-cluster-manager 1/1 1 1 5d22h +kosmos-operator 1/1 1 1 5d22h +kosmos-webhook 1/1 1 1 11 +```` +如果主集群与 `cluster7` 集群之间存在网络波动,Kosmos 将检测到此异常,并将主集群上叶节点 `kosmos-cluster7` 的状态设置为 "NotReady"。 +这将触发 Kubernetes 的 Pod 驱逐行为,意味着在 "NotReady" 节点上的 Pod 将被驱逐到其他 Ready 节点。 + +然而,由于网络波动,`kosmos-cluster7` 的状态在驱逐过程中可能会再次变为 "Ready"。 +但最初驱逐的 Pod 的事件仍将发送到 "cluster7" 集群,导致在 "cluster7" 集群上的正常运行的 Pod 被删除或重新启动,从而影响业务。 + +### 解决方案:集成 Kyverno 解决 Kosmos 节点 NotReady 的问题 +[Kyverno](https://kyverno.io/) 通过 Kubernetes 准入 Webhook、后台扫描和源代码库扫描来验证、变更、生成和清理配置。 +Kyverno 策略可以作为 Kubernetes 资源进行管理。 + +它的主要功能如下: + +- 验证、变更、生成或清理(删除)任何资源 +- 验证容器镜像以用于软件供应链安全性 +- 使用标签选择器和通配符匹配资源 +- 在命名空间间同步配置 +- 使用准入控制阻止非符合资源,或报告策略违规 + +本文将解释如何使用 Kyverno 的准入 Webhook 来防止 Kosmos 节点 NotReady 时的 Pod 驱逐。 + +#### 什么是准入 Webhook? +准入 Webhook 是一段代码,在对象持久化到 Kubernetes API 服务器之前拦截请求。 +它允许请求通过认证和授权后才能通过。准入控制器可以执行验证、变更或两者都执行。 +变更控制器修改它们处理的资源对象,而验证控制器不会。如果任何控制器在任何阶段拒绝请求,整个请求将立即被拒绝,并将错误返回给最终用户。 + +![K8s_Admission_Webhook.png](img/K8s_Admission_Webhook.png) + +#### 解决方案 + +##### 安装 Kyverno +[安装 Kyverno](https://kyverno.io/docs/installation/methods/) + +```shell script +kubectl create -f https://github.com/kyverno/kyverno/releases/download/v1.10.0/install.yaml +``` + +##### 配置 ClusterPolicy +以下是四种情况下 K8s 驱逐 Pod: + +- **用户发起**:由 API 发起的驱逐请求。例如,节点维护期间,为了避免节点突然下线对服务造成的影响,会驱逐节点上的所有 Pod。 +- **Kubelet 发起**:定期检查节点资源。当资源不足时,基于优先级,将驱逐一些 Pod。 +- **kube-controller-manager 发起**:定期检测所有节点。当节点的 NotReady 状态超过一段时间时,将驱逐节点上的所有 Pod,以便将其重新调度到其他正常节点上运行。启用污点驱逐时,在节点上出现 `NoExecute` 污点后,无法容忍污点的 Pod 将立即被驱逐。对于可以容忍污点的 Pod,在 Pod 上配置的最小污点容忍时间后,将被驱逐。 +- **kube-scheduler 发起**:当实现抢占调度时,低优先级 Pod 可能会被驱逐,以为高优先级和抢占 Pod 腾出位置,从而使高优先级 Pod 可以正常调度。 + +使用以下配置,我们将仅阻止符合以下三个条件的 Pod 删除事件: + +(1) 节点状态为 NotReady + +(2) 节点是 KosmosNode + +(3) 用户名为 system:serviceaccount:kube-system:node-controller(属于 node-controller 的 kube-controller-manager) + +```yaml +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: kosmos-node-not-ready +spec: + validationFailureAction: Enforce + background: false + rules: + - match: + any: + - resources: + kinds: + - Pod + operations: + - DELETE + name: kosmos-node-not-read + context: + - name: nodeStatus + apiCall: + urlPath: /api/v1/nodes/{{request.oldObject.spec.nodeName}} + jmesPath: status.conditions[?type=='Ready'].status | [0] + - name: isKosmosNode + apiCall: + urlPath: /api/v1/nodes/{{request.oldObject.spec.nodeName}} + jmesPath: metadata.labels."kosmos.io/node" + preconditions: + all: + - key: "{{ request.userInfo.username }}" + operator: Equals + value: "system:serviceaccount:kube-system:node-controller" + - key: "{{ nodeStatus }}" + operator: NotEquals + value: "True" + - key: "{{ length(isKosmosNode) }}" + operator: GreaterThan + value: 0 + validate: + message: "{{ request.userInfo.username }} 不允许删除 NotReady Kosmos {{request.oldObject.spec.nodeName}} 节点上的 Pod {{request.oldObject.metadata.name}}。" + deny: {} +``` + +当 Kosmos 节点状态为 NotReady 时,将阻止在此类节点上的 Pod。您可以通过查看 kyverno-admission-controller 来查看以下日志。 + +```shell script +handlers.go:139] webhooks/resource/validate "msg"="admission request denied" "clusterroles"=["system:basic-user","system:controller:node-controller","system:discovery","system:public-info-viewer","system:service-account-issuer-discovery"] "gvk"={"group":"","version":"v1","kind":"Pod"} "gvr"={"group":"","version":"v1","resource":"pods"} "kind"="Pod" "name"="example-deployment-6cc4fd9bd7-kkm8z" "namespace"="default" "operation"="DELETE" "resource.gvk"={"Group":"","Version":"v1","Kind":"Pod"} "roles + +"=null "uid"="7f25ee88-4522-45fd-a6ba-38733122b443" "user"={"username":"system:serviceaccount:kube-system:node-controller","uid":"5a13be66-71fd-40e3-9553-00eb0825fbb0","groups":["system:serviceaccounts","system:serviceaccounts:kube-system","system:authenticated"]} +event.go:307] "Event occurred" object="kosmos-node-not-ready" fieldPath="" kind="ClusterPolicy" apiVersion="kyverno.io/v1" type="Warning" reason="PolicyViolation" message="Pod default/example-deployment-6cc4fd9bd7-kkm8z: [kosmos-node-not-ready] fail (blocked); system:serviceaccount:kube-system:node-controller delete pod example-deployment-6cc4fd9bd7-kkm8z of NotReady Kosmos kosmos-cluster2 Node is not allowed. " +validation.go:103] webhooks/resource/validate "msg"="validation failed" "action"="Enforce" "clusterroles"=["system:basic-user","system:controller:node-controller","system:discovery","system:public-info-viewer","system:service-account-issuer-discovery"] "failed rules"=["kosmos-node-not-ready"] "gvk"={"group":"","version":"v1","kind":"Pod"} "gvr"={"group":"","version":"v1","resource":"pods"} "kind"="Pod" "name"="example-deployment-6cc4fd9bd7-sb7m7" "namespace"="default" "operation"="DELETE" "policy"="kosmos-node-not-ready" "resource"="default/Pod/example-deployment-6cc4fd9bd7-sb7m7" "resource.gvk"={"Group":"","Version":"v1","Kind":"Pod"} "roles"=null "uid"="251f1877-4f2c-40ec-9bca-8ceb7c9c845f" "user"={"username":"system:serviceaccount:kube-system:node-controller","uid":"5a13be66-71fd-40e3-9553-00eb0825fbb0","groups":["system:serviceaccounts","system:serviceaccounts:kube-system","system:authenticated"]} +``` diff --git a/kosmos/docs/i18n/zh/v0.2.0/pv-pvc-dynamic-storage_zh.md b/kosmos/docs/i18n/zh/v0.2.0/pv-pvc-dynamic-storage_zh.md new file mode 100644 index 0000000..72b6edd --- /dev/null +++ b/kosmos/docs/i18n/zh/v0.2.0/pv-pvc-dynamic-storage_zh.md @@ -0,0 +1,196 @@ +--- +id: pv-pvc-dynamic-storage_zh +title: '多集群 PV/PVC 动态存储' +--- + +# 多集群 PV/PVC 动态存储解决方案 + +## 多集群 PV/PVC 动态存储实现 + +### 介绍 +本文主要介绍在 Kosmos 跨集群中,为有状态服务相关的 Pod 实现 PV/PVC 存储管理。 +详细说明了创建、更新和绑定 Pod 的 PV 和 PVC 的过程。 +通过本文,您可以全面了解在 Kosmos 中管理有状态服务的细节。 + +:::info 提示 +目前的实现是一个中间版本,未来会对全球存储进行进一步优化。 +::: + +### 方法 + +#### 单个 Kubernetes 集群中 PVC、PV 和 SC 的角色 +1. 持久卷 (Persistent Volume, PV): +- PV 是 Kubernetes 集群中的存储卷资源,将其与实际的存储后端抽象和分离开来。 +- PV 可以是任何形式的存储,如网络存储、本地存储、云存储等。 +- PV 可以由 PV 管理员或集群中的动态存储插件预先创建,也可以根据 PVC 的要求动态创建。 +- PV 描述了存储属性,如容量、访问模式(例如,读/写)和回收策略。 + +2. 持久卷声明 (Persistent Volume Claim, PVC): +- PVC 是应用程序对存储资源的请求,它在 Pod 中指定所需的存储容量和其他属性,如访问模式和卷模式。 +- 应用程序使用 PVC 声明其存储需求,而无需指定实际的存储位置或类型。Kubernetes 会根据 PVC 的需求匹配集群中的可用 PV 以满足 PVC 的需求。 +- PVC 可以请求动态配置的匹配 PV 或手动选择特定的 PV 对象。 + +3. 存储类 (StorageClass, SC): +- SC 定义了 PV 的动态配置策略,指定了如何根据 PVC 的需求自动创建 PV。 +- 当 PVC 请求特定的 StorageClass 时,Kubernetes 会根据 StorageClass 中定义的规则创建 PV 并自动将 PV 绑定到 PVC。 +- StorageClass 允许定义不同类型的存储,为不同的应用程序提供不同的存储选项。 + +#### 单个 Kubernetes 集群中 PVC、PV 和 StorageClass 的实现过程 +- 当应用程序中的 Pod 需要访问持久存储时,会创建一个 PVC 对象来声明所需的存储。 +- 根据 PVC 中定义的需求,Kubernetes 会通过 StorageClass 匹配适合的 PV 并进行绑定。 +- 在 PV 和 PVC 成功绑定后,应用程序可以直接使用 PVC 提供的存储并在 Pod 中挂载存储路径。 + +#### StorageClass 卷绑定模式 +在 StorageClass 定义中,'volumeBindingMode' 字段指定了动态配置器如何绑定 PVC 和 PV。以下是几种常见的卷绑定模式: +- Immediate: 在这种模式下,配置器会立即将可用的 PV 绑定到 PVC。如果没有可用的 PV 满足 PVC 的要求,PVC 将保持在 Pending 状态。 +- WaitForFirstConsumer: 在这种模式下,配置器会等待引用 PVC 的 Pod 尝试挂载卷后再分配 PV。当 Pod 使用 PVC 时,PV 会被动态绑定。 +- Cluster: 这是默认的绑定模式。PV 会立即分配给 PVC。这种模式类似于 'Immediate',但允许集群管理员覆盖 StorageClass 的默认绑定模式。 +每个 StorageClass 只能有一种绑定模式,并且一旦设置后不能更改。 + +根据需求和环境配置选择适当得绑定模式。 + +#### CSI(动态卷配置)相关过程 +1. 用户创建一个 Pod 和 PVC。 +2. VolumeController 的 PersistentVolumeController 控制循环检测到 PVC 的创建并跳过它,因为它使用的是 Out-of-Tree 模式。 +该控制循环主要处理 In-Tree 模式下的 PV 和 PVC 绑定。 +3. External-provisioner 检测到 PVC 的创建: +- 调用 Controller Service 的 'CreateVolume' 方法创建底层存储卷。此时,卷处于 CREATED 状态,仅在存储系统中存在,对任何节点或容器不可见。 +- 创建 PV。 +- 将 PV 绑定到 PVC(绑定:在 PVC 对象的 spec.volumeName 字段中填写该 PV 对象的名称)。 +4. VolumeController 的 AttachDetachController 控制循环检测到卷未附加到主机,需要执行 Attach 操作。它创建 'VolumeAttachment' 对象。 +5. 当 external-attacher 检测到 'VolumeAttachment' 资源的创建时,它调用 Controller Service 的 'ControllerPublishVolume' 方法。 +此时,卷处于 NODE_READY 状态,意味着节点可以检测到卷,但在容器内部仍不可见。 +6. Kubelet 的 VolumeManagerReconciler 控制循环: +- 调用 Node Service 的 'NodeStageVolume' 方法执行 MountDevice 操作。该方法主要处理格式化卷并将其挂载到临时目录(Staging 目录)。 +此操作后,卷进入 VOL_READY 状态。 +- 调用 Node Service 的 'NodePublishVolume' 方法执行 SetUp 操作。 +- 它绑定 Staging 目录并将其挂载到卷的相应主机目录。 +- 卷进入 PUBLISHED 状态,用户现在可以正常使用它。 + +#### 跨集群实现 +基于单个 Kubernetes 集群中 PVC、PV 和 StorageClass 的逻辑,并结合 Kosmos 中跨集群创建 Pod 实例的逻辑,跨集群实现 PV/PVC 的方法如下: +- 在主集群(Host-Cluster)中,StorageClass 的 volumeBindingMode 设置为 WaitForFirstConsumer,确保延迟绑定和配置 PV(等待与成员集群同步)直到创建使用 PersistentVolumeClaim 的 Pod。 +PersistentVolumes 将根据 Pod 中指定的调度约束(包括资源要求、节点选择器、Pod 亲和性和反亲和性、污点和容忍度)进行选择或配置。 +- 主集群(Host-Cluster)中的 PVC 和 PV 绑定应与 Kosmos 中跨集群创建 Pod 的过程一致。 +- 主集群(Host-Cluster)中的 PV 控制器仅处理 PV 删除事件,创建和更新操作由成员集群中的 PV 控制器执行。 + +### 流程 +Kosmos PV/PVC 的实现流程如下: + +![PV_PVC_Dynamic_Storage.png](img/PV_PVC_Dynamic_Storage.png) + +- 当在主集群(Host-Cluster)中创建 Pod 并有相关的 PVC 请求时,Kosmos 将根据 Pod 创建事件在成员集群中创建相应的 PVC。 +- 在成员集群(Member-Cluster)中创建 PVC 后,流程与单个 Kubernetes 集群中的流程相同,包括 Pod 创建、PVC 创建、PV 创建和 PVC-PV 绑定的完成。 +- 当在成员集群(Member-Cluster)中创建 PV 时,相应的 PV 控制器将根据 PV 创建事件在主集群(Host-Cluster)中创建 PV。 +- 在成员集群(Member-Cluster)中成功调度并绑定 PVC 和 PV 后,主集群(Host-Cluster)中的 PV 创建将完成 PVC 和 PV 的绑定。 + +### 相关 + +#### 调度模块(主集群) +此模块可以通过扩展 Kosmos 调度器中的 VolumeBinding 插件实现。可以通过使用带有 "kosmos.io/node=true:NoSchedule" 污点的虚拟节点来实现。 + +#### 编排模块 +此模块的实现主要基于第 3 节中描述的步骤,包括 Kosmos 集群管理器中的 root_pod_controller.go、root_pvc_controller.go、leaf_pvc_controller.go、root_pv_controller.go 和 leaf_pv_controller.go。 + +### 示例 +1. YAML 示例: +````shell script +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: nginx-pvc + namespace: test-new +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + storageClassName: openebs-hostpath +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-new + namespace: test-new +spec: + selector: + matchLabels: + app: nginx + replicas: 1 + template: + metadata: + labels: + app: nginx + deletionGracePeriodSeconds: 30 + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - kosmos-cluster38 + tolerations: + - key: "kosmos.io/node" + operator: "Equal" + value: "true" + effect: "NoSchedule" + containers: + - name: nginx + image: registry.paas/cnp/nginx:1.14-alpine + ports: + - containerPort: 80 + volumeMounts: + - name: data + mountPath: /data + volumes: + - name: data + persistentVolumeClaim: + claimName: "nginx-pvc" +```` + +2. 在主集群中执行创建操作: +````shell script +[root@kosmos-control-cluster ylc]# kubectl apply -f test.yaml +persistentvolumeclaim/nginx-pvc created +deployment.apps/nginx-new + + created +[root@kosmos-control-cluster ylc]# kubectl get all -n test-new +NAME READY STATUS RESTARTS AGE +pod/nginx-new-5677468b6c-ns9k2 0/1 Pending 0 5s + +NAME READY UP-TO-DATE AVAILABLE AGE +deployment.apps/nginx-new 0/1 1 0 5s + +NAME DESIRED CURRENT READY AGE +replicaset.apps/nginx-new-5677468b6c 1 1 0 5s +[root@kosmos-control-cluster ylc]# kubectl get all -n test-new -owide +NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES +pod/nginx-new-5677468b6c-ns9k2 1/1 Running 0 11s 10.*.*.252 kosmos-cluster38 + +NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR +deployment.apps/nginx-new 1/1 1 1 11s nginx nginx:1.14-alpine app=nginx + +NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR +replicaset.apps/nginx-new-5677468b6c 1 1 1 11s nginx nginx:1.14-alpine app=nginx,pod-template-hash=56774 +[root@kosmos-control-cluster ylc]# kubectl get pvc -n test-new +NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE +nginx-pvc Bound pvc-ad86ef86-23c1-407e-a8e7-0b3e44d36254 1Gi RWO openebs-hostpath 21s +```` + +3. 查询成员集群中的状态: +````shell script +[root@cluster38 ~]# kubectl get all -n test-new +NAME READY STATUS RESTARTS AGE +pod/nginx-new-5677468b6c-ns9k2 1/1 Running 0 2m36s +[root@cluster38 ~]# kubectl get pvc -n test-new +NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE +nginx-pvc Bound pvc-ad86ef86-23c1-407e-a8e7-0b3e44d36254 1Gi RWO openebs-hostpath 2m41s +```` + +### 结论 +Kosmos 中 PV/PVC 的动态存储实现需要扩展以支持全球存储。目前的实现粒度较小,仍需进一步改进和演进。 \ No newline at end of file