cmd/k8s-operator: allow specifying replicas for connectors (#16721)

This commit adds a `replicas` field to the `Connector` custom resource that
allows users to specify the number of desired replicas deployed for their
connectors.

This allows users to deploy exit nodes, subnet routers and app connectors
in a highly available fashion.

Fixes #14020

Signed-off-by: David Bond <davidsbond93@gmail.com>
This commit is contained in:
David Bond
2025-09-02 13:10:03 +01:00
committed by GitHub
parent d05e6dc09e
commit 12ad630128
13 changed files with 665 additions and 202 deletions

View File

@@ -115,9 +115,19 @@ spec:
Connector node. If unset, hostname defaults to <connector
name>-connector. Hostname can contain lower case letters, numbers and
dashes, it must not start or end with a dash and must be between 2
and 63 characters long.
and 63 characters long. This field should only be used when creating a connector
with an unspecified number of replicas, or a single replica.
type: string
pattern: ^[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$
hostnamePrefix:
description: |-
HostnamePrefix specifies the hostname prefix for each
replica. Each device will have the integer number
from its StatefulSet pod appended to this prefix to form the full hostname.
HostnamePrefix can contain lower case letters, numbers and dashes, it
must not start with a dash and must be between 1 and 62 characters long.
type: string
pattern: ^[a-z0-9][a-z0-9-]{0,61}$
proxyClass:
description: |-
ProxyClass is the name of the ProxyClass custom resource that
@@ -125,6 +135,14 @@ spec:
resources created for this Connector. If unset, the operator will
create resources with the default configuration.
type: string
replicas:
description: |-
Replicas specifies how many devices to create. Set this to enable
high availability for app connectors, subnet routers, or exit nodes.
https://tailscale.com/kb/1115/high-availability. Defaults to 1.
type: integer
format: int32
minimum: 0
subnetRouter:
description: |-
SubnetRouter defines subnet routes that the Connector device should
@@ -168,6 +186,10 @@ spec:
message: A Connector needs to have at least one of exit node, subnet router or app connector configured.
- rule: '!((has(self.subnetRouter) || (has(self.exitNode) && self.exitNode == true)) && has(self.appConnector))'
message: The appConnector field is mutually exclusive with exitNode and subnetRouter fields.
- rule: '!(has(self.hostname) && has(self.replicas) && self.replicas > 1)'
message: The hostname field cannot be specified when replicas is greater than 1.
- rule: '!(has(self.hostname) && has(self.hostnamePrefix))'
message: The hostname and hostnamePrefix fields are mutually exclusive.
status:
description: |-
ConnectorStatus describes the status of the Connector. This is set
@@ -235,11 +257,32 @@ spec:
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
devices:
description: Devices contains information on each device managed by the Connector resource.
type: array
items:
type: object
properties:
hostname:
description: |-
Hostname is the fully qualified domain name of the Connector replica.
If MagicDNS is enabled in your tailnet, it is the MagicDNS name of the
node.
type: string
tailnetIPs:
description: |-
TailnetIPs is the set of tailnet IP addresses (both IPv4 and IPv6)
assigned to the Connector replica.
type: array
items:
type: string
hostname:
description: |-
Hostname is the fully qualified domain name of the Connector node.
If MagicDNS is enabled in your tailnet, it is the MagicDNS name of the
node.
node. When using multiple replicas, this field will be populated with the
first replica's hostname. Use the Hostnames field for the full list
of hostnames.
type: string
isAppConnector:
description: IsAppConnector is set to true if the Connector acts as an app connector.

View File

@@ -140,9 +140,19 @@ spec:
Connector node. If unset, hostname defaults to <connector
name>-connector. Hostname can contain lower case letters, numbers and
dashes, it must not start or end with a dash and must be between 2
and 63 characters long.
and 63 characters long. This field should only be used when creating a connector
with an unspecified number of replicas, or a single replica.
pattern: ^[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$
type: string
hostnamePrefix:
description: |-
HostnamePrefix specifies the hostname prefix for each
replica. Each device will have the integer number
from its StatefulSet pod appended to this prefix to form the full hostname.
HostnamePrefix can contain lower case letters, numbers and dashes, it
must not start with a dash and must be between 1 and 62 characters long.
pattern: ^[a-z0-9][a-z0-9-]{0,61}$
type: string
proxyClass:
description: |-
ProxyClass is the name of the ProxyClass custom resource that
@@ -150,6 +160,14 @@ spec:
resources created for this Connector. If unset, the operator will
create resources with the default configuration.
type: string
replicas:
description: |-
Replicas specifies how many devices to create. Set this to enable
high availability for app connectors, subnet routers, or exit nodes.
https://tailscale.com/kb/1115/high-availability. Defaults to 1.
format: int32
minimum: 0
type: integer
subnetRouter:
description: |-
SubnetRouter defines subnet routes that the Connector device should
@@ -194,6 +212,10 @@ spec:
rule: has(self.subnetRouter) || (has(self.exitNode) && self.exitNode == true) || has(self.appConnector)
- message: The appConnector field is mutually exclusive with exitNode and subnetRouter fields.
rule: '!((has(self.subnetRouter) || (has(self.exitNode) && self.exitNode == true)) && has(self.appConnector))'
- message: The hostname field cannot be specified when replicas is greater than 1.
rule: '!(has(self.hostname) && has(self.replicas) && self.replicas > 1)'
- message: The hostname and hostnamePrefix fields are mutually exclusive.
rule: '!(has(self.hostname) && has(self.hostnamePrefix))'
status:
description: |-
ConnectorStatus describes the status of the Connector. This is set
@@ -260,11 +282,32 @@ spec:
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
devices:
description: Devices contains information on each device managed by the Connector resource.
items:
properties:
hostname:
description: |-
Hostname is the fully qualified domain name of the Connector replica.
If MagicDNS is enabled in your tailnet, it is the MagicDNS name of the
node.
type: string
tailnetIPs:
description: |-
TailnetIPs is the set of tailnet IP addresses (both IPv4 and IPv6)
assigned to the Connector replica.
items:
type: string
type: array
type: object
type: array
hostname:
description: |-
Hostname is the fully qualified domain name of the Connector node.
If MagicDNS is enabled in your tailnet, it is the MagicDNS name of the
node.
node. When using multiple replicas, this field will be populated with the
first replica's hostname. Use the Hostnames field for the full list
of hostnames.
type: string
isAppConnector:
description: IsAppConnector is set to true if the Connector acts as an app connector.