TheKoguryo's 기술 블로그

 Version 2023.11.20

4.6 게임서비스를 위한 Agones 테스트

게임 서버를 쿠버네티스에서 서비스하기 많이 사용되는 Agones가 OKE에서 잘 동작하는 확인하기 위한 테스트입니다. Agones 공식문서를 참조하여 진행하였습니다.

OKE Cluster 1.26에서 VCN-Native Pod Networking, Flannel 모두 동작함을 확인하였습니다.

Agones 설치를 위한 OKE 클러스터 준비

  1. OKE Cluster 지원 버전 확인

    • Agones and Kubernetes Supported Versions을 참고하여 지원하는 쿠버네티스 버전을 확인하고 준비합니다.
    • 여기서는 최신버전인 Agones 1.33을 OKE Cluster 1.26에 설치하겠습니다.
    Agones versionKubernetes version(s)
    1.331.24, 1.25, 1.26
  2. Agones 설치후 생성되는 GameServer에 할당되는 주소는 Worker Node의 IP가 할당됩니다. GameServer에 Public IP 할당이 필요한 경우, OKE Cluster 생성시 Worker Node를 Public Subnet에 배치합니다.

    • 참고

      How are IP addresses allocated to GameServers?

      Each GameServer inherits the IP Address of the Node on which it resides. If it can find an ExternalIP address on the Node (which it should if it’s a publicly addressable Node), that it utilised, otherwise it falls back to using the InternalIP address.

    • Create Cluster - Quick Mode 시

      image-20230714171852621

  3. 클라이언트가 GameServer에 접속할 수 있도록, Worker Nodes가 속한 서브넷에 UDP 프로토콜로 7000-8000 포트들을 개방합니다.

    image-20230714174000050

Agones를 OKE 클러스터에 설치하기

  1. Helm Chart를 이용해 설치합니다.

    helm repo add agones https://agones.dev/chart/stable
    helm repo update
    helm install my-release --namespace agones-system --create-namespace agones/agones --version 1.33.0
    
  2. 설치 상태를 확인합니다.

    kubectl get pods --namespace agones-system
    
    • 확인 결과 예시

      $ kubectl get pods --namespace agones-system
      NAME                                 READY   STATUS    RESTARTS   AGE
      agones-allocator-56885bfc8f-czz99    1/1     Running   0          79s
      agones-allocator-56885bfc8f-dxm2h    1/1     Running   0          79s
      agones-allocator-56885bfc8f-t9k5v    1/1     Running   0          79s
      agones-controller-587bdb474-6k5m6    1/1     Running   0          78s
      agones-controller-587bdb474-xlpgl    1/1     Running   0          78s
      agones-extensions-7c785c6b8c-2z2tg   1/1     Running   0          78s
      agones-extensions-7c785c6b8c-qhdkw   1/1     Running   0          78s
      agones-ping-7486954d88-5xrzh         1/1     Running   0          78s
      agones-ping-7486954d88-mnjzf         1/1     Running   0          78s
      

