AWS 기술 블로그

Amazon GameLift Anywhere를 활용하여 다양한 AWS 서비스 연동하기 – Part1 : 컴퓨팅

Amazon GameLift Anywhere의 정식 출시를 통해 세션 기반의 멀티플레이어 게임 서버 워크로드에 기존의 관리형 Fleet 뿐만아니라 다양한 컴퓨팅 옵션을 사용할 수 있게 되었습니다. 기존 Amazon GameLift는 게임 서버를 위한 관리형 Fleet을 AWS 글로벌 리전 및 Local Zone에서 제공했습니다. Amazon GameLift Anywhere는 기존 Fleet 유형에 Anywhere Fleet이 추가되어 온프레미스 혹은 사용자 AWS 계정의 Amazon EC2 서버를 Anywhere Fleet으로 등록하여 직접 인프라를 관리할 수 있는 시나리오를 제공합니다. 또한 게임 서버의 개발 및 테스트 과정에서 개발자의 로컬 머신을 Anywhere Fleet에 등록하여 GameLift 연동을 테스트하는 용도로도 활용할 수 있습니다.

관리형 Fleet의 경우, EC2 인스턴스들은 AWS가 관리하는 VPC 내에 생성되기 때문에 다른 AWS 서비스들을 연동하는데 제약이 있었습니다. Amazon GameLift Anywhere를 이용하는 경우, 사용자 계정에 있는 EC2 인스턴스들을 사용하기 때문에 다양한 AWS 서비스와의 연동이 가능해집니다. 예를 들어 글로벌 게임의 네트워크 성능 및 안정성을 높이기 위해 Amazon Global Accelerator와 연동하거나 사용자 VPC에 있는 게임 백엔드 서비스와의 연동을 위한 VPC Peering 혹은 AWS Transit Gateway 연동이 가능해집니다.

이번 기고문은 Amazon GameLift Anywhere를 활용하여 다양한 시나리오를 구현하는 연재 기고문 중 첫번째 주제로 EC2 Auto Scaling 및 개발자 머신 등의 컴퓨팅 리소스를 Amazon GameLift Anywhere 와 연동하는 시나리오를 소개합니다. 먼저 사용자 계정의 EC2 Auto Scaling Group 기반의 GameLift Anywhere Fleet 구성으로 운영 환경을 구성해보고, AWS Cloud9를 개발자 머신으로 가정하고 Amazon GameLift Anywhere와 연동하여 테스트 및 디버깅하는 시나리오를 구성 해보겠습니다.

솔루션 개요

본 예제에서는 Amazon GameLift Anywhere Fleet을 구성하고 단일 Auto Scaling Group 내의 EC2 인스턴스들을 게임 서버로 등록합니다. Auto Scaling Group은 사용자 계정내에 생성되기 때문에 Auto Scaling Group 에서 제공하는 Custom AMI 및 Auto-scaling 웜풀(warm pool)등의 기능을 이용할 수 있습니다. Amazon GameLift는 Anywhere Fleet에 등록된 EC2 인스턴스들에 대한 게임 세선 관리를 수행합니다. 하지만 기존 관리형 Fleet에서 제공하였던 게임 서버의 Auto Scaling 및 게임이 진행 중인 세션 종료 보호를 위한 스케일 인 보호(Scale-in protection) 기능 등과 같이 게임 서버 운영에 있어서 필요한 기능들은 사용자가 추가로 설정해야 합니다. 본 예제에서는 세션형 게임 서버에 적합한 EC2 Auto Scaling 정책 및 스케일 인 보호 정책을 설정하는 과정을 보여줍니다.

추가로 게임서버와 Amazon GameLift 연동 기능 개발 및 테스트 단계에서의 디버깅 시나리오도 기술합니다. 참고로 GameLift Anywhere를 구성하기 위해서는 Amazon GameLift SDK 버전 5.0 이상을 사용하여 게임 서버와 연동해야 합니다. 이전 버전의 SDK에서는 Amazon GameLift Local이 번들로 제공되어 이를 기반으로 게임 통합 테스트를 할 수 있었습니다. 하지만 Amazon GameLift SDK 5.0 부터는 GameLift Local을 더이상 지원하지 않고 대신 Amazon GameLift Anywhere 기능을 통해 통합 테스트 및 디버깅을 할 수 있습니다.

단계 요약

본 예제에서는 먼저 AWS Cloud9을 개발자 머신으로 가정하고, go 언어 기반의 오목 게임 서버를 빌드 합니다 (오목 게임은 기존 Visual C++기반의 Gomoku sample 게임서버를 go 언어로 porting하였습니다. 원본 게임은 링크를 참조하세요). AWS Cloud Development Kit(CDK)를 통해 Amazon GameLift Anywhere 와 Amazon EC2 Auto Scaling 설정을 배포하고, AWS Cloud9을 통해서 Amazon GameLift 연동 테스트 및 디버깅을 수행 해보도록 하겠습니다.

  • 단계 1 : 게임 서버 개발 환경 배포 및 게임서버 빌드 하기
  • 단계 2 : AWS CDK로 Amazon GameLift 및 EC2 Auto Scaling 배포하기
  • 단계 3 : 게임 서버로 연결하기
  • 단계 4 : Auto Scaling
  • 단계 5 : 디버깅 하기

사전 준비 사항

배포하기 위해서는 아래와 같은 사항을 미리 준비 해야 합니다.

