Signed-off-by: Irbe Krumina <irbe@tailscale.com>
This commit is contained in:
Irbe Krumina 2025-05-15 16:11:48 +01:00
parent 824985afe1
commit 9e76b22414
6 changed files with 166 additions and 1 deletions

View File

@ -2203,6 +2203,25 @@ spec:
won't make it *more* imbalanced. won't make it *more* imbalanced.
It's a required field. It's a required field.
type: string type: string
tailnetListener:
type: object
required:
- type
properties:
nodePortConfig:
type: object
properties:
portRanges:
type: array
items:
type: string
selector:
type: object
additionalProperties:
type: string
type:
description: Cannot change after creation
type: string
tailscale: tailscale:
description: |- description: |-
TailscaleConfig contains options to configure the tailscale-specific TailscaleConfig contains options to configure the tailscale-specific

View File

@ -2679,6 +2679,25 @@ spec:
type: array type: array
type: object type: object
type: object type: object
tailnetListener:
properties:
nodePortConfig:
properties:
portRanges:
items:
type: string
type: array
selector:
additionalProperties:
type: string
type: object
type: object
type:
description: Cannot change after creation
type: string
required:
- type
type: object
tailscale: tailscale:
description: |- description: |-
TailscaleConfig contains options to configure the tailscale-specific TailscaleConfig contains options to configure the tailscale-specific

View File

