Skip to content

Commit

Permalink
Allow exposing ovn DB using a k8s service
Browse files Browse the repository at this point in the history
Using multus to attach the ovn db pods to the networks
that the edpm nodes can access it won't work for BGP. A
loadbalancer service, like metallb, could be used in this case.

This introduces service override to the ovndbcluster, like we
have for other services which use a LB service to expose them
to the outside. Adding the AnnotationHostnameKey annotation
the service hostname gets automatic registered in the DNS instance.

In general this could replace all the current implementation of
attaching the ovn db pods using multus, creating the headless
service and creating the dnsdata to register it in dns. For
update/backward compatability this is kept as if if no service
override is provided.

To expose the ovndbcluster-sb via a metallb loadbalancer would
look like:

```
  ovn:
    enabled: true
    template:
      ...
      ovnDBCluster:
        ovndbcluster-nb:
	  ...
        ovndbcluster-sb:
          dbType: SB
	  ...
          override:
            service:
              metadata:
                annotations:
                  metallb.universe.tf/address-pool: internalapi
                  metallb.universe.tf/allow-shared-ip: internalapi
                  metallb.universe.tf/loadBalancerIPs: 172.17.0.80
              spec:
                type: LoadBalancer
      ovnNorthd:
        ...
```

Jira: OSPRH-651

Signed-off-by: Martin Schuppert <[email protected]>
  • Loading branch information
stuggi committed Nov 6, 2024
1 parent a1bccc7 commit a7d6881
Show file tree
Hide file tree
Showing 7 changed files with 750 additions and 22 deletions.
164 changes: 164 additions & 0 deletions api/bases/ovn.openstack.org_ovndbclusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,170 @@ spec:
description: NodeSelector to target subset of worker nodes running
this service
type: object
override:
description: Override, provides the ability to override the generated
manifest of several child resources.
properties:
service:
description: Override configuration for the Service created to
serve traffic to the cluster.
properties:
metadata:
description: EmbeddedLabelsAnnotations is an embedded subset
of the fields included in k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta.
Only labels and annotations are included.
properties:
annotations:
additionalProperties:
type: string
description: 'Annotations is an unstructured key value
map stored with a resource that may be set by external
tools to store and retrieve arbitrary metadata. They
are not queryable and should be preserved when modifying
objects. More info: http://kubernetes.io/docs/user-guide/annotations'
type: object
labels:
additionalProperties:
type: string
description: 'Map of string keys and values that can be
used to organize and categorize (scope and select) objects.
May match selectors of replication controllers and services.
More info: http://kubernetes.io/docs/user-guide/labels'
type: object
type: object
spec:
description: OverrideServiceSpec is a subset of the fields
included in https://pkg.go.dev/k8s.io/[email protected]/core/v1#ServiceSpec
Limited to Type, SessionAffinity, LoadBalancerSourceRanges,
ExternalName, ExternalTrafficPolicy, SessionAffinityConfig,
IPFamilyPolicy, LoadBalancerClass and InternalTrafficPolicy
properties:
externalName:
description: externalName is the external reference that
discovery mechanisms will return as an alias for this
service (e.g. a DNS CNAME record). No proxying will
be involved. Must be a lowercase RFC-1123 hostname
(https://tools.ietf.org/html/rfc1123) and requires `type`
to be "ExternalName".
type: string
externalTrafficPolicy:
description: externalTrafficPolicy describes how nodes
distribute service traffic they receive on one of the
Service's "externally-facing" addresses (NodePorts,
ExternalIPs, and LoadBalancer IPs). If set to "Local",
the proxy will configure the service in a way that assumes
that external load balancers will take care of balancing
the service traffic between nodes, and so each node
will deliver traffic only to the node-local endpoints
of the service, without masquerading the client source
IP. (Traffic mistakenly sent to a node with no endpoints
will be dropped.) The default value, "Cluster", uses
the standard behavior of routing to all endpoints evenly
(possibly modified by topology and other features).
Note that traffic sent to an External IP or LoadBalancer
IP from within the cluster will always get "Cluster"
semantics, but clients sending to a NodePort from within
the cluster may need to take traffic policy into account
when picking a node.
type: string
internalTrafficPolicy:
description: InternalTrafficPolicy describes how nodes
distribute service traffic they receive on the ClusterIP.
If set to "Local", the proxy will assume that pods only
want to talk to endpoints of the service on the same
node as the pod, dropping the traffic if there are no
local endpoints. The default value, "Cluster", uses
the standard behavior of routing to all endpoints evenly
(possibly modified by topology and other features).
type: string
ipFamilyPolicy:
description: IPFamilyPolicy represents the dual-stack-ness
requested or required by this Service. If there is no
value provided, then this field will be set to SingleStack.
Services can be "SingleStack" (a single IP family),
"PreferDualStack" (two IP families on dual-stack configured
clusters or a single IP family on single-stack clusters),
or "RequireDualStack" (two IP families on dual-stack
configured clusters, otherwise fail). The ipFamilies
and clusterIPs fields depend on the value of this field.
This field will be wiped when updating a service to
type ExternalName.
type: string
loadBalancerClass:
description: loadBalancerClass is the class of the load
balancer implementation this Service belongs to. If
specified, the value of this field must be a label-style
identifier, with an optional prefix, e.g. "internal-vip"
or "example.com/internal-vip". Unprefixed names are
reserved for end-users. This field can only be set when
the Service type is 'LoadBalancer'. If not set, the
default load balancer implementation is used, today
this is typically done through the cloud provider integration,
but should apply for any default implementation. If
set, it is assumed that a load balancer implementation
is watching for Services with a matching class. Any
default load balancer implementation (e.g. cloud providers)
should ignore Services that set this field. This field
can only be set when creating or updating a Service
to type 'LoadBalancer'. Once set, it can not be changed.
This field will be wiped when a service is updated to
a non 'LoadBalancer' type.
type: string
loadBalancerSourceRanges:
description: 'If specified and supported by the platform,
this will restrict traffic through the cloud-provider
load-balancer will be restricted to the specified client
IPs. This field will be ignored if the cloud-provider
does not support the feature." More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/'
items:
type: string
type: array
sessionAffinity:
description: 'Supports "ClientIP" and "None". Used to
maintain session affinity. Enable client IP based session
affinity. Must be ClientIP or None. Defaults to None.
More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies'
type: string
sessionAffinityConfig:
description: sessionAffinityConfig contains the configurations
of session affinity.
properties:
clientIP:
description: clientIP contains the configurations
of Client IP based session affinity.
properties:
timeoutSeconds:
description: timeoutSeconds specifies the seconds
of ClientIP type session sticky time. The value
must be >0 && <=86400(for 1 day) if ServiceAffinity
== "ClientIP". Default value is 10800(for 3
hours).
format: int32
type: integer
type: object
type: object
type:
description: 'type determines how the Service is exposed.
Defaults to ClusterIP. Valid options are ExternalName,
ClusterIP, NodePort, and LoadBalancer. "ClusterIP" allocates
a cluster-internal IP address for load-balancing to
endpoints. Endpoints are determined by the selector
or if that is not specified, by manual construction
of an Endpoints object or EndpointSlice objects. If
clusterIP is "None", no virtual IP is allocated and
the endpoints are published as a set of endpoints rather
than a virtual IP. "NodePort" builds on ClusterIP and
allocates a port on every node which routes to the same
endpoints as the clusterIP. "LoadBalancer" builds on
NodePort and creates an external load-balancer (if supported
in the current cloud) which routes to the same endpoints
as the clusterIP. "ExternalName" aliases this service
to the specified externalName. Several other fields
do not apply to ExternalName services. More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types'
type: string
type: object
type: object
type: object
probeIntervalToActive:
default: 60000
description: Active probe interval from standby to active ovsdb-server
Expand Down
13 changes: 12 additions & 1 deletion api/v1beta1/ovndbcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"