단계 1: 게임 서버 개발 환경 배포 및 게임서버 빌드 하기

본 예제에서는 AWS Cloud9을 개발자 환경으로 사용합니다. AWS Cloud9 환경을 생성하여 게임 서버를 빌드를 수행합니다.

  1. gamelift-dev의 이름을 갖는 AWS Cloud9 환경을 생성합니다.
    • AWS Cloud9 환경 생성 페이지로 이동합니다.
    • 아래와 같이 필요한 항목을 입력 및 선택합니다.
      1. 환경 이름 : gamelift-dev
      2. 환경 타입 : New EC2 Instance
      3. 인스턴스 타입 : m5.large
      4. 연결 유형 : AWS Systems Manager (SSM)
    • 입력 값을 확인하고, 환경을 생성합니다.
      AWS CLI를 사용하는 경우, 아래의 커맨드를 사용하면 됩니다.

      aws cloud9 create-environment-ec2 --name gamelift-dev --instance-type m5.large --connection-type CONNECT_SSM

      본 예제는 AWS Cloud9의 관리형 임시 자격 증명을 사용하여, Amazon GameLift를 포함한 AWS 리소스를 생성 및 관리합니다. 따라서 AWS Cloud9을 생성하는 IAM 사용자 혹은 역할은 솔루션 개요에 도식화된 AWS 리소스들에 대한 생성 및 읽기 권한이 필요합니다.

  2. AWS Cloud9 콘솔로 이동하여 생성된 gamelift-dev 환경의 Cloud9 IDE 로 이동합니다.

  3. AWS Cloud9에는 AWS CLI v1이 설치되어 있습니다. 본 실습을 위해서 AWS CLI v2를 설치합니다.
    curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
    unzip awscliv2.zip
    sudo ./aws/install --update

    버전 정보가 아래와 같이 2.0 이상으로 나오면 다음 단계로 진행합니다.

    aws --version
    aws-cli/2.13.30 Python/3.11.6 Linux/5.10.197-186.748.amzn2.x86_64 exe/x86_64.amzn.2 prompt/off
    
  4. 본 예제를 실행하기 위해서는 ‘jq’ json parsor를 설치합니다.
    sudo yum install jq
  5. 샘플 게임 서버 바이너리가 포함된 소스 코드를 다운로드 받습니다. 샘플 게임 서버는 Go 언어 기반의 오목 서버로 Amazon Game Server SDK 연동까지 구현이 되어있습니다.
    git clone https://github.com/aws-samples/amazon-gamelift-anywhere-sample
  6. 게임서버 빌드에 필요한 Amazon GameLift SDK 번들을 다운로드 후 Go 언어 SDK를 소스코드가 위치한 디렉토리에 복사합니다.
    cd amazon-gamelift-anywhere-sample/
    wget https://gamelift-server-sdk-release.s3.us-west-2.amazonaws.com/go/GameLift-Go-ServerSDK-5.0.0.zip
    unzip GameLift-Go-ServerSDK-5.0.0.zip
    cd gomoku-game-server/
    cp -R ../GameLift-Go-ServerSDK-5.0.0 ./
  7. 필요한 Go 모듈을 다운로드 후 게임 서버 빌드를 수행하고, 게임 바이너리를 gomoku-in-go/gl-anywhere/gamebinaries로 복사합니다. 이렇게 복사된 게임 바이너리는 [단계 2] 에서 제공되는 AWS CDK 코드에 의해 Amazon S3 버킷으로 업로드 되며, Auto Scaling Group 에서 신규 EC2 인스턴스가 생성될 때, Launch Template 의 User Data에 정의된 스크립트에 의해서 게임 바이너리가 게임 서버로 다운로드 및 실행됩니다.
    go mod tidy
    go build -o gomoku-in-go .
    cp gomoku-in-go ../gamelift-anywhere-with-autoscaling-group/cdk/gamebinaries/

단계 2: AWS CDK 로 Amazon GameLift 및 EC2 Auto Scaling 배포하기