@ -206,6 +206,20 @@ func (r *ProxyGroupReconciler) Reconcile(ctx context.Context, req reconcile.Requ
return setStatusReady(pg, metav1.ConditionTrue, reasonProxyGroupReady, reasonProxyGroupReady) return setStatusReady(pg, metav1.ConditionTrue, reasonProxyGroupReady, reasonProxyGroupReady)
} }
func (r *ProxyGroupReconciler) maybeExposeViaNodePort(ctx context.Context, pc *tsapi.ProxyClass, pg *tsapi.ProxyGroup) error {
// TODO: make NodePort a const
if pc == nil || pc.Spec.TailnetListenerConfig == nil || pc.Spec.TailnetListenerConfig.Type != "NodePort" {
return nil
}
// 1. Create a NodePort Service per each replica
// TODO: support setting NodePort range
for i := range *(pg.Spec.Replicas) {
}
return nil
}
// validateProxyClassForPG applies custom validation logic for ProxyClass applied to ProxyGroup. // validateProxyClassForPG applies custom validation logic for ProxyClass applied to ProxyGroup.
func validateProxyClassForPG(logger *zap.SugaredLogger, pg *tsapi.ProxyGroup, pc *tsapi.ProxyClass) { func validateProxyClassForPG(logger *zap.SugaredLogger, pg *tsapi.ProxyGroup, pc *tsapi.ProxyClass) {
if pg.Spec.Type == tsapi.ProxyGroupTypeIngress { if pg.Spec.Type == tsapi.ProxyGroupTypeIngress {

View File

@ -425,6 +425,23 @@ _Appears in:_
| `ip` _string_ | IP is the ClusterIP of the Service fronting the deployed ts.net nameserver.<br />Currently you must manually update your cluster DNS config to add<br />this address as a stub nameserver for ts.net for cluster workloads to be<br />able to resolve MagicDNS names associated with egress or Ingress<br />proxies.<br />The IP address will change if you delete and recreate the DNSConfig. | | | | `ip` _string_ | IP is the ClusterIP of the Service fronting the deployed ts.net nameserver.<br />Currently you must manually update your cluster DNS config to add<br />this address as a stub nameserver for ts.net for cluster workloads to be<br />able to resolve MagicDNS names associated with egress or Ingress<br />proxies.<br />The IP address will change if you delete and recreate the DNSConfig. | | |
#### NodePort
_Appears in:_
- [TailnetListenerConfig](#tailnetlistenerconfig)
| Field | Description | Default | Validation |
| --- | --- | --- | --- |
| `portRanges` _string array_ | | | |
| `selector` _object (keys:string, values:string)_ | | | |
#### Pod #### Pod
@ -518,6 +535,7 @@ _Appears in:_
| `metrics` _[Metrics](#metrics)_ | Configuration for proxy metrics. Metrics are currently not supported<br />for egress proxies and for Ingress proxies that have been configured<br />with tailscale.com/experimental-forward-cluster-traffic-via-ingress<br />annotation. Note that the metrics are currently considered unstable<br />and will likely change in breaking ways in the future - we only<br />recommend that you use those for debugging purposes. | | | | `metrics` _[Metrics](#metrics)_ | Configuration for proxy metrics. Metrics are currently not supported<br />for egress proxies and for Ingress proxies that have been configured<br />with tailscale.com/experimental-forward-cluster-traffic-via-ingress<br />annotation. Note that the metrics are currently considered unstable<br />and will likely change in breaking ways in the future - we only<br />recommend that you use those for debugging purposes. | | |
| `tailscale` _[TailscaleConfig](#tailscaleconfig)_ | TailscaleConfig contains options to configure the tailscale-specific<br />parameters of proxies. | | | | `tailscale` _[TailscaleConfig](#tailscaleconfig)_ | TailscaleConfig contains options to configure the tailscale-specific<br />parameters of proxies. | | |
| `useLetsEncryptStagingEnvironment` _boolean_ | Set UseLetsEncryptStagingEnvironment to true to issue TLS<br />certificates for any HTTPS endpoints exposed to the tailnet from<br />LetsEncrypt's staging environment.<br />https://letsencrypt.org/docs/staging-environment/<br />This setting only affects Tailscale Ingress resources.<br />By default Ingress TLS certificates are issued from LetsEncrypt's<br />production environment.<br />Changing this setting true -> false, will result in any<br />existing certs being re-issued from the production environment.<br />Changing this setting false (default) -> true, when certs have already<br />been provisioned from production environment will NOT result in certs<br />being re-issued from the staging environment before they need to be<br />renewed. | | | | `useLetsEncryptStagingEnvironment` _boolean_ | Set UseLetsEncryptStagingEnvironment to true to issue TLS<br />certificates for any HTTPS endpoints exposed to the tailnet from<br />LetsEncrypt's staging environment.<br />https://letsencrypt.org/docs/staging-environment/<br />This setting only affects Tailscale Ingress resources.<br />By default Ingress TLS certificates are issued from LetsEncrypt's<br />production environment.<br />Changing this setting true -> false, will result in any<br />existing certs being re-issued from the production environment.<br />Changing this setting false (default) -> true, when certs have already<br />been provisioned from production environment will NOT result in certs<br />being re-issued from the staging environment before they need to be<br />renewed. | | |
| `tailnetListener` _[TailnetListenerConfig](#tailnetlistenerconfig)_ | | | |
#### ProxyClassStatus #### ProxyClassStatus
@ -999,6 +1017,36 @@ _Appears in:_
| `tailnetIPs` _string array_ | TailnetIPs is the set of tailnet IP addresses (both IPv4 and IPv6)<br />assigned to the device. | | | | `tailnetIPs` _string array_ | TailnetIPs is the set of tailnet IP addresses (both IPv4 and IPv6)<br />assigned to the device. | | |
#### TailnetListenerConfig
_Appears in:_
- [ProxyClassSpec](#proxyclassspec)
| Field | Description | Default | Validation |
| --- | --- | --- | --- |
| `type` _[TailnetListenerConfigMode](#tailnetlistenerconfigmode)_ | Cannot change after creation | | |
| `nodePortConfig` _[NodePort](#nodeport)_ | | | |
#### TailnetListenerConfigMode
_Underlying type:_ _string_
_Appears in:_
- [TailnetListenerConfig](#tailnetlistenerconfig)
#### TailscaleConfig #### TailscaleConfig

View File

@ -81,7 +81,20 @@ type ProxyClassSpec struct {
// being re-issued from the staging environment before they need to be // being re-issued from the staging environment before they need to be
// renewed. // renewed.
// +optional // +optional
UseLetsEncryptStagingEnvironment bool `json:"useLetsEncryptStagingEnvironment,omitempty"` UseLetsEncryptStagingEnvironment bool `json:"useLetsEncryptStagingEnvironment,omitempty"`
TailnetListenerConfig *TailnetListenerConfig `json:"tailnetListener,omitempty"`
}
type TailnetListenerConfig struct {
// Cannot change after creation
Type TailnetListenerConfigMode `json:"type"`
NodePortConfig *NodePort `json:"nodePortConfig,omitempty"`
}
type TailnetListenerConfigMode string
type NodePort struct {
PortRanges []string `json:"portRanges,omitempty"`
Selector map[string]string `json:"selector,omitempty"`
} }
type TailscaleConfig struct { type TailscaleConfig struct {

View File

@ -407,6 +407,33 @@ func (in *NameserverStatus) DeepCopy() *NameserverStatus {
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NodePort) DeepCopyInto(out *NodePort) {
*out = *in
if in.PortRanges != nil {
in, out := &in.PortRanges, &out.PortRanges
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Selector != nil {
in, out := &in.Selector, &out.Selector
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodePort.
func (in *NodePort) DeepCopy() *NodePort {
if in == nil {
return nil
}
out := new(NodePort)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Pod) DeepCopyInto(out *Pod) { func (in *Pod) DeepCopyInto(out *Pod) {
*out = *in *out = *in
@ -559,6 +586,11 @@ func (in *ProxyClassSpec) DeepCopyInto(out *ProxyClassSpec) {
*out = new(TailscaleConfig) *out = new(TailscaleConfig)
**out = **in **out = **in
} }
if in.TailnetListenerConfig != nil {
in, out := &in.TailnetListenerConfig, &out.TailnetListenerConfig
*out = new(TailnetListenerConfig)
(*in).DeepCopyInto(*out)
}
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyClassSpec. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyClassSpec.
@ -1152,6 +1184,26 @@ func (in *TailnetDevice) DeepCopy() *TailnetDevice {
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TailnetListenerConfig) DeepCopyInto(out *TailnetListenerConfig) {
*out = *in
if in.NodePortConfig != nil {
in, out := &in.NodePortConfig, &out.NodePortConfig
*out = new(NodePort)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TailnetListenerConfig.
func (in *TailnetListenerConfig) DeepCopy() *TailnetListenerConfig {
if in == nil {
return nil
}
out := new(TailnetListenerConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TailscaleConfig) DeepCopyInto(out *TailscaleConfig) { func (in *TailscaleConfig) DeepCopyInto(out *TailscaleConfig) {
*out = *in *out = *in