Skip to content

Commit 5a15888

Browse files
authored
feat: add ReclaimPolicy for GameServer (#115)
Signed-off-by: ChrisLiu <[email protected]>
1 parent ecf81d9 commit 5a15888

File tree

12 files changed

+510
-168
lines changed

12 files changed

+510
-168
lines changed

apis/v1alpha1/gameserverset_types.go

+14
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,22 @@ type GameServerTemplate struct {
6464
// +kubebuilder:validation:Schemaless
6565
corev1.PodTemplateSpec `json:",inline"`
6666
VolumeClaimTemplates []corev1.PersistentVolumeClaim `json:"volumeClaimTemplates,omitempty"`
67+
// ReclaimPolicy indicates the reclaim policy for GameServer.
68+
// Default is Cascade.
69+
ReclaimPolicy GameServerReclaimPolicy `json:"reclaimPolicy,omitempty"`
6770
}
6871

72+
type GameServerReclaimPolicy string
73+
74+
const (
75+
// CascadeGameServerReclaimPolicy indicates that GameServer is deleted when the pod is deleted.
76+
// The age of GameServer is exactly the same as that of the pod.
77+
CascadeGameServerReclaimPolicy GameServerReclaimPolicy = "Cascade"
78+
// DeleteGameServerReclaimPolicy indicates that GameServers will be deleted when replicas of GameServerSet decreases.
79+
// The GameServer will not be deleted when the corresponding pod is deleted due to manual deletion, update, eviction, etc.
80+
DeleteGameServerReclaimPolicy GameServerReclaimPolicy = "Delete"
81+
)
82+
6983
type Network struct {
7084
NetworkType string `json:"networkType,omitempty"`
7185
NetworkConf []NetworkConfParams `json:"networkConf,omitempty"`

config/crd/bases/game.kruise.io_gameserversets.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ spec:
7070
description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
7171
Important: Run "make" to regenerate code after modifying this file'
7272
properties:
73+
reclaimPolicy:
74+
description: ReclaimPolicy indicates the reclaim policy for GameServer.
75+
Default is Cascade.
76+
type: string
7377
volumeClaimTemplates:
7478
items:
7579
description: PersistentVolumeClaim is a user's request for and

docs/en/user_manuals/CRD_field_description.md

+16
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,24 @@ type GameServerTemplate struct {
3838

3939
// Requests and claims for persistent volumes.
4040
VolumeClaimTemplates []corev1.PersistentVolumeClaim `json:"volumeClaimTemplates,omitempty"`
41+
42+
// ReclaimPolicy indicates the reclaim policy for GameServer.
43+
// Default is Cascade.
44+
ReclaimPolicy GameServerReclaimPolicy `json:"reclaimPolicy,omitempty"`
4145
}
4246

47+
type GameServerReclaimPolicy string
48+
49+
const (
50+
// CascadeGameServerReclaimPolicy indicates that GameServer is deleted when the pod is deleted.
51+
// The age of GameServer is exactly the same as that of the pod.
52+
CascadeGameServerReclaimPolicy GameServerReclaimPolicy = "Cascade"
53+
54+
// DeleteGameServerReclaimPolicy indicates that GameServers will be deleted when replicas of GameServerSet decreases.
55+
// The GameServer will not be deleted when the corresponding pod is deleted due to manual deletion, update, eviction, etc.
56+
DeleteGameServerReclaimPolicy GameServerReclaimPolicy = "Delete"
57+
)
58+
4359
```
4460

4561
#### UpdateStrategy

docs/中文/用户手册/CRD字段说明.md

+16
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,23 @@ type GameServerTemplate struct {
7272
7373
// 对持久卷的请求和声明
7474
VolumeClaimTemplates []corev1.PersistentVolumeClaim `json:"volumeClaimTemplates,omitempty"`
75+
76+
// ReclaimPolicy 表明GameServer的回收策略
77+
// 当前支持两种,Cascade与Delete。默认为Cascade
78+
ReclaimPolicy GameServerReclaimPolicy `json:"reclaimPolicy,omitempty"`
7579
}
80+
81+
type GameServerReclaimPolicy string
82+
83+
const (
84+
// Cascade 表明pod删除时GameServer一并删除。GameServer的生命周期与pod相同
85+
CascadeGameServerReclaimPolicy GameServerReclaimPolicy = "Cascade"
86+
87+
// Delete 表明 GameServers 只会在GameServerSet副本数目减少时被删除。
88+
// 当对应的pod被手动删除、更新重建、被驱逐时,GameServer都不会被删除。
89+
DeleteGameServerReclaimPolicy GameServerReclaimPolicy = "Delete"
90+
)
91+
7692
```
7793

7894
### UpdateStrategy

pkg/controllers/gameserver/gameserver_controller.go

+26-53
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import (
2626
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2727
"k8s.io/apimachinery/pkg/runtime"
2828
"k8s.io/apimachinery/pkg/types"
29-
"k8s.io/apimachinery/pkg/util/intstr"
3029
"k8s.io/client-go/tools/record"
3130
"k8s.io/client-go/util/workqueue"
3231
"k8s.io/klog/v2"
@@ -173,8 +172,15 @@ func (r *GameServerReconciler) Reconcile(ctx context.Context, req ctrl.Request)
173172
}
174173

175174
if podFound && !gsFound {
176-
err := r.initGameServer(pod)
177-
if err != nil && !errors.IsAlreadyExists(err) && !errors.IsNotFound(err) {
175+
gss, err := r.getGameServerSet(pod)
176+
if err != nil {
177+
if errors.IsNotFound(err) {
178+
return reconcile.Result{}, nil
179+
}
180+
return reconcile.Result{}, err
181+
}
182+
err = r.initGameServerByPod(gss, pod)
183+
if err != nil && !errors.IsAlreadyExists(err) {
178184
klog.Errorf("failed to create GameServer %s in %s, because of %s.", namespacedName.Name, namespacedName.Namespace, err.Error())
179185
return reconcile.Result{}, err
180186
}
@@ -237,57 +243,24 @@ func (r *GameServerReconciler) getGameServerSet(pod *corev1.Pod) (*gamekruiseiov
237243
return gss, err
238244
}
239245

240-
func (r *GameServerReconciler) initGameServer(pod *corev1.Pod) error {
241-
gs := &gamekruiseiov1alpha1.GameServer{}
242-
gs.Name = pod.GetName()
243-
gs.Namespace = pod.GetNamespace()
244-
245-
// set owner reference
246-
gss, err := r.getGameServerSet(pod)
247-
if err != nil {
248-
return err
249-
}
250-
ors := make([]metav1.OwnerReference, 0)
251-
or := metav1.OwnerReference{
252-
APIVersion: gss.APIVersion,
253-
Kind: gss.Kind,
254-
Name: gss.GetName(),
255-
UID: gss.GetUID(),
256-
Controller: pointer.BoolPtr(true),
257-
BlockOwnerDeletion: pointer.BoolPtr(true),
258-
}
259-
ors = append(ors, or)
260-
gs.OwnerReferences = ors
261-
262-
// set Labels
263-
gsLabels := gss.Spec.GameServerTemplate.GetLabels()
264-
if gsLabels == nil {
265-
gsLabels = make(map[string]string)
266-
}
267-
gsLabels[gamekruiseiov1alpha1.GameServerOwnerGssKey] = gss.GetName()
268-
gs.SetLabels(gsLabels)
269-
270-
// set Annotations
271-
gsAnnotations := gss.Spec.GameServerTemplate.GetAnnotations()
272-
if gsAnnotations == nil {
273-
gsAnnotations = make(map[string]string)
246+
func (r *GameServerReconciler) initGameServerByPod(gss *gamekruiseiov1alpha1.GameServerSet, pod *corev1.Pod) error {
247+
// default fields
248+
gs := util.InitGameServer(gss, pod.Name)
249+
250+
if gss.Spec.GameServerTemplate.ReclaimPolicy == gamekruiseiov1alpha1.CascadeGameServerReclaimPolicy || gss.Spec.GameServerTemplate.ReclaimPolicy == "" {
251+
// rewrite ownerReferences
252+
ors := make([]metav1.OwnerReference, 0)
253+
or := metav1.OwnerReference{
254+
APIVersion: pod.APIVersion,
255+
Kind: pod.Kind,
256+
Name: pod.GetName(),
257+
UID: pod.GetUID(),
258+
Controller: pointer.BoolPtr(true),
259+
BlockOwnerDeletion: pointer.BoolPtr(true),
260+
}
261+
ors = append(ors, or)
262+
gs.OwnerReferences = ors
274263
}
275-
gsAnnotations[gamekruiseiov1alpha1.GsTemplateMetadataHashKey] = util.GetGsTemplateMetadataHash(gss)
276-
gs.SetAnnotations(gsAnnotations)
277-
278-
// set NetWork
279-
gs.Spec.NetworkDisabled = false
280-
281-
// set OpsState
282-
gs.Spec.OpsState = gamekruiseiov1alpha1.None
283-
284-
// set UpdatePriority
285-
updatePriority := intstr.FromInt(0)
286-
gs.Spec.UpdatePriority = &updatePriority
287-
288-
// set deletionPriority
289-
deletionPriority := intstr.FromInt(0)
290-
gs.Spec.DeletionPriority = &deletionPriority
291264

292265
return r.Client.Create(context.Background(), gs)
293266
}

pkg/controllers/gameserverset/gameserverset_controller.go

-6
Original file line numberDiff line numberDiff line change
@@ -252,12 +252,6 @@ func (r *GameServerSetReconciler) Reconcile(ctx context.Context, req ctrl.Reques
252252
return reconcile.Result{}, err
253253
}
254254

255-
err = gsm.SyncGameServerReplicas()
256-
if err != nil {
257-
klog.Errorf("GameServerSet %s failed to adjust the replicas of GameServers to match that of Pods in %s, because of %s.", namespacedName.Name, namespacedName.Namespace, err.Error())
258-
return reconcile.Result{}, err
259-
}
260-
261255
return ctrl.Result{}, nil
262256
}
263257

pkg/controllers/gameserverset/gameserverset_manager.go

+72-49
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,6 @@ package gameserverset
1818

1919
import (
2020
"context"
21-
"k8s.io/apimachinery/pkg/labels"
22-
"k8s.io/client-go/tools/record"
23-
"sort"
24-
"sync"
25-
"time"
26-
2721
kruiseV1alpha1 "github.com/openkruise/kruise-api/apps/v1alpha1"
2822
kruiseV1beta1 "github.com/openkruise/kruise-api/apps/v1beta1"
2923
corev1 "k8s.io/api/core/v1"
@@ -32,9 +26,13 @@ import (
3226
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3327
"k8s.io/apimachinery/pkg/types"
3428
"k8s.io/apimachinery/pkg/util/json"
29+
"k8s.io/client-go/tools/record"
3530
"k8s.io/klog/v2"
3631
"k8s.io/utils/pointer"
3732
"sigs.k8s.io/controller-runtime/pkg/client"
33+
"sort"
34+
"strconv"
35+
"sync"
3836

3937
gameKruiseV1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
4038
"github.com/openkruise/kruise-game/pkg/util"
@@ -47,7 +45,6 @@ type Control interface {
4745
IsNeedToScale() bool
4846
IsNeedToUpdateWorkload() bool
4947
SyncPodProbeMarker() error
50-
SyncGameServerReplicas() error
5148
GetReplicasAfterKilling() *int32
5249
}
5350

@@ -129,7 +126,15 @@ func (manager *GameServerSetManager) GameServerScale() error {
129126
klog.Infof("GameServers %s/%s already has %d replicas, expect to have %d replicas.", gss.GetNamespace(), gss.GetName(), currentReplicas, expectedReplicas)
130127
manager.eventRecorder.Eventf(gss, corev1.EventTypeNormal, ScaleReason, "scale from %d to %d", currentReplicas, expectedReplicas)
131128

132-
newReserveIds := computeToScaleGs(gssReserveIds, reserveIds, notExistIds, expectedReplicas, podList, gss.Spec.ScaleStrategy.ScaleDownStrategyType)
129+
newManageIds, newReserveIds := computeToScaleGs(gssReserveIds, reserveIds, notExistIds, expectedReplicas, podList, gss.Spec.ScaleStrategy.ScaleDownStrategyType)
130+
131+
if gss.Spec.GameServerTemplate.ReclaimPolicy == gameKruiseV1alpha1.DeleteGameServerReclaimPolicy {
132+
err := SyncGameServer(gss, c, newManageIds, util.GetIndexListFromPodList(podList))
133+
if err != nil {
134+
return err
135+
}
136+
}
137+
133138
asts.Spec.ReserveOrdinals = newReserveIds
134139
asts.Spec.Replicas = gss.Spec.Replicas
135140
asts.Spec.ScaleStrategy = &kruiseV1beta1.StatefulSetScaleStrategy{
@@ -157,7 +162,7 @@ func (manager *GameServerSetManager) GameServerScale() error {
157162
return nil
158163
}
159164

160-
func computeToScaleGs(gssReserveIds, reserveIds, notExistIds []int, expectedReplicas int, pods []corev1.Pod, scaleDownType gameKruiseV1alpha1.ScaleDownStrategyType) []int {
165+
func computeToScaleGs(gssReserveIds, reserveIds, notExistIds []int, expectedReplicas int, pods []corev1.Pod, scaleDownType gameKruiseV1alpha1.ScaleDownStrategyType) ([]int, []int) {
161166
workloadManageIds := util.GetIndexListFromPodList(pods)
162167

163168
var toAdd []int
@@ -215,12 +220,13 @@ func computeToScaleGs(gssReserveIds, reserveIds, notExistIds []int, expectedRepl
215220
}
216221
}
217222

223+
newManageIds := append(workloadManageIds, util.GetSliceInANotInB(toAdd, workloadManageIds)...)
224+
newManageIds = util.GetSliceInANotInB(newManageIds, toDelete)
225+
218226
if scaleDownType == gameKruiseV1alpha1.ReserveIdsScaleDownStrategyType {
219-
return append(gssReserveIds, util.GetSliceInANotInB(toDelete, gssReserveIds)...)
227+
return newManageIds, append(gssReserveIds, util.GetSliceInANotInB(toDelete, gssReserveIds)...)
220228
}
221229

222-
newManageIds := append(workloadManageIds, util.GetSliceInANotInB(toAdd, workloadManageIds)...)
223-
newManageIds = util.GetSliceInANotInB(newManageIds, toDelete)
224230
var newReserveIds []int
225231
if len(newManageIds) != 0 {
226232
sort.Ints(newManageIds)
@@ -231,63 +237,80 @@ func computeToScaleGs(gssReserveIds, reserveIds, notExistIds []int, expectedRepl
231237
}
232238
}
233239

234-
return newReserveIds
240+
return newManageIds, newReserveIds
235241
}
236242

237-
func (manager *GameServerSetManager) SyncGameServerReplicas() error {
238-
gss := manager.gameServerSet
239-
gsList := &gameKruiseV1alpha1.GameServerList{}
240-
err := manager.client.List(context.Background(), gsList, &client.ListOptions{
241-
Namespace: gss.GetNamespace(),
242-
LabelSelector: labels.SelectorFromSet(map[string]string{
243-
gameKruiseV1alpha1.GameServerOwnerGssKey: gss.GetName(),
244-
})})
245-
if err != nil {
246-
return err
247-
}
248-
podIds := util.GetIndexListFromPodList(manager.podList)
249-
250-
gsMap := make(map[int]int)
251-
deleteIds := make([]int, 0)
252-
for id, gs := range gsList.Items {
253-
gsId := util.GetIndexFromGsName(gs.Name)
254-
if !util.IsNumInList(gsId, podIds) {
255-
gsMap[gsId] = id
256-
deleteIds = append(deleteIds, gsId)
257-
}
258-
}
259-
260-
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
243+
func SyncGameServer(gss *gameKruiseV1alpha1.GameServerSet, c client.Client, newManageIds, oldManageIds []int) error {
244+
ctx, cancel := context.WithCancel(context.Background())
261245
defer cancel()
262246

263-
errch := make(chan error, len(deleteIds))
247+
addIds := util.GetSliceInANotInB(newManageIds, oldManageIds)
248+
deleteIds := util.GetSliceInANotInB(oldManageIds, newManageIds)
249+
250+
errch := make(chan error, len(addIds)+len(deleteIds))
264251
var wg sync.WaitGroup
265-
for _, gsId := range deleteIds {
252+
for _, gsId := range append(addIds, deleteIds...) {
266253
wg.Add(1)
267254
id := gsId
268255
go func(ctx context.Context) {
269256
defer wg.Done()
270257
defer ctx.Done()
271258

272-
gs := gsList.Items[gsMap[id]].DeepCopy()
273-
gsLabels := make(map[string]string)
274-
gsLabels[gameKruiseV1alpha1.GameServerDeletingKey] = "true"
275-
patchGs := map[string]interface{}{"metadata": map[string]map[string]string{"labels": gsLabels}}
276-
patchBytes, err := json.Marshal(patchGs)
259+
gs := &gameKruiseV1alpha1.GameServer{}
260+
gsName := gss.Name + "-" + strconv.Itoa(id)
261+
err := c.Get(ctx, types.NamespacedName{
262+
Name: gsName,
263+
Namespace: gss.Namespace,
264+
}, gs)
277265
if err != nil {
266+
if errors.IsNotFound(err) {
267+
return
268+
}
278269
errch <- err
270+
return
279271
}
280-
err = manager.client.Patch(context.TODO(), gs, client.RawPatch(types.MergePatchType, patchBytes))
281-
if err != nil && !errors.IsNotFound(err) {
282-
errch <- err
272+
273+
if util.IsNumInList(id, addIds) && gs.GetLabels()[gameKruiseV1alpha1.GameServerDeletingKey] == "true" {
274+
gsLabels := make(map[string]string)
275+
gsLabels[gameKruiseV1alpha1.GameServerDeletingKey] = "false"
276+
patchGs := map[string]interface{}{"metadata": map[string]map[string]string{"labels": gsLabels}}
277+
patchBytes, err := json.Marshal(patchGs)
278+
if err != nil {
279+
errch <- err
280+
return
281+
}
282+
err = c.Patch(ctx, gs, client.RawPatch(types.MergePatchType, patchBytes))
283+
if err != nil && !errors.IsNotFound(err) {
284+
errch <- err
285+
return
286+
}
287+
klog.Infof("GameServer %s/%s DeletingKey turn into false", gss.Namespace, gsName)
283288
}
289+
290+
if util.IsNumInList(id, deleteIds) && gs.GetLabels()[gameKruiseV1alpha1.GameServerDeletingKey] != "true" {
291+
gsLabels := make(map[string]string)
292+
gsLabels[gameKruiseV1alpha1.GameServerDeletingKey] = "true"
293+
patchGs := map[string]interface{}{"metadata": map[string]map[string]string{"labels": gsLabels}}
294+
patchBytes, err := json.Marshal(patchGs)
295+
if err != nil {
296+
errch <- err
297+
return
298+
}
299+
err = c.Patch(ctx, gs, client.RawPatch(types.MergePatchType, patchBytes))
300+
if err != nil && !errors.IsNotFound(err) {
301+
errch <- err
302+
return
303+
}
304+
klog.Infof("GameServer %s/%s DeletingKey turn into true, who will be deleted", gss.Namespace, gsName)
305+
}
306+
284307
}(ctx)
285308
}
309+
286310
wg.Wait()
287311
close(errch)
288-
err = <-errch
312+
err := <-errch
289313
if err != nil {
290-
klog.Errorf("failed to delete GameServers %s in %s because of %s.", gss.GetName(), gss.GetNamespace(), err.Error())
291314
return err
292315
}
293316

0 commit comments

Comments
 (0)