GameServer 설치

  1. 테스트로 배포할 GameServer의 YAML 파일입니다.

    apiVersion: "agones.dev/v1"
    kind: GameServer
    metadata:
      generateName: "simple-game-server-"
    spec:
      ports:
      - name: default
        portPolicy: Dynamic
        containerPort: 7654
      template:
        spec:
          containers:
          - name: simple-game-server
            image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.16
            resources:
              requests:
                memory: "64Mi"
                cpu: "20m"
              limits:
                memory: "64Mi"
                cpu: "20m"
    
  2. 해당 YAML을 배포하여 테스트용 GameServer를 설치합니다.

    kubectl create -f https://raw.githubusercontent.com/googleforgames/agones/release-1.33.0/examples/simple-game-server/gameserver.yaml
    
  3. Worker Node의 Public IP 확인

    $ kubectl get nodes -o wide
    NAME          STATUS   ROLES   AGE     VERSION   INTERNAL-IP   EXTERNAL-IP      OS-IMAGE
    10.0.10.105   Ready    node    8m34s   v1.26.2   10.0.10.105   146.56.xx.xxx    ...
    10.0.10.233   Ready    node    8m51s   v1.26.2   10.0.10.233   144.24.xx.xx     ...
    10.0.10.29    Ready    node    9m22s   v1.26.2   10.0.10.29    158.180.xx.xxx   ...
    
  4. 생성된 GameServer를 확인합니다.

    • GameServer의 주소(ADDRESS)가 해당 Pod가 속한 NODE(10.0.10.29)의 EXTERNAL-IP인 것을 확인할 수 있습니다.
    • 각 노드의 7000-8000 범위로 UDP로 오픈됩니다.
    • 아래와 같이 GameServer Kind가 Pod에 대응됩니다.
    $ kubectl get gameservers
    NAME                       STATE   ADDRESS          PORT   NODE         AGE
    simple-game-server-pkj5d   Ready   158.180.xx.xxx   7365   10.0.10.29   87s
    $ kubectl get pods -o wide
    NAME                       READY   STATUS    RESTARTS   AGE     IP           NODE         NOMINATED NODE   READINESS GATES
    simple-game-server-pkj5d   2/2     Running   0          7m22s   10.244.0.6   10.0.10.29   <none>           <none>
    
  5. GameServer 연결확인을 위해 Pod 로그를 확인합니다.

    kubectl logs -f simple-game-server-pkj5d --all-containers
    
  6. GameServer에 nc 명령을 통해 메세지를 전송해 봅니다.

    • -u 옵션을 통해 UDP로 게임서버 포트로 연결되는 것을 테스트합니다.
    • Hello World ! 를 전달시 아래와 같이 서버에서 에코 응답이 오는 것을 볼 수 있습니다.
    $ nc -u 158.180.xx.xxx 7365
    Hello World !
    ACK: Hello World !
    EXIT
    ACK: EXIT
    ^C
    
  7. GameServer Pod 로그에서도 수신된 메시지를 확인할 수 있습니다.

    $ kubectl logs -f simple-game-server-pkj5d --all-containers
    2023/07/14 08:50:39 Creating SDK instance
    2023/07/14 08:50:39 Starting Health Ping
    2023/07/14 08:50:39 Marking this server as ready
    2023/07/14 08:50:39 Starting UDP server, listening on port 7654
    ...
    2023/07/14 09:01:59 Health Ping
    2023/07/14 09:02:01 Received packet from 129.213.xxx.xxx:37487: Hello World !
    2023/07/14 09:02:01 Received UDP: Hello World !
    2023/07/14 09:13:09 Health Ping
    2023/07/14 09:13:11 Received packet from 129.213.xxx.xxx:43110: EXIT
    2023/07/14 09:13:11 Received UDP: EXIT
    2023/07/14 09:13:11 Received EXIT command. Exiting.
    
  8. 끝에 EXIT를 입력하면, GameServer가 종료되고, Pod도 종료됩니다.

    $ kubectl get gameserver
    No resources found in default namespace.
    

Fleet