본 예제에서는 Amazon GameLift Anywhere Fleet 및 Auto Scaling Group 을 포함한 AWS 리소스를 AWS CDK 로 배포합니다. AWS CDK 는 개발자가 익숙한 프로그래밍 언어를 사용하여 클라우드 리소스를 정의하고 배포할 수 있는 오픈소스 Infrastructure as a Code (IaC) 도구 입니다. 본 예제에서는 Go 언어로 작성된 CDK 를 배포해 봅니다. CDK를 통해 아키텍처 다이어그램에 기재된 AWS 리소스가 생성됩니다. AWS Cloud9 에는 AWS CDK 가 기본으로 설치되어 제공됩니다.

  1. 본 예제의 CDK 코드가 작성된 ../gamelift-anywhere-with-autoscaling-group/cdk로 이동합니다.
    cd ../gamelift-anywhere-with-autoscaling-group/cdk
  2. 리소스를 배포하기 전에 사용자 환경에 맞는 변수 설정 작업을 진행합니다. AWS CDK는 cdk.json 파일에 정의된 context 변수 값을 읽어올 수 있습니다. 본 예제에서는 사용자가 GameLift를 사용하는 리전 및 EC2 접근에 필요한 SSH 키를 커스텀하게 정의할 수 있습니다. cdk.json 파일을 Cloud9 에디터에서 열고 context 블럭의 "GameLiftEndpoint”, “keyPairName” 을 필요시 수정합니다.
    "context": {
      ..
      "ConcurrentExecutions": 5,
      "GameServerFromPort": 4000,
      "GameLiftEndpoint": "wss://ap-northeast-2.api.amazongamelift.com",
      "deploymentRegion": "ap-northeast-2",
      "keyPairName": "yoursshkey"
    }
    • GameLiftEndpoiont : 게임서버가 GameLift API 통신을 위한 API 엔드 포인트 정보. 사용하는 GameLift 리전에 맞는 엔드포인트로 변경하세요.
    • keyPairName : EC2 SSH 접근을 위한 키 페어 정보. CDK의 성공적인 배포를 위해서는 키 페어 정보가 반드시 필요합니다. “yoursshkey" 문자열 대신 계정에서 사용 중인 키 페어 이름을 입력하세요. 만약 키 페어가 없는 경우, 신규 키페어를 생성하고 해당 키 페어 이름을 입력하세요. 수정이 완료되었으면 cdk.json 파일을 저장합니다. 해당 cdk.json에서 값이 지정된 ConcurrentExecutions, GameServerFromPort, GameLiftEndpoint 정보는 CDK에서 AutoScaling Group 리소스 생성시 해당 리소스의 태그(tag)에 추가됩니다. 아래 cdk deploy 과정에서 Auto Scaling Group 내에 생성되는 EC2 인스턴스들은 부팅 과정에서 자동으로 수행되는 스크립트인 user_data.txt에 명시된 bash 스크립트를 수행합니다. 이 스크립트는 인스턴스 메타데이타 서비스로 부터 해당 태그값들을 읽어와서 concurrentExecutions 값에 지정된 개수대로 게임 서버 프로세스들을 생성하고 해당 프로세스들의 실행 상태를 관리합니다.
  3. AWS CDK 는 작성된 코드를 기반으로 CloudFormation 템플릿을 자동으로 생성하고, 이를 통해 AWS 자원을 배포합니다.
    cdk synth 명령은 CDK 앱을 실행하며, 앱에 정의된 리소스가 AWS CloudFormation 템플릿으로 변환됩니다. cdk synth 출력은 YAML 형식 템플릿이며, cdk.out 디렉터리에도 JSON 형식으로 저장됩니다.

    cdk synth
  4. AWS CDK를 사용하여 스택을 배포할려면 cdk deploy 명령어를 사용합니다.
    cdk deploy

    변경 사항을 배포할지에 대해서 동의 ( ‘y’ 입력) 하고 배포를 진행합니다. 배포 진행 사항은 터미널을 통해서 확인할 수 있으며, CloudFormation 콘솔에서도 GlAnywhereStack 이라는 이름으로 확인이 가능합니다.

  5. 배포가 성공적으로 완료되었다면, 아래 명령어로 Auto Scaling Group을 구성하는 EC2 인스턴스가 GameLift fleet의 컴퓨팅 자원으로 정상적으로 등록되었는지 확인합니다.
    FLEET_NAME=anywhere-demo-fleet
    FLEET_ID=`aws gamelift describe-fleet-attributes --query "FleetAttributes[?Name=='$FLEET_NAME'].FleetId" --output text`
    aws gamelift list-compute --fleet-id $FLEET_ID
    
    
    {
        "ComputeList": [
            {
                "FleetId": "fleet-xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx",
                "FleetArn": "arn:aws:gamelift:ap-northeast-2:xxxxxxxxxxxx:fleet/fleet-xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx",
                "ComputeName": "i-xxxxxxxxxxxxxxxxx",
                "ComputeArn": "arn:aws:gamelift:ap-northeast-2:xxxxxxxxxxxx:compute/i-xxxxxxxxxxxxxxxxx",
                "IpAddress": "xx.xx.xx.xx",
                "ComputeStatus": "Active",
                "Location": "custom-anywhere-location",
                "CreationTime": "2023-10-31T08:57:20.861000+00:00",
                "GameLiftServiceSdkEndpoint": "wss://ap-northeast-2.api.amazongamelift.com"
            }
        ]
    }

단계 3: 게임 서버로 연결하기

