Skip to content
Permalink
Browse files

PortPolicy of Passthrough - Same Port for Container and Host (#817)

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 committed Jun 12, 2019
1 parent 6dd7d97 commit e750bfe942f497664d84c78798edf825c80a7136
@@ -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)))
@@ -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"
)

@@ -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
@@ -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
@@ -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"]
@@ -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)/../..)

# _____ _
@@ -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"
@@ -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"
@@ -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"
@@ -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"
@@ -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
@@ -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()
@@ -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()
@@ -24,7 +24,7 @@ import (
"strings"
"time"

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

type interceptor struct {
@@ -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. :

@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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

0 comments on commit e750bfe

Please sign in to comment.
You can’t perform that action at this time.