Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More Local Dev Server Support #3252

Merged
merged 24 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2203efb
More Local Dev Server Support
CauhxMilloy Jul 8, 2023
a04cfd2
Merge remote-tracking branch 'remotes/original_origin/main' into more…
CauhxMilloy Jul 8, 2023
9d2be3b
* Update documentation clarification location... -ation.
CauhxMilloy Jul 8, 2023
df14a37
* Fixing formatting (had 1 too many spaces).
CauhxMilloy Jul 8, 2023
559901f
* Fixing ref relative paths.
CauhxMilloy Jul 9, 2023
d7020c1
* Removing quotes missed in previous cleanups.
CauhxMilloy Jul 9, 2023
1c83925
* As per review feedback, updating `GAMESERVER_NAME` and `POD_NAMESPA…
CauhxMilloy Jul 12, 2023
8ace56c
* As per review feedback, changing from negative to positive logic fo…
CauhxMilloy Jul 12, 2023
6c070c4
* Updating links to use `ref` instead of absolute site link.
CauhxMilloy Jul 12, 2023
125bfde
* Switching "out of cluster" command example to use binary instead of…
CauhxMilloy Jul 12, 2023
60bc8d9
Merge remote-tracking branch 'remotes/original_origin/main' into more…
CauhxMilloy Jul 12, 2023
060e3c8
* Adding controller test for RequestReady -> Ready state progression.
CauhxMilloy Jul 15, 2023
62cb705
* Adding `RequestReady` -> `Ready` state progressing in `TestDevelopm…
CauhxMilloy Jul 17, 2023
597ecf0
* Fixing call to `StartInformers()` in test.
CauhxMilloy Jul 22, 2023
7a6bfb5
* Moving discussion of running from source code down to the bottom.
CauhxMilloy Jul 22, 2023
b0bc52f
* Adding more cross-reference links for game server allocation.
CauhxMilloy Jul 22, 2023
de032f7
* Moving "out of cluster" documentation into its own file.
CauhxMilloy Jul 22, 2023
3a6036a
* Switching OS/file description back to bulleted form similar to how …
CauhxMilloy Jul 22, 2023
6347a99
Merge remote-tracking branch 'remotes/original_origin/main' into more…
CauhxMilloy Jul 22, 2023
d94cfe5
* Removing link to moved section (covered by "Next Steps" section).
CauhxMilloy Jul 23, 2023
608f415
* Cleaning up some wording.
CauhxMilloy Jul 23, 2023
af34674
* Adding comments about restarting locally run binaries.
CauhxMilloy Jul 23, 2023
fddea9d
* Proofread and update.
CauhxMilloy Jul 23, 2023
6dba945
Merge remote-tracking branch 'remotes/original_origin/main' into more…
CauhxMilloy Jul 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 44 additions & 29 deletions cmd/sdk-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import (
"google.golang.org/grpc/credentials/insecure"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)