Amazon GameLift Anywhere Fleet 및 게임 프로세스가 실행되는 EC2가 정상적으로 구성되었으니, 이제 AWS Cloud9을 클라이언트로 하여 게임 서버에 연결을 해보도록 하겠습니다. 본 기고문에서는 Python 기반의 headless 클라이언트를 이용하여 간단한 연결성 테스트만 수행합니다. gomoku 윈도우즈 클라이언트를 이용하여 GUI 환경에서도 테스트가 가능하며 이부분은 github samples에 등록된 클라이언트를 사용하면 됩니다.

  1. Amazon Python SDK 를 설치합니다. AWS Cloud9에는 Python이 자동으로 설치되어 제공되지만, Amazon Python SDK는 설치되어 있지 않습니다. 샘플 클라이언트에서는 Amazon Python SDK (boto3)를 활용하여 매치 메이킹을 요청하기 때문에 테스트 전에 이를 설치합니다.
    sudo pip3 install boto3
  2. '~/environment/amazon-gamelift-anywhere-sample-main/gomoku-client/python’ 폴더의 demo-matchmaking-test Python 스크립트를 사용하여 온라인 1:1 매칭을 시뮬레이션 해봅니다.
    cd ~/environment/amazon-gamelift-anywhere-sample/gomoku-client/python/
    python3 demo-matchmaking-test.py

    정상적으로 연결 되었다면 아래와 같은 메시지를 확인할 수 있습니다.

    [player 0 ] start_matchmaking sent to Client Backend Service.
    [player 1 ] start_matchmaking sent to Client Backend Service.
    [player 0 ][score: 1000 ] matchmaking status: PLACING
    [player 1 ][score: 1000 ] matchmaking status: PLACING
    [player 0 ][score: 1000 ] match created: 1.2.3.4 4004
    [player 1 ][score: 1000 ] match created: 1.2.3.4 4004
    [player 1 ] connected to game server
    [player 1 ] StartRequest sent to game server
    [player 0 ] connected to game server
    [player 0 ] StartRequest sent to game server
    [player 1 ] GameStartBroadcast received
    [player 0 ] GameStartBroadcast received
    Please enter any key to terminate game sessions:
    [player 0 ] ClientPing sent to server skipped...
    [player 1 ] ClientPing sent to server skipped...
  3. 게임 세션은 해당 터미널에서 임의의 키를 입력하면 자동으로 종료하는 로직을 가지고 있습니다. 따라서, 현재 상황을 유지한 상태에서 Amazon GameLift 콘솔 에서 세션 정보를 확인해 봅니다. 콘솔 화면에서 생성된 anywhere-demo-fleet을 선택합니다.
    Fleet 상세 페이지에서 Game sessions 탭을 선택하면, 하단에 현재 활성화된 게임 세션 정보를 확인할 수 있습니다.

    해당 세션을 클릭하여 세션 상세 정보를 확인할 수 있습니다.

    AWS CLI를 사용하는 경우, 아래의 커맨드를 사용하면 됩니다.

    aws gamelift describe-game-sessions --fleet-id $FLEET_ID
  4. 세션 정보를 확인하였으면, 다시 테스트 클라이언트가 실행 중인 터미널에서 임의의 키를 입력하여 아래의 로그와 함께 세션이 정상적으로 종료되는 것을 확인합니다.
    [player 0 ] ExitRequest sent to game server
    [player 0 ] thread done
    [player 1 ] ExitRequest sent to game server
    [player 1 ] thread done
    Exiting...

단계 4: Auto Scaling

다음으로 EC2 Auto Scaling을 활용하여 Auto Scaling Group 기반의 게임 서버 Fleet에 적합한 Auto Scaling 설정에 대해서 살펴 보겠습니다. EC2 Auto Scaling은 Target tracking 정책을 통해서 정의된 대상 메트릭을 기반으로 동적으로 Auto Scaling Group을 구성하는 인스턴스 수를 늘리거나 줄입니다. Target tracking 정책에는 어떤 메트릭 값을 모니터링할지 정의해야하며, 기본으로 제공되는 메트릭 값을 선택하거나 다른 CloudWatch 메트릭을 선택할 수 있는 커스텀 옵션이 있습니다.

본 예시에서는 Amazon GameLift에서 제공되는 CloudWatch 메트릭 중 PercentAvailableGameSessions 지표를 응용하여 세션형 게임 서버 Fleet Auto Scaling에 적합한 Target tracking 정책을 정의합니다. PercentAvailableGameSessions 메트릭은 전체 활성화된 서버 프로세스 중 현재 가용한 (게임이 플레이 되고 있지 않는) 게임 세션 슬롯의 비율은 나타냅니다. 이를 활용하면 전체 게임 서버 Fleet의 가용률 (현재 세션이 진행되고 있는 비율)을 기준으로 Fleet이 확장하거나 축소하게 됩니다. Target tracking 정책은 대상 지표가 특정 임계치를 초과하면 알람이 발생하고 이를 통해 자동 확장이 발생하는 구조 입니다. PercentAvailableGameSessions 지표가 줄어들 때 (게임 서버 Fleet의 가용 세션 비중이 줄어들 때) 자동 확장이 필요하기 때문에 Metric math를 사용하여 전체 게임 서버 Fleet의 가용률 (100 – PercentAvailableGameSessions)을 구할 수 있습니다. Metric math를 통해 전체 서버 세션 가용률 메트릭을 정의하고 해당 메트릭에 대해 Target tracking 정책에서 목표 수치를 정의하게 되면 Auto Scaling Group은 GameLift Anywhere Fleet 내에서 일정 수준의 가용(Idle) 세션 용량을 유지하기 위해 자동으로 인스턴스 개수를 늘리거나 줄입니다.

