> For the complete documentation index, see [llms.txt](https://docs.edgegap.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.edgegap.com/zh/learn/advanced-features/managed-clusters.md).

# 托管集群

在 Edgegap 托管集群上运行自定义后端服务，快速开始集成你自己的基础设施。

了解托管集群，并通过自定义后端解决方案快速入门。

## ✔️ 简介

托管集群让托管自管理游戏服务和游戏后端变得简单而快速。你准备服务镜像，我们提供一个高可用、弹性的云环境来运行它们：

* 玩家身份验证，
* 数据存储 - 账户、进度、库存、奖励，...
* 社交服务 - 聊天、公会、排行榜、锦标赛，...
* 自定义匹配 - 使用 [#advanced-matchmaker](#advanced-matchmaker "mention"), [#nakama-by-heroic-labs](#nakama-by-heroic-labs "mention"), ...
* 无服务器计算 - 托管 [函数即服务](https://github.com/openfaas/faas) （也称 cloudscript、lambda），...

{% hint style="success" %}
查看 [匹配系统](/zh/learn/pi-pei-xi-tong.md) 和 [服务器浏览器](/zh/learn/fu-wu-qi-liu-lan-qi.md) 以开始进行游戏客户端集成。
{% endhint %}

专有集群可确保你的服务拥有 **专用计算资源，24/7 为你的玩家提供服务**.

我们目前提供 [3 个私有集群层级](https://edgegap.com/resources/pricing#managed-infrastructure) 以满足每个人的需求：

<table><thead><tr><th width="160">层级</th><th align="right">爱好者层级</th><th align="right">工作室层级</th><th align="right">企业层级</th></tr></thead><tbody><tr><td>最适合</td><td align="right">爱好者，<br>独立开发者</td><td align="right">商业发布</td><td align="right">高流量上线</td></tr><tr><td>速率限制（请求/秒）</td><td align="right">200</td><td align="right">750</td><td align="right">2,000</td></tr><tr><td>资源</td><td align="right">1 vCPU + 2GB 内存</td><td align="right">6 vCPU + 12GB 内存</td><td align="right">18 vCPU + 48GB 内存</td></tr><tr><td>冗余</td><td align="right">1 个虚拟节点</td><td align="right">3 个虚拟节点</td><td align="right">3 个虚拟节点</td></tr><tr><td>价格，每小时</td><td align="right">$0.0312</td><td align="right"> $0.146</td><td align="right">$0.548</td></tr><tr><td><strong>价格，30 天</strong><br>（不间断使用）</td><td align="right"><strong>$22.464</strong></td><td align="right"><strong>$105.12</strong></td><td align="right"><strong>$394.56</strong></td></tr></tbody></table>

{% hint style="info" %}
我们的集群使用云机器，配备 AMD/Intel CPU，时钟速度最高可达 3.7 GHz。
{% endhint %}

## 🛠️ 开发者工具

如果你发现有改进机会，请在我们的 [社区 Discord](https://discord.gg/NgCnkHbsGp).

我们希望你能享受流畅的体验。🚀

### Docker

为了帮助你的服务器保持可靠，我们使用 [Docker](https://www.docker.com/) - 虚拟化软件，以确保你的所有服务器代码依赖项直到操作系统层级，无论服务器在何处或如何启动，它们始终完全相同。

{% hint style="info" %}
我们建议观看 [“永远不要本地安装”（视频）](https://www.youtube.com/watch?v=J0NuOlA2xDc\&ab_channel=Coderized). **使用 Docker 不需要使用 Dockerhub**。Docker ≠ Dockerhub。把 Docker 想象成一个编程引擎，把 Dockerhub 想成它的应用商店。
{% endhint %}

### Kubernetes（K8s）

[Kubernetes](https://kubernetes.io/docs/concepts/overview/)，也称为 K8s，是一个用于自动化部署、扩展和管理容器化应用程序（Docker 镜像）的开源系统。它将构成应用程序的容器分组为逻辑单元，以便于管理和发现。

Edgegap 托管集群为管理目的提供 Kubernetes API。

### K8s Lens

拥有超过 100 万用户， [K8s Lens](https://k8slens.dev/) 是全球最受欢迎的 Kubernetes IDE。连接到集群，进行探索，获取洞察，学习并在需要时采取行动。Lens 可实时提供来自你的工作负载和资源的所有信息，并始终处于正确的上下文中。

Edgegap 集群 Kubernetes API 可通过 Lens 或其他 Kubernetes IDE 使用。

### Helm 包管理器

[Helm](https://helm.sh/) 是查找、分享和使用为 Kubernetes 构建的软件的最佳方式。Helm 帮助你管理 Kubernetes 应用程序 - Helm Chart 可帮助你定义、安装和升级即使是最复杂的 Kubernetes 应用程序。Chart 易于创建、版本管理、共享和发布 - 所以开始使用 Helm，停止复制粘贴吧。

[安装 Helm CLI](https://helm.sh/docs/intro/install/) 为开发者提供一个简单的界面来管理其集群包。

## 🚀 快速开始

☑️ [已注册你的免费 Edgegap 账户](https://app.edgegap.com/auth/register) 并升级到按需付费层以解锁 Clusters。

☑️ 前往 [托管集群](https://app.edgegap.com/cluster-management/clusters/list) 页面。

☑️ 点击 **创建集群** ，然后输入：

* **标签** 为你的集群设置，以便日后轻松找到它，
* **集群大小 -** 请参见 [#introduction](#introduction "mention").

{% hint style="danger" %}
**我们强烈建议为开发和生产环境分别创建独立集群。**
{% endhint %}

☑️ 查看预计费用并点击 **创建集群** 以启动你的新集群。

☑️ 一旦集群准备就绪， **点击 Kubeconfig 以下载你的配置和凭据** 用于连接和管理你的新集群。

☑️ [移动你的 kubeconfig 文件](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/) 以便 `kubectl` 找到它。

☑️ Lens 用户： [导入你的 kubeconfig 文件](https://docs.k8slens.dev/getting-started/add-cluster/#specify-kubeconfig-files).

☑️ 使用以下命令测试你的集群连接 `kubectl get nodes` :

```bash
kubectl get nodes
名称                            状态   角色    存在时长    版本
lke334087-533013-294dcfe70000   Ready    <none>   10m   v1.31.0
lke334087-533013-4e69edc10000   Ready    <none>   10m   v1.31.0
lke334087-533013-50bf39880000   Ready    <none>   10m   v1.31.0
```

🙌 恭喜，你已完成托管集群设置！你现在可以安装你的服务了。

## 📦 Heroic Labs 提供的 Nakama

{% hint style="success" %}
参见 [托管集群](/zh/learn/advanced-features/managed-clusters.md#getting-started) 在受管集群上设置您的服务之前。
{% endhint %}

{% hint style="info" %}
将 Edgegap 集成到 [Nakama 插件](https://github.com/edgegap/nakama-edgegap) + [Unity 插件](https://github.com/edgegap/edgegap-server-nakama-plugin-unity)! [其他平台/功能请联系我们。](https://discord.gg/NgCnkHbsGp)
{% endhint %}

按照以下步骤托管你自己的 [Nakama 游戏后端](https://heroiclabs.com/docs/nakama/getting-started/) 在托管集群上：

☑️ 安装一个 **证书管理器** 以支持游戏客户端使用 HTTPS 请求：

```bash
helm repo add jetstack https://charts.jetstack.io --force-update;
helm upgrade --install cert-manager jetstack/cert-manager \
  --namespace cert-manager --create-namespace \
  --version v1.16.1 --set crds.enabled=true;
```

☑️ Lens：在 Services / Network 部分验证安装， `cert-manager` 应处于运行状态。

☑️ 编写一个 **集群签发器** 文件，记得替换 `<YOUR_EMAIL>` 如下：

<pre class="language-yaml"><code class="lang-yaml">apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
  namespace: cert-manager
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: <a data-footnote-ref href="#user-content-fn-1">&#x3C;YOUR_EMAIL></a>
    privateKeySecretRef:
      name: <a data-footnote-ref href="#user-content-fn-2">letsencrypt-staging</a>
    solvers:
    - http01:
        ingress:
          class: nginx
          
</code></pre>

{% hint style="danger" %}
一旦就绪，部署会被分配一个 URL（ `letsencrypt-prod` 用于你的生产集群 `privateKeySecretRef`.
{% endhint %}

☑️ 创建一个 **集群签发器** 在命令行中：

```bash
kubectl create -f <FILE_PATH>/issuer.yaml
```

☑️ Lens：在自定义资源部分验证安装 / `cert-manager.io` - 已创建集群签发器。

☑️ 安装 **nginx Ingress** 用于接收客户端请求并将其转发到集群中的服务：

```
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --create-namespace
```

☑️ Lens：在 Services / Network 部分验证安装， `nginx` 应处于运行状态。

☑️ 创建一个 **A 记录类型的 DNS 记录** 在你的 DNS 提供商中（例如 [Cloudflare](https://developers.cloudflare.com/dns/get-started/)），并记下 URL 以便后续使用。你的 **DNS 记录的外部 IP** 可在 Lens 的 Services / 下找到 `ingress-nginx-controller` .

☑️ 通过执行查询来验证你的 DNS 是否配置正确 [使用 DNSchecker](https://dnschecker.org/ns-lookup.php).

☑️ 创建名为 `values.yaml` 的文件，并填入以下内容（使用你自己的值）：

<pre class="language-yaml"><code class="lang-yaml">isProductionEnvironment: true

# Nakama 服务器的外部主机名 - 上一步中的 DNS 记录
externalHostName: <a data-footnote-ref href="#user-content-fn-3">&#x3C;DNS_A_RECORD_URL></a>

nakama:
  # 要部署的 Nakama 版本。
  # 可用版本请参见 https://hub.docker.com/r/heroiclabs/nakama/tags。
  version: 3.26.0
  # Nakama 控制台的用户名和密码
  username: <a data-footnote-ref href="#user-content-fn-4">&#x3C;USERNAME></a>
  password: <a data-footnote-ref href="#user-content-fn-5">&#x3C;PASSWORD></a>
</code></pre>

{% hint style="danger" %}
**将上面的 \<VALUES> 替换为你自己的值** 在上面的文件中。
{% endhint %}

☑️ 部署 Nakama helm chart：

```bash
helm upgrade --install \\
  --namespace nakama --create-namespace -f <FILE_PATH>/values.yaml \\
  --version 1.0.0 <RELEASE_NAME> oci://registry-1.docker.io/edgegap/heroiclabs-nakama
```

☑️ Lens：在 Workloads / Deployments 部分验证安装， `nakama` 应处于运行状态。

✅ **连接到你的 Nakama 控制台** 使用来自以下内容的 URL 和凭据 `values.yaml` 文件。

🙌 恭喜，你已完成自托管 Nakama 游戏后端的设置！

### 服务更新

按照以下步骤更新托管集群中托管的服务：

☑️ 更新你的 `value.yaml` 文件中的新文件。

☑️ 使用此命令更新你的 helm chart：

```bash
helm upgrade --reuse-values \\
  --namespace nakama -f <FILE_PATH>/values.yaml \\
  --version 1.0.0 <RELEASE_NAME> oci://registry-1.docker.io/edgegap/heroiclabs-nakama
```

☑️ 通过关闭已更新的 pod 来重新加载更改，我们会自动重启这些 pod，从而使用新的 helm chart。

{% hint style="warning" %}
此 **该更新将导致短暂停机** 在 Pods 重启期间。
{% endhint %}

🙌 恭喜，你已完成 Nakama 集群更新！

## 👷 高级匹配器

{% hint style="success" %}
参见 [托管集群](/zh/learn/advanced-features/managed-clusters.md#getting-started) 在受管集群上设置您的服务之前。
{% endhint %}

按照以下步骤托管你的 [OpenMatch](https://open-match.dev/site/) 在托管集群上。

☑️ 安装一个 **证书管理器** 以支持游戏客户端使用 HTTPS 请求：

```bash
helm repo add jetstack https://charts.jetstack.io --force-update;
helm upgrade --install cert-manager jetstack/cert-manager \
  --namespace cert-manager --create-namespace \
  --version v1.16.1 --set crds.enabled=true;
```

☑️ Lens：在 Services / Network 部分验证安装， `cert-manager` 应处于运行状态。

☑️ 编写一个 **集群签发器** 文件，记得替换 `<YOUR_EMAIL>` 如下：

<pre class="language-yaml"><code class="lang-yaml">apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
  namespace: cert-manager
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: <a data-footnote-ref href="#user-content-fn-1">&#x3C;YOUR_EMAIL></a>
    privateKeySecretRef:
      name: <a data-footnote-ref href="#user-content-fn-2">letsencrypt-staging</a>
    solvers:
    - http01:
        ingress:
          class: nginx
          
</code></pre>

{% hint style="danger" %}
一旦就绪，部署会被分配一个 URL（ `letsencrypt-prod` 用于你的生产集群 `privateKeySecretRef`.
{% endhint %}

☑️ 创建一个 **集群签发器** 在命令行中：

```bash
kubectl create -f <FILE_PATH>/issuer.yaml
```

☑️ Lens：在自定义资源部分验证安装 / `cert-manager.io` - 已创建集群签发器。

☑️ 安装 **nginx Ingress** 用于接收客户端请求并将其转发到集群中的服务：

```
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --create-namespace
```

☑️ Lens：在 Services / Network 部分验证安装， `nginx` 应处于运行状态。

☑️ 在你的 DNS 提供商中创建一个 A 记录类型的 DNS 记录（例如 [Cloudflare](https://developers.cloudflare.com/dns/get-started/)），并记下 URL 以便后续使用。你的 **DNS 记录的外部 IP** 可在 Lens 的 Services / 下找到 `ingress-nginx-controller` .

☑️ 通过执行查询来验证你的 DNS 是否配置正确 [使用 DNSchecker](https://dnschecker.org/ns-lookup.php).

☑️ 创建名为 `values.yaml` 的文件，并填入以下内容（使用你自己的值）：

```yaml
isProductionEnvironment: false

director:
  credential:
    registry: <YOUR_DIRECTOR_REGISTRY>
    username: <YOUR_DIRECTOR_REGISTRY_USERNAME>
    password: <YOUR_DIRECTOR_REGISTRY_PASSWORD>
  image: <DIRECTOR_IMAGE>
  env: {
    "KEY": "VALUE"
  }

mmf:
  credential:
    registry: <MATCHMAKER_FUNCTION_REGISTRY>
    username: <MATCHMAKER_FUNCTION_REGISTRY_USERNAME>
    password: <MATCHMAKER_FUNCTION_REGISTRY_PASSWORD>
  image: <MATCHMAKER_FUNCTION_IMAGE>
  env: {
    "KEY": "VALUE"
  }

frontend:
  credential:
    registry: <FRONTEND_REGISTRY>
    username: <FRONTEND_REGISTRY_USERNAME>
    password: <FRONTEND_REGISTRY_PASSWORD>
  externalHostName: <YOUR_CLOUDFLARE_HOST_NAME> # 例如 exemple.test.com
  image: <FRONTEND_IMAGE>
  env: {
    "KEY": "VALUE"
  }

# 所有子图表都可见的全局配置
global:
  kubernetes:
    resources:
      requests:
        memory: 100Mi
        cpu: 100m
      limits:
        memory: 100Mi
        cpu: 100m
```

{% hint style="danger" %}
**将上面的 \<VALUES> 替换为你自己的值** 在上面的文件中。
{% endhint %}

☑️ 添加 **Edgegap 仓库** 到你的仓库列表中：

```bash
helm repo add edgegap-public https://registry.edgegap.com/chartrepo/edgegap-public
```

☑️ 部署高级匹配器 helm chart：

```bash
helm upgrade --install \\
  --namespace matchmaker --create-namespace -f <FILE_PATH>/values.yaml \\
  --version 1.0.1 <RELEASE_NAME> edgegap-public/open-match-edgegap
```

🙌 恭喜，你已完成高级匹配器设置！

### 服务更新

按照以下步骤更新托管集群中托管的服务：

☑️ 更新你的 `value.yaml` 文件中的新文件。

☑️ 使用此命令更新你的 helm chart：

```bash
helm upgrade --reuse-values \\
  --namespace matchmaker -f <FILE_PATH>/values.yaml \\
  --version 1.0.1 <RELEASE_NAME> edgegap-public/open-match-edgegap
```

☑️ 通过关闭已更新的 pod（director、mmf、frontend）来重新加载更改，我们会自动重启这些 pod，从而使用新的 helm chart。

{% hint style="warning" %}
此 **该更新将导致短暂停机** 在 Pods 重启期间。
{% endhint %}

🙌 恭喜，你已完成高级匹配器更新！

### 持续部署

通过将此 shell 脚本添加到你的部署流水线中，实现服务更新自动化：

```bash
#!/bin/bash

RELEASE_NAME="<RELEASE_NAME>"
NAMESPACE="matchmaker"  # 如果你更改了命名空间，请在此修改。

helm upgrade --reuse-values -f <FILE_PATH>/value.yaml --namespace $NAMESPACE --version 1.0.1 $RELEASE_NAME edgegap-public/open-match-edgegap

echo "正在安装 redis-tools"
apt-get update
apt-get install -y redis-tools

DIRECTOR_DEPLOYMENT_NAME="$RELEASE_NAME-director"
MMF_DEPLOYMENT_NAME="$RELEASE_NAME-mmf"
CUSTOM_FRONTEND_DEPLOYMENT_NAME="$RELEASE_NAME-custom-frontend"
REDIS_HOST="$RELEASE_NAME-redis-master"

declare -A replicas

# 对于每个部署（director、mmf、custom-frontend），停止其 pod
for deployment in $DIRECTOR_DEPLOYMENT_NAME $MMF_DEPLOYMENT_NAME $CUSTOM_FRONTEND_DEPLOYMENT_NAME
do
  echo "正在停止部署的 pod：$deployment"
  replicas[$deployment]=$(kubectl get deployment $deployment -o=jsonpath='{.spec.replicas}' --namespace $NAMESPACE)
  kubectl scale deployment/$deployment --replicas=0 --namespace $NAMESPACE
done

# 等待 pod 被终止
for deployment in $DIRECTOR_DEPLOYMENT_NAME $MMF_DEPLOYMENT_NAME $CUSTOM_FRONTEND_DEPLOYMENT_NAME
do

  echo "等待部署的 pod 被终止：$deployment"
  kubectl wait --for=delete pod -l app=$deployment --timeout=60s --namespace $NAMESPACE

  # 检查 wait 命令是否成功。如果不成功，则退出脚本
  if [ $? -ne 0 ]; then
    echo "等待部署的 pod 被终止失败：$deployment"
    exit 1
  fi
done

# 清理 redis 数据库
echo "正在清理 redis 数据库"
redis-cli -h $REDIS_HOST flushall

# 对于每个部署（director、mmf、custom-frontend），将 pod 重新缩放到原始数量
for deployment in $DIRECTOR_DEPLOYMENT_NAME $MMF_DEPLOYMENT_NAME $CUSTOM_FRONTEND_DEPLOYMENT_NAME
do
  echo "将 pod 重新缩放到 ${replicas[$deployment]}，用于部署：$deployment"
  kubectl scale deployment/$deployment --replicas=${replicas[$deployment]} --namespace $NAMESPACE
done
```

{% hint style="warning" %}
此 **该更新将导致短暂停机** 在 Pods 重启期间。
{% endhint %}

### Letsencrypt 证书验证（C#）

对于某些客户端，推荐的 Letsencrypt 证书验证可能会失败，并出现以下错误：

```bash
Curl error 60: Cert verify failed. Certificate has expired. UnityTls error code: 7
```

{% hint style="success" %}
更新你的操作系统可能会解决根证书颁发机构过旧的问题。
{% endhint %}

作为最后手段，游戏客户端可以实现自定义证书处理函数：

````csharp
```csharp
public class CustomCertificateHandler : CertificateHandler
{
  private readonly string EXPECTED_CERT = "-----BEGIN CERTIFICATE-----<key>-----END CERTIFICATE-----\r\n";
  protected override bool ValidateCertificate(byte[] certificateData)
  {
    X509Certificate2 certificate = new X509Certificate2(certificateData);
    X509Certificate2 expectedCert = new X509Certificate2(Encoding.ASCII.GetBytes(EXPECTED_CERT));

    using (SHA256 sha256 = SHA256.Create())
    {
      Debug.Log("certificate.Thumbprint: " + certificate.Thumbprint);
      Debug.Log("expectedCert.Thumbprint: " + expectedCert.Thumbprint);

      return certificate.Thumbprint == expectedCert.Thumbprint;
    }
  }
}
```
````

用法：

```csharp
UnityWebRequest request = UnityWebRequest.Get(...);
request.certificateHandler = new BypassCertificateHandler();
request.SendWebRequest();
request.certificateHandler.Dispose();
```

我们建议将 `EXPECTED_CERT` 的值存储在你自己的文件存储中，并在运行时检索它，这样你就可以在不发布游戏客户端更新的情况下对其进行更新。

## 🟢 运维与可观测性

### 集群层级更改

为成功做好准备并在上线后持续优化，这样就不会在发布日阻碍你的玩家。

{% hint style="warning" %}
&#x20;更改集群大小需要停止你的集群。请参见 [蓝绿部署](https://circleci.com/blog/canary-vs-blue-green-downtime/) 以实现零停机更新。
{% endhint %}

### 支持与未来更新

**你的成功是我们的首要任务。** 如果你想提交自定义请求、提出缺失的关键功能，或表达任何想法， [请在我们的 Community Discord 中联系我们](https://discord.gg/MmJf8fWjnt).

[^1]: 替换为你的电子邮件

[^2]: 生产环境请使用 letsencrypt-prod

[^3]: 上一步中的 DNS 记录

[^4]: 选择你自己的管理员用户名

[^5]: 为管理员选择一个安全密码