const (
Expand All @@ -53,15 +54,17 @@ const (
podNamespaceEnv = "POD_NAMESPACE"

// Flags (that can also be env vars)
localFlag = "local"
fileFlag = "file"
testFlag = "test"
testSdkNameFlag = "sdk-name"
addressFlag = "address"
delayFlag = "delay"
timeoutFlag = "timeout"
grpcPortFlag = "grpc-port"
httpPortFlag = "http-port"
localFlag = "local"
fileFlag = "file"
testFlag = "test"
testSdkNameFlag = "sdk-name"
kubeconfigFlag = "kubeconfig"
noGracefulTerminationFlag = "no-graceful-termination"
addressFlag = "address"
delayFlag = "delay"
timeoutFlag = "timeout"
grpcPortFlag = "grpc-port"
httpPortFlag = "http-port"
)

var (
Expand Down Expand Up @@ -118,7 +121,8 @@ func main() {
}
default:
var config *rest.Config
config, err := rest.InClusterConfig()
// if the kubeconfig fails BuildConfigFromFlags will try in cluster config
config, err := clientcmd.BuildConfigFromFlags("", ctlConf.KubeConfig)
if err != nil {
logger.WithError(err).Fatal("Could not create in cluster config")
}
Expand Down Expand Up @@ -146,7 +150,9 @@ func main() {
if err := s.WaitForConnection(ctx); err != nil {
logger.WithError(err).Fatalf("Sidecar networking failure")
}
ctx = s.NewSDKServerContext(ctx)
if !ctlConf.NoGracefulTermination {
ctx = s.NewSDKServerContext(ctx)
}
go func() {
err := s.Run(ctx)
if err != nil {
Expand Down Expand Up @@ -277,6 +283,10 @@ func parseEnvFlags() config {
pflag.Int(timeoutFlag, viper.GetInt(timeoutFlag), "Time of execution (in seconds) before close. Useful for tests")
pflag.String(testFlag, viper.GetString(testFlag), "List functions which should be called during the SDK Conformance test run.")
pflag.String(testSdkNameFlag, viper.GetString(testSdkNameFlag), "SDK name which is tested by this SDK Conformance test.")
pflag.String(kubeconfigFlag, viper.GetString(kubeconfigFlag),
"Optional. kubeconfig to run the SDK server out of the cluster.")
pflag.Bool(noGracefulTerminationFlag, viper.GetBool(noGracefulTerminationFlag),
"Immediately quits when receiving interrupt instead of waiting for GameServer state to progress to \"Shutdown\".")
runtime.FeaturesBindFlags()
pflag.Parse()

Expand All @@ -286,6 +296,7 @@ func parseEnvFlags() config {
runtime.Must(viper.BindEnv(addressFlag))
runtime.Must(viper.BindEnv(testFlag))
runtime.Must(viper.BindEnv(testSdkNameFlag))
runtime.Must(viper.BindEnv(kubeconfigFlag))
runtime.Must(viper.BindEnv(gameServerNameEnv))
runtime.Must(viper.BindEnv(podNamespaceEnv))
runtime.Must(viper.BindEnv(delayFlag))
Expand All @@ -298,29 +309,33 @@ func parseEnvFlags() config {
runtime.Must(runtime.ParseFeaturesFromEnv())

return config{
IsLocal: viper.GetBool(localFlag),
Address: viper.GetString(addressFlag),
LocalFile: viper.GetString(fileFlag),
Delay: viper.GetInt(delayFlag),
Timeout: viper.GetInt(timeoutFlag),
Test: viper.GetString(testFlag),
TestSdkName: viper.GetString(testSdkNameFlag),
GRPCPort: viper.GetInt(grpcPortFlag),
HTTPPort: viper.GetInt(httpPortFlag),
IsLocal: viper.GetBool(localFlag),
Address: viper.GetString(addressFlag),
LocalFile: viper.GetString(fileFlag),
Delay: viper.GetInt(delayFlag),
Timeout: viper.GetInt(timeoutFlag),
Test: viper.GetString(testFlag),
TestSdkName: viper.GetString(testSdkNameFlag),
KubeConfig: viper.GetString(kubeconfigFlag),
NoGracefulTermination: viper.GetBool(noGracefulTerminationFlag),
GRPCPort: viper.GetInt(grpcPortFlag),
HTTPPort: viper.GetInt(httpPortFlag),
}
}

// config is all the configuration for this program
type config struct {
Address string
IsLocal bool
LocalFile string
Delay int
Timeout int
Test string
TestSdkName string
GRPCPort int
HTTPPort int
Address string
IsLocal bool
LocalFile string
Delay int
Timeout int
Test string
TestSdkName string
KubeConfig string
NoGracefulTermination bool
GRPCPort int
HTTPPort int
}

// healthCheckWrapper ensures that an http 400 response is returned
Expand Down
26 changes: 16 additions & 10 deletions pkg/gameservers/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -543,23 +543,29 @@ func (c *Controller) syncDevelopmentGameServer(ctx context.Context, gs *agonesv1
return gs, nil
}

// Only move from Creating -> Ready. Other manual state changes are up to the end user.
// We also don't want to move from Allocated -> Ready every time someone allocates a GameServer.
if gs.Status.State != agonesv1.GameServerStateCreating {
// Only move from Creating -> Ready or RequestReady -> Ready.
// Shutdown -> Delete will still be handled normally by syncGameServerShutdownState.
// Other manual state changes are up to the end user.
if gs.Status.State != agonesv1.GameServerStateCreating && gs.Status.State != agonesv1.GameServerStateRequestReady {
return gs, nil
}

loggerForGameServer(gs, c.baseLogger).Debug("GS is a development game server and will not be managed by Agones.")
gsCopy := gs.DeepCopy()
var ports []agonesv1.GameServerStatusPort
for _, p := range gs.Spec.Ports {
ports = append(ports, p.Status())
}

gsCopy.Status.State = agonesv1.GameServerStateReady
gsCopy.Status.Ports = ports
gsCopy.Status.Address = devIPAddress
gsCopy.Status.NodeName = devIPAddress

if gs.Status.State == agonesv1.GameServerStateCreating {
var ports []agonesv1.GameServerStatusPort
for _, p := range gs.Spec.Ports {
ports = append(ports, p.Status())
}

gsCopy.Status.Ports = ports
gsCopy.Status.Address = devIPAddress
gsCopy.Status.NodeName = devIPAddress
}

gs, err := c.gameServerGetter.GameServers(gs.ObjectMeta.Namespace).Update(ctx, gsCopy, metav1.UpdateOptions{})
if err != nil {
return gs, errors.Wrapf(err, "error updating GameServer %s to %v status", gs.Name, gs.Status)
Expand Down
92 changes: 82 additions & 10 deletions site/content/en/docs/Guides/Client SDKs/local.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,41 @@ namespace as it - usually referred to in Kubernetes terms as a "sidecar".

Therefore, when developing locally, we also need a process for the SDK to connect to!

To do this, we can run the same binary that runs inside Agones, but pass in a flag
To do this, we can run the same binary (the SDK Server) that runs inside Agones, but pass in a flag
to run it in "local mode". Local mode means that the sidecar binary
will not try to connect to anything, and will just send log messages to stdout and persist local state in memory so
that you can see exactly what the SDK in your game server is doing, and can
confirm everything works.

To do this you will need to download {{% ghrelease file_prefix="agonessdk-server" %}}, and unzip it.
For local development with integration into your cluster, the SDK Server can also be run in "out of cluster mode", discussed more [below](#running-locally-using-out-of-cluster-mode).

## Running the SDK Server

To run the SDK Server, you will need a copy of the binary.
This can either be done by downloading a prebuilt binary or running from source code.

### Getting the prebuilt binary

To run the prebuilt binary, for the latest release, you will need to download {{% ghrelease file_prefix="agonessdk-server" %}}, and unzip it.
You will find the executables for the SDK server, for each type of operating system.
`sdk-server.darwin.amd64` and `sdk-server.darwin.arm64` are for <u>MacOS</u>, `sdk-server.linux.amd64` and `sdk-server.linux.arm64` are for <u>Linux</u>, and `sdk-server.windows.amd64.exe` is for <u>Windows</u>.

macOS
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to keep this section in. Not everyone knows what OS matches to what code names, etc. Better to be explicit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section was still here. It's right above this. I just changed this to be a formatted sentence, rather than half-bullets. I went ahead and changed this mostly back (although, now its a single set of bullets).

* sdk-server.darwin.amd64
* sdk-server.darwin.arm64
### Running from source code
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this section either above/below "Running Local Mode in a Container" as "Running Local Mode from Source" - then it's consistent and we don't force new developer to decide which one they want (analysis paralysis) before they have even learned how to use the tool.

We can add a section at the top saying "if you want alternate ways to run the local sdk server, see further down the documentation", or similar.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to last section (before Next Steps).


Linux
* sdk-server.linux.amd64
* sdk-server.linux.arm64
Instead of downloading and running executable binaries from the internet, you can simply run from source code.
First clone the [Agones GitHub repo](https://github.com/googleforgames/agones).
You can switch to a specific release's branch/tag or run from main.
Running from source code will require having golang installed, which can be done by following the instructions [here](https://go.dev/doc/install).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Instead of downloading and running executable binaries from the internet, you can simply run from source code.
First clone the [Agones GitHub repo](https://github.com/googleforgames/agones).
You can switch to a specific release's branch/tag or run from main.
Running from source code will require having golang installed, which can be done by following the instructions [here](https://go.dev/doc/install).
If you wish to run from source rather than pre-built binaries, you will need [Go installed](https://go.dev/doc/install).
**Disclaimer:** Agones is run and tested with the version of Go specified by the `GO_VERSION` variable in the project's [build Dockerfile](https://github.com/googleforgames/agones/blob/main/build/build-image/Dockerfile). Other versions are not supported, but may still work.
You will need to clone the [Agones GitHub repo](https://github.com/googleforgames/agones) and switch to your installed specific release's branch/tag. For example:
```bash
git clone https://github.com/googleforgames/agones.git
cd agones
git checkout release-{{< release-version >}}

Adding an example and simplifying the language (although I think my suggestion formatting in here got a bit weird).

Copy link
Contributor Author

@CauhxMilloy CauhxMilloy Jul 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved "running from source" down to the last section (just above Next Steps). Reworded to be a mix of new and old. Feel free to suggest further edits.


Windows
* sdk-server.windows.amd64.exe
With golang installed and the Agones repository cloned, the SDK Server can easily be run with the following command (from the agones clone directory):
```bash
go run cmd/sdk-server/main.go
```
Note: This command does not contain any of the necessary command line flags used in the following sections.
It simply serves as an example of how to run from source code instead of running the prebuilt binary.
Passing commandline flags (e.g. `--local`) will work in the same way.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
With golang installed and the Agones repository cloned, the SDK Server can easily be run with the following command (from the agones clone directory):
```bash
go run cmd/sdk-server/main.go
```
Note: This command does not contain any of the necessary command line flags used in the following sections.
It simply serves as an example of how to run from source code instead of running the prebuilt binary.
Passing commandline flags (e.g. `--local`) will work in the same way.
With Go installed and the Agones repository cloned, the SDK Server can be run with the following command (from the Agones clone directory):
```bash
go run cmd/sdk-server/main.go --local
/```
Commandline flags (e.g. `--local`) are exactly the same as command line flags when utilising a pre-built binary.

Tech writer nit: Some things aren't "easily" or "simple" for some people, so better to remove the adjective.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleaned up.


### Running In "Local Mode"

To run in local mode, pass the flag `--local` to the executable.

Expand All @@ -40,6 +56,11 @@ For example:
```bash
./sdk-server.linux.amd64 --local
```
or
```bash
go run cmd/sdk-server/main.go --local
```
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
or
```bash
go run cmd/sdk-server/main.go --local
```

Since we have the section above now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleaned up any go run outside of the "run from source" section.

You should see output similar to the following:
```
{"ctlConf":{"Address":"localhost","IsLocal":true,"LocalFile":"","Delay":0,"Timeout":0,"Test":"","GRPCPort":9357,"HTTPPort":9358},"message":"Starting sdk sidecar","severity":"info","source":"main","time":"2019-10-30T21:44:37.973139+03:00","version":"1.1.0"}
{"grpcEndpoint":"localhost:9357","message":"Starting SDKServer grpc service...","severity":"info","source":"main","time":"2019-10-30T21:44:37.974585+03:00"}
Expand All @@ -50,6 +71,8 @@ For example:
{"message":"gameserver update received","severity":"info","time":"2019-10-30T21:46:18.179459+03:00"}
```

An alternative to "local mode" ("out of cluster mode", which uses an agones cluster) is discussed [below](#running-locally-using-out-of-cluster-mode).

## Providing your own `GameServer` configuration for local development

By default, the local sdk-server will create a default `GameServer` configuration that is used for `GameServer()`
Expand Down Expand Up @@ -149,3 +172,52 @@ wget https://raw.githubusercontent.com/googleforgames/agones/{{< release-branch
chmod o+r gameserver.yaml
docker run --network=host --rm -v $(pwd)/gameserver.yaml:/tmp/gameserver.yaml us-docker.pkg.dev/agones-images/release/agones-sdk:{{<release-version>}} --local -f /tmp/gameserver.yaml
```

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same as our other docs:

Suggested change
## Next Steps:
* Learn how to connect your local development game server binary into a running Agones Kubernetes cluster for even more live [development options](({{< ref "/docs/Guides/local-game-server.md" >}})).

(This would be at the bottom of the page -- see note on moving below to local-game-server.md).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added/updated Next Steps on site/content/en/docs/Guides/Client SDKs/local.md and site/content/en/docs/Guides/local-game-server.md to link to the new site/content/en/docs/Advanced/out-of-cluster-dev-server.md page.

## Running locally using "out of cluster" mode
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a heads up, our docs publish on merge, so if you have new features that aren't in the current release, please wrap them in a feature shortcode like so: https://agones.dev/site/docs/contribute/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added publishDate to new page. Wrapped links with {{% feature publishVersion="1.34.0" %}}.


An alternative to running completely isolated from a cluster is to run in "out of cluster" mode.
This allows you to run locally but interact with the controllers within a cluster.
This workflow works well when running a [Local Game Server](https://agones.dev/site/docs/guides/local-game-server/) in your cluster and want to run the server locally.
This means being able to allocate your game in its normal flow (much more prod-like environment) and be able to debug (e.g. breakpoint) your server code.
This can also be done with [running Minikube locally](https://agones.dev/site/docs/installation/creating-cluster/minikube/), which is great for early prototyping.

The name "out of cluster" mode is to contrast [InClusterConfig](https://pkg.go.dev/k8s.io/client-go/tools/clientcmd#InClusterConfig) which is used in the internal golang kubeconfig API.

To run in "out of cluster" mode, instead of passing `--local` or `-f ./gameserver.yaml`, you'd use `--kubeconfig` to connect into your cluster.
However, there are a number of commands that are necessary/useful to run when running in "out of cluster" mode.
Here is a sample with each piece discussed after.
```bash
GAMESERVER_NAME='my-local-server' \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like to do this cleanly, we should update the sdkserver to also allow command line args for the GameServer name and Pod Namespace -- just to be consistent, and make life easier for end users. Then we don't have to mix args and env vars.

Also would prefer to see these docs using a binary, not running from source.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we don't have to mix args and env vars.

I agree that this would be nicer. I can add in the extra flags.

Also would prefer to see these docs using a binary, not running from source.

As mentioned in the other comment, I think running from source is nicer than downloaded binaries. But sure, for the sake of documentation consistency, I can update this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to follow up here, this work has been done. --gameserver-name and --pod-namespace can be used as cli args, and GAMESERVER_NAME and POD_NAMESPACE still work as env vars (which are used in k8s). Also updated this to be consistent and use pre-built binary commands.

POD_NAMESPACE='default' \
go run cmd/sdk-server/main.go \
--kubeconfig "$HOME/.kube/config" \
--address 0.0.0.0 \
--no-graceful-termination
```

* `GAMESERVER_NAME` is a necessary enviroment variable.
* It is set to the name of the dev `GameServer` k8s resource.
* It tells the SDK Sever which resource to read/write to on the k8s cluster.
* This example value of `my-local-server` matches to the instructions for setting up a [Local Game Server](https://agones.dev/site/docs/guides/local-game-server/).
* `POD_NAMESPACE` is a necessary enviroment variable.
* It is set set to the namespace which your `GameServer` resides in.
* It tells the SDK Sever which namespace to look under for the `GameServer` to read/write to on the k8s cluster.
* This example value of `default` is used as most instructions in this documentation assumes `GameServers` to be created in the `default` namespace.
* `--kubeconfig` tells the SDK Server how to connect to your cluster.
* This actually does not trigger any special flow.
* The SDK Server will run just as it would when created as a Sidecar in a k8s cluster.
* Passing this argument simply provides where to connect along with the credentials to do so.
* This example value of `"$HOME/.kube/config"` is the default location for your k8s authentication information. This requires you be logged in via `kubectl` and have the desired cluster selected via [`kubectl config use-context`](https://jamesdefabia.github.io/docs/user-guide/kubectl/kubectl_config_use-context/).
* `--address` specifies the binding IP address for the SDK Server.
* By default, the binding address is `localhost`. This may be difficult for some development setups.
* Overriding this value changes which IP address(es) the server will bind to for receiving gRPC/REST SDK API calls.
* This example value of `0.0.0.0` sets the SDK Server to receive API calls that are sent to any IP address (that reach your machine).
* `--no-graceful-termination` disables some smooth state transitions when exiting.
* By default, the SDK Server will wait until the `GameServer` has reached the `Shutdown` state before exiting.
* This will cause the SDK Server to hang (waiting on state update) when attempting to terminate (e.g. with `^C`).
* When running binaries in a development context, quickly exiting and restarting the SDK Server is handy.

Now that you have the SDK Server running locally with k8s credentials, you can run your game server binary in an integrated fashion.
Your game server's SDK calls will reach the local SDK Server, which will then interact with the `GameServer` resource on your cluster.
You can allocate this `GameServer` just as you would for a normal `GameServer` running completely on k8s.
The state update to `Allocated` will show in your local game server binary.
2 changes: 2 additions & 0 deletions site/content/en/docs/Guides/local-game-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ description: >

You can register a local game server with Agones. This means you can run an experimental build of your game server in the Agones environment without the need of packaging and deploying it to a fleet. This allows you to quickly iterate on your game server code while still being able to plugin to your Agones environment.

This can be used in combination with a [local SDK Server]({{< ref "./Client SDKs/local.md" >}}) in ["out of cluster" mode]({{< ref "./Client SDKs/local.md#running-locally-using-out-of-cluster-mode" >}}).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So when reading the "out of cluster mode" - I automatically assumed I could connect to my local game server binary.... but reading this, it doesn't seem to be the case.

I'm wondering if there's a way we can combine it into one whole process? 🤔 not entirely sure how, but it feels like it's worth exploring. WDYT?

Copy link
Contributor Author

@CauhxMilloy CauhxMilloy Jul 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I automatically assumed I could connect to my local game server binary

That is the case. This is what I do for local testing. I have my custom game server running in Visual Studio, I run the SDK Server on a terminal, and I have it connect to my cluster. This allows me to allocate the game server via normal prod flows (e.g. external calls onto the allocator service) which are then fully integrated with my breakpoint-able game server in VS.

I'm wondering if there's a way we can combine it into one whole process?

I mean, the steps to do so are mentioned in documentation. One would need to call kubectl apply -f dev-gameserver.yaml, then run ./sdk-server.linux.amd64 --kubeconfig ..., then run their custom game server binary. Everything is then connected.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few thoughts on this:

  1. From reading the documentation, the combination of the two approaches wasn't immediately obvious to me. I'm almost wondering if this would be better as a part of https://agones.dev/site/docs/guides/local-game-server/ than here 🤔 (at the very least, they should probably link to each other though).
  2. We should be super clear that you need both to actually connect. With the current docs it's easy to assume you can and you may not realise until the very end that you can't (or even that the agones.dev/dev-address GameSever approach exists -- which is kinda why I'm thinking we may want this in https://agones.dev/site/docs/guides/local-game-server/ as well, since one really does lead into the other.
  3. Possibly a wacky idea 😄 since we can pass a gameserver.yaml to the local game server for state -- could we make the "out of cluster mode" server create the agones.dev/dev-address for you? It's using local kubectl permissions anyway -- save you a kubectl apply? Just trying to streamline development even more.

Copy link
Contributor Author

@CauhxMilloy CauhxMilloy Jul 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm almost wondering if this would be better as a part of https://agones.dev/site/docs/guides/local-game-server/ than here 🤔

I'm thinking we may want this in https://agones.dev/site/docs/guides/local-game-server/ as well

Ummm, this is https://agones.dev/site/docs/guides/local-game-server/ (site/content/en/docs/Guides/local-game-server.md). Maybe I'm misunderstanding you? 😅

(at the very least, they should probably link to each other though).

I added links to both pages, this is the one from https://agones.dev/site/docs/guides/local-game-server/ to https://agones.dev/site/docs/guides/client-sdks/local/. In site/content/en/docs/Guides/Client SDKs/local.md (line 180) I have the reverse link.

could we make the "out of cluster mode" server create the agones.dev/dev-address for you?

That seems like a large expansion of the behavior of the SDK Server. While it obviously isn't my call to say what's best for the codebase, it just seems like that change would be larger and more out of place.

On a slightly separate note, one of the goals here was for this dev flow to be more representative of prod. While we are manually running the SDK Server locally instead of it being created in a sidecar container, it is still running the "out of cluster" mode using the exact same logic flow as it would be in the sidecar. Adding in extra steps/logic of the SDK Server, or changing how the SDK Server and the GameServer resource interact, builds less confidence in "what is developed" == "what goes on prod".

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ummm, this is https://agones.dev/site/docs/guides/local-game-server/ (site/content/en/docs/Guides/local-game-server.md). Maybe I'm misunderstanding you?

Sorry, I 100% wasn't clear. I was wondering it the whole new documentation set in local.md should be in this documentation - since my gut says that they are likely always going to be used together. WDYT? That also then solves any confusion around connection etc.

Also I was providing feedback generally to the docs, not just these specific pages -- understandably confusing.

could we make the "out of cluster mode" server create the agones.dev/dev-address for you?

That seems like a large expansion of the behavior of the SDK Server. While it obviously isn't my call to say what's best for the codebase, it just seems like that change would be larger and more out of place.

What do you think of the idea though? Can always be a secondary issue filed for future work, just thought it might be handy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering it the whole new documentation set in local.md should be in this documentation - since my gut says that they are likely always going to be used together.

I suppose it could go in either place. Personally, I feel like this has more to do with running the local SDK Server (as you need to change the commands used when running it). I definitely think "out of cluster" mode should be mentioned in both spots.

What do you think of the idea though? Can always be a secondary issue filed for future work, just thought it might be handy.

If you're just asking for my opinion, I don't particularly see any use for it (for me). I suppose some might like omitting a kubectl apply, but that's not really what I'd be optimizing for. What I'd be looking for is "breakpoint locally but in the most prod-y way possible". As the expected order of lifetimes/creation on prod would be: GameServer resource, SDK Server binary, custom game server binary, I would want to keep it in that order. This means that the custom game binary, the allocation system, etc, can all be run in a consistent state (code abstracting away from this flow vs prod). Swapping around the order or operations, or changing what creates what, for dev testing (in such an integrated context) doesn't really make sense to me, as it isn't representative of how things will be working at the end.

Speaking of "other things that could be done for handy-ness":
As I alluded to in #3252 (comment), I have other desires for potential future PRs. Namely that dev servers wouldn't automatically go from Creating to Ready. Instead, they would do a normal Creating to Scheduled, and would only progress to Ready after the SDK call was made (+ controller state progression) -- all of this would match https://agones.dev/site/docs/reference/gameserver/#gameserver-state-diagram. An annotation could be used to "auto-ready" (e.g. agones.dev/auto-ready: true) to keep the current functionality. Also an annotation for agones.dev/recycle-gs: true would be nice to progress from Shutdown to Creating/Scheduled (so when the binary exits, calling SDK Shutdown, the GameServer would just be reset instead of deleted). Again, all of this is a bit different/extra -- this PR is just trying to add in the finishing touches for a very useful flow that's mostly there already. Lol, I hesitated to really go into all this extra stuff as I don't want it to distract from this (seemingly more straightforward) PR. Hopefully this helps with the perspective that I'm looking at things from.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are cool ideas! I'd love you to write up some issues and designs for these and we can discuss them further.

Thinking about docs organisation some more, https://agones.dev/site/docs/guides/client-sdks/local/ is about a purely local experience (and the simplest to get started with).

This file is about integrating with your online system, likely tied to how you like to run things in production (also it's further down in the docs, so it's assumed by this point, you've managed to work out how the SDK works, done some integration etc).

Jumping from "how do I integrate the SDK" to "now I'm working in a cluster" within the same page as it is now seems to me like a big leap concept with for new user onboarding to me.

So let's move the out-of-cluster documentation into a new section here, and add a link to this doc at the bottom (I'll add a suggestion to local.md on what I think will work there), since I think the annotations and the out-of-cluster mode is all interlinked (I don't see one being done without the other), without changing the learning path drastically.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love you to write up some issues and designs for these and we can discuss them further.

I went ahead and filed #3284.

let's move the out-of-cluster documentation into a new section

I've now moved all the "out of cluster" documentation into site/content/en/docs/Advanced/out-of-cluster-dev-server.md. This actually allowed me to go much further into various details. I've updated site/content/en/docs/Guides/Client SDKs/local.md and site/content/en/docs/Guides/local-game-server.md with Next Steps that link to out of cluster configuration.


## Register your server with Agones

To register your local game server you'll need to know the IP address of the machine running it and the port. With that you'll create a game server config like the one below.
Expand Down