Automate creation of Production Fleets (using Extend)
Automating dedicated server uploads and fleet creation enables you to seamlessly deploy new game server builds on AccelByte Multiplayer Servers (AMS). This guide covers the steps to create such automation, to be used in, for example, your CI/CD pipeline or build machine. Before automating the process, make sure you understand the concepts of how to Upload a Dedicated Server build and how to Create Fleets.
If you're using development fleets, refer to Automate Build Configuration creation instead.
Prerequisites
- Make sure you have an IAM client with the correct permissions. To learn how to create an IAM client, see Create an IAM client.
- For private cloud add the permission
ADMIN:NAMESPACE:{namespace}:ARMADA:FLEET (Create)
(for creating build configurations) andAMS:UPLOAD (Create, Update)
(for uploading your dedicated server image). - For shared cloud use the Dedicated Server Tools template, which includes the required Dedicated Server Toolkit and Dedicated Server permissions.
- For private cloud add the permission
- Download AMS Command Line Interface (CLI) tools to your build machine. Note that the download does not require authentication, so your pipeline could download the latest version from, for example,
https://cdn.prod.ams.accelbyte.io/linux_amd64/ams
.
Uploading a Dedicated Server Image
Use the AMS CLI in your script to upload your dedicated server image to AMS. The CLI tool can be run manually on the command line, but in this guide we will call it programmatically.
Creating a Fleet via the API
Call the Create Fleet endpoint (API Explorer). Note that, instead of calling the API endpoint directly, we recommend using the AccelByte Extend SDK, which aims to help developers invoke AccelByte Gaming Services (AGS) by simplifying getting an access token and calling the required endpoints.
Additional notes:
- A list of instance IDs can be located using the Supported Instances endpoint. Provide your access token by clicking the lock icon, in the form
Bearer <accesstoken>
. For shared cloud, thenamespace
parameter must be formatted as<studionamespace>-<gamenamespace>
. - Set
active
to true to activate the new fleet immediately upon creation. - Leave
onDemand
false for production fleets. If it's true the fleet will be created as a development fleet. - The option
dynamicBuffer
can be kept false.
Example script: Creating a Production Fleet (Extend SDK)
Below is an example Python script that uploads your dedicated server image and creates a production fleet with the new image.
import accelbyte_py_sdk
import accelbyte_py_sdk.services.auth as auth_service
import json
import os
import re
import subprocess
from datetime import datetime
from accelbyte_py_sdk.core import run_request
from accelbyte_py_sdk.api.ams.operations.fleets import FleetCreate
from accelbyte_py_sdk.api.ams.models import (
ApiFleetParameters,
ApiDSHostConfigurationParameters,
ApiImageDeploymentProfile,
ApiPortConfiguration,
ApiFleetArtifactsSampleRules,
ApiRegionConfig,
ApiCoredumpSamplingRules,
ApiArtifactTypeSamplingRules,
ApiArtifactSamplingRule
)
# Constants, update these according to your environment.
# Set the following environment variables: AB_BASE_URL, AB_CLIENT_ID, AB_CLIENT_SECRET, and AB_NAMESPACE.
AMS_CLI_PATH = "./ams-cli"
DS_FOLDER_PATH = "build"
DS_EXECUTABLE_NAME = "runserver"
DS_IMAGE_NAME = f"fleet-image-{datetime.now().strftime('%Y-%m-%d_%H-%M')}"
FLEET_NAME = f"my-production-fleet-{datetime.now().strftime('%Y-%m-%d_%H-%M')}"
FLEET_COMMAND_LINE = "-dsid ${dsid} -port ${default_port}"
AB_BASE_URL, AB_CLIENT_ID, AB_CLIENT_SECRET, AB_NAMESPACE = (
os.getenv(var) for var in ["AB_BASE_URL", "AB_CLIENT_ID", "AB_CLIENT_SECRET", "AB_NAMESPACE"]
)
def upload_image():
if not os.path.exists(AMS_CLI_PATH):
print("AMS CLI not found. Use `wget https://cdn.prod.ams.accelbyte.io/linux_amd64/ams -o ams-cli` to get it.")
exit(1)
hostname = AB_BASE_URL.split("//")[-1]
command = [
AMS_CLI_PATH,
"upload",
"-c", AB_CLIENT_ID,
"-s", AB_CLIENT_SECRET,
"-e", DS_EXECUTABLE_NAME,
"-n", DS_IMAGE_NAME,
"-H", hostname,
"-p", DS_FOLDER_PATH
]
try:
# Execute the CLI to upload the DS
result = subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print("Upload successful.")
image_id = re.search(r'img_[a-zA-Z0-9_-]+', result.stderr.decode()).group(0)
print(f"DS Image ID: {image_id}")
return image_id
except subprocess.CalledProcessError as e:
print("An error occurred during the upload process:" + e.stderr.decode())
def create_fleet(image_id: str):
accelbyte_py_sdk.initialize()
_, err = auth_service.login_client()
if err:
print("Login failed:", err)
exit(1)
params = ApiFleetParameters.create(
active=False,
ds_host_configuration=ApiDSHostConfigurationParameters.create(
servers_per_vm=1,
instance_id="01884fee-1e9b-7b1b-b0d3-ab01420951d5" # see https://docs.accelbyte.io/api-explorer/#AMS/InfoSupportedInstances
),
image_deployment_profile=ApiImageDeploymentProfile.create(
command_line=FLEET_COMMAND_LINE,
image_id=image_id,
port_configurations=[
ApiPortConfiguration.create(name="default_port", protocol="UDP")
]
),
name=FLEET_NAME,
on_demand=False,
regions=[
ApiRegionConfig.create(
region="us-east-2",
buffer_size=1,
min_server_count=0,
max_server_count=5,
dynamic_buffer=False, # Recommended to leave this False.
)
],
sampling_rules=ApiFleetArtifactsSampleRules.create(
coredumps=ApiCoredumpSamplingRules.create(
crashed=ApiArtifactSamplingRule.create(collect=True, percentage=1)
),
logs=ApiArtifactTypeSamplingRules.create(
crashed=ApiArtifactSamplingRule.create(collect=True, percentage=100),
success=ApiArtifactSamplingRule.create(collect=True, percentage=0),
unclaimed=ApiArtifactSamplingRule.create(collect=True, percentage=0)
)
)
)
operation = FleetCreate.create(namespace=AB_NAMESPACE, body=params)
result, error = run_request(operation)
if error:
print("Fleet creation failed:", error)
exit(1)
print("Production fleet created successfully.")
print(json.dumps(result.to_dict(), indent=2))
if __name__ == "__main__":
for var_name in ["AMS_CLI_PATH", "AB_CLIENT_ID", "AB_NAMESPACE", "AB_CLIENT_SECRET", "DS_EXECUTABLE_NAME", "DS_IMAGE_NAME", "DS_FOLDER_PATH"]:
var_value = globals().get(var_name)
if var_value is None or var_value == "":
raise ValueError(f"Missing or empty required variable: {var_name}")
image_id = upload_image()
print(f"Image ID: {image_id}")
create_fleet(image_id)
print("Done.")