Skip to content

Commit

Permalink
feat(gameserver): New DirectToGameServer PortPolicy allows direct tra…
Browse files Browse the repository at this point in the history
…ffic to a GameServer (googleforgames#3807)

* gameservers: adds a new DirectToGameServer PortPolicy

To be able to access a GameServer with a publicly routable address, this policy allows
connecting directly wihout going via the host port. The other policies assume that a
host port is always needed.

* gameservers: e2e test for DirectToGameServer PortPolicy

* update install.yaml

Revert the line with line ending changes.

* more yaml fixes

* docs: changes to the text for DirectToGameServer PortPolicy

* test fix - int vs int32 fail

* e2e: simplify the test for DirectToGameServer PodPolicy

Can't find a good way to send UDP traffic directly to a pod. This is not something that
k8s does out of the box and requires a product like Calico or similar that uses BGP to
provide direct access to pods. Removing the udp call and making the test much simpler

* rename PortPolicy to None and removes unneeded validation rules

* Empty commit to retrigger hung build

* change e2e test to run on gke

* changed gke validation to accept PortPolicy None

* PortPolicyNone feature gate

* fix e2e test

* docs: fix merge conflict
  • Loading branch information
daniellee authored May 16, 2024
1 parent 2023077 commit 9cc12e6
Show file tree
Hide file tree
Showing 18 changed files with 396 additions and 122 deletions.
2 changes: 1 addition & 1 deletion build/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ GS_TEST_IMAGE ?= us-docker.pkg.dev/agones-images/examples/simple-game-server:0.3
BETA_FEATURE_GATES ?= "CountsAndLists=true&DisableResyncOnSDKServer=true"

# Enable all alpha feature gates. Keep in sync with `false` (alpha) entries in pkg/util/runtime/features.go:featureDefaults
ALPHA_FEATURE_GATES ?= "PlayerAllocationFilter=true&PlayerTracking=true&RollingUpdateFix=true&PortRanges=true&Example=true"
ALPHA_FEATURE_GATES ?= "PlayerAllocationFilter=true&PlayerTracking=true&RollingUpdateFix=true&PortRanges=true&PortPolicyNone=true&Example=true"

# Build with Windows support
WITH_WINDOWS=1
Expand Down
2 changes: 1 addition & 1 deletion cloudbuild.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ steps:
declare -A versionsAndRegions=( [1.27]=us-east1 [1.28]=us-west1 [1.29]=europe-west1 )
# Keep in sync with (the inverse of) pkg/util/runtime/features.go:featureDefaults
featureWithGate="PlayerAllocationFilter=true&PlayerTracking=true&CountsAndLists=false&RollingUpdateFix=true&PortRanges=true&DisableResyncOnSDKServer=false&Example=true"
featureWithGate="PlayerAllocationFilter=true&PlayerTracking=true&CountsAndLists=false&RollingUpdateFix=true&PortRanges=true&PortPolicyNone=true&DisableResyncOnSDKServer=false&Example=true"
featureWithoutGate=""
# Use this if specific feature gates can only be supported on specific Kubernetes versions.
Expand Down
5 changes: 4 additions & 1 deletion examples/gameserver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,15 @@ spec:
# range is the optional port range name from which to select a port when using a 'Dynamic' or 'Passthrough' port policy.
# Defaults to 'default'.
range: default
# portPolicy has three options:
# portPolicy has four options:
# - "Dynamic" (default) the system allocates a free hostPort for the gameserver, for game clients to connect to
# - "Static", user defines the hostPort that the game client will connect to. Then onus is on the user to ensure that the
# port is available. When static is the policy specified, `hostPort` is required to be populated
# - "Passthrough" dynamically sets the `containerPort` to the same value as the dynamically selected hostPort.
# This will mean that users will need to lookup what port has been opened through the server side SDK.
# [Stage:Alpha]
# [FeatureFlag:PortPolicyNone]
# - "None" means the `hostPort` is ignored and if defined, the `containerPort` (optional) is used to set the port on the GameServer instance.
portPolicy: Dynamic
# The name of the container to open the port on. Defaults to the game server container if omitted or empty.
container: simple-game-server
Expand Down
39 changes: 39 additions & 0 deletions examples/simple-game-server/gameserver-none.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
# Copyright 2024 Google LLC All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [Stage:Alpha]
# [FeatureFlag:PortPolicyNone]
# - "None" means the `hostPort` is ignored and if defined, the `containerPort` (optional) is used to set the port on the GameServer instance.
apiVersion: agones.dev/v1
kind: GameServer
metadata:
generateName: simple-game-server-
spec:
ports:
- name: default
portPolicy: None
containerPort: 7777
template:
spec:
containers:
- name: simple-game-server
image: us-docker.pkg.dev/agones-images/examples/simple-game-server:0.28
resources:
requests:
memory: 64Mi
cpu: 20m
limits:
memory: 64Mi
cpu: 20m
1 change: 1 addition & 0 deletions install/helm/agones/defaultfeaturegates.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ PlayerAllocationFilter: false
PlayerTracking: false
RollingUpdateFix: false
PortRanges: false
PortPolicyNone: false

# Dev features
FeatureAutopilotPassthroughPort: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,19 @@ properties:
portPolicy:
title: the port policy that will be applied to the game server
description: |
portPolicy has three options:
portPolicy has four options:
- "Dynamic" (default) the system allocates a random free hostPort for the gameserver, for game clients to connect to
- "Static", user defines the hostPort that the game client will connect to. Then onus is on the user to ensure that the
port is available. When static is the policy specified, `hostPort` is required to be populated
- "Passthrough" dynamically sets the `containerPort` to the same value as the dynamically selected hostPort.
This will mean that users will need to lookup what port has been opened through the server side SDK.
- "None" means the `hostPort` is ignored and if defined, the `containerPort` (optional) is used to set the port on the GameServer instance.
type: string
enum:
- Dynamic
- Static
- Passthrough
- None
protocol:
title: Protocol being used. Defaults to UDP. TCP and TCPUDP are other options.
type: string
Expand Down
12 changes: 9 additions & 3 deletions install/yaml/install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5375,17 +5375,19 @@ spec:
portPolicy:
title: the port policy that will be applied to the game server
description: |
portPolicy has three options:
portPolicy has four options:
- "Dynamic" (default) the system allocates a random free hostPort for the gameserver, for game clients to connect to
- "Static", user defines the hostPort that the game client will connect to. Then onus is on the user to ensure that the
port is available. When static is the policy specified, `hostPort` is required to be populated
- "Passthrough" dynamically sets the `containerPort` to the same value as the dynamically selected hostPort.
This will mean that users will need to lookup what port has been opened through the server side SDK.
- "None" means the `hostPort` is ignored and if defined, the `containerPort` (optional) is used to set the port on the GameServer instance.
type: string
enum:
- Dynamic
- Static
- Passthrough
- None
protocol:
title: Protocol being used. Defaults to UDP. TCP and TCPUDP are other options.
type: string
Expand Down Expand Up @@ -10800,17 +10802,19 @@ spec:
portPolicy:
title: the port policy that will be applied to the game server
description: |
portPolicy has three options:
portPolicy has four options:
- "Dynamic" (default) the system allocates a random free hostPort for the gameserver, for game clients to connect to
- "Static", user defines the hostPort that the game client will connect to. Then onus is on the user to ensure that the
port is available. When static is the policy specified, `hostPort` is required to be populated
- "Passthrough" dynamically sets the `containerPort` to the same value as the dynamically selected hostPort.
This will mean that users will need to lookup what port has been opened through the server side SDK.
- "None" means the `hostPort` is ignored and if defined, the `containerPort` (optional) is used to set the port on the GameServer instance.
type: string
enum:
- Dynamic
- Static
- Passthrough
- None
protocol:
title: Protocol being used. Defaults to UDP. TCP and TCPUDP are other options.
type: string
Expand Down Expand Up @@ -16347,17 +16351,19 @@ spec:
portPolicy:
title: the port policy that will be applied to the game server
description: |
portPolicy has three options:
portPolicy has four options:
- "Dynamic" (default) the system allocates a random free hostPort for the gameserver, for game clients to connect to
- "Static", user defines the hostPort that the game client will connect to. Then onus is on the user to ensure that the
port is available. When static is the policy specified, `hostPort` is required to be populated
- "Passthrough" dynamically sets the `containerPort` to the same value as the dynamically selected hostPort.
This will mean that users will need to lookup what port has been opened through the server side SDK.
- "None" means the `hostPort` is ignored and if defined, the `containerPort` (optional) is used to set the port on the GameServer instance.
type: string
enum:
- Dynamic
- Static
- Passthrough
- None
protocol:
title: Protocol being used. Defaults to UDP. TCP and TCPUDP are other options.
type: string
Expand Down
16 changes: 15 additions & 1 deletion pkg/apis/agones/v1/gameserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ const (
// Passthrough dynamically sets the `containerPort` to the same value as the dynamically selected hostPort.
// This will mean that users will need to lookup what port has been opened through the server side SDK.
Passthrough PortPolicy = "Passthrough"
// None means the `hostPort` is ignored and if defined, the `containerPort` (optional) is used to set the port on the GameServer instance.
None PortPolicy = "None"
)

// EvictionSafe specified whether the game server supports termination via SIGTERM
Expand Down Expand Up @@ -276,6 +278,8 @@ type GameServerPort struct {
// at installation time.
// When `Static` portPolicy is specified, `HostPort` is required, to specify the port that game clients will
// connect to
// `Passthrough` dynamically sets the `containerPort` to the same value as the dynamically selected hostPort.
// `None` portPolicy ignores `HostPort` and the `containerPort` (optional) is used to set the port on the GameServer instance.
PortPolicy PortPolicy `json:"portPolicy,omitempty"`
// Container is the name of the container on which to open the port. Defaults to the game server container.
// +optional
Expand Down Expand Up @@ -740,9 +744,15 @@ func (gs *GameServer) Pod(apiHooks APIHooks, sidecars ...corev1.Container) (*cor

gs.podObjectMeta(pod)
for _, p := range gs.Spec.Ports {
var hostPort int32

if !runtime.FeatureEnabled(runtime.FeaturePortPolicyNone) || p.PortPolicy != None {
hostPort = p.HostPort
}

cp := corev1.ContainerPort{
ContainerPort: p.ContainerPort,
HostPort: p.HostPort,
HostPort: hostPort,
Protocol: p.Protocol,
}
err := gs.ApplyToPodContainer(pod, *p.Container, func(c corev1.Container) corev1.Container {
Expand Down Expand Up @@ -853,6 +863,10 @@ func (gs *GameServer) HasPortPolicy(policy PortPolicy) bool {

// Status returns a GameServerStatusPort for this GameServerPort
func (p GameServerPort) Status() GameServerStatusPort {
if runtime.FeatureEnabled(runtime.FeaturePortPolicyNone) && p.PortPolicy == None {
return GameServerStatusPort{Name: p.Name, Port: p.ContainerPort}
}

return GameServerStatusPort{Name: p.Name, Port: p.HostPort}
}

Expand Down
Loading

0 comments on commit 9cc12e6

Please sign in to comment.