5.1 게임서비스를 위한 Agones 테스트
게임 서버를 쿠버네티스에서 서비스하기 많이 사용되는 Agones가 OKE에서 잘 동작하는 확인하기 위한 테스트입니다. Agones 공식문서를 참조하여 진행하였습니다.
OKE Cluster 1.26에서 VCN-Native Pod Networking, Flannel 모두 동작함을 확인하였습니다.
Agones 설치를 위한 OKE 클러스터 준비
-
OKE Cluster 지원 버전 확인
- Agones and Kubernetes Supported Versions을 참고하여 지원하는 쿠버네티스 버전을 확인하고 준비합니다.
- 여기서는 최신버전인 Agones 1.33을 OKE Cluster 1.26에 설치하겠습니다.
Agones version Kubernetes version(s) 1.33 1.24, 1.25, 1.26 -
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 anExternalIP
address on the Node (which it should if it’s a publicly addressable Node), that it utilised, otherwise it falls back to using theInternalIP
address. -
Create Cluster - Quick Mode 시
-
-
클라이언트가 GameServer에 접속할 수 있도록, Worker Nodes가 속한 서브넷에 UDP 프로토콜로 7000-8000 포트들을 개방합니다.
- A Kubernetes cluster with the UDP port range 7000-8000 open on each node.
Agones를 OKE 클러스터에 설치하기
-
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
-
설치 상태를 확인합니다.
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 설치
-
테스트로 배포할 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"
-
해당 YAML을 배포하여 테스트용 GameServer를 설치합니다.
kubectl create -f https://raw.githubusercontent.com/googleforgames/agones/release-1.33.0/examples/simple-game-server/gameserver.yaml
-
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 ...
-
생성된 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>
-
GameServer 연결확인을 위해 Pod 로그를 확인합니다.
kubectl logs -f simple-game-server-pkj5d --all-containers
-
GameServer에 nc 명령을 통해 메세지를 전송해 봅니다.
- -u 옵션을 통해 UDP로 게임서버 포트로 연결되는 것을 테스트합니다.
Hello World !
를 전달시 아래와 같이 서버에서 에코 응답이 오는 것을 볼 수 있습니다.
$ nc -u 158.180.xx.xxx 7365 Hello World ! ACK: Hello World ! EXIT ACK: EXIT ^C
-
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.
-
끝에 EXIT를 입력하면, GameServer가 종료되고, Pod도 종료됩니다.
$ kubectl get gameserver No resources found in default namespace.
Fleet
앞서 GameServer 실행시 EXIT가 되면, GameServer가 종료되었습니다. 안정적인 게임 서비스를 위해 Fleet를 사용하면, 특정 Pod에서 게임이 종료되어도, Fleet를 통해 지정한 GameServer를 유지하게 됩니다.
-
테스트로 배포할 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"
-
해당 YAML을 배포하여 Fleet를 생성합니다.
kubectl apply -f https://raw.githubusercontent.com/googleforgames/agones/release-1.33.0/examples/simple-game-server/fleet.yaml
-
생성결과를 확인합니다. 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
-
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
-
-
GameServer를 할당합니다.
kubectl create -f https://raw.githubusercontent.com/googleforgames/agones/release-1.33.0/examples/simple-game-server/gameserverallocation.yaml -o yaml
-
할당후 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
-
Scale In 합니다.
kubectl scale fleet simple-game-server --replicas=0
-
할당된 서버는 삭제되지 않는 것을 볼 수 있습니다.
$ 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
-
할당된 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
-
현재 GameServer를 다시 조회합니다. 할당된 GameServer의 서비스가 종료되었습니다.
$ kubectl get gameserver No resources found in default namespace.
Fleet Autoscaler
-
테스트로 배포할 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
-
해당 YAML을 배포하여 Fleet Autoscaler를 배포합니다.
kubectl apply -f https://raw.githubusercontent.com/googleforgames/agones/release-1.33.0/examples/simple-game-server/fleetautoscaler.yaml
-
현재 상태를 확인합니다. 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
-
GameServer를 할당합니다.
kubectl create -f https://raw.githubusercontent.com/googleforgames/agones/release-1.33.0/examples/simple-game-server/gameserverallocation.yaml -o yaml
-
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
-
할당된 GameServer에 접속하여 사용하고 종료합니다.
$ nc -u 158.180.xx.xxx 7178 Hello World ! ACK: Hello World ! EXIT ACK: EXIT ^C
-
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개를 만들어 봤습니다.
-
배포된 Fleet Autoscaler을 수정하여, bufferSize: 50, maxReplicas:100 으로 변경합니다.
-
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
-
새로운 Worker Nodes에 생긴 GameServer를 테스트해도 잘 동작합니다.
$ nc -u 146.56.xx.xxx 7468 Hello World ! ACK: Hello World ! EXIT ACK: EXIT ^C
SuperTuxKart: 오픈 소스 아케이드 레이서 게임 테스트
실 게임 서버의 예로 Agones 예제로 나와 있는 카트 게임인 SuperTuxKart를 배포해서 테스트 해봅니다.
-
테스트로 배포할 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
-
해당 YAML을 배포하여 Fleet를 생성합니다.
kubectl apply -f https://raw.githubusercontent.com/googleforgames/agones/release-1.33.0/examples/supertuxkart/fleet.yaml
-
생성결과를 확인합니다. 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
-
SuperTuxKart 다운로드 페이지에 가서 게임 클라이언트를 다운로드 받습니다.
-
다운받은 클라이언트를 실행하고, Online 메뉴에서 Enter server address를 클릭합니다.
-
접속할 GameServer 주소와 UDP 포트를 사용하여 접속합니다.
-
GameServer에 접속되었습니다.
-
접속한 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
-
카트를 고르고 게임을 시작합니다. 잘 동작하는 것을 볼 수 있습니다.
-
연속해서 레이스를 진행할 수도 있습니다. 레이스가 끝나면, 왼쪽 상단의 화살표를 클릭하여, 게임서버에서 나갑니다.
-
게임서버에서 나가면, 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
이 글은 개인으로서, 개인의 시간을 할애하여 작성된 글입니다. 글의 내용에 오류가 있을 수 있으며, 글 속의 의견은 개인적인 의견입니다.