Skip to content

Commit

Permalink
PortPolicy of Passthrough - Same Port for Container and Host (#817)
Browse files Browse the repository at this point in the history
This implements a new PortPolicy, such that the containerPort that is
specified for the game server is dynamically set to the same random
value that the hostPort is.

This is useful for game servers that have already been configured to
broadcast the port that they originally started on as their connection
port, with no overrides.

Closes #294
  • Loading branch information
markmandel authored Jun 12, 2019
1 parent 6dd7d97 commit e750bfe
Show file tree
Hide file tree
Showing 30 changed files with 259 additions and 75 deletions.
2 changes: 1 addition & 1 deletion build/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ KIND_PROFILE ?= agones
KIND_CONTAINER_NAME=kind-$(KIND_PROFILE)-control-plane

# Game Server image to use while doing end-to-end tests
GS_TEST_IMAGE ?= gcr.io/agones-images/udp-server:0.9
GS_TEST_IMAGE ?= gcr.io/agones-images/udp-server:0.10

# Directory that this Makefile is in.
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
Expand Down
2 changes: 1 addition & 1 deletion examples/allocator-service/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"agones.dev/agones/pkg/apis/stable/v1alpha1"
"agones.dev/agones/pkg/client/clientset/versioned"
"agones.dev/agones/pkg/util/runtime" // for the logger
"k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/rest"
)

Expand Down
2 changes: 1 addition & 1 deletion examples/fleet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,4 @@ spec:
spec:
containers:
- name: simple-udp
image: gcr.io/agones-images/udp-server:0.9
image: gcr.io/agones-images/udp-server:0.10
2 changes: 2 additions & 0 deletions examples/gameserver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ spec:
# portPolicy has two 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
# - "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.
# port is available. When static is the policy specified, `hostPort` is required to be populated
portPolicy: Dynamic
# the port that is being opened on the game server process
Expand Down
4 changes: 2 additions & 2 deletions examples/simple-udp/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ COPY . /go/src/agones.dev/agones
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o server .

# final image
FROM alpine:3.8
FROM alpine:3.9

RUN adduser -D server
COPY --from=builder /go/src/simple-udp/server /home/server/server
RUN chown -R server /home/server && \
chmod o+x /home/server/server

USER server
ENTRYPOINT /home/server/server
ENTRYPOINT ["/home/server/server"]
2 changes: 1 addition & 1 deletion examples/simple-udp/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ REPOSITORY = gcr.io/agones-images

mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
project_path := $(dir $(mkfile_path))
server_tag = $(REPOSITORY)/udp-server:0.9
server_tag = $(REPOSITORY)/udp-server:0.10
root_path = $(realpath $(project_path)/../..)

# _____ _
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-udp/fleet-distributed.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ spec:
spec:
containers:
- name: simple-udp
image: gcr.io/agones-images/udp-server:0.9
image: gcr.io/agones-images/udp-server:0.10
resources:
requests:
memory: "32Mi"
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-udp/fleet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ spec:
spec:
containers:
- name: simple-udp
image: gcr.io/agones-images/udp-server:0.9
image: gcr.io/agones-images/udp-server:0.10
resources:
requests:
memory: "64Mi"
Expand Down
37 changes: 37 additions & 0 deletions examples/simple-udp/gameserver-passthrough.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Copyright 2017 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.

apiVersion: "stable.agones.dev/v1alpha1"
kind: GameServer
metadata:
generateName: "simple-udp-"
spec:
ports:
- name: default
portPolicy: Passthrough
template:
spec:
containers:
- name: simple-udp
image: gcr.io/agones-images/udp-server:0.10
env:
- name: "PASSTHROUGH"
value: "TRUE"
resources:
requests:
memory: "32Mi"
cpu: "20m"
limits:
memory: "32Mi"
cpu: "20m"
2 changes: 1 addition & 1 deletion examples/simple-udp/gameserver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ spec:
spec:
containers:
- name: simple-udp
image: gcr.io/agones-images/udp-server:0.9
image: gcr.io/agones-images/udp-server:0.10
resources:
requests:
memory: "32Mi"
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-udp/gameserverset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ spec:
spec:
containers:
- name: simple-udp
image: gcr.io/agones-images/udp-server:0.9
image: gcr.io/agones-images/udp-server:0.10
28 changes: 22 additions & 6 deletions examples/simple-udp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,15 @@ func main() {
go doSignal()

port := flag.String("port", "7654", "The port to listen to udp traffic on")
passthrough := flag.Bool("passthrough", false, "Get listening port from the SDK, rather than use the 'port' value")
flag.Parse()
if ep := os.Getenv("PORT"); ep != "" {
port = &ep
}

log.Printf("Starting UDP server, listening on port %s", *port)
conn, err := net.ListenPacket("udp", ":"+*port)
if err != nil {
log.Fatalf("Could not start udp server: %v", err)
if epass := os.Getenv("PASSTHROUGH"); epass != "" {
p := strings.ToUpper(epass) == "TRUE"
passthrough = &p
}
defer conn.Close() // nolint: errcheck

log.Print("Creating SDK instance")
s, err := sdk.NewSDK()
Expand All @@ -58,6 +56,24 @@ func main() {
stop := make(chan struct{})
go doHealth(s, stop)

if *passthrough {
var gs *coresdk.GameServer
gs, err = s.GameServer()
if err != nil {
log.Fatalf("Could not get gameserver port details: %s", err)
}

p := strconv.FormatInt(int64(gs.Status.Ports[0].Port), 10)
port = &p
}

log.Printf("Starting UDP server, listening on port %s", *port)
conn, err := net.ListenPacket("udp", ":"+*port)
if err != nil {
log.Fatalf("Could not start udp server: %v", err)
}
defer conn.Close() // nolint: errcheck

log.Print("Marking this server as ready")
// This tells Agones that the server is ready to receive connections.
err = s.Ready()
Expand Down
2 changes: 1 addition & 1 deletion examples/xonotic/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
"strings"
"time"

"agones.dev/agones/sdks/go"
sdk "agones.dev/agones/sdks/go"
)

type interceptor struct {
Expand Down
2 changes: 1 addition & 1 deletion install/helm/agones/templates/NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ spec:
spec:
containers:
- name: simple-udp
image: gcr.io/agones-images/udp-server:0.9
image: gcr.io/agones-images/udp-server:0.10

Finally don't forget to explore our documentation and usage guides on how to develop and host dedicated game servers on top of Agones. :

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,22 +58,23 @@ properties:
title: array of ports to expose on the game server container
type: array
minItems: 1
required:
- containerPort
items:
type: object
properties:
portPolicy:
title: the port policy that will be applied to the game server
description: |
portPolicy has two options:
- "Dynamic" (default) the system allocates a free hostPort for the gameserver, for game clients to connect to
portPolicy has three 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.
type: string
enum:
- Dynamic
- Static
- Passthrough
protocol:
title: Protocol being used. Defaults to UDP. TCP is the only other option
type: string
Expand All @@ -87,7 +88,7 @@ properties:
maximum: 65535
hostPort:
title: The port exposed on the host
description: Only required when `portPolicy` is "Static". Overwritten when portPolicy is "dynamic".
description: Only required when `portPolicy` is "Static". Overwritten when portPolicy is "Dynamic" or "Passthrough".
type: integer
minimum: 1
maximum: 65535
Expand Down
33 changes: 18 additions & 15 deletions install/yaml/install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -301,22 +301,23 @@ spec:
title: array of ports to expose on the game server container
type: array
minItems: 1
required:
- containerPort
items:
type: object
properties:
portPolicy:
title: the port policy that will be applied to the game server
description: |
portPolicy has two options:
- "Dynamic" (default) the system allocates a free hostPort for the gameserver, for game clients to connect to
portPolicy has three 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.
type: string
enum:
- Dynamic
- Static
- Passthrough
protocol:
title: Protocol being used. Defaults to UDP. TCP is the only other option
type: string
Expand All @@ -330,7 +331,7 @@ spec:
maximum: 65535
hostPort:
title: The port exposed on the host
description: Only required when `portPolicy` is "Static". Overwritten when portPolicy is "dynamic".
description: Only required when `portPolicy` is "Static". Overwritten when portPolicy is "Dynamic" or "Passthrough".
type: integer
minimum: 1
maximum: 65535
Expand Down Expand Up @@ -620,22 +621,23 @@ spec:
title: array of ports to expose on the game server container
type: array
minItems: 1
required:
- containerPort
items:
type: object
properties:
portPolicy:
title: the port policy that will be applied to the game server
description: |
portPolicy has two options:
- "Dynamic" (default) the system allocates a free hostPort for the gameserver, for game clients to connect to
portPolicy has three 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.
type: string
enum:
- Dynamic
- Static
- Passthrough
protocol:
title: Protocol being used. Defaults to UDP. TCP is the only other option
type: string
Expand All @@ -649,7 +651,7 @@ spec:
maximum: 65535
hostPort:
title: The port exposed on the host
description: Only required when `portPolicy` is "Static". Overwritten when portPolicy is "dynamic".
description: Only required when `portPolicy` is "Static". Overwritten when portPolicy is "Dynamic" or "Passthrough".
type: integer
minimum: 1
maximum: 65535
Expand Down Expand Up @@ -882,22 +884,23 @@ spec:
title: array of ports to expose on the game server container
type: array
minItems: 1
required:
- containerPort
items:
type: object
properties:
portPolicy:
title: the port policy that will be applied to the game server
description: |
portPolicy has two options:
- "Dynamic" (default) the system allocates a free hostPort for the gameserver, for game clients to connect to
portPolicy has three 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.
type: string
enum:
- Dynamic
- Static
- Passthrough
protocol:
title: Protocol being used. Defaults to UDP. TCP is the only other option
type: string
Expand All @@ -911,7 +914,7 @@ spec:
maximum: 65535
hostPort:
title: The port exposed on the host
description: Only required when `portPolicy` is "Static". Overwritten when portPolicy is "dynamic".
description: Only required when `portPolicy` is "Static". Overwritten when portPolicy is "Dynamic" or "Passthrough".
type: integer
minimum: 1
maximum: 65535
Expand Down
8 changes: 5 additions & 3 deletions pkg/apis/stable/v1alpha1/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ import (

// Block of const Error messages
const (
ErrContainerRequired = "Container is required when using multiple containers in the pod template"
ErrHostPortDynamic = "HostPort cannot be specified with a Dynamic PortPolicy"
ErrPortPolicyStatic = "PortPolicy must be Static"
ErrContainerRequired = "Container is required when using multiple containers in the pod template"
ErrHostPortDynamic = "HostPort cannot be specified with a Dynamic PortPolicy"
ErrPortPolicyStatic = "PortPolicy must be Static"
ErrContainerPortRequired = "ContainerPort must be defined for Dynamic and Static PortPolicies"
ErrContainerPortPassthrough = "ContainerPort cannot be specified with Passthrough PortPolicy"
)

// crd is an interface to get Name and Kind of CRD
Expand Down
Loading

0 comments on commit e750bfe

Please sign in to comment.