본 예제에서는 Target tracking 설정을 쉽게 할 수 있는 AWS CLI 기반의 스크립트를 함께 제공하고 있습니다.

  1. 샘플 폴더의 create_targettrackingscalingpolicy.sh 파일을 실행합니다. 해당 스크립트는 생성된 GameLift Anywhere Fleet 정보를 바탕으로 TargetTracking config.json 파일을 업데이트 하고, TargetTracking 정책을 정의합니다.
    cd ~/environment/amazon-gamelift-anywhere-sample/gamelift-anywhere-with-autoscaling-group/cdk/
    chmod a+x create_targettrackingscalingpolicy.sh
    ./create_targettrackingscalingpolicy.sh
  2. 스크립트가 정상적으로 수행되면, 아래와 같이 Target tracking 수행을 위한 CloudWatch Alarm이 생성 됩니다.
    "PolicyARN": "arn:aws:autoscaling:ap-northeast-2:xxxxxxxxxxxx:scalingPolicy:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:autoScalingGroupName/GlAnywereStack-asg:policyName/GlAnywereStack-GameLiftAnywhereDemoTargetTrackingScalingPolicy",
    "Alarms": [
    {
    "AlarmName": "TargetTracking-GlAnywereStack-asg-AlarmHigh-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "AlarmARN": "arn:aws:cloudwatch:ap-northeast-2:xxxxxxxxxxxx:alarm:TargetTracking-GlAnywereStack-asg-AlarmHigh-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    },
    {
    "AlarmName": "TargetTracking-GlAnywereStack-asg-AlarmLow-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "AlarmARN": "arn:aws:cloudwatch:ap-northeast-2:xxxxxxxxxxxx:alarm:TargetTracking-GlAnywereStack-asg-AlarmLow-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    }
    ]
    }
  3. Auto Scaling 테스트를 위한 스크립트를 수행합니다. 해당 스크립트는 8명의 플레이어에 대한 게임 세션을 생성합니다. 본 예제에서 단일 EC2 인스턴스 당 5개의 프로세스가 실행되며, 최초 1대의 EC2 인스턴스가 GameLift Anywhere Fleet을 구성하게 되어있습니다. 오목은 1:1 대전이기 때문에 5개의 가용 세션 중 4개의 세션에서 게임이 진행되므로, 오목 서버 Fleet의 가용률이 80% 가 되게 됩니다.
    python3 gomoku-client/demo4-autoscaling.py
  4. 위 단계에서 실행 시킨 스크립트를 유지한 상태에서 Auto Scaling이 발생하는지 확인 해봅니다. 아래의 AWS CLI 커맨드 혹은 EC2 Auto Scaling Group 콘솔의 “Activity” 탭에서 Target tracking으로 인한 스케일 아웃이 발생함을 확인할수 있습니다.
    aws autoscaling describe-scaling-activities --auto-scaling-group-name GlAnywereStack-asg

    또한 CloudWatch 콘솔의 Alarm 페이지에서 아래와 같이 오목 게임 서버의 가용률 및 설정한 임계치를 동시에 확인할 수 있습니다.

  5. [단계 3]에서 테스트 스크립트를 실행한 터미널에서 아무키나 입력하여 스크립트를 종료하여 기존 플레이어 세션들이 종료됩니다. 그렇게 되면 다시 임계치가 떨어져서 Fleet의 크기가 1대로 자동 축소됩니다. 자동 축소의의 경우에는 보수적으로 줄어들게 세팅되어 있기 때문에 약 15분의 시간이 필요합니다.

자동 축소(Scale-in)가 발생하는 경우, 플레이어 세션이 있는 인스턴스가 삭제되는 것을 막기 위해 scale-in protection 기능을 활용할 수 있습니다. 본 예제에서도 오목 프로세스를 모니터링하는 프로세스가 활성 세션이 있는 경우, 해당 보호 기능을 활성화하고 활성 세션이 없는 경우에는 해제하고 있습니다. 이렇게 하면 세션이 없는 유휴 오목 인스턴스들부터 삭제할 수 있습니다.

단계 5: 디버깅 하기

