Skip to content

Commit 5fa785c

Browse files
committed
Fleet update strategy: Replace
When the template for a Fleet is edited, a deployment strategy can be defined. At the moment, this is just the `Replace` strategy, which terminates all current non-allocated GameServers and immeadiately starts up new GameServers to replace them. Includes documentation as well.
1 parent 33c1f86 commit 5fa785c

File tree

15 files changed

+631
-70
lines changed

15 files changed

+631
-70
lines changed

cmd/controller/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"agones.dev/agones/pkg"
2626
"agones.dev/agones/pkg/client/clientset/versioned"
2727
"agones.dev/agones/pkg/client/informers/externalversions"
28+
"agones.dev/agones/pkg/fleetallocation"
2829
"agones.dev/agones/pkg/fleets"
2930
"agones.dev/agones/pkg/gameservers"
3031
"agones.dev/agones/pkg/gameserversets"
@@ -39,7 +40,6 @@ import (
3940
"k8s.io/client-go/informers"
4041
"k8s.io/client-go/kubernetes"
4142
"k8s.io/client-go/rest"
42-
"agones.dev/agones/pkg/fleetallocation"
4343
)
4444

4545
const (
@@ -134,7 +134,7 @@ func main() { // nolint: gocyclo
134134

135135
gsController := gameservers.NewController(wh, health, minPort, maxPort, sidecarImage, alwaysPullSidecar, kubeClient, kubeInformationFactory, extClient, agonesClient, agonesInformerFactory)
136136
gsSetController := gameserversets.NewController(wh, health, kubeClient, extClient, agonesClient, agonesInformerFactory)
137-
fleetController := fleets.NewController(health, kubeClient, extClient, agonesClient, agonesInformerFactory)
137+
fleetController := fleets.NewController(wh, health, kubeClient, extClient, agonesClient, agonesInformerFactory)
138138
faController := fleetallocation.NewController(wh, kubeClient, extClient, agonesClient, agonesInformerFactory)
139139

140140
stop := signals.NewStopChannel()

docs/create_fleet.md

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ While not required, you may wish to go through the [Create a Game Server](create
2525
## Objectives
2626

2727
- Create a Fleet in Kubernetes using Agones custom resource.
28-
- Scale the Fleet up from it's initial configuration
29-
- Request a GameServer allocation from the Fleet to play on
28+
- Scale the Fleet up from it's initial configuration.
29+
- Request a GameServer allocation from the Fleet to play on.
3030
- Connect to the allocated GameServer.
31-
31+
- Deploy a new GameServer configuration to the Fleet
3232

3333
### 1. Create a Fleet
3434

@@ -244,10 +244,7 @@ This will get you a list of all the current `Status > State` of all the `GameSev
244244
State: Ready
245245
```
246246

247-
### 5. Deploy a new version of the GameServer on the Fleet
248-
_Coming Soon._
249-
250-
### 6. Scale down the Fleet
247+
### 5. Scale down the Fleet
251248

252249
Not only can we scale our fleet up, but we can scale it down as well.
253250

@@ -260,7 +257,7 @@ Run `kubectl edit fleet simple-udp` and replace `replicas: 5` with `replicas 0`,
260257

261258
It may take a moment for all the `GameServers` to shut down, so let's watch them all and see what happens:
262259
```
263-
watch kubectl describe gs | grep State
260+
watch 'kubectl describe gs | grep State'
264261
```
265262

266263
Eventually, one by one they will be removed from the list, and you should simply see:
@@ -274,7 +271,7 @@ That lone `Allocated` `GameServer` is left all alone, but still running!
274271
If you would like, try editing the `Fleet` configuration `replicas` field and watch the list of `GameServers`
275272
grow and shrink.
276273

277-
### 7. Connect to the GameServer
274+
### 6. Connect to the GameServer
278275

279276
Since we've only got one allocation, we'll just grab the details of the IP and port of the
280277
only allocated `GameServer`:
@@ -302,6 +299,44 @@ If you run `kubectl describe gs | grep State` again - either the GameServer will
302299
Since we are running a `Fleet`, Agones will always do it's best to ensure there are always the configured number
303300
of `GameServers` in the pool in either a `Ready` or `Allocated` state.
304301

302+
### 7. Deploy a new version of the GameServer on the Fleet
303+
304+
We can also change the configuration of the `GameServer` of the running `Fleet`, and have the changes
305+
roll out, without interrupting the currently `Allocated` `GameServers`.
306+
307+
Let's take this for a spin! Run `kubectl edit fleet simple-udp` and set the `replicas` field to back to `5`.
308+
309+
Let's also allocate ourselves a `GameServer`
310+
311+
```
312+
kubectl create -f https://raw.githubusercontent.com/GoogleCloudPlatform/agones/master/examples/simple-udp/server/fleetallocation.yaml -o yaml
313+
```
314+
315+
We should now have four `Ready` `GameServers` and one `Allocated`. We can check this by running `kubectl describe gs | grep State`.
316+
317+
```
318+
State: Allocated
319+
State: Ready
320+
State: Ready
321+
State: Ready
322+
State: Ready
323+
```
324+
325+
In production, we'd likely be changing a `containers > image` configuration to update our `Fleet`
326+
to run a new game server process, but to make this example simple, change `containerPort` from `7654`
327+
to `6000`. Save the file and exit.
328+
329+
This will start the deployment of a new set of `GameServers` running
330+
with a Container Port of `6000`.
331+
332+
> NOTE: This will make it such that you can no longer connect to the simple-udp game server.
333+
334+
Run `watch 'kubectl describe gs | grep "Container Port"'` until you can see that there are
335+
one of `7654`, which is the `Allocated` `GameServer`, and four instances to `6000` which
336+
is the new configuration.
337+
338+
You have now deployed a new version of your game!
339+
305340
## Next Steps
306341

307342
If you want to use your own GameServer container make sure you have properly integrated the [Agones SDK](../sdks/).

docs/fleet_spec.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ metadata:
1515
name: fleet-example
1616
spec:
1717
replicas: 2
18+
strategy:
19+
type: Recreate
1820
template:
1921
metadata:
2022
labels:
@@ -45,8 +47,12 @@ This is a very common pattern in the Kubernetes ecosystem.
4547

4648
The `spec` field is the actual `Fleet` specification and it is composed as follow:
4749

48-
- `replicas` is the number of GameServers to keep Ready or Allocated in this Fleet
49-
- `template` a full `GameServer` configuration template.
50+
- `replicas` is the number of `GameServers` to keep Ready or Allocated in this Fleet
51+
- `strategy` is the `GameServer` replacement strategy for when the `GameServer` template is edited.
52+
`type` "Recreate" is the only option. A "RollingUpdate" option will be implemented soon.
53+
- `Recreate` terminates all non-allocated `GameServers`, and starts up a new set with
54+
the new `GameServer` configuration to replace them.
55+
- `template` a full `GameServer` configuration template.
5056
See the [GameServer](./gameserver_spec.md) reference for all available fields.
5157

5258
# Fleet Allocation Specification

examples/fleet.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ spec:
2929
replicas: 2
3030
# a GameServer template - see:
3131
# https://github.com/GoogleCloudPlatform/agones/blob/master/docs/gameserver_spec.md for all the options
32+
strategy:
33+
# The replacement strategy for when the GameServer template is changed. Current option is "Recreate",
34+
# "RollingUpdate" will come at a later date.
35+
# "Recreate" terminates all non-allocated GameServers, and starts up a new set with the new details to replace them.
36+
type: Recreate
3237
template:
3338
# GameServer metadata
3439
metadata:

examples/xonotic/fleet.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ metadata:
2121
name: xonotic
2222
spec:
2323
replicas: 2
24+
strategy:
25+
type: Recreate
2426
template:
2527
spec:
26-
portPolicy: "dynamic"
2728
containerPort: 26000
29+
portPolicy: "dynamic"
2830
health:
2931
initialDelaySeconds: 30
3032
periodSeconds: 60

install/helm/agones/templates/crds/fleet.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,11 @@ spec:
3737
replicas:
3838
type: integer
3939
minimum: 0
40+
strategy:
41+
properties:
42+
type:
43+
enum:
44+
- Recreate
45+
- RollingUpdate
4046
template:
4147
{{- include "gameserver.validation" . | indent 14 }}

install/helm/agones/templates/mutatingwebhook.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ webhooks:
3737
- stable.agones.dev
3838
resources:
3939
- "gameservers"
40+
- "fleets"
4041
- "fleetallocations"
4142
apiVersions:
4243
- "v1alpha1"

install/yaml/install.yaml

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,4 @@
11
---
2-
# Source: agones/templates/namespace.yaml
3-
# Copyright 2018 Google Inc. All Rights Reserved.
4-
#
5-
# Licensed under the Apache License, Version 2.0 (the "License");
6-
# you may not use this file except in compliance with the License.
7-
# You may obtain a copy of the License at
8-
#
9-
# http://www.apache.org/licenses/LICENSE-2.0
10-
#
11-
# Unless required by applicable law or agreed to in writing, software
12-
# distributed under the License is distributed on an "AS IS" BASIS,
13-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14-
# See the License for the specific language governing permissions and
15-
# limitations under the License.
16-
17-
apiVersion: v1
18-
kind: Namespace
19-
metadata:
20-
name: agones-system
21-
labels:
22-
app: agones
23-
chart: agones-0.2.0
24-
release: agones-manual
25-
heritage: Tiller
26-
---
272
# Source: agones/templates/serviceaccounts/controller.yaml
283
# Copyright 2018 Google Inc. All Rights Reserved.
294
#
@@ -199,6 +174,12 @@ spec:
199174
replicas:
200175
type: integer
201176
minimum: 0
177+
strategy:
178+
properties:
179+
type:
180+
enum:
181+
- Recreate
182+
- RollingUpdate
202183
template:
203184
required:
204185
- spec
@@ -747,12 +728,38 @@ webhooks:
747728
- stable.agones.dev
748729
resources:
749730
- "gameservers"
731+
- "fleets"
750732
- "fleetallocations"
751733
apiVersions:
752734
- "v1alpha1"
753735
operations:
754736
- CREATE
755737
---
738+
# Source: agones/templates/namespace.yaml
739+
# Copyright 2018 Google Inc. All Rights Reserved.
740+
#
741+
# Licensed under the Apache License, Version 2.0 (the "License");
742+
# you may not use this file except in compliance with the License.
743+
# You may obtain a copy of the License at
744+
#
745+
# http://www.apache.org/licenses/LICENSE-2.0
746+
#
747+
# Unless required by applicable law or agreed to in writing, software
748+
# distributed under the License is distributed on an "AS IS" BASIS,
749+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
750+
# See the License for the specific language governing permissions and
751+
# limitations under the License.
752+
753+
apiVersion: v1
754+
kind: Namespace
755+
metadata:
756+
name: agones-system
757+
labels:
758+
app: agones
759+
chart: agones-0.2.0
760+
release: agones-manual
761+
heritage: Tiller
762+
---
756763
# Source: agones/templates/validatingwebhook.yaml
757764
# Copyright 2018 Google Inc. All Rights Reserved.
758765
#

pkg/apis/stable/v1alpha1/fleet.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package v1alpha1
1616

1717
import (
1818
"agones.dev/agones/pkg/apis/stable"
19+
appsv1 "k8s.io/api/apps/v1"
1920
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2021
)
2122

@@ -52,6 +53,8 @@ type FleetList struct {
5253
type FleetSpec struct {
5354
// Replicas are the number of GameServers that should be in this set
5455
Replicas int32 `json:"replicas"`
56+
// Deployment strategy
57+
Strategy appsv1.DeploymentStrategy `json:"strategy"`
5558
// Template the GameServer template to apply for this Fleet
5659
Template GameServerTemplateSpec `json:"template"`
5760
}
@@ -95,3 +98,22 @@ func (f *Fleet) GameServerSet() *GameServerSet {
9598

9699
return gsSet
97100
}
101+
102+
// ApplyDefaults applies default values to the Fleet
103+
func (f *Fleet) ApplyDefaults() {
104+
if f.Spec.Strategy.Type == "" {
105+
f.Spec.Strategy.Type = appsv1.RecreateDeploymentStrategyType
106+
}
107+
}
108+
109+
// ReplicasMinusSumAllocated returns the number of Replicas that are
110+
// currently configured against this fleet, subtracting the number
111+
// of allocated GameServers counted on this list of GameServerSets
112+
func (f *Fleet) ReplicasMinusSumAllocated(list []*GameServerSet) int32 {
113+
result := f.Spec.Replicas
114+
for _, gsSet := range list {
115+
result -= gsSet.Status.AllocatedReplicas
116+
}
117+
118+
return result
119+
}

pkg/apis/stable/v1alpha1/fleet_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"testing"
1919

2020
"github.com/stretchr/testify/assert"
21+
appsv1 "k8s.io/api/apps/v1"
2122
corev1 "k8s.io/api/core/v1"
2223
"k8s.io/apimachinery/pkg/apis/meta/v1"
2324
)
@@ -53,3 +54,28 @@ func TestFleetGameServerSetGameServer(t *testing.T) {
5354
assert.Equal(t, f.Spec.Template, gsSet.Spec.Template)
5455
assert.True(t, v1.IsControlledBy(gsSet, &f))
5556
}
57+
58+
func TestFleetReplicasMinusSumAllocated(t *testing.T) {
59+
f := Fleet{
60+
Spec: FleetSpec{Replicas: 10},
61+
}
62+
63+
assert.Equal(t, int32(10), f.ReplicasMinusSumAllocated(nil))
64+
gsSet1 := f.GameServerSet()
65+
gsSet1.Status.AllocatedReplicas = 2
66+
67+
gsSet2 := f.GameServerSet()
68+
gsSet2.Status.AllocatedReplicas = 3
69+
70+
assert.Equal(t, int32(5), f.ReplicasMinusSumAllocated([]*GameServerSet{gsSet1, gsSet2}))
71+
}
72+
73+
func TestFleetApplyDefaults(t *testing.T) {
74+
f := &Fleet{}
75+
76+
// gate
77+
assert.EqualValues(t, "", f.Spec.Strategy.Type)
78+
79+
f.ApplyDefaults()
80+
assert.Equal(t, appsv1.RecreateDeploymentStrategyType, f.Spec.Strategy.Type)
81+
}

0 commit comments

Comments
 (0)