From e750a66b9637e5bc55c094d44fb895b42f0540a9 Mon Sep 17 00:00:00 2001 From: Sanskar Jaiswal Date: Tue, 14 Jan 2025 00:15:52 +0530 Subject: [PATCH] feat: add option to generate headless services Add a new field `.spec.service.headless` which if set to true results in Flagger generating headless Services, i.e. with the Service's `.spec.clusterIP` set to None. Signed-off-by: Sanskar Jaiswal --- artifacts/flagger/crd.yaml | 3 +++ charts/flagger/crds/crd.yaml | 3 +++ kustomize/base/flagger/crd.yaml | 3 +++ pkg/apis/flagger/v1beta1/canary.go | 5 +++++ pkg/router/kubernetes_default.go | 3 +++ pkg/router/kubernetes_default_test.go | 4 ++++ 6 files changed, 21 insertions(+) diff --git a/artifacts/flagger/crd.yaml b/artifacts/flagger/crd.yaml index 145eda608..acc07dcad 100644 --- a/artifacts/flagger/crd.yaml +++ b/artifacts/flagger/crd.yaml @@ -198,6 +198,9 @@ spec: portDiscovery: description: Enable port dicovery type: boolean + headless: + description: Headless if set to true, generates headless Kubernetes services. + type: boolean timeout: description: HTTP or gRPC request timeout type: string diff --git a/charts/flagger/crds/crd.yaml b/charts/flagger/crds/crd.yaml index 145eda608..acc07dcad 100644 --- a/charts/flagger/crds/crd.yaml +++ b/charts/flagger/crds/crd.yaml @@ -198,6 +198,9 @@ spec: portDiscovery: description: Enable port dicovery type: boolean + headless: + description: Headless if set to true, generates headless Kubernetes services. + type: boolean timeout: description: HTTP or gRPC request timeout type: string diff --git a/kustomize/base/flagger/crd.yaml b/kustomize/base/flagger/crd.yaml index 145eda608..acc07dcad 100644 --- a/kustomize/base/flagger/crd.yaml +++ b/kustomize/base/flagger/crd.yaml @@ -198,6 +198,9 @@ spec: portDiscovery: description: Enable port dicovery type: boolean + headless: + description: Headless if set to true, generates headless Kubernetes services. + type: boolean timeout: description: HTTP or gRPC request timeout type: string diff --git a/pkg/apis/flagger/v1beta1/canary.go b/pkg/apis/flagger/v1beta1/canary.go index f5797e876..5c92cbac2 100644 --- a/pkg/apis/flagger/v1beta1/canary.go +++ b/pkg/apis/flagger/v1beta1/canary.go @@ -146,6 +146,11 @@ type CanaryService struct { // PortDiscovery adds all container ports to the generated Kubernetes service PortDiscovery bool `json:"portDiscovery"` + // Headless if set to true, generates headless Kubernetes services. + // ref: https://kubernetes.io/docs/concepts/services-networking/service/#headless-services + // +optional + Headless bool `json:"headless,omitempty"` + // Timeout of the HTTP or gRPC request // +optional Timeout string `json:"timeout,omitempty"` diff --git a/pkg/router/kubernetes_default.go b/pkg/router/kubernetes_default.go index 840005672..184b62331 100644 --- a/pkg/router/kubernetes_default.go +++ b/pkg/router/kubernetes_default.go @@ -113,6 +113,9 @@ func (c *KubernetesDefaultRouter) reconcileService(canary *flaggerv1.Canary, nam }, }, } + if canary.Spec.Service.Headless { + svcSpec.ClusterIP = "None" + } if v := canary.Spec.Service.AppProtocol; v != "" { svcSpec.Ports[0].AppProtocol = &v diff --git a/pkg/router/kubernetes_default_test.go b/pkg/router/kubernetes_default_test.go index c0f969958..b428c4a99 100644 --- a/pkg/router/kubernetes_default_test.go +++ b/pkg/router/kubernetes_default_test.go @@ -34,6 +34,8 @@ import ( func TestServiceRouter_Create(t *testing.T) { mocks := newFixture(nil) + mocks.canary.Spec.Service.Headless = true + router := &KubernetesDefaultRouter{ kubeClient: mocks.kubeClient, flaggerClient: mocks.flaggerClient, @@ -53,11 +55,13 @@ func TestServiceRouter_Create(t *testing.T) { assert.Equal(t, &appProtocol, canarySvc.Spec.Ports[0].AppProtocol) assert.Equal(t, "http", canarySvc.Spec.Ports[0].Name) assert.Equal(t, int32(9898), canarySvc.Spec.Ports[0].Port) + assert.Equal(t, "None", canarySvc.Spec.ClusterIP) primarySvc, err := mocks.kubeClient.CoreV1().Services("default").Get(context.TODO(), "podinfo-primary", metav1.GetOptions{}) require.NoError(t, err) assert.Equal(t, "http", primarySvc.Spec.Ports[0].Name) assert.Equal(t, int32(9898), primarySvc.Spec.Ports[0].Port) + assert.Equal(t, "None", primarySvc.Spec.ClusterIP) } func TestServiceRouter_Update(t *testing.T) {