본 단계에서는 Anywhere Fleet을 이용하여 개발자머신에서 GameLift를 통한 게임 클라이언트와 개발머신에서 구동되는 게임 서버간의 연동 테스트를 수행합니다.

  1. 개발 머신을 위한 신규 Fleet을 생성하고 해당 Fleet에 개발 머신을 등록합니다. (본 예제에서는 AWS Cloud9 환경을 Anywhere Fleet으로 등록합니다.) AWS CLI 를 사용하여 아래 명령줄을 차례대로 입력하여 Anywhere Fleet 등록에 필요한 리소스를 생성하고 개발자 머신을 등록합니다.
    # EC2 metadata API를 이용하여 compute name, IP address 정보를 읽습니다.
    TOKEN=`curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
    COMPUTE_NAME=`curl -s http://169.254.169.254/latest/meta-data/instance-id -H "X-aws-ec2-metadata-token: $TOKEN"`
    MAC=`curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs -H "X-aws-ec2-metadata-token: $TOKEN"`
    IPADDRESS=`curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/$MAC/public-ipv4s -H "X-aws-ec2-metadata-token: $TOKEN"`
    
    # 생성할 location name과 Fleet name을 설정합니다.
    LOCATION_NAME=custom-devmachine-location
    FLEET_NAME=anywhere-devmachine-fleet
    
    # custom location 리소스를 생성합니다.
    aws gamelift create-location --location-name $LOCATION_NAME
    
    # anywhere 타입의 fleet 리소스를 생성합니다.
    FLEET_ID=`aws gamelift create-fleet --name $FLEET_NAME --compute-type ANYWHERE --locations "Location=$LOCATION_NAME" --query "FleetAttributes.FleetId" --output text`
    
    # fleet에 대한 alias 리소스를 생성합니다.
    ALIAS_ARN=`aws gamelift create-alias --name AnywhereDevFleetAlias --description "Anywhere Dev Fleet Alias" --routing-strategy "Type=SIMPLE,FleetId=$FLEET_ID" --query "Alias.AliasArn" --output text`
    
    # 세션 queue의 destination에 해당 alias를 추가합니다. (본 예제에서는 단계1에서 CDK배포를 통해 생성된 AnywhereDemoQueue를 사용합니다.)
    DESTINATIONS=`aws gamelift describe-game-session-queues --query "GameSessionQueues[?Name=='AnywhereDemoQueue'].Destinations" --output text`
    aws gamelift update-game-session-queue --name AnywhereDemoQueue --destinations "DestinationArn=$ALIAS_ARN" "DestinationArn=$DESTINATIONS"
    
    # 해당 fleet에 개발자 머신을 등록합니다. (본 예제에서는 compute name으로 EC2 instance ID를 사용하였습니다.)
    aws gamelift register-compute --compute-name $COMPUTE_NAME --fleet-id $FLEET_ID  --ip-address $IPADDRESS --location $LOCATION_NAME
    
  2. 개발자 머신으로의 세션 접속을 위한 Security Group 정책을 추가합니다.
    윗 단계 aws gamelift register-compute 명령을 사용할 때 --ip-address 값으로 게임 클라이언트와의 통신에 사용할 IP 주소를 지정하였습니다. 매치 메이킹을 통해 세션이 할당되면 게임 클라이언트는 Amazon GameLift로 부터 등록된 IP 주소를 받아와 게임 서버에 접속하게 됩니다. 본 예제에서는 개발자 머신 (AWS Cloud9가 구동되는 Amazon EC2)에 할당된 Public IP 주소를 사용하며, 4000 번 포트로 TCP 프로토콜을 사용하여 연결합니다. 이를 위해 해당 Amazon EC2 인스턴스에 연결된 Security Group에 TCP 4000번에 대한 연결을 허용하는 인바운드 규칙을 추가합니다. (만약 같은 EC2 머신 상에서 아래 4번의 테스트 클라이언트 스크립트를 실행한다면 EC2의 private IP주소를 할당해도 무방합니다. 이 경우 별도의 Security Group rule을 추가하지 않아도 됩니다.)

    SG_ID=`aws ec2 describe-instance-attribute --instance-id $COMPUTE_NAME --attribute groupSet --query "Groups[0].GroupId" --output text`
    aws ec2 authorize-security-group-ingress --group-id $SG_ID --protocol tcp --port 4000 --cidr 0.0.0.0/0
  3. 이제 게임 서버 프로세스를 실행합니다.
    cd ~/environment/amazon-gamelift-anywhere-sample-main/gomoku-game-server/
    GAMESERVER_PATH=./gomoku-in-go
    gamelift_endpoint=wss://ap-northeast-2.api.amazongamelift.com
    $GAMESERVER_PATH --port 4000 --endpoint $gamelift_endpoint --fleet-id $FLEET_ID  --host-id $COMPUTE_NAME
    

    아래 예제와 같이 게임 서버 프로세스가 수행되고 GameLift의 웹소켓 endpoint에 연결되고 GameLift의 Health Check 요청을 처리하는 로그를 볼 수 있습니다.

    $GAMESERVER_PATH --port 4000 --endpoint $gamelift_endpoint --fleet-id $FLEET_ID  --host-id $COMPUTE_NAME2023/11/01 05:19:57 [DEBUG]:Connection string: wss://ap-northeast-2.api.amazongamelift.com?pID=28505&sdkVersion=5.0.0&sdkLanguage=Go&Authorization=fe79587b-3d1b-43c8-89f5-b218fad7dc22&ComputeId=i-0268a481b268b27f7&FleetId=fleet-ff9efa5e-cccb-4a5b-a3df-8bcd3007732b
    2023/11/01 05:19:57 [DEBUG]:Try connect to the network: tcp by addr: ap-northeast-2.api.amazongamelift.com:443
    2023/11/01 05:19:57 [DEBUG]:Connection to the ap-northeast-2.api.amazongamelift.com:443 fine
    2023/11/01 05:19:57 [DEBUG]:TLS handshake starts
    2023/11/01 05:19:57 [DEBUG]:TLS handshake OK
    2023/11/01 05:19:57 [DEBUG]:Request header Host:ap-northeast-2.api.amazongamelift.com
    2023/11/01 05:19:57 [DEBUG]:Request header User-Agent:gamelift-go-sdk/1.0
    2023/11/01 05:19:57 [DEBUG]:Request header Connection:Upgrade
    2023/11/01 05:19:57 [DEBUG]:Request header Sec-WebSocket-Key:5Ag9ur4vbezTjd/pwpc1hg==
    2023/11/01 05:19:57 [DEBUG]:Request header Sec-WebSocket-Version:13
    2023/11/01 05:19:57 [DEBUG]:Request header Upgrade:websocket
    2023/11/01 05:19:57 [DEBUG]:Starts receive response
    2023/11/01 05:19:57 [DEBUG]:Connected to GameLift API Gateway.
    2023/11/01 05:19:57 [DEBUG]:HealthCheck thread started.
    2023/11/01 05:19:57 [DEBUG]:Reporting health using the OnHealthCheck callback.
    2023/11/01 05:19:57 [DEBUG]:Received health response from the server process: true
    2023/11/01 05:19:57 [DEBUG]:Received HeartbeatServerProcess for GameLift with status 200. Data is {"Action":"HeartbeatServerProcess","RequestId":"8ac1025b-efa6-46b5-a2a4-e2e7ddc1b9fd","StatusCode":200}
    2023/11/01 05:19:57 [DEBUG]:Received ActivateServerProcess for GameLift with status 200. Data is {"Action":"ActivateServerProcess","RequestId":"dcfbfb55-21cc-4978-91b5-c39fedf2715d","StatusCode":200}
    2023/11/01 05:19:57 [DEBUG]:Response received for message with ID: dcfbfb55-21cc-4978-91b5-c39fedf2715d
  4. AWS Cloud9에서 새로운 터미널 창을 열고 Python으로 작성된 게임 테스트 클라이언트 스크립트(testclient/demo-matchmaking-test.py)를 실행합니다. 이 테스트 스크립트는 2개의 게임 클라이언트들이 각각 TCP 소켓을 초기화 하고 Python AWS SDK를 이용하여 Amazon GameLift에 매치 메이킹을 요청하고 수행된 결과를 쿼리하여 할당 받은 게임 서버 주소로 연결을 하도록 작성되었습니다.
    cd ~/environment/amazon-gamelift-anywhere-sample/gomoku-client/python/
    python3 demo-matchmaking-test.py

    테스트 스크립트가 실행되면 위와 같이 각각의 테스트 플레이어가 매치매이킹을 요청하고 서로간의 매치가 이루어지고 할당된 게임 서버의 주소를 받아와 해당 게임서버로 연결하는 로그를 볼 수 있습니다.

    $ python3 demo-matchmaking-test.py
    [player 0 ] start_matchmaking sent to Client Backend Service.
    [player 1 ] start_matchmaking sent to Client Backend Service.
    [player 0 ][score: 1000 ] matchmaking status:  PLACING
    [player 1 ][score: 1000 ] matchmaking status:  PLACING
    [player 0 ][score: 1000 ] match created:  1.2.3.4 4000
    [player 1 ][score: 1000 ] match created:  1.2.3.4 4000
    [player 0 ] connected to game server
    [player 0 ] StartRequest sent to game server
    [player 1 ] connected to game server
    [player 1 ] StartRequest sent to game server
    [player 1 ] GameStartBroadcast received
    [player 0 ] GameStartBroadcast received
    Please enter any key to terminate game sessions:
    

    이 때 이전 터미널에서 실행되고 있는 게임 서버 프로세스의 콘솔 출력에서 두명의 플레이어가 접속하여 새로운 게임 세션이 생성되는 로그를 볼 수 있습니다.

    2023/11/01 05:23:55 [DEBUG]:Received CreateGameSession for GameLift with status 0. Data is {"Action":"CreateGameSession","GameSessionId":"arn:aws:gamelift:ap-northeast-2::gamesession/fleet-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/custom-devmachine-location/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","GameSessionName":"AnywhereDemoMatchmakingConfig","MaximumPlayerSessionCount":2,"GameProperties":{},"GameSessionData":null,"MatchmakerData":"{\"matchId\":\"2831201d-0035-476f-b96a-db8d7d7a51ba\",\"matchmakingConfigurationArn\":\"arn:aws:gamelift:ap-northeast-2:xxxxxxxxxxxx:matchmakingconfiguration/AnywhereDemoMatchmakingConfig\",\"teams\":[{\"name\":\"blue\",\"players\":[{\"playerId\":\"87e20071-6c51-4e24-8861-675e9b421896\",\"attributes\":{\"score\":{\"attributeType\":\"DOUBLE\",\"valueAttribute\":1000.0}}}]},{\"name\":\"red\",\"players\":[{\"playerId\":\"cb1439c4-f2ea-4084-bedd-1fd83f057e88\",\"attributes\":{\"score\":{\"attributeType\":\"DOUBLE\",\"valueAttribute\":1000.0}}}]}],\"autoBackfillMode\":null,\"autoBackfillTicketId\":null}","IpAddress":"3.34.28.193","DnsName":null,"Port":4000,"Status":"ACTIVATING","StatusReason":null,"Location":"custom-devmachine-location"}
    2023/11/01 05:23:55 [DEBUG]:server got the startGameSession signal. GameSession : arn:aws:gamelift:ap-northeast-2::gamesession/fleet-ff9efa5e-cccb-4a5b-a3df-8bcd3007732b/custom-devmachine-location/2831201d-0035-476f-b96a-db8d7d7a51ba 
    2023/11/01 05:23:55 [DEBUG]:Received ActivateGameSession for GameLift with status 200. Data is {"Action":"ActivateGameSession","RequestId":"cc60b11c-29c2-4b17-ac38-7c02c6c87e05","StatusCode":200}
    2023/11/01 05:23:55 [DEBUG]:Response received for message with ID: cc60b11c-29c2-4b17-ac38-7c02c6c87e05

    메치메이킹 Python 스크립트를 수행한 AWS Cloud9 터미널에서 아무키나 입력하여 세션을 종료합니다.

    [player 1 ] ExitRequest sent to game server
    [player 0 ] ExitRequest sent to game server
    [player 0 ] thread done
    [player 1 ] thread done
    Exiting...

    이와 같이 개발 서버를 Anywhere Fleet에 등록하여 Amazon GameLift와의 연동을 점검하고 디버깅을 수행할 수 있습니다. 개발 및 테스트가 완료되면 본 예제에서의 사례와 같이 Auto Scaling Group 기반의 게임 서버를 GameLift Anyhwere Fleet 으로 운영하거나, 동일한 호환성을 제공하는 Amazon GameLift 관리형 Fleet 으로 운영할 수 있습니다.

