Skip to content

Commit

Permalink
feat: add option to generate headless services
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
aryan9600 committed Jan 14, 2025
1 parent ff4051f commit 45618b9
Show file tree
Hide file tree
Showing 7 changed files with 26 additions and 0 deletions.
3 changes: 3 additions & 0 deletions artifacts/flagger/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions charts/flagger/crds/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions docs/gitbook/usage/how-it-works.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ spec:
appProtocol: http
targetPort: 9898
portDiscovery: true
headless: false
```

The container port from the target workload should match the `service.port` or `service.targetPort`.
Expand All @@ -155,6 +156,7 @@ The `service.targetPort` can be a container port number or name.
The `service.portName` is optional (defaults to `http`), if your workload uses gRPC then set the port name to `grpc`.
The `service.appProtocol` is optional, more details can be found [here](https://kubernetes.io/docs/concepts/services-networking/service/#application-protocol).


If port discovery is enabled, Flagger scans the target workload and extracts the containers ports
excluding the port specified in the canary service and service mesh sidecar ports.
These ports will be used when generating the ClusterIP services.
Expand Down Expand Up @@ -204,6 +206,9 @@ Note that the `apex` annotations are added to both the generated Kubernetes Serv
generated service mesh/ingress object. This allows using external-dns with Istio `VirtualServices`
and `TraefikServices`. Beware of configuration conflicts [here](../faq.md#ExternalDNS).

If you want for the generated Kubernetes ClusterIP services to be [headless](https://kubernetes.io/docs/concepts/services-networking/service/#headless-services),
then set `service.headless` to true.

Besides port mapping and metadata, the service specification can
contain URI match and rewrite rules, timeout and retry polices:

Expand Down
3 changes: 3 additions & 0 deletions kustomize/base/flagger/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/flagger/v1beta1/canary.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down
3 changes: 3 additions & 0 deletions pkg/router/kubernetes_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions pkg/router/kubernetes_default_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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) {
Expand Down

0 comments on commit 45618b9

Please sign in to comment.