"github.com/openstack-k8s-operators/lib-common/modules/common/condition"
"github.com/openstack-k8s-operators/lib-common/modules/common/service"
"github.com/openstack-k8s-operators/lib-common/modules/common/tls"

corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -122,6 +123,16 @@ type OVNDBClusterSpecCore struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec
// TLS - Parameters related to TLS
TLS tls.SimpleService `json:"tls,omitempty"`

// +kubebuilder:validation:Optional
// Override, provides the ability to override the generated manifest of several child resources.
Override OVNDBClusterOverrideSpec `json:"override,omitempty"`
}

// OVNDBClusterOverrideSpec to override the generated manifest of several child resources.
type OVNDBClusterOverrideSpec struct {
// Override configuration for the Service created to serve traffic to the cluster.
Service *service.OverrideSpec `json:"service,omitempty"`
}

// OVNDBClusterStatus defines the observed state of OVNDBCluster
Expand Down Expand Up @@ -208,7 +219,7 @@ func (instance OVNDBCluster) GetInternalEndpoint() (string, error) {

// GetExternalEndpoint - return the DNS that openstack dnsmasq can resolve
func (instance OVNDBCluster) GetExternalEndpoint() (string, error) {
if instance.Spec.NetworkAttachment != "" && instance.Status.DBAddress == "" {
if (instance.Spec.NetworkAttachment != "" || instance.Spec.Override.Service != nil) && instance.Status.DBAddress == "" {
return "", fmt.Errorf("external DBEndpoint not ready yet for %s", instance.Spec.DBType)
}
return instance.Status.DBAddress, nil
Expand Down
22 changes: 22 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit a7d6881

Please sign in to comment.