# 应用与版本

了解版本管理和应用程序——用于更深入理解的概念与最佳实践。

## 📦 应用程序

应用程序封装了服务器项目。这种上下文分离在以下情况下尤其有用：

* 处理多个游戏或非游戏项目（合并计费），
* 作为共同开发者参与外部项目（稍后再转移所有权），
* 依赖多个松耦合的服务器类型，它们具有不同的扩展模式或需求。

你可以使用我们的插件在 Edgegap 上管理你的应用程序， [控制台](https://app.edgegap.com/application-management/applications/list)，或通过我们的 API。

{% hint style="success" %}
探索我们的 [应用程序 API 参考](https://docs.edgegap.com/api/#tag/Applications)，或进一步了解我们的 [管理 API](https://docs.edgegap.com/api/).
{% endhint %}

## 🏷️ 应用版本

随着你开发应用并持续产出新构建，你需要将每个构建作为单独的版本保存，以便：

* **保持兼容性** 在客户端和服务器之间，
* 比较你的 **增量发布** 的各个方面（性能、用户反馈），
* 测试 **多个应用版本同时运行** （开发、质量保证、预发布、Beta）。

{% hint style="info" %}
每个应用版本都指向你选择的一个构建制品。多个版本可以指向同一个构建。
{% endhint %}

你可以使用我们的方式在 Edgegap 上管理你的应用版本 [控制台](https://app.edgegap.com/application-management/applications/list)，或通过我们的 API。

{% hint style="success" %}
探索我们的 [应用版本 API 参考](https://docs.edgegap.com/api/#tag/Applications/operation/app-version-post)，或阅读更多关于 [API](https://docs.edgegap.com/api/).
{% endhint %}

每个版本在其父应用程序内通过以下方式唯一标识： **应用版本名称**。你可以自由决定自己的命名约定。这里有一些流行示例供你参考：

* `2024.01.30-16.23.00-UTC` - 时间戳对于保留许多历史版本很透明，
* `1.1.0` - [语义化版本控制](https://semver.org/) 是传达变更范围的绝佳选择，
* `dev` , `staging`, `qa`, `prod` - 每个环境只保留最新版本非常容易，
* `blue`, `green` - 版本可用作滚动更新发布策略的别名。

{% hint style="success" %}
只要你保持客户端/服务器兼容性，你可以随时更改方法。
{% endhint %}

{% hint style="info" %}
你可以在我们的系统中禁用任何应用或版本 [控制台](https://app.edgegap.com/application-management/applications/list) 设为 **以防止人为（开发）错误**.
{% endhint %}

{% hint style="info" %}
免费层仅限 2 个应用程序、2 个版本以及 5 GB 的容器镜像仓库存储。
{% endhint %}

### 组合版本控制策略

很多时候，最佳解决方案是混合使用版本控制策略，例如：

* 对开发构建使用时间戳或语义化版本控制，以获得更细粒度的跟踪；
* 保留 `staging`, `qa` 和 `prod` 带有环境特定参数的版本；
* 交替使用 `blue` 和 `green` 版本作为别名，用于 [零匹配停机时间更新](https://docs.edgegap.com/docs/gen2-matchmaker#rolling-updates-ab-tests).

## 🧱 必需参数

这些基础参数必须始终定义。

### 资源需求

除了 **版本名称**之外，创建新版本还需要以下几个参数：

* **vCPU** - 你的应用运行需要多少虚拟 CPU 单元（1024 单元 = 1 vCPU），
  * **允许的最小 vCPU 数量为 0.25 vCPU（256 单元），**
  * 此设置无法在现有应用版本上编辑，你必须创建一个新版本。
* **内存** - 你的应用运行需要多少 MB 的 RAM（1024MB = 1GB），
  * 此设置无法在现有应用版本上编辑，你必须创建一个新版本。
* **GPU** - 你的应用运行需要多少图形处理单元，
  * 此功能尚不可用，如果你感兴趣，请联系我们。

{% hint style="success" %}
版本会自动按 2:1 的 RAM-vCPU 比例包含 RAM， **每 0.25 vCPU 最高可提供 512MB RAM**.
{% endhint %}

{% hint style="info" %}
我们的服务器机器使用 AMD/Intel CPU，时钟速度为 2.4 - 3.2 GHz，具体取决于地点。为确保你的服务器有足够的可用资源，请在以下渠道联系： [社区 Discord](https://discord.gg/MmJf8fWjnt).
{% endhint %}

### 镜像详情

这些参数将帮助我们的系统决定之后应启动你的服务器的哪个构建：

* **仓库** - `registry.edgegap.com` 如果你正在使用我们的 [容器镜像仓库](https://docs.edgegap.com/docs/container/edgegap-container-registry),
  * 如果要使用第三方镜像仓库，请输入你的第三方镜像仓库 Docker 凭据，
  * 镜像仓库作为你和其他用户仓库的共享存储服务。
* **镜像仓库** - 指你的应用程序专用仓库，
  * 在我们的以下位置找到你所有的仓库： [控制台的容器镜像仓库页面](https://app.edgegap.com/registry-management/repositories/list),
  * 每个仓库可能包含你服务器镜像的多个标签。
* **标签** - 指你的服务器镜像的特定构建制品（版本），
  * 我们的插件默认会将标签值从应用版本名称中复制，
  * 你可以在 Docker Desktop 的 Images 中或使用 docker CLI 查看本地存储的标签。

{% hint style="danger" %}
:x: **不要 - 覆盖现有标签或使用 `latest` 标签** 以避免部署过时（缓存）的构建。\
:white\_check\_mark: **应该 - 始终增加你的版本标签** 以部署预期的构建并防止发布问题。
{% endhint %}

* **私有仓库** - 如果你仓库的访问受保护（私有仓库），我们还需要：
  * **用户名令牌** - 你的仓库程序化访问用户名，
  * **密码令牌** - 你的仓库程序化访问密码，
  * 对于 Edgegap [容器镜像仓库](https://docs.edgegap.com/docs/container/edgegap-container-registry)，你可以 [从我们的控制台复制这些值](https://app.edgegap.com/registry-management/repositories/list),
  * 这些对于公共仓库不是必需的。

<details>

<summary>故障排除与常见问题</summary>

我在推送服务器镜像时收到了错误 `401 未授权` 。

* 这表示你尚未登录到你的容器镜像仓库。请查看容器镜像仓库中的 [Edgegap 容器镜像仓库说明](https://docs.edgegap.com/docs/container/edgegap-container-registry#getting-your-credentials)，或你的仓库提供商对应的说明。重复上一次操作无法解决该错误。

***

我在推送服务器镜像时收到了错误 `403 禁止访问` 。

* 这表示你当前登录的仓库用户没有足够的权限（通常是推送新镜像的权限），或者你登录到了错误的仓库提供商。请尝试退出并使用具有足够权限的正确提供商和用户重新登录。重复上一次操作无法解决该错误。

***

仓库、仓库（repository）和项目有什么区别？

* 可以把 registry 想成存储设施，把 repository 想成存储单元，把 project 想成存储单元编号。每个 registry 通常包含许多 repository，其中一些是公开的，一些对组织和用户是私有的。
* 示例仓库： `registry.edgegap.com` .
* 示例 repository： `registry.edgegap.com/my-edgegap-org/my-game-server`.
* 示例项目名称： `my-game-server` .

***

在推送新的镜像标签/构建时，我的更改没有正确重新加载。

* 请确保每次重新构建时都使用新的镜像标签进行推送。Edgegap 的内部缓存系统使用标签名称，如果你覆盖了某个标签值（例如 `latest`），它将不会识别新的构建。

***

我可以为同一个构建制品打多个标签吗？

* 可以，你可以为同一个制品打多个标签而不会有问题，它们会作为同一构建的多个别名。继续阅读，了解之后如何移除这些标签。

***

当我删除一个标签时会发生什么？为什么我不能使用哈希值删除特定制品？

* 删除标签也会导致相关的构建制品被删除，前提是在 [API 请求](https://docs.edgegap.com/api/#tag/Container-Registry/operation/image-tag-delete).
* 时该制品没有其他关联标签。由于 docker API 标准以及为了确保尽可能好的用户体验，我们只提供删除标签的界面。关于删除构建制品，请参见上文。

</details>

## ⚙️ 可选参数

这些参数可以配置，以进一步自定义你的部署。

### 注入变量

此版本的所有部署都会注入自定义环境变量：

* 常见示例包括：引擎参数、第三方密钥和端点，
* 请参见 [部署](/zh/learn/bian-pai/deployments.md#injected-environment-variables) 以了解根据部署上下文注入环境变量的不同方式，除了应用版本变量之外，
* 每个环境变量最多可包含 4KB（千字节）的字符串数据。

{% hint style="warning" %}
请务必 **将敏感变量（密钥、令牌）设为隐藏** 以增强安全性！
{% endhint %}

### 主动缓存

:star2: [**升级到按需付费套餐**](https://app.edgegap.com/user-settings?tab=memberships) **即可解锁全球 0.5 秒部署时间！**

**加快部署速度，在几秒内启动服务器，无需待命服务器。** 与此应用版本关联的服务器镜像将自动预加载到我们全球所有位置。

一旦你的应用版本缓存等级达到🟢 良好，缓存就会完全生效。

{% hint style="success" %}
多个应用版本可以复用同一个镜像标签。 **为一个版本启用缓存将自动为所有链接到同一镜像标签的版本启用缓存**，从而轻松实现参数化部署。
{% endhint %}

{% hint style="info" %}
镜像在部署时也会被被动缓存，仅保存在部署它的主机上。
{% endhint %}

{% hint style="warning" %}
**如果镜像连续 72 小时未被部署，将会从缓存中移除。**
{% endhint %}

### 端口映射

每个服务器至少需要一个端口，以便接受传入的客户端连接：

* **端口** 值指的是 **内部端口** 值，通常来自你的网络代码集成，
* **协议** 将取决于你的网络代码集成传输方式，
* **名称** 是一个供你自己使用的人类可读标识符，可以与端口相同，
* **验证** 可以启用，以确保你的容器在被标记为 READY 之前已初始化完成。

{% hint style="success" %}
大多数游戏只需要为端口添加一个 UDP 端口映射 `7777`.
{% endhint %}

虽然服务器进程的内部端口是在应用版本中定义的， **外部端口会在创建部署后随机分配**，这样潜在的恶意方（黑客）会被延缓并在造成损害前被检测到。

<figure><img src="/files/a9beeb419bfb59f63e55b32a7622aff167022fcb" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
如果你的服务器通过多个协议通信，请在端口映射中添加更多端口。
{% endhint %}

### 安全护栏

这些参数有助于处理各种边缘情况和常规服务器故障排查：

* **时间限制** - 这些功能可以帮助你管理部署资源的生命周期：
  * **游戏最长持续时间** 可设置为在给定时间后优雅地关闭服务器，或设为 `-1`  配合 [应用版本 API 创建/编辑](/zh/docs/api/ban-ben-kong-zhi.md#post-v1-app-app_name-version) 用于 [持久化](/zh/learn/bian-pai/chi-jiu-hua.md) 配合 [私有舰队](/zh/learn/bian-pai/si-you-jian-dui.md).
  * **最大部署时间** 可帮助你清理启动时间过长的部署。
* **进程重启策略** - 控制当你的服务器进程停止时的部署行为。
  * 始终重启（默认）- 在成功退出码（0）和任何错误退出时都会重启。
  * 永不重启（推荐）- 在成功和错误退出码时都会停止部署。
  * 崩溃时重启 - 仅在错误退出码时重启，适用于持久化服务器。
* **容器日志存储** - 如需在部署停止后导出服务器日志，请指定预配置的 S3 兼容存储桶来导出你的容器日志，
  * 请参见 [端点存储](https://docs.edgegap.com/docs/deployment/endpoint-storage) 了解配置和使用详情。

{% hint style="warning" %}
没有外部存储的版本日志将在部署终止时被删除。
{% endhint %}

{% hint style="info" %}
免费层仅限 2 个应用程序、2 个版本以及 5 GB 的容器镜像仓库存储。
{% endhint %}

## ⏩ 更新一致性

为了确保通过我们的 [控制台](https://app.edgegap.com/application-management/applications/list)创建新应用版本时不会更改任何参数，我们建议使用 **复制** 功能，在你之前的应用版本仪表板页面右上角进行复制。复制时，你可以在保存前编辑任何参数。

{% hint style="success" %}
**复制或编辑你的应用版本不需要重新构建服务器镜像。**
{% endhint %}

{% hint style="info" %}
参见 [匹配器滚动更新](https://docs.edgegap.com/docs/gen2-matchmaker#rolling-updates-ab-tests) 以了解更多 **发布自动化**.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.edgegap.com/zh/learn/bian-pai/application-and-versions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
