Skip to content

Commit c20bdce

Browse files
Support specifying externalTrafficPolicy in Services created by listener-operator (#773)
* Support specifying externalTrafficPolicy in Services created by listener-operator * Update crates/stackable-operator/src/commons/listener.rs Co-authored-by: Nick <[email protected]> * Use strum::Display * changelog * add newlines * Remove KubernetesTrafficPolicy::default(), switch to serde(default) * changelog * Use serde(default) * Impl Default for ListenerSpec again * typo * fix changelog * docs: Improve wording * Move default into ListenerSpec::default_service_external_traffic_policy --------- Co-authored-by: Nick <[email protected]>
1 parent c9ce606 commit c20bdce

File tree

3 files changed

+49
-5
lines changed

3 files changed

+49
-5
lines changed

crates/stackable-operator/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
44

55
## [Unreleased]
66

7+
- Support specifying externalTrafficPolicy in Services created by listener-operator ([#773]).
8+
- BREAKING: Rename `commons::listener::ServiceType` to `commons::listener::KubernetesServiceType` ([#773]).
9+
10+
[#773]: https://github.com/stackabletech/operator-rs/pull/773
11+
712
## [0.67.1] - 2024-05-08
813

914
### Added

crates/stackable-operator/src/cluster_resources.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::{
44
client::{Client, GetApi},
55
commons::{
66
cluster_operation::ClusterOperation,
7+
listener::Listener,
78
resources::{
89
ComputeResource, ResourceRequirementsExt, ResourceRequirementsType,
910
LIMIT_REQUEST_RATIO_CPU, LIMIT_REQUEST_RATIO_MEMORY,
@@ -203,6 +204,7 @@ impl ClusterResource for Service {}
203204
impl ClusterResource for ServiceAccount {}
204205
impl ClusterResource for RoleBinding {}
205206
impl ClusterResource for PodDisruptionBudget {}
207+
impl ClusterResource for Listener {}
206208

207209
impl ClusterResource for Job {
208210
fn pod_spec(&self) -> Option<&PodSpec> {
@@ -612,6 +614,7 @@ impl ClusterResources {
612614
self.delete_orphaned_resources_of_kind::<ServiceAccount>(client),
613615
self.delete_orphaned_resources_of_kind::<RoleBinding>(client),
614616
self.delete_orphaned_resources_of_kind::<PodDisruptionBudget>(client),
617+
self.delete_orphaned_resources_of_kind::<Listener>(client),
615618
)?;
616619

617620
Ok(())

crates/stackable-operator/src/commons/listener.rs

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
2828
use std::collections::BTreeMap;
2929

30+
use derivative::Derivative;
3031
use kube::CustomResource;
3132
use schemars::JsonSchema;
3233
use serde::{Deserialize, Serialize};
@@ -50,24 +51,45 @@ use crate::builder::pod::volume::ListenerOperatorVolumeSourceBuilder;
5051
)]
5152
#[serde(rename_all = "camelCase")]
5253
pub struct ListenerClassSpec {
53-
pub service_type: ServiceType,
54+
pub service_type: KubernetesServiceType,
5455

5556
/// Annotations that should be added to the Service object.
5657
#[serde(default)]
5758
pub service_annotations: BTreeMap<String, String>,
5859
}
5960

6061
/// The method used to access the services.
61-
#[derive(Serialize, Deserialize, Clone, Copy, Debug, JsonSchema, PartialEq, Eq)]
62-
pub enum ServiceType {
62+
//
63+
// Please note that this represents a Kubernetes type, so the name of the enum variant needs to exactly match the
64+
// Kubernetes service type.
65+
#[derive(Serialize, Deserialize, Clone, Copy, Debug, JsonSchema, PartialEq, Eq, strum::Display)]
66+
pub enum KubernetesServiceType {
6367
/// Reserve a port on each node.
6468
NodePort,
69+
6570
/// Provision a dedicated load balancer.
6671
LoadBalancer,
72+
6773
/// Assigns an IP address from a pool of IP addresses that your cluster has reserved for that purpose.
6874
ClusterIP,
6975
}
7076

77+
/// Service Internal Traffic Policy enables internal traffic restrictions to only route internal traffic to endpoints
78+
/// within the node the traffic originated from. The "internal" traffic here refers to traffic originated from Pods in
79+
/// the current cluster. This can help to reduce costs and improve performance.
80+
/// See [Kubernetes docs](https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/).
81+
//
82+
// Please note that this represents a Kubernetes type, so the name of the enum variant needs to exactly match the
83+
// Kubernetes traffic policy.
84+
#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, PartialEq, Eq, strum::Display)]
85+
pub enum KubernetesTrafficPolicy {
86+
/// Obscures the client source IP and may cause a second hop to another node, but allows Kubernetes to spread the load between all nodes.
87+
Cluster,
88+
89+
/// Preserves the client source IP and avoid a second hop for LoadBalancer and NodePort type Services, but makes clients responsible for spreading the load.
90+
Local,
91+
}
92+
7193
/// Exposes a set of pods to the outside world.
7294
///
7395
/// Essentially a Stackable extension of a Kubernetes Service. Compared to a Service, a Listener changes three things:
@@ -78,8 +100,9 @@ pub enum ServiceType {
78100
///
79101
/// Learn more in the [Listener documentation](DOCS_BASE_URL_PLACEHOLDER/listener-operator/listener).
80102
#[derive(
81-
CustomResource, Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq,
103+
CustomResource, Serialize, Deserialize, Clone, Debug, JsonSchema, PartialEq, Eq, Derivative,
82104
)]
105+
#[derivative(Default)]
83106
#[kube(
84107
group = "listeners.stackable.tech",
85108
version = "v1alpha1",
@@ -100,14 +123,27 @@ pub struct ListenerSpec {
100123
pub ports: Option<Vec<ListenerPort>>,
101124

102125
/// Whether incoming traffic should also be directed to Pods that are not `Ready`.
103-
#[schemars(default = "Self::default_publish_not_ready_addresses")]
126+
#[serde(default = "ListenerSpec::default_publish_not_ready_addresses")]
104127
pub publish_not_ready_addresses: Option<bool>,
128+
129+
/// `externalTrafficPolicy` that should be set on the [`Service`] object.
130+
///
131+
/// The default is `Local` (in contrast to `Cluster`), as we aim to direct traffic to a node running the workload
132+
/// and we should keep testing that as the primary configuration. Cluster is a fallback option for providers that
133+
/// break Local mode (IONOS so far).
134+
#[derivative(Default(value = "ListenerSpec::default_service_external_traffic_policy()"))]
135+
#[serde(default = "ListenerSpec::default_service_external_traffic_policy")]
136+
pub service_external_traffic_policy: KubernetesTrafficPolicy,
105137
}
106138

107139
impl ListenerSpec {
108140
const fn default_publish_not_ready_addresses() -> Option<bool> {
109141
Some(true)
110142
}
143+
144+
const fn default_service_external_traffic_policy() -> KubernetesTrafficPolicy {
145+
KubernetesTrafficPolicy::Local
146+
}
111147
}
112148

113149
#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, PartialEq, Eq)]

0 commit comments

Comments
 (0)