앞서 GameServer 실행시 EXIT가 되면, GameServer가 종료되었습니다. 안정적인 게임 서비스를 위해 Fleet를 사용하면, 특정 Pod에서 게임이 종료되어도, Fleet를 통해 지정한 GameServer를 유지하게 됩니다.

  1. 테스트로 배포할 Fleet YAML 파일입니다. 2개의 GameServer를 만드는 예제입니다.

    • Fleet 형식에서 보듯 Deployment에 해당된다고 보면 됩니다.
    apiVersion: "agones.dev/v1"
    kind: Fleet
    metadata:
      name: simple-game-server
    spec:
      replicas: 2
      template:
        spec:
          ports:
          - name: default
            containerPort: 7654
          template:
            spec:
              containers:
              - name: simple-game-server
                image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.16
                resources:
                  requests:
                    memory: "64Mi"
                    cpu: "20m"
                  limits:
                    memory: "64Mi"
                    cpu: "20m"
    
  2. 해당 YAML을 배포하여 Fleet를 생성합니다.

    kubectl apply -f https://raw.githubusercontent.com/googleforgames/agones/release-1.33.0/examples/simple-game-server/fleet.yaml
    
  3. 생성결과를 확인합니다. Fleet에 의해 2개의 GameServer가 생성되었습니다.

    • GameServer의 Deployment 역할 해주는 것이 Fleet으로 생각하면 됩니다.
    $ kubectl get fleet
    NAME                 SCHEDULING   DESIRED   CURRENT   ALLOCATED   READY   AGE
    simple-game-server   Packed       2         2         0           2       19s 
    
    $ kubectl get gameserver
    NAME                             STATE   ADDRESS          PORT   NODE         AGE
    simple-game-server-fvcsc-dbl9v   Ready   158.180.xx.xxx   7392   10.0.10.29   32s
    simple-game-server-fvcsc-ldsg5   Ready   158.180.xx.xxx   7023   10.0.10.29   32s
    
  4. Scale Out 합니다.

    kubectl scale fleet simple-game-server --replicas=5
    
    • 실행결과

      $ kubectl scale fleet simple-game-server --replicas=5
      fleet.agones.dev/simple-game-server scaled
      $ kubectl get gameserver
      NAME                             STATE   ADDRESS          PORT   NODE         AGE
      simple-game-server-fvcsc-4xp4r   Ready   158.180.xx.xxx   7223   10.0.10.29   12s
      simple-game-server-fvcsc-7pfgk   Ready   158.180.xx.xxx   7123   10.0.10.29   12s
      simple-game-server-fvcsc-dbl9v   Ready   158.180.xx.xxx   7392   10.0.10.29   4m31s
      simple-game-server-fvcsc-ldsg5   Ready   158.180.xx.xxx   7023   10.0.10.29   4m31s
      simple-game-server-fvcsc-wnz4d   Ready   158.180.xx.xxx   7234   10.0.10.29   12s
      
  5. GameServer를 할당합니다.

    kubectl create -f https://raw.githubusercontent.com/googleforgames/agones/release-1.33.0/examples/simple-game-server/gameserverallocation.yaml -o yaml
    
  6. 할당후 GameServer 상태를 보면, 하나의 GameServer의 상태가 Allocated로 변경되었습니다.

    $ kubectl get gameserver
    NAME                             STATE       ADDRESS          PORT   NODE         AGE
    simple-game-server-fvcsc-4xp4r   Allocated   158.180.xx.xxx   7223   10.0.10.29   4m58s
    simple-game-server-fvcsc-7pfgk   Ready       158.180.xx.xxx   7123   10.0.10.29   4m58s
    simple-game-server-fvcsc-dbl9v   Ready       158.180.xx.xxx   7392   10.0.10.29   9m17s
    simple-game-server-fvcsc-ldsg5   Ready       158.180.xx.xxx   7023   10.0.10.29   9m17s
    simple-game-server-fvcsc-wnz4d   Ready       158.180.xx.xxx   7234   10.0.10.29   4m58s
    
  7. Scale In 합니다.

    kubectl scale fleet simple-game-server --replicas=0
    
  8. 할당된 서버는 삭제되지 않는 것을 볼 수 있습니다.

    $ kubectl get gameserver
    NAME                             STATE       ADDRESS          PORT   NODE         AGE
    simple-game-server-fvcsc-4xp4r   Allocated   158.180.xx.xxx   7223   10.0.10.29   5s
    
  9. 할당된 GameServer에 접속하여 앞서와 동일하게 테스트후 EXIT합니다.

    $ kubectl get gameservers | grep Allocated | awk '{print $3":"$4 }'
    158.180.xx.xxx:7223
    $ nc -u 158.180.xx.xxx 7223
    Hello World !
    ACK: Hello World !
    EXIT
    ACK: EXIT
    ^C
    
  10. 현재 GameServer를 다시 조회합니다. 할당된 GameServer의 서비스가 종료되었습니다.

    $ kubectl get gameserver
    No resources found in default namespace.
    

Fleet Autoscaler

  1. 테스트로 배포할 Fleet Autoscaler YAML을 확인합니다.

    apiVersion: "autoscaling.agones.dev/v1"
    kind: FleetAutoscaler
    metadata:
      name: simple-game-server-autoscaler
    spec:
      fleetName: simple-game-server
      policy:
        type: Buffer
        buffer:
          bufferSize: 2
          minReplicas: 0
          maxReplicas: 10
    
  2. 해당 YAML을 배포하여 Fleet Autoscaler를 배포합니다.

    kubectl apply -f https://raw.githubusercontent.com/googleforgames/agones/release-1.33.0/examples/simple-game-server/fleetautoscaler.yaml
    
  3. 현재 상태를 확인합니다. bufferSize: 2에 의해 GameServer 2개로 스케일되었습니다.

    $ kubectl describe fleetautoscaler simple-game-server-autoscaler
    ...
    Spec:
      Fleet Name:  simple-game-server
      Policy:
        Buffer:
          Buffer Size:   2
          Max Replicas:  10
          Min Replicas:  0
        Type:            Buffer
      Sync:
        Fixed Interval:
          Seconds:  30
        Type:       FixedInterval
    Status:
      Able To Scale:     true
      Current Replicas:  2
      Desired Replicas:  2
      Last Scale Time:   2023-07-14T09:52:19Z
      Scaling Limited:   false
    Events:
      Type    Reason            Age    From                        Message
      ----    ------            ----   ----                        -------
      Normal  AutoScalingFleet  3m25s  fleetautoscaler-controller  Scaling fleet simple-game-server from 0 to 2
    
  4. GameServer를 할당합니다.

    kubectl create -f https://raw.githubusercontent.com/googleforgames/agones/release-1.33.0/examples/simple-game-server/gameserverallocation.yaml -o yaml
    
  5. Fleet Autoscaler의 현재 상태를 확인합니다. 스케일되어 3개가 되었습니다. 할당된 것을 제외하고 여전히 2개가 Ready 상태입니다.

    $ kubectl describe fleetautoscaler simple-game-server-autoscaler
    ...
    Status:
      Able To Scale:     true
      Current Replicas:  2
      Desired Replicas:  3
      Last Scale Time:   2023-07-14T09:57:49Z
      Scaling Limited:   false
    Events:
      Type    Reason            Age    From                        Message
      ----    ------            ----   ----                        -------
      ...
      Normal  AutoScalingFleet  19s    fleetautoscaler-controller  Scaling fleet simple-game-server from 2 to 3
    
    $ kubectl get gameserver
    NAME                             STATE       ADDRESS          PORT   NODE         AGE
    simple-game-server-fvcsc-6btkj   Ready       158.180.xx.xxx   7232   10.0.10.29   34s
    simple-game-server-fvcsc-7rps5   Allocated   158.180.xx.xxx   7178   10.0.10.29   94s
    simple-game-server-fvcsc-x8tvh   Ready       158.180.xx.xxx   7045   10.0.10.29   94s
    
  6. 할당된 GameServer에 접속하여 사용하고 종료합니다.

    $ nc -u 158.180.xx.xxx 7178
    Hello World !
    ACK: Hello World !
    EXIT
    ACK: EXIT
    ^C
    
  7. Fleet Autoscaler의 현재 상태를 확인합니다. 서비스된 GameServer가 종료되어 다시 스케일되어 2개가 되었습니다.

    $ kubectl describe fleetautoscaler simple-game-server-autoscaler
    ...
    Status:
      Able To Scale:     true
      Current Replicas:  3
      Desired Replicas:  2
      Last Scale Time:   2023-07-14T10:03:19Z
      Scaling Limited:   false
    Events:
      Type    Reason            Age                From                        Message
      ----    ------            ----               ----                        -------
      ...
      Normal  AutoScalingFleet  21s (x2 over 11m)  fleetautoscaler-controller  Scaling fleet simple-game-server from 3 to 2
    
    $ kubectl get gameserver
    NAME                             STATE   ADDRESS          PORT   NODE         AGE
    simple-game-server-fvcsc-x8tvh   Ready   158.180.xx.xxx   7045   10.0.10.29   2m22s
    simple-game-server-fvcsc-zf2mq   Ready   158.180.xx.xxx   7122   10.0.10.29   37s
    

추가 테스트

5개로 스케일해도 단일 Worker Node에 계속 GameServer가 만들어 지길래, 50개를 만들어 봤습니다.

  1. 배포된 Fleet Autoscaler을 수정하여, bufferSize: 50, maxReplicas:100 으로 변경합니다.

  2. GameServer 확인

    $ kubectl get gameserver
    NAME                             STATE   ADDRESS          PORT   NODE          AGE
    simple-game-server-fvcsc-2b6hn   Ready   158.180.xx.xxx   7877   10.0.10.29    67s
    simple-game-server-fvcsc-4mdrp   Ready   146.56.xx.xxx    7783   10.0.10.105   67s
    simple-game-server-fvcsc-4xzrf   Ready   146.56.xx.xxx    7252   10.0.10.105   67s
    simple-game-server-fvcsc-5sjkf   Ready   158.180.xx.xxx   7369   10.0.10.29    67s
    simple-game-server-fvcsc-6p5qk   Ready   158.180.xx.xxx   7185   10.0.10.29    67s
    simple-game-server-fvcsc-6pkxz   Ready   158.180.xx.xxx   7339   10.0.10.29    67s
    ...
    simple-game-server-fvcsc-xnb2c   Ready   146.56.xx.xxx    7468   10.0.10.105   67s
    simple-game-server-fvcsc-zf2mq   Ready   158.180.xx.xxx   7122   10.0.10.29    5m41s
    
  3. 새로운 Worker Nodes에 생긴 GameServer를 테스트해도 잘 동작합니다.

    $ nc -u 146.56.xx.xxx 7468
    Hello World !
    ACK: Hello World !
    EXIT
    ACK: EXIT
    ^C
    

SuperTuxKart: 오픈 소스 아케이드 레이서 게임 테스트

실 게임 서버의 예로 Agones 예제로 나와 있는 카트 게임인 SuperTuxKart를 배포해서 테스트 해봅니다.

  1. 테스트로 배포할 Fleet YAML 파일입니다.

    apiVersion: "agones.dev/v1"
    kind: Fleet
    metadata:
      name: supertuxkart
    spec:
      replicas: 2
      strategy:
        type: Recreate
      template:
        spec:
          ports:
          - name: default
            containerPort: 8080
          health:
            initialDelaySeconds: 30
            periodSeconds: 60
          template:
            spec:
              containers:
              - name: supertuxkart
                image: us-docker.pkg.dev/agones-images/examples/supertuxkart-example:0.8
    
  2. 해당 YAML을 배포하여 Fleet를 생성합니다.

    kubectl apply -f https://raw.githubusercontent.com/googleforgames/agones/release-1.33.0/examples/supertuxkart/fleet.yaml
    
  3. 생성결과를 확인합니다. Fleet에 의해 2개의 GameServer가 생성되었습니다.

    • GameServer의 Deployment 역할 해주는 것이 Fleet으로 생각하면 됩니다.
    • 이후 사용할 첫번째 GameServer의 주소와 Port를 사용하겠습니다.
    $ kubectl get fleet
    NAME           SCHEDULING   DESIRED   CURRENT   ALLOCATED   READY   AGE
    supertuxkart   Packed       2         2         0           0       10s
    $ kubectl get gameserver
    NAME                       STATE   ADDRESS         PORT   NODE         AGE
    supertuxkart-82ds7-p8zl7   Ready   138.2.xxx.xxx   7150   10.0.10.32   2m22s
    supertuxkart-82ds7-wwdtl   Ready   138.2.xxx.xxx   7510   10.0.10.32   2m22s
    
  4. SuperTuxKart 다운로드 페이지에 가서 게임 클라이언트를 다운로드 받습니다.

  5. 다운받은 클라이언트를 실행하고, Online 메뉴에서 Enter server address를 클릭합니다.

    image-20230809235830372

  6. 접속할 GameServer 주소와 UDP 포트를 사용하여 접속합니다.

    image-20230810000016249

  7. GameServer에 접속되었습니다.

    image-20230810000322263

  8. 접속한 GameServer 컨테이너의 로그를 확인합니다. 새로운 플레이어가 접속되었다는 로그를 확인할 수 있습니다.

    $ kubectl logs -f supertuxkart-82ds7-p8zl7 --all-containers
    ...
    Wed Aug 09 14:50:32 2023 [info   ] STKHost: Host initialized.
    Wed Aug 09 14:50:32 2023 [info   ] STKHost: Server port is 8080
    Wed Aug 09 14:50:32 2023 [info   ] ServerLobby: Resetting the server to its initial state.
    Wed Aug 09 14:50:32 2023 [info   ] ProtocolManager: A 11ServerLobby protocol has been started.
    Wed Aug 09 14:50:32 2023 [info   ] main: Creating a LAN server 'agones stk server'.
    Wed Aug 09 14:50:32 2023 [info   ] STKHost: Listening has been started.
    [wrapper] 2023/08/09 14:50:32 server ready
    Wed Aug 09 14:55:01 2023 [info   ] STKHost: 220.117.xxx.x:62438 has just connected. There are now 1 peers.
    Wed Aug 09 14:55:01 2023 [info   ] ServerLobby: Message of type 1 received.
    Wed Aug 09 14:55:01 2023 [info   ] ServerLobby: New player TheKoguryo with online id 0 from 220.117.xxx.x:62438 with SuperTuxKart/1.4 (Macintosh).
    [wrapper] 2023/08/09 14:55:01 Player TheKoguryo joined
    
  9. 카트를 고르고 게임을 시작합니다. 잘 동작하는 것을 볼 수 있습니다.

    image-20230810000943396

  10. 연속해서 레이스를 진행할 수도 있습니다. 레이스가 끝나면, 왼쪽 상단의 화살표를 클릭하여, 게임서버에서 나갑니다.

  11. 게임서버에서 나가면, GameServer가 종료되고, 새로운 서버가 만들어 진 것을 확인할 수 있습니다.

    $ kubectl get gameserver
    NAME                       STATE   ADDRESS         PORT   NODE         AGE
    supertuxkart-82ds7-qwcr5   Ready   138.2.xxx.xxx   7599   10.0.10.32   9s
    supertuxkart-82ds7-wwdtl   Ready   138.2.xxx.xxx   7510   10.0.10.32   22m
    


이 글은 개인으로서, 개인의 시간을 할애하여 작성된 글입니다. 글의 내용에 오류가 있을 수 있으며, 글 속의 의견은 개인적인 의견입니다.

Last updated on 14 Jul 2023