使用 Knative Operator v1.22 将 Knative Serving 与 Eventing 部署到远程集群:Hub-Spoke 多集群架构实战

📅 发布时间:2026/10/14 2:05:58
使用 Knative Operator v1.22 将 Knative Serving 与 Eventing 部署到远程集群:Hub-Spoke 多集群架构实战
文档教程云原生【免费下载链接】docsUser documentation for Knative components.项目地址https://gitcode.com/gh_mirrors/docs1/docs点击查看免费下载本文以 Knative 官方文档仓库中的博客文章《Deploying Knative to remote clusters with the Operator》为核心骨架结合仓库内配套的完整操作指南multi-cluster-deployment.md与 CR 配置文档configuring-serving-cr.md、configuring-eventing-cr.md系统讲解如何让一个位于 hub 集群上的 Knative Operator通过spec.clusterProfileRef把 Knative Serving / Eventing 组件部署到远端的spoke 集群并涵盖启用多集群支持、注册 ClusterProfile、部署、运维、清理与故障排查的完整闭环。为什么需要多集群部署从逐集群安装到 Hub-Spoke 统一管理平台团队通常同时管理不止一个 Kubernetes 集群有的按区域拆分、有的按环境拆分、有的按租户或业务单元拆分。在 Knative Operator v1.22 之前要在这些集群上安装 Knative通常需要在每个集群里分别运行一个 Operator或者围绕安装清单manifests自行搭建额外的自动化脚本。从Knative Operator v1.22 开始单个 Operator 就可以把 Knative 组件部署到另一个 Kubernetes 集群运行 Operator 的集群称为hub 集群控制面接收 Knative Serving 或 Knative Eventing 组件的集群称为spoke 集群工作负载侧通过在KnativeServing或KnativeEventing自定义资源CR上设置spec.clusterProfileRef来选定目标 spoke 集群。该能力基于 SIG-Multicluster 的Cluster Inventory APIKubernetes Enhancement Proposal KEP-5339实现Operator 读取一个ClusterProfile资源来发现远端集群的 API Server 地址与访问方式然后对远端集群执行正常的 Knative 安装流水线。关键兼容性保证是如果 CR 上没有设置spec.clusterProfileRef行为与旧版本完全一致Operator 仍然把 Knative 部署到本地Operator 所在集群。该特性的适用场景与价值多集群支持让 Knative Operator 更适配舰队式fleet-oriented平台从单一控制点管理多个 spoke 集群的 Knative 安装与发布ClusterProfile资源的舰队管理平台fleet manager集成例如 Open Cluster ManagementOCM本地安装与远端安装继续使用同一套KnativeServing/KnativeEventingAPI学习成本为零跨区域、跨环境应用一致的配置删除 hub 侧的 CROperator 会自动清理远端安装。该特性刻意基于 Cluster Inventory API 而非绑定某一家舰队管理器生产环境中的舰队系统如 Open Cluster Management、MultiKueue可以发布ClusterProfile资源而 PoC概念验证环境可以手动注册这些资源。仓库配套指南 multi-cluster-deployment.md 中明确说明该特性可配合任何发布ClusterProfile资源的舰队管理器使用。重要提示多集群部署是Knative Operator v1.22 及以后的 beta 特性且依赖仍处于 alpha 阶段的 SIG-Multicluster Cluster Inventory API。该 API 的 schema 与推荐的访问提供者插件access provider plugin可能在后续版本中发生变化生产环境使用前需评估版本锁定策略。Operator 如何定位远程集群Reconcile 流水线全解析Operator 在调和reconciliation流程开始时解析目标集群。当spec.clusterProfileRef存在时它依次执行以下步骤对应 multi-cluster-deployment.md 中的 Overview 一节读取并校验ClusterProfile确认 spoke 集群健康ControlPlaneHealthyTrue且存在可用的 access provider调用配置的 access provider 插件为 spoke 集群构建一个 Kubernetes 客户端rest.Config在 spoke 上创建辅助资源helper resource作为命名空间级 Knative 资源的归属锚点用于后续垃圾回收garbage collection对 spoke 客户端运行标准的 Knative 安装流水线Deployments、Services、ConfigMaps、CRDs、RBAC 等全部落在 spoke 集群上。也就是说安装阶段本身没有任何特殊化——Operator 仍然应用标准的 Knative manifests、CRDs、ConfigMaps、Deployments、Services 和 RBAC 资源唯一区别是这些资源落地在哪个集群。在清理cleanup方面命名空间级资源通过 KubernetesownerReference级联垃圾回收集群级资源如 ClusterRoles、CRDs则由hub 侧的 finalizer 显式删除。卸载纪律卸载远程 Knative 部署时始终在 hub 上删除KnativeServing或KnativeEventingCR。如果 spoke 集群暂时不可达finalizer 会持续重试直到重新可以访问 spoke 为止。启用多集群支持之前的前置条件在把 Knative 部署到远程集群前需要准备以下内容见 multi-cluster-deployment.md 的 Before you begin 一节Knative Operator v1.22 或更高版本hub 集群运行 Kubernetes v1.35 或更高版本。Knative v1.22 对标准安装支持 Kubernetes v1.34但远程部署在 hub 上使用Kubernetes image volumes来挂载凭据插件二进制该卷类型从Kubernetes v1.35 起默认启用且目前不支持其他凭据插件投递方式hub 上已安装 Cluster Inventory API 的ClusterProfileCRD安装指引见 kubernetes-sigs/cluster-inventory-api 仓库文档hub 集群到每个 spoke 集群 API Server 的网络连通性。若 hub 无法直接访问 spoke可使用反向隧道如 OCM 的 cluster-proxy一个实现了 Cluster Inventory API access provider 接口的凭据插件。上游 kubernetes-sigs/cluster-inventory-api 项目发布了两个插件registry.k8s.io/cluster-inventory-api/secretreader:v0.1.2从Secret的data.token字段读取 bearer tokenregistry.k8s.io/cluster-inventory-api/kubeconfig-secretreader:v0.1.2从Secret中读取完整 kubeconfig。按你打算使用的凭据格式二选一也可以使用其他来源的插件spoke 集群上的 RBAC 权限插件返回的凭据必须能够创建和管理 Knative 资源详见下文。Spoke RBAC 要求Operator 会在 spoke 集群上应用以下类型的资源NamespaceDeployment、Service、ConfigMap、Secret、ServiceAccountRole、RoleBinding、ClusterRole、ClusterRoleBindingMutatingWebhookConfiguration、ValidatingWebhookConfigurationHorizontalPodAutoscaler、PodDisruptionBudgetCustomResourceDefinition以及 Knative Serving / Eventing 自带的组件 CRDsaccess provider 插件返回的凭据必须拥有等价于cluster-adminClusterRole 的权限。Knative 目前不提供最小化的聚合角色minimal aggregated role。如果组织限制使用cluster-admin可以自定义一个ClusterRole对上述资源种类授予*权限并绑定到插件使用的 ServiceAccount 上。安全提醒不要将 spoke 凭据复用于 Knative Operator 调和路径之外的任何工作负载。在 Knative Operator 上启用多集群支持Operator 默认关闭多集群支持。可以通过 Helm values全新安装/升级或 patch 现有 Operator Deployment 两种方式启用。方式一通过 Helm values 启用安装或升级 Operator 时设置knative_operator.multicluster.*系列 valuesknative_operator: multicluster: enabled: true accessProvidersConfig: providers: - name: secretreader execConfig: apiVersion: client.authentication.k8s.io/v1 command: /access-plugins/secretreader/bin/secretreader-plugin interactiveMode: Never provideClusterInfo: true plugins: - name: secretreader image: registry.k8s.io/cluster-inventory-api/secretreader:v0.1.2 mountPath: /access-plugins/secretreader remoteDeploymentsPollInterval: 10s关键约束源码注释与指南均有说明accessProvidersConfig.providers[].name必须与ClusterProfilestatus中公布的 provider 名称一致execConfig.command必须指向某个已配置的plugins[].mountPath之下的二进制文件应用 valueshelm upgrade --install knative-operator \ --namespace knative-operator \ --create-namespace \ -f values.yaml \ knative-operator/knative-operatorHelm 会把 access provider 配置渲染进 Operator 命名空间下名为clusterprofile-provider-file的ConfigMap并挂载到 Operator Pod 上该 ConfigMap 名称与挂载路径是固定的。方式二在现有 Operator Deployment 上启用非 Helm 场景在 Operator 命名空间创建 access provider 配置 ConfigMapkubectl create configmap clusterprofile-provider-file \ --namespace knative-operator \ --from-fileconfig.json./access-providers.jsonaccess-providers.json与 Helm 渲染出的结构一致{ providers: [ { name: secretreader, execConfig: { apiVersion: client.authentication.k8s.io/v1, command: /access-plugins/secretreader/bin/secretreader-plugin, interactiveMode: Never, provideClusterInfo: true } } ] }使用 strategic merge patch 给 Operator Deployment 追加--clusterprofile-provider-file参数并挂载凭据插件二进制以 image volume 方式kubectl patch deployment knative-operator \ --namespace knative-operator \ --typestrategic \ --patch-fileoperator-patch.yamloperator-patch.yaml内容如下spec: template: spec: containers: - name: knative-operator args: - --clusterprofile-provider-file/etc/cluster-inventory/config.json volumeMounts: - name: access-config mountPath: /etc/cluster-inventory readOnly: true - name: secretreader mountPath: /access-plugins/secretreader readOnly: true volumes: - name: access-config configMap: name: clusterprofile-provider-file - name: secretreader image: reference: registry.k8s.io/cluster-inventory-api/secretreader:v0.1.2 pullPolicy: IfNotPresent等待 rollout 完成kubectl rollout status deployment/knative-operator --namespace knative-operator重要如果 Operator 启动时未带--clusterprofile-provider-file任何设置了spec.clusterProfileRef的 CR 都会停止调和表现为TargetClusterResolvedFalse且reasonMulticlusterDisabled而没有clusterProfileRef的 CR 不受影响、照常调和。注册 spoke 集群ClusterProfile 的两种来源hub 通过ClusterProfile资源发现 spoke 集群舰队管理器托管由 OCM 等舰队管理器负责更新ClusterProfile的spec与statusKnative Operator 无需额外步骤手动注册适用于 PoC 环境可自行 applyClusterProfile并手工更新其 status。一个ClusterProfile在spec中携带集群管理器身份在status.accessProviders中携带远端访问信息Operator 还会检查ControlPlaneHealthy条件是否为True。整个链路的关键对应关系是KnativeServing/KnativeEventing通过 name namespace 指向某个ClusterProfile该ClusterProfile公布某个 access provider 名称Operator 配置了同名 provider凭据插件返回该 spoke 集群的凭据。这些环节全部对齐后Operator 就能为 spoke 构建客户端并开始调和 Knative。手动注册 ClusterProfile 的完整步骤以下以secretreader插件registry.k8s.io/cluster-inventory-api/secretreader:v0.1.2为例若换用其他插件请替换镜像引用与配置字段。第 1 步在 spoke 集群创建 ServiceAccount、权限与 token Secretkubectl create serviceaccount knative-operator-spoke --namespace kube-system kubectl create clusterrolebinding knative-operator-spoke \ --clusterrolecluster-admin \ --serviceaccountkube-system:knative-operator-spoke kubectl apply -f - EOF apiVersion: v1 kind: Secret metadata: name: knative-operator-spoke-token namespace: kube-system annotations: kubernetes.io/service-account.name: knative-operator-spoke type: kubernetes.io/service-account-token EOF第 2 步在 spoke 集群采集 API Server 地址、CA 证书与 bearer tokenkubectl get secret knative-operator-spoke-token -n kube-system \ -o jsonpath{.data.token} | base64 -d kubectl get secret knative-operator-spoke-token -n kube-system \ -o jsonpath{.data.ca\.crt} kubectl cluster-info不同集群类型的 API Server 地址获取方式kind运行docker inspect kind-control-plane --format {{.NetworkSettings.Networks.kind.IPAddress}}并使用https://ip:6443或运行kubectl config view --minify --raw -o jsonpath{.clusters[0].cluster.server}EKS运行aws eks describe-cluster --name name --query cluster.endpointGKE运行gcloud container clusters describe name --zone zone --formatvalue(endpoint)。kubectl get ... -o jsonpath{.data.ca\.crt}的输出本身就是 base64 编码的直接原样粘贴到第 5 步ClusterProfilestatus 的certificate-authority-data字段即可。第 3 步在 hub 集群创建凭据插件读取的 Secretkubectl create secret generic spoke-cluster-1 \ --namespace knative-operator \ --from-literaltokenspoke-tokensecretreader插件读取 Operator 命名空间内某个Secret的data.token字段该 Secret 名称必须与第 5 步ClusterProfilestatus extension 中的clusterName值一致。CA 证书通过ClusterProfilestatus 单独提供。若使用kubeconfig-secretreader或其他插件请按该插件文档组织Secret内容。第 4 步在 hub 集群 applyClusterProfilespecapiVersion: multicluster.x-k8s.io/v1alpha1 kind: ClusterProfile metadata: name: spoke-cluster-1 namespace: fleet-system labels: x-k8s.io/cluster-manager: knative-operator spec: displayName: Spoke Cluster 1 clusterManager: name: knative-operator第 5 步以子资源方式更新ClusterProfilestatusOperator 读取的是status.accessProviders与status.conditions[typeControlPlaneHealthy]kubectl patch clusterprofile spoke-cluster-1 \ --namespace fleet-system \ --subresourcestatus \ --typemerge \ --patch-filecluster-profile-status.yamlcluster-profile-status.yaml内容如下status: conditions: - type: ControlPlaneHealthy status: True reason: Manual message: Status set manually lastTransitionTime: 2026-04-22T00:00:00Z accessProviders: - name: secretreader cluster: server: https://spoke-api-server:6443 certificate-authority-data: spoke-ca-base64 extensions: - name: client.authentication.k8s.io/exec extension: clusterName: spoke-cluster-1重要ClusterProfile的 status 是子资源必须使用kubectl patch --subresourcestatus直接用普通kubectl apply提交的 status 更新会被忽略。第 6 步确认 ClusterProfile 就绪kubectl get clusterprofile spoke-cluster-1 -n fleet-system \ -o jsonpath{.status.conditions[?(.typeControlPlaneHealthy)].status}将 Knative Serving 部署到 spoke 集群启用多集群支持并注册ClusterProfile后在KnativeServingCR 上设置spec.clusterProfileRefapiVersion: operator.knative.dev/v1beta1 kind: KnativeServing metadata: name: knative-serving namespace: knative-serving spec: clusterProfileRef: name: spoke-cluster-1 namespace: fleet-system ingress: kourier: enabled: true config: network: ingress-class: kourier.ingress.networking.knative.dev在hub 集群上 apply 该 CROperator 运行在 hub但 Serving 资源会创建到spoke-cluster-1所描述的 spoke 集群上。Ingress 选型要提前定Kourier最简路径Operator 会随 Serving 安装一起把 Kourier 部署到 spoke你只需保证 spoke 上有可用的LoadBalancer或NodePortIstio 或 Gateway APInet-gateway-api需要在 apply CR之前在 spoke 上预装 ingress 实现。使用 Gateway API 时Operator 调和前必须先在 spoke 上 applyGatewayClass与Gateway资源。Ingress 字段结构可参考 configuring-serving-cr.md。验证命令Target Cluster列会报告ClusterProfile引用kubectl apply -f knative-serving.yaml kubectl get knativeserving -n knative-serving将 Knative Eventing 部署到 spoke 集群Knative Eventing不需要在 spoke 上做任何 ingress 相关准备。设置spec.clusterProfileRef并 apply 即可apiVersion: operator.knative.dev/v1beta1 kind: KnativeEventing metadata: name: knative-eventing namespace: knative-eventing spec: clusterProfileRef: name: spoke-cluster-1 namespace: fleet-systemkubectl apply -f knative-eventing.yaml kubectl get knativeeventing -n knative-eventing配置远端命名空间设置labels / annotations可以通过spec.namespaceConfiguration预配置 spoke 上承载 Knative 组件的命名空间的标签与注解apiVersion: operator.knative.dev/v1beta1 kind: KnativeServing metadata: name: knative-serving namespace: knative-serving spec: clusterProfileRef: name: spoke-cluster-1 namespace: fleet-system namespaceConfiguration: labels: pod-security.kubernetes.io/enforce: privileged annotations: example.com/owner: platform-team注意这些 labels/annotations只在 Operator 于 spoke 上创建命名空间时生效不会修改已存在的命名空间。若要调整已存在命名空间的设置请直接用kubectl label/kubectl annotate在 spoke 上编辑。舰队规模下的运营要点一个 CR 对应一个 spoke多 spoke 靠命名约定区分每个KnativeServing/KnativeEventingCR恰好指向一个ClusterProfile。要部署到多个 spoke就为每个 spoke 创建一个 CR并使用能看清目标的命名约定例如knative-serving-us-east、knative-eventing-prod-eu。clusterProfileRef不可变spec.clusterProfileRef在 CR 创建后不可变更。要把某个安装迁移到另一个 spoke需要删除现有 CR 并新建一个指向新ClusterProfile的 CR。通过TargetClusterResolved条件观测远端定位Operator 通过TargetClusterResolved条件报告远端定位结果。定位失败时条件 reason 会指明下一步动作ClusterProfileNotFound引用指向的 profile 不存在MulticlusterDisabledOperator 未以 provider 文件启动未开启多集群AccessProviderFailed凭据插件返回错误。调优远端就绪轮询间隔Operator 在成功 apply 后会轮询 spoke 上的 Deployment 就绪状态默认间隔10s可通过--remote-deployments-poll-interval或 Helm valueknative_operator.multicluster.remoteDeploymentsPollInterval调整。小于 1 秒的值会被忽略并回落到默认值。建议起点Spoke 数量建议起始值少于 1010s10 到 10030s超过 10060sHelm 方式knative_operator: multicluster: remoteDeploymentsPollInterval: 30s已有 Deployment 上追加 flagkubectl patch deployment knative-operator \ --namespace knative-operator \ --typejson \ --patch[{op:add,path:/spec/template/spec/containers/0/args/-,value:--remote-deployments-poll-interval30s}]远端资源的垃圾回收与卸载Helper 资源与两种回收机制Operator 会在 spoke 上创建一个辅助资源helper resource作为命名空间级 Knative 资源的归属锚点。该 helper 带有operator.knative.dev/protected: true注解仅作为给人工运维者的提示信息Operator 并不会通过准入 webhook 强制执行。如果 helper 被误删下一次调和会自动重建。命名空间级资源Deployments、Services、ConfigMaps 等通过ownerReference指向 helperhelper 被移除时由标准 Kubernetes 垃圾回收级联删除集群级资源ClusterRoles、webhook 配置、CRDs 等不带ownerReference由hub 侧 finalizer 在 CR 删除时显式删除。警告helper 资源的确切名称是内部实现细节可能在版本间变化不要编写针对该名称的脚本。卸载与强制删除正确卸载方式在 hub 上删除 CR让 finalizer 清理 spokekubectl delete knativeserving knative-serving -n knative-servingfinalizer 会等待 spoke 可达后移除其上由 Operator 管理的资源。警告如果 spoke 集群永久不可达finalizer 无法完成CR 会无限期停留在 terminating 状态。此时可强制删除移除 finalizer但这会在 spoke 上遗留孤儿资源kubectl patch knativeserving name -n namespace \ --typemerge -p {metadata:{finalizers:null}}请勿直接在 spoke 上删除 helper 资源这会级联删除所有命名空间级 Knative 资源一步移除整个部署而这通常不是预期结果。升级与降级注意事项升级到 v1.22 不会自动启用多集群Helm valuemulticluster.enabled默认false未设置clusterProfileRef的既有 CR 在升级后行为保持不变spec.clusterProfileRef不可变迁移 spoke 时删除重建降级到 v1.22 之前的版本旧版 Operator 不认识clusterProfileRef字段。降级前必须删除所有使用clusterProfileRef的 CR否则在无法识别该字段的 Operator 上运行这类 CR 属于不受支持的操作行为未定义。故障排查条件原因速查表读取TargetClusterResolved条件kubectl get knativeserving name -n namespace \ -o jsonpath{.status.conditions[?(.typeTargetClusterResolved)]}Eventing CR 把资源类型换成knativeeventing即可两种 kind 上都存在同一条件。需要完整视图含 Events 与其他条件时运行kubectl describe knativeserving name -n namespace。最常见的TargetClusterResolvedFalse原因与对策Reason含义处置建议ClusterProfileNotFoundspec.clusterProfileRef引用的ClusterProfile在指定命名空间中不存在核对spec.clusterProfileRef.name与.namespace确认ClusterProfile发布位置ClusterProfileNotReadyprofile 存在但 status 中没有ControlPlaneHealthyTrue等待舰队管理器更新 status或按上文手动更新ClusterProfileUnavailableprofile 没有公布 access provider或公布的 provider 名称 Operator 不认识确认status.accessProviders[].name与 Operator access provider 配置中的名称一致MulticlusterDisabledOperator 未以--clusterprofile-provider-file启动Helm 场景设置multicluster.enabled: true并提供multicluster.accessProvidersConfig手动场景给 Deployment 加 flagAccessProviderFailed凭据插件调用报错查看 Operator 日志中插件的 stderr确认插件二进制与节点架构匹配、插件读取的Secret存在于 Operator 命名空间RemoteClientCreationFailedOperator 已从插件输出构建rest.Config但创建客户端失败确认 spoke API Server 可达、CA 证书有效、bearer token 未过期瞬态原因通常下一次调和自动消除RemoteClusterStaleOperator 正在刷新缓存的 spoke 客户端ClusterProviderClosedOperator 正在关闭。若这些原因持续存在请检查 Operator Deployment 日志与 Pod 重启次数。常见 FAQ 场景CR 上MulticlusterDisabled持续存在Operator 未带 provider 文件启动。Helm 场景确认multicluster.enabled: true与accessProvidersConfig已提供且新 Pod 已 rollout手动场景给 Deployment 加 flag。AccessProviderFailed: exec format error凭据插件二进制架构与 Operator 节点架构不匹配。为正确架构重建插件镜像或将 Operator 调度到与现有插件匹配的节点。一个 hub 部署到很多 spoke每个 spoke 一个 CR用knative-serving-region这类命名约定区分超过 100 个 spoke 时将--remote-deployments-poll-interval提高到60s。spoke 凭据轮换更新ClusterProfilestatus 或插件读取的Secret。CR 会短暂报告RemoteClusterStale缓存客户端刷新中下一次调和后恢复True。spoke 已退役但 CR 仍引用它删除 CR 会触发 finalizer 并因无法到达 spoke 而停滞。spoke 永久不可达时按上文 force-delete 步骤移除 CR。spoke 上的 helper 资源被误删命名空间级 Knative 资源会被垃圾回收。给 hub 上的 CR 打注解触发一次新调和例如kubectl annotate knativeserving name --overwrite reconcile.knative.dev/trigger$(date %s)Operator 会重建 helper 与命名空间级资源。已知限制spec.clusterProfileRef不可变跨集群迁移需要删除重建每个 CR 恰好指向一个ClusterProfile多 spoke 需要每 spoke 一个 CROperator不导出针对TargetClusterResolved条件的独立 Prometheus 指标可通过 kube-state-metrics 的 CRD 配置或现有条件指标采集 CR status永久不可达的 spoke 会让 CR 停留在TargetClusterResolvedFalse直到删除 CR 或恢复连通性。总结Knative Operator v1.22 提供了一种在集群舰队中运行 Knative 的新方式把 Operator 与安装 API 留在 hub 集群上通过spec.clusterProfileRef将 Serving / Eventing 组件部署到远程 spoke 集群。单集群路径保持完全不变同时为平台团队提供了面向远程安装、清理与舰队集成的声明式 API。仓库内配套的完整指南 multi-cluster-deployment.md 提供了端到端步骤CR 字段细节可继续阅读 configuring-serving-cr.md 与 configuring-eventing-cr.mdOperator 的常规安装与配置总览见 configuring-with-operator.md 与 knative-with-operators.md。赞分享文档教程云原生【免费下载链接】docsUser documentation for Knative components.项目地址https://gitcode.com/gh_mirrors/docs1/docs点击查看免费下载相关推荐Knative Serving PHP Hello World 示例从 index.php 到集群部署的完整实践Knative Serving PHP Hello World 示例从 index.php 到集群部署的完整实践 本文以 Knative 官方文档仓库中 co文档教程云原生Knative Serving 上的 Quarkus Hello World 示例从零创建、镜像构建到集群部署全流程Knative Serving 上的 Quarkus Hello World 示例从零创建、镜像构建到集群部署全流程 本篇技术指南围绕 Knative 官方仓文档教程云原生使用 Knative Eventing IntegrationSource 将 AWS SQS 消息接入 Knative Broker使用 Knative Eventing IntegrationSource 将 AWS SQS 消息接入 Knative Broker 本文围绕 Knative文档教程云原生上一篇如何使用Duplicati实现从S3到Backblaze B2的云存储无缝迁移完整指南下一篇终极指南如何快速搭建企业级离线翻译服务器 LibreTranslate 1.9.6创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考