리소스 정리하기

리소를 정리하기 위해서는 AWS CLI 를 통해서 생성한 자원을 먼저 삭제하고, CDK 툴을 통해서 전체 클라우드 자원을 제거합니다.

  1. [단계5] ‘디버깅 하기’에서 생성한 리소스들을 삭제합니다.
    aws gamelift delete-alias --alias-id $ALIAS_ARN
    aws gamelift delete-fleet --fleet-id $FLEET_ID
    aws gamelift delete-location --location-name $LOCATION_NAME\
  2. 샘플 디렉토리의 삭제 스크립트를 통해 Auto Scaling 을 위해 별도로 등록한 Target Tracking 정책을 삭제합니다.
    cd ../gamelift-anywhere-with-autoscaling-group/cdk/
    chmod a+x delete_targettrackingscalingpolicy.sh
    ./delete_targettrackingscalingpolicy.sh
  3. CDK CLI를 통해 GameLift 및 EC2 Auto Scaling 자원을 삭제합니다.
    cdk destroy
  4. 마지막으로 AWS Cloud9 콘솔에서 개발자 환경으로 사용한 AWS Cloud9을 삭제합니다.

결론

Amazon GameLift Anywhere를 통해 게임 서버를 운영하는 방식에 따라 관리형 Fleet 혹은 Anywhere Fleet 을 구성할 수 있는 선택지가 생겼습니다. GameLift Anywhere는 Amazon GameLift에서 제공하는 관리형 매치 메이킹, 세션 큐 등의 기능을 활용하여 사용자가 관리하는 인프라스트럭쳐 기반의 게임 서버를 직접 구성하고 운영할수 있는 장점이 있습니다.

Amazon GameLift 의 Fleet 구성에 참고할 수 있는 관리형 Fleet과 Anywhere Fleet의 주요 차이는 다음과 같습니다.

관리형 Fleet:

  • AWS가 관리하는 계정에 Fleet의 EC2 인스턴스들을 생성하고 Auto Scaling을 수행
  • Spot 인스턴스 사용 시 Spot 인터럽션을 줄이기 위한 FleetIQ 알고리즘 지원
  • 배포 방식의 경우 고객이 S3에 게임서버 바이너리를 업로드 하면 AWS가 Fleet 내의 EC2 인스턴스들에 업데이트 수행
  • Multi-location Fleet 구성을 통해 글로벌 (Region 혹은 Local Zone) 에 분포한 다수의 Fleet에 대한 통합 운영 기능 지원

Anywhere Fleet:

  • 고객이 관리하는 서버 또는 고객의 AWS 계정의 EC2를 사용하고 고객이 Auto Scaling에 대한 관리를 수행
  • FleetIQ 알고리즘 사용할 수 없음 (Anywhere Fleet 대신 GameLift FleetIQ 기능을 사용하여 고객 계정의 EC2 인스턴스들을 연동하는 예제는 링크의 블로그를 참고)
  • 배포 방식의 경우 고객이 배포 파이프라인을 유연하게 구축할 수 있음
  • 고객 계정의 EC2 인스턴스들로 구성된 Anywhere Fleet을 사용하여 Amazon Global Accelerator, VPC peering, AWS Transit Gateway 등과의 연동 구성이 가능

Anywhere Fleet의 경우 GameLift에 의해 배치된 게임 세션 당 또한 서버 프로세스 연결 분당 요금이 추가로 발생합니다. 요금에 대한 자세한 설명은 링크를 참고하시기 바랍니다.

본 기고문을 통해서 Amazon GameLift 에서 제공하는 매치 메이킹, 세션 큐 등의 관리형 기능들을 사용하면서 사용자가 직접 관리할 수 있는 컴퓨팅 환경을 연동하는 방법에 대해서 살펴보았습니다. 특히 Amazon EC2를 중심으로 운영 환경에서 필요한 Auto Scaling과 관련된 요구사항들을 충족하기 위해 필요한 Amazon EC2 Auto Scaling의 핵심 기능들을 살펴 보았으며, 이를 Amazon GameLift Anywhere와 연동하는 내용을 다루었습니다. 그리고 Amazon GameLift Anywhere Fleet에 개발자 머신을 등록하여 게임 서버 개발 과정에서 Amazon GameLift와의 연동 테스트를 수행하는 방법에 대해서도 살펴보았습니다.

이어지는 기고문은 AWS Fargate 를 활용한 컨테이너 기반의 세션 게임 서버를 GameLift Anywhere와 연동하는 아키텍처 및 고려 사항에 대해서 다룰 예정입니다.

Hyundong Kim

Hyundong Kim

김현동 솔루션스 아키텍트는 SW 개발자로 커리어를 시작하여 네트워크 및 통신 분야의 다양한 제품 개발 프로젝트를 수행하였고 이후 여러 산업군의 고객들에게 클라우드 서비스 도입을 지원하는 역할을 수행하였습니다. 현재는 아마존 웹서비스에서 게임사 고객들이 AWS 서비스를 통해 성공적으로 게임을 서비스하도록 도움을 주고 있습니다.

Minsuk Kim

Minsuk Kim

김민석 솔루션즈 아키텍트는 다양한 클라우드 네이티브에 대한 기술 경험을 바탕으로 사용자 워크로드에 맞는 최적의 아키텍처를 수립할 수 있도록 노력하고 있습니다. 서버리스 및 컨테이너 기술에 관심이 있으며, 현재는 게임 산업의 여러 사용자가 AWS 를 보다 잘 활용할 수 있도록 노력하고 있습니다.