[Operator] Use sticky web sessions for primary Gerrits
This change makes web sessions sticky, i.e. the ingress provider will
try to ensure that requests of one client always reach the same
pod. This is done by creating a cookie. Thus, this only works well
from browsers for now.
This should improve issues that can occur due to latencies caused by
NFS.
Change-Id: Idcdb17e7449a8bf2a238351484b7622538988882
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ingress/dependent/GerritClusterIngress.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ingress/dependent/GerritClusterIngress.java
index fc879ac..04102d8 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/network/ingress/dependent/GerritClusterIngress.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/ingress/dependent/GerritClusterIngress.java
@@ -14,6 +14,8 @@
package com.google.gerrit.k8s.operator.network.ingress.dependent;
+import static com.google.gerrit.k8s.operator.network.model.GerritNetwork.SESSION_COOKIE_NAME;
+
import com.google.gerrit.k8s.operator.cluster.model.GerritCluster;
import com.google.gerrit.k8s.operator.gerrit.dependent.GerritService;
import com.google.gerrit.k8s.operator.network.model.GerritNetwork;
@@ -86,6 +88,13 @@
"nginx.ingress.kubernetes.io/configuration-snippet",
createNginxConfigSnippet(gerritNetwork.getMetadata().getNamespace(), svcName));
}
+
+ annotations.put("nginx.ingress.kubernetes.io/affinity", "cookie");
+ annotations.put("nginx.ingress.kubernetes.io/session-cookie-name", SESSION_COOKIE_NAME);
+ annotations.put("nginx.ingress.kubernetes.io/session-cookie-path", "/");
+ annotations.put("nginx.ingress.kubernetes.io/session-cookie-max-age", "60");
+ annotations.put("nginx.ingress.kubernetes.io/session-cookie-expires", "60");
+
return annotations;
}
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritIstioDestinationRule.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritIstioDestinationRule.java
index c9a08e4..087719d 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritIstioDestinationRule.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/istio/dependent/GerritIstioDestinationRule.java
@@ -14,6 +14,9 @@
package com.google.gerrit.k8s.operator.network.istio.dependent;
+import static com.google.gerrit.k8s.operator.network.model.GerritNetwork.SESSION_COOKIE_NAME;
+import static com.google.gerrit.k8s.operator.network.model.GerritNetwork.SESSION_COOKIE_TTL;
+
import com.google.gerrit.k8s.operator.cluster.model.GerritCluster;
import com.google.gerrit.k8s.operator.gerrit.dependent.GerritService;
import com.google.gerrit.k8s.operator.gerrit.model.GerritTemplate;
@@ -21,6 +24,7 @@
import io.fabric8.istio.api.networking.v1beta1.DestinationRule;
import io.fabric8.istio.api.networking.v1beta1.DestinationRuleBuilder;
import io.fabric8.istio.api.networking.v1beta1.LoadBalancerSettingsSimpleLB;
+import io.fabric8.istio.api.networking.v1beta1.TrafficPolicy;
import io.fabric8.istio.api.networking.v1beta1.TrafficPolicyBuilder;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.dependent.Deleter;
@@ -45,7 +49,8 @@
super(DestinationRule.class);
}
- protected DestinationRule desired(GerritNetwork gerritNetwork, String gerritName) {
+ protected DestinationRule desired(
+ GerritNetwork gerritNetwork, String gerritName, boolean isReplica) {
return new DestinationRuleBuilder()
.withNewMetadata()
@@ -59,18 +64,37 @@
.endMetadata()
.withNewSpec()
.withHost(GerritService.getHostname(gerritName, gerritNetwork.getMetadata().getNamespace()))
- .withTrafficPolicy(
- new TrafficPolicyBuilder()
- .withNewLoadBalancer()
- .withNewLoadBalancerSettingsSimpleLbPolicy()
- .withSimple(LoadBalancerSettingsSimpleLB.LEAST_CONN)
- .endLoadBalancerSettingsSimpleLbPolicy()
- .endLoadBalancer()
- .build())
+ .withTrafficPolicy(getTrafficPolicy(isReplica))
.endSpec()
.build();
}
+ private TrafficPolicy getTrafficPolicy(boolean isReplica) {
+ if (isReplica) {
+ return new TrafficPolicyBuilder()
+ .withNewLoadBalancer()
+ .withNewLoadBalancerSettingsSimpleLbPolicy()
+ .withSimple(LoadBalancerSettingsSimpleLB.LEAST_CONN)
+ .endLoadBalancerSettingsSimpleLbPolicy()
+ .endLoadBalancer()
+ .build();
+ }
+ return new TrafficPolicyBuilder()
+ .withNewLoadBalancer()
+ .withNewLoadBalancerSettingsConsistentHashLbPolicy()
+ .withNewConsistentHash()
+ .withNewLoadBalancerSettingsConsistentHashLBHttpCookieKey()
+ .withNewHttpCookie()
+ .withName(SESSION_COOKIE_NAME)
+ .withTtl(SESSION_COOKIE_TTL)
+ .endHttpCookie()
+ .endLoadBalancerSettingsConsistentHashLBHttpCookieKey()
+ .endConsistentHash()
+ .endLoadBalancerSettingsConsistentHashLbPolicy()
+ .endLoadBalancer()
+ .build();
+ }
+
public static String getName(GerritTemplate gerrit) {
return gerrit.getMetadata().getName();
}
@@ -85,11 +109,11 @@
Map<String, DestinationRule> drs = new HashMap<>();
if (gerritNetwork.hasPrimaryGerrit()) {
String primaryGerritName = gerritNetwork.getSpec().getPrimaryGerrit().getName();
- drs.put(primaryGerritName, desired(gerritNetwork, primaryGerritName));
+ drs.put(primaryGerritName, desired(gerritNetwork, primaryGerritName, false));
}
if (gerritNetwork.hasGerritReplica()) {
String gerritReplicaName = gerritNetwork.getSpec().getGerritReplica().getName();
- drs.put(gerritReplicaName, desired(gerritNetwork, gerritReplicaName));
+ drs.put(gerritReplicaName, desired(gerritNetwork, gerritReplicaName, true));
}
return drs;
}
diff --git a/operator/src/main/java/com/google/gerrit/k8s/operator/network/model/GerritNetwork.java b/operator/src/main/java/com/google/gerrit/k8s/operator/network/model/GerritNetwork.java
index cc70a1e..c6e37dd 100644
--- a/operator/src/main/java/com/google/gerrit/k8s/operator/network/model/GerritNetwork.java
+++ b/operator/src/main/java/com/google/gerrit/k8s/operator/network/model/GerritNetwork.java
@@ -28,6 +28,9 @@
public class GerritNetwork extends CustomResource<GerritNetworkSpec, Status> implements Namespaced {
private static final long serialVersionUID = 1L;
+ public static final String SESSION_COOKIE_NAME = "Gerrit_Session";
+ public static final String SESSION_COOKIE_TTL = "60s";
+
@JsonIgnore
public String getDependentResourceName(String nameSuffix) {
return String.format("%s-%s", getMetadata().getName(), nameSuffix);
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_primary.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_primary.yaml
index 5c6bfa6..9b18d5c 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_primary.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_primary.yaml
@@ -6,6 +6,11 @@
annotations:
nginx.ingress.kubernetes.io/use-regex: true
kubernetes.io/ingress.class: nginx
+ nginx.ingress.kubernetes.io/affinity: cookie
+ nginx.ingress.kubernetes.io/session-cookie-name: Gerrit_Session
+ nginx.ingress.kubernetes.io/session-cookie-path: /
+ nginx.ingress.kubernetes.io/session-cookie-max-age: 60
+ nginx.ingress.kubernetes.io/session-cookie-expires: 60
spec:
rules:
- host: example.com
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_primary_replica.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_primary_replica.yaml
index f6bb13f..d6aae78 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_primary_replica.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_primary_replica.yaml
@@ -12,6 +12,11 @@
set $proxy_host $proxy_upstream_name;
set $service_name "replica";
}
+ nginx.ingress.kubernetes.io/affinity: cookie
+ nginx.ingress.kubernetes.io/session-cookie-name: Gerrit_Session
+ nginx.ingress.kubernetes.io/session-cookie-path: /
+ nginx.ingress.kubernetes.io/session-cookie-max-age: 60
+ nginx.ingress.kubernetes.io/session-cookie-expires: 60
spec:
rules:
- host: example.com
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_primary_replica_tls.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_primary_replica_tls.yaml
index 29be349..adbe808 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_primary_replica_tls.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_primary_replica_tls.yaml
@@ -12,6 +12,11 @@
set $proxy_host $proxy_upstream_name;
set $service_name "replica";
}
+ nginx.ingress.kubernetes.io/affinity: cookie
+ nginx.ingress.kubernetes.io/session-cookie-name: Gerrit_Session
+ nginx.ingress.kubernetes.io/session-cookie-path: /
+ nginx.ingress.kubernetes.io/session-cookie-max-age: 60
+ nginx.ingress.kubernetes.io/session-cookie-expires: 60
spec:
tls:
- hosts:
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_receiver_replica.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_receiver_replica.yaml
index b297627..e123b27 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_receiver_replica.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_receiver_replica.yaml
@@ -6,6 +6,11 @@
annotations:
nginx.ingress.kubernetes.io/use-regex: true
kubernetes.io/ingress.class: nginx
+ nginx.ingress.kubernetes.io/affinity: cookie
+ nginx.ingress.kubernetes.io/session-cookie-name: Gerrit_Session
+ nginx.ingress.kubernetes.io/session-cookie-path: /
+ nginx.ingress.kubernetes.io/session-cookie-max-age: 60
+ nginx.ingress.kubernetes.io/session-cookie-expires: 60
spec:
rules:
- host: example.com
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_receiver_replica_tls.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_receiver_replica_tls.yaml
index 024d450..51dd65c 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_receiver_replica_tls.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_receiver_replica_tls.yaml
@@ -6,6 +6,11 @@
annotations:
nginx.ingress.kubernetes.io/use-regex: true
kubernetes.io/ingress.class: nginx
+ nginx.ingress.kubernetes.io/affinity: cookie
+ nginx.ingress.kubernetes.io/session-cookie-name: Gerrit_Session
+ nginx.ingress.kubernetes.io/session-cookie-path: /
+ nginx.ingress.kubernetes.io/session-cookie-max-age: 60
+ nginx.ingress.kubernetes.io/session-cookie-expires: 60
spec:
tls:
- hosts:
diff --git a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_replica.yaml b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_replica.yaml
index 61426c5..07dfe7d 100644
--- a/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_replica.yaml
+++ b/operator/src/test/resources/com/google/gerrit/k8s/operator/network/ingress/dependent/ingress_replica.yaml
@@ -6,6 +6,11 @@
annotations:
nginx.ingress.kubernetes.io/use-regex: true
kubernetes.io/ingress.class: nginx
+ nginx.ingress.kubernetes.io/affinity: cookie
+ nginx.ingress.kubernetes.io/session-cookie-name: Gerrit_Session
+ nginx.ingress.kubernetes.io/session-cookie-path: /
+ nginx.ingress.kubernetes.io/session-cookie-max-age: 60
+ nginx.ingress.kubernetes.io/session-cookie-expires: 60
spec:
rules:
- host: example.com