Skip to content

Commit 07497c7

Browse files
authored
Merge pull request #8 from arangodb/pod-affinity
Pod affinity
2 parents 9329b3b + af63283 commit 07497c7

File tree

4 files changed

+95
-9
lines changed

4 files changed

+95
-9
lines changed

pkg/deployment/pods.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,6 @@ func (d *Deployment) createReadinessProbe(apiObject *api.ArangoDeployment, group
285285
// ensurePods creates all Pods listed in member status
286286
func (d *Deployment) ensurePods(apiObject *api.ArangoDeployment) error {
287287
kubecli := d.deps.KubeCli
288-
owner := apiObject.AsOwner()
289288

290289
if err := apiObject.ForeachServerGroup(func(group api.ServerGroup, spec api.ServerGroupSpec, status *api.MemberStatusList) error {
291290
for _, m := range *status {
@@ -305,7 +304,7 @@ func (d *Deployment) ensurePods(apiObject *api.ArangoDeployment) error {
305304
if err != nil {
306305
return maskAny(err)
307306
}
308-
if err := k8sutil.CreateArangodPod(kubecli, apiObject, role, m.ID, m.PersistentVolumeClaimName, apiObject.Spec.Image, apiObject.Spec.ImagePullPolicy, args, env, livenessProbe, readinessProbe, owner); err != nil {
307+
if err := k8sutil.CreateArangodPod(kubecli, apiObject.Spec.IsDevelopment(), apiObject, role, m.ID, m.PersistentVolumeClaimName, apiObject.Spec.Image, apiObject.Spec.ImagePullPolicy, args, env, livenessProbe, readinessProbe); err != nil {
309308
return maskAny(err)
310309
}
311310
} else if group.IsArangosync() {
@@ -315,7 +314,11 @@ func (d *Deployment) ensurePods(apiObject *api.ArangoDeployment) error {
315314
if err != nil {
316315
return maskAny(err)
317316
}
318-
if err := k8sutil.CreateArangoSyncPod(kubecli, apiObject, role, m.ID, apiObject.Spec.Sync.Image, apiObject.Spec.Sync.ImagePullPolicy, args, env, livenessProbe, owner); err != nil {
317+
affinityWithRole := ""
318+
if group == api.ServerGroupSyncWorkers {
319+
affinityWithRole = api.ServerGroupDBServers.AsRole()
320+
}
321+
if err := k8sutil.CreateArangoSyncPod(kubecli, apiObject.Spec.IsDevelopment(), apiObject, role, m.ID, apiObject.Spec.Sync.Image, apiObject.Spec.Sync.ImagePullPolicy, args, env, livenessProbe, affinityWithRole); err != nil {
319322
return maskAny(err)
320323
}
321324
}

pkg/util/k8sutil/affinity.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2018 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
// Author Ewout Prangsma
21+
//
22+
23+
package k8sutil
24+
25+
import (
26+
"k8s.io/api/core/v1"
27+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28+
)
29+
30+
// createAffinity creates pod anti-affinity for the given role.
31+
// role contains the name of the role to configure any-affinity with.
32+
// affinityWithRole contains the role to configure affinity with.
33+
func createAffinity(deploymentName, role string, required bool, affinityWithRole string) *v1.Affinity {
34+
a := &v1.Affinity{
35+
PodAntiAffinity: &v1.PodAntiAffinity{},
36+
}
37+
labels := LabelsForDeployment(deploymentName, role)
38+
labelSelector := &metav1.LabelSelector{
39+
MatchLabels: labels,
40+
}
41+
if required {
42+
a.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution = append(a.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution, v1.PodAffinityTerm{
43+
LabelSelector: labelSelector,
44+
TopologyKey: TopologyKeyHostname,
45+
})
46+
} else {
47+
a.PodAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution = append(a.PodAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution, v1.WeightedPodAffinityTerm{
48+
Weight: 1,
49+
PodAffinityTerm: v1.PodAffinityTerm{
50+
LabelSelector: labelSelector,
51+
TopologyKey: TopologyKeyHostname,
52+
},
53+
})
54+
}
55+
if affinityWithRole != "" {
56+
a.PodAffinity = &v1.PodAffinity{}
57+
labelSelector := &metav1.LabelSelector{
58+
MatchLabels: LabelsForDeployment(deploymentName, affinityWithRole),
59+
}
60+
if required {
61+
a.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution = append(a.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution, v1.PodAffinityTerm{
62+
LabelSelector: labelSelector,
63+
TopologyKey: TopologyKeyHostname,
64+
})
65+
} else {
66+
a.PodAffinity.PreferredDuringSchedulingIgnoredDuringExecution = append(a.PodAffinity.PreferredDuringSchedulingIgnoredDuringExecution, v1.WeightedPodAffinityTerm{
67+
Weight: 1,
68+
PodAffinityTerm: v1.PodAffinityTerm{
69+
LabelSelector: labelSelector,
70+
TopologyKey: TopologyKeyHostname,
71+
},
72+
})
73+
}
74+
}
75+
return a
76+
}

pkg/util/k8sutil/constants.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ const (
2929
// K8s constants
3030
ClusterIPNone = "None"
3131
TolerateUnreadyEndpointsAnnotation = "service.alpha.kubernetes.io/tolerate-unready-endpoints"
32+
TopologyKeyHostname = "kubernetes.io/hostname"
3233
)

pkg/util/k8sutil/pods.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ func newPod(deploymentName, ns, role, id string) v1.Pod {
125125
// CreateArangodPod creates a Pod that runs `arangod`.
126126
// If the pod already exists, nil is returned.
127127
// If another error occurs, that error is returned.
128-
func CreateArangodPod(kubecli kubernetes.Interface, deployment metav1.Object, role, id, pvcName, image string, imagePullPolicy v1.PullPolicy,
129-
args []string, env map[string]string, livenessProbe *HTTPProbeConfig, readinessProbe *HTTPProbeConfig, owner metav1.OwnerReference) error {
128+
func CreateArangodPod(kubecli kubernetes.Interface, developmentMode bool, deployment APIObject, role, id, pvcName, image string, imagePullPolicy v1.PullPolicy,
129+
args []string, env map[string]string, livenessProbe *HTTPProbeConfig, readinessProbe *HTTPProbeConfig) error {
130130
// Prepare basic pod
131131
p := newPod(deployment.GetName(), deployment.GetNamespace(), role, id)
132132

@@ -157,7 +157,10 @@ func CreateArangodPod(kubecli kubernetes.Interface, deployment metav1.Object, ro
157157
p.Spec.Volumes = append(p.Spec.Volumes, vol)
158158
}
159159

160-
if err := createPod(kubecli, &p, deployment.GetNamespace(), owner); err != nil {
160+
// Add (anti-)affinity
161+
p.Spec.Affinity = createAffinity(deployment.GetName(), role, !developmentMode, "")
162+
163+
if err := createPod(kubecli, &p, deployment.GetNamespace(), deployment.AsOwner()); err != nil {
161164
return maskAny(err)
162165
}
163166
return nil
@@ -166,16 +169,19 @@ func CreateArangodPod(kubecli kubernetes.Interface, deployment metav1.Object, ro
166169
// CreateArangoSyncPod creates a Pod that runs `arangosync`.
167170
// If the pod already exists, nil is returned.
168171
// If another error occurs, that error is returned.
169-
func CreateArangoSyncPod(kubecli kubernetes.Interface, deployment metav1.Object, role, id, image string, imagePullPolicy v1.PullPolicy,
170-
args []string, env map[string]string, livenessProbe *HTTPProbeConfig, owner metav1.OwnerReference) error {
172+
func CreateArangoSyncPod(kubecli kubernetes.Interface, developmentMode bool, deployment APIObject, role, id, image string, imagePullPolicy v1.PullPolicy,
173+
args []string, env map[string]string, livenessProbe *HTTPProbeConfig, affinityWithRole string) error {
171174
// Prepare basic pod
172175
p := newPod(deployment.GetName(), deployment.GetNamespace(), role, id)
173176

174177
// Add arangosync container
175178
c := arangosyncContainer(p.GetName(), image, imagePullPolicy, args, env, livenessProbe)
176179
p.Spec.Containers = append(p.Spec.Containers, c)
177180

178-
if err := createPod(kubecli, &p, deployment.GetNamespace(), owner); err != nil {
181+
// Add (anti-)affinity
182+
p.Spec.Affinity = createAffinity(deployment.GetName(), role, !developmentMode, affinityWithRole)
183+
184+
if err := createPod(kubecli, &p, deployment.GetNamespace(), deployment.AsOwner()); err != nil {
179185
return maskAny(err)
180186
}
181187
return nil

0 commit comments

Comments
 (0)