# 관리형 클러스터

Managed Clusters에 대해 알아보고 맞춤형 백엔드 솔루션으로 빠르게 시작하세요.

## ✔️ 소개

Managed Clusters는 자체 관리형 게임 서비스와 게임 백엔드의 호스팅을 쉽고 빠르게 만들어줍니다. 서비스 이미지를 준비하면 저희가 고가용성이고 탄력적인 클라우드 환경을 제공하여 이를 실행합니다:

* 플레이어 인증,
* 데이터 저장 - 계정, 진행 상황, 인벤토리, 보상 등
* 소셜 서비스 - 채팅, 클랜, 순위표, 토너먼트 등
* 맞춤 매치메이킹 - 사용 [#advanced-matchmaker](#advanced-matchmaker "mention"), [#nakama-by-heroic-labs](#nakama-by-heroic-labs "mention"), ...
* 서버리스 컴퓨팅 - 관리형 [함수형 서비스](https://github.com/openfaas/faas) (대안: cloudscript, lambda), ...

프라이빗 클러스터는 귀하의 서비스에 **전용 컴퓨팅을 제공하여 플레이어에게 24/7 서비스할 수 있도록 합니다**.

{% hint style="info" %}
저희 클러스터 머신은 2.4 - 3.2 GHz 클럭 속도의 AMD/Intel CPU를 사용합니다. 부하 테스트 조정 및 서버에 충분한 리소스가 있는지 확인하려면 [커뮤니티 디스코드](https://discord.gg/MmJf8fWjnt) 로 연락해 주세요.
{% endhint %}

## 🛠️ 개발자 도구

개선할 부분을 발견하시면 저희 [커뮤니티 디스코드](https://discord.gg/NgCnkHbsGp).

에 알려 주세요. 원활한 경험이 되시길 바랍니다. 🚀

### Docker

서버의 신뢰성을 높이기 위해 저희는 [Docker](https://www.docker.com/) - 가상화 소프트웨어를 사용하여 운영체제 수준까지 모든 서버 코드 종속성이 서버가 어디서 어떻게 시작되든 항상 정확히 동일하도록 보장합니다.

### Kubernetes (K8s)

[Kubernetes](https://kubernetes.io/docs/concepts/overview/)는 K8s로도 알려져 있으며 컨테이너화된 애플리케이션(Docker 이미지)의 배포, 확장 및 관리를 자동화하는 오픈 소스 시스템입니다. 애플리케이션을 구성하는 컨테이너를 논리적 단위로 그룹화하여 관리 및 검색을 쉽게 합니다.

Edgegap Managed Clusters는 관리 목적으로 Kubernetes API를 제공합니다.

### K8s Lens

100만 명 이상의 사용자와 함께, [K8s Lens](https://k8slens.dev/) 는 전 세계에서 가장 인기 있는 Kubernetes IDE입니다. 클러스터에 연결하고 탐색하며 인사이트를 얻고 필요할 때 조치를 취하세요. Lens는 워크로드와 리소스의 모든 정보를 항상 적절한 컨텍스트로 실시간 제공해 줍니다.

Edgegap Cluster Kubernetes API는 Lens 또는 다른 Kubernetes IDE를 통해 사용할 수 있습니다.

### Helm 패키지 관리자

[Helm](https://helm.sh/) 은 Kubernetes용으로 빌드된 소프트웨어를 찾고 공유하며 사용하는 가장 좋은 방법입니다. Helm은 Kubernetes 애플리케이션을 관리하는 데 도움을 줍니다 - Helm 차트는 가장 복잡한 Kubernetes 애플리케이션도 정의, 설치 및 업그레이드할 수 있도록 해줍니다. 차트는 만들기, 버전 관리, 공유 및 게시가 쉬우므로 Helm을 사용하고 복사-붙여넣기를 그만두세요.

[Helm CLI 설치](https://helm.sh/docs/intro/install/) 는 개발자가 클러스터 패키지를 관리할 수 있는 간단한 인터페이스를 제공합니다.

## 🚀 시작하기

☑️ [무료 Edgegap 계정에 가입](https://app.edgegap.com/auth/register) 하고 종량제 요금제로 업그레이드하여 Clusters를 활성화하세요.

☑️ 이동: [Managed 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
NAME                            STATUS   ROLES    AGE    VERSION
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
```

🙌 축하합니다! Managed Cluster 설정을 완료했습니다. 이제 서비스를 설치할 수 있습니다.

## 📦 Heroic Labs의 Nakama

{% 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/) 을(를) Managed Clusters에 호스팅하려면:

☑️ 생성: **DNS 레코드 타입 A** 를 DNS 제공자에 생성하세요(예:  [Cloudflare](https://developers.cloudflare.com/dns/get-started/)). 이후 URL을 기록해 두세요. 귀하의 **DNS 레코드용 외부 IP** 는 Lens의 Services / `ingress-nginx-controller` .

에서 확인할 수 있습니다. [☑️ DNS 설정이 올바른지 확인하려면 조회를 수행하세요](https://dnschecker.org/ns-lookup.php).

DNSchecker `☑️ 다음 이름으로 파일을 생성하세요:` values.yaml

<pre class="language-yaml"><code class="lang-yaml">내용(자신의 값 사용):

isProductionEnvironment: true
# Nakama 서버의 외부 호스트명 - 이전 단계의 DNS 레코드 <a data-footnote-ref href="#user-content-fn-1">externalHostName:</a>

이전 단계의 DNS 레코드
  nakama:
  # 배포할 Nakama 버전.
  # 사용 가능한 버전은 https://hub.docker.com/r/heroiclabs/nakama/tags 를 참조하세요.
  version: 3.26.0
  # Nakama 콘솔의 사용자 이름과 비밀번호 <a data-footnote-ref href="#user-content-fn-2">username:</a>
  관리자 사용자 이름을 직접 선택하세요 <a data-footnote-ref href="#user-content-fn-3">password:</a>
</code></pre>

{% hint style="danger" %}
**관리자용으로 안전한 비밀번호를 선택하세요** 위의 \<VALUES>를 파일 내의 본인 값으로 교체하세요.
{% endhint %}

☑️ Nakama helm 차트 배포:

```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 및 자격증명은 `☑️ 다음 이름으로 파일을 생성하세요:` 파일에서 확인하세요.

🙌 축하합니다! 자체 호스팅 Nakama 게임 백엔드 설정을 완료했습니다!

### 서비스 업데이트

Managed Cluster에서 호스팅 중인 서비스를 업데이트하려면 다음 단계를 따르세요:

☑️ 귀하의 `value.yaml` 파일을 새 파일로 업데이트하세요.

☑️ 다음 명령으로 helm 차트를 업데이트하세요:

```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
```

☑️ 업데이트된 파드를 종료하여 변경 사항을 다시 로드하세요. 그러면 파드가 자동으로 재시작된 후 새 helm 차트가 사용됩니다.

🙌 축하합니다! Nakama Cluster 업데이트를 완료했습니다!

## 👷 고급 매치메이커

다음 단계를 따라 [OpenMatch](https://open-match.dev/site/) 을(를) Managed Cluster에 호스팅하세요.

☑️ DNS 제공자에 DNS 레코드 타입 A를 생성하세요(예:  [Cloudflare](https://developers.cloudflare.com/dns/get-started/)). 이후 URL을 기록해 두세요. 귀하의 **DNS 레코드용 외부 IP** 는 Lens의 Services / `ingress-nginx-controller` .

에서 확인할 수 있습니다. [☑️ DNS 설정이 올바른지 확인하려면 조회를 수행하세요](https://dnschecker.org/ns-lookup.php).

DNSchecker `☑️ 다음 이름으로 파일을 생성하세요:` 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 차트 배포:

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

🙌 축하합니다! 고급 매치메이커 설정을 완료했습니다!

### 서비스 업데이트

Managed Cluster에서 호스팅 중인 서비스를 업데이트하려면 다음 단계를 따르세요:

☑️ 귀하의 `value.yaml` 파일을 새 파일로 업데이트하세요.

☑️ 다음 명령으로 helm 차트를 업데이트하세요:

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

☑️ 업데이트된 파드(director, mmf, frontend)를 종료하여 변경 사항을 다시 로드하세요. 그러면 파드가 자동으로 재시작된 후 새 helm 차트가 사용됩니다.

🙌 축하합니다! 고급 매치메이커 업데이트를 완료했습니다!

### 지속적 배포

배포 파이프라인에 다음 셸 스크립트를 추가하여 서비스 업데이트를 자동화하세요:

```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)에 대해 파드를 중지합니다
for deployment in $DIRECTOR_DEPLOYMENT_NAME $MMF_DEPLOYMENT_NAME $CUSTOM_FRONTEND_DEPLOYMENT_NAME
do
  echo "배포의 파드 중지: $deployment"
  replicas[$deployment]=$(kubectl get deployment $deployment -o=jsonpath='{.spec.replicas}' --namespace $NAMESPACE)
  kubectl scale deployment/$deployment --replicas=0 --namespace $NAMESPACE
done

# 파드가 종료될 때까지 기다립니다
for deployment in $DIRECTOR_DEPLOYMENT_NAME $MMF_DEPLOYMENT_NAME $CUSTOM_FRONTEND_DEPLOYMENT_NAME
do

  echo "파드 종료 대기 중: $deployment"
  kubectl wait --for=delete pod -l app=$deployment --timeout=60s --namespace $NAMESPACE

  # 대기 명령이 성공했는지 확인합니다. 실패하면 스크립트를 종료합니다
  if [ $? -ne 0 ]; then
    echo "파드 종료 대기 실패: $deployment"
    exit 1
  fi
done

# Redis 데이터베이스 정리
echo "Redis 데이터베이스 정리 중"
redis-cli -h $REDIS_HOST flushall

# 각 배포(director, mmf, custom-frontend)에 대해 파드를 원래 수로 다시 조정합니다
for deployment in $DIRECTOR_DEPLOYMENT_NAME $MMF_DEPLOYMENT_NAME $CUSTOM_FRONTEND_DEPLOYMENT_NAME
do
  echo "배포의 파드 수를 ${replicas[$deployment]}로 재조정 중: $deployment"
  kubectl scale deployment/$deployment --replicas=${replicas[$deployment]} --namespace $NAMESPACE
done
```

### 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;클러스터 크기 변경은 클러스터를 중지해야 합니다. 무중단 업데이트에 대해서는 [blue/green 배포](https://circleci.com/blog/canary-vs-blue-green-downtime/) 를 참조하세요.
{% endhint %}

### 지원 및 향후 업데이트

**귀하의 성공이 저희의 최우선 과제입니다.** 맞춤 요청을 보내거나, 필수 기능이 누락되었음을 요청하거나, 의견을 표현하고 싶으시면, [커뮤니티 디스코드로 연락해 주세요](https://discord.gg/MmJf8fWjnt).

[^1]: \<DNS\_A\_RECORD\_URL>

[^2]: \<USERNAME>

[^3]: \<PASSWORD>
