Skip to content

Commit 395a401

Browse files
authored
chart(add): Default ingress annotations for upstream keepalive, or disable HTTP/2 (#2328)
Fix: #2195 Docs for SeleniumHQ/selenium#14258 Signed-off-by: Viet Nguyen Duc <[email protected]>
1 parent e15df42 commit 395a401

File tree

5 files changed

+77
-6
lines changed

5 files changed

+77
-6
lines changed

Diff for: Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -772,7 +772,7 @@ chart_test_autoscaling_disabled:
772772

773773
chart_test_autoscaling_deployment_https:
774774
PLATFORMS=$(PLATFORMS) CHART_FULL_DISTRIBUTED_MODE=true CHART_ENABLE_BASIC_AUTH=true \
775-
SECURE_INGRESS_ONLY_DEFAULT=true SELENIUM_GRID_PROTOCOL=https CHART_ENABLE_INGRESS_HOSTNAME=true SELENIUM_GRID_PORT=443 \
775+
SECURE_INGRESS_ONLY_DEFAULT=true INGRESS_DISABLE_USE_HTTP2=true SELENIUM_GRID_PROTOCOL=https CHART_ENABLE_INGRESS_HOSTNAME=true SELENIUM_GRID_PORT=443 \
776776
SELENIUM_GRID_AUTOSCALING_MIN_REPLICA=1 \
777777
VERSION=$(TAG_VERSION) VIDEO_TAG=$(FFMPEG_TAG_VERSION)-$(BUILD_DATE) NAMESPACE=$(NAMESPACE) BINDING_VERSION=$(BINDING_VERSION) \
778778
./tests/charts/make/chart_test.sh DeploymentAutoscaling

Diff for: charts/selenium-grid/README.md

+47-2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ This chart enables the creation of a Selenium Grid Server in Kubernetes.
3636
* [Create TLS Secret](#create-tls-secret)
3737
* [Secure Connection to Selenium Grid components](#secure-connection-to-selenium-grid-components)
3838
* [Secure Connection to the Ingress proxy](#secure-connection-to-the-ingress-proxy)
39+
* [TLS termination in the ingress controller, HTTP/2, and related troubleshooting](#tls-termination-in-the-ingress-controller-http2-and-related-troubleshooting)
3940
* [Node Registration](#node-registration)
4041
* [Configuration of tracing observability](#configuration-of-tracing-observability)
4142
* [Configuration of Selenium Grid chart](#configuration-of-selenium-grid-chart)
@@ -268,8 +269,9 @@ List mapping of chart values and default annotation(s)
268269
nginx.ingress.kubernetes.io/proxy-connect-timeout
269270
nginx.ingress.kubernetes.io/proxy-send-timeout
270271
nginx.ingress.kubernetes.io/proxy-read-timeout
271-
nginx.ingress.kubernetes.io/proxy-next-upstream-timeout
272-
nginx.ingress.kubernetes.io/auth-keepalive-timeout
272+
nginx.ingress.kubernetes.io/proxy-stream-timeout
273+
nginx.ingress.kubernetes.io/upstream-keepalive-timeout
274+
nginx.ingress.kubernetes.io/ssl-session-timeout
273275

274276
# `ingress.nginx.proxyBuffer` pass value to to annotation(s)
275277
nginx.ingress.kubernetes.io/proxy-request-buffering: "on"
@@ -292,6 +294,14 @@ nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
292294
# `ingress.nginx.sslSecret` to specify a Secret with the certificate `tls.crt`, key `tls.key`, the name in the form "namespace/secretName"
293295
# By default, it is empty, the chart will use internal TLS secret resource (or the first `secretName` under `ingress.tls` if set)
294296
nginx.ingress.kubernetes.io/proxy-ssl-secret: {{ template "seleniumGrid.tls.fullname" $ }}
297+
298+
# `ingress.nginx.useHttp2` pass boolean value to enable/disable HTTP/2 in TLS termination in the ingress controller
299+
nginx.ingress.kubernetes.io/use-http2: "true"
300+
301+
# `ingress.nginx.upstreamKeepalive` pass value to upstream keepalive
302+
nginx.ingress.kubernetes.io/upstream-keepalive-connections: "10000"
303+
nginx.ingress.kubernetes.io/upstream-keepalive-time: "1h"
304+
nginx.ingress.kubernetes.io/upstream-keepalive-request: "10000"
295305
```
296306
297307
Refer to [NGINX Ingress Controller Annotations](https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/annotations.md) for more details.
@@ -792,6 +802,41 @@ helm upgrade -i $RELEASENAME -n $NAMESPACE docker-selenium/selenium-grid \
792802
--set ingress-nginx.controller.extraArgs.default-ssl-certificate=$NAMESPACE/my-external-tls-secret
793803
```
794804

805+
#### TLS termination in the ingress controller, HTTP/2, and related troubleshooting
806+
807+
In case the Selenium Grid is deployed with the Ingress controller in front, and the Ingress controller has configured the secure connection with approach SSL termination to terminate the TLS connection, the backend components (mostly Hub/Router to process the request and return to the client) will receive the incoming in plain HTTP. In a few confirmations (also referred to ChatGPT)
808+
809+
> When TLS termination is performed by an ingress controller, HTTP/2 is typically enabled by default. This is because many ingress controllers are designed to support modern web protocols to ensure better performance and efficiency. For example, popular ingress controllers like NGINX and HAProxy enable HTTP/2 by default when handling HTTPS traffic.
810+
811+
At that time, the Selenium Grid server returns the response in HTTP/1.1. However, this mismatch is not expected to cause any problems. Selenium Grid is using JDKHttpClient to communicate between components since the following OpenJDK [docs](https://openjdk.org/groups/net/httpclient/intro.html) mentioned that
812+
813+
> The Java HTTP Client supports both HTTP/1.1 and HTTP/2. By default, the client will send requests using HTTP/2. Requests sent to servers that do not yet support HTTP/2 will automatically be downgraded to HTTP/1.1
814+
815+
A few reports mention the error `java.io.IOException: HTTP/1.1 header parser received no bytes`, `java.io.IOException: /: GOAWAY received`, or a timed-out issue with a stack trace containing `jdk.internal.net.http.Http2Connection`, or `Http2ClientImpl` when creating a RemoteWebDriver session.
816+
817+
What could be the issue around this? It could be due to different JDK versions used. Since JDK20, the default keepalive timeout has been adjusted; see [docs](https://docs.oracle.com/en/java/javase/20/core/java-networking.html) on `jdk.httpclient.keepalive.timeout` (default to 30). Or it could be `jdk.httpclient.maxstreams` (default to 100) if Grid serves many client requests at the same time, it could reach the maximum stream limit.
818+
819+
In some scenarios, the issue might be resolved by setting ClientConfig with HTTP/1.1 when creating RemoteWebDriver. For example, in Java binding you can try this:
820+
821+
```java
822+
ClientConfig config = ClientConfig.defaultConfig().baseUrl(seleniumGridUrl)
823+
.readTimeout(300)
824+
.version(HttpClient.Version.HTTP_1_1.name());
825+
826+
driver = RemoteWebDriver.builder().oneOf(new ChromeOptions())
827+
.config(config).build();
828+
```
829+
830+
With the workaround set http version via ClientConfig also there was a point mentioned that we can understand something like `HTTP/1.1 header parser received no bytes`, or `GOAWAY` is an IOException thrown by client HTTP/2, and when switching client to HTTP/1.1, it could go to a situation that would continue to get "random" IOExceptions with a different message from the server.
831+
832+
For example, in [this case](https://stackoverflow.com/questions/55087292/how-to-handle-http-2-goaway-with-java-net-httpclient) the issue could be due to HTTP/2 configs on Ingress controller. Refer to usage of [Annotations](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/) [ConfigMap](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/) settings in NGINX Ingress Controller.
833+
834+
- `use-http2` (default is true) - enable or disable HTTP/2 support in secure connection.
835+
- `upstream-keepalive-timeout` (default to 60) - timeout during which an idle keepalive connection to an upstream server will stay open.
836+
- `upstream-keepalive-connections` (default to 320) - maximum number of idle keepalive connections to upstream servers. When this number is exceeded, the least recently used connections are closed
837+
838+
The above notes are motivated by [SeleniumHQ/selenium#14258](https://github.com/SeleniumHQ/selenium/issues/14258). Kindly let us know if you have further troubleshooting on this.
839+
795840
### Node Registration
796841

797842
To enable secure in the node registration to make sure that the node is one you control and not a rouge node, you can enable and provide a registration secret string to Distributor, Router and

Diff for: charts/selenium-grid/templates/_helpers.tpl

+15-2
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,9 @@ Get default certificate file name in chart
105105
nginx.ingress.kubernetes.io/proxy-connect-timeout: {{ . | quote }}
106106
nginx.ingress.kubernetes.io/proxy-send-timeout: {{ . | quote }}
107107
nginx.ingress.kubernetes.io/proxy-read-timeout: {{ . | quote }}
108-
nginx.ingress.kubernetes.io/proxy-next-upstream-timeout: {{ . | quote }}
109-
nginx.ingress.kubernetes.io/auth-keepalive-timeout: {{ . | quote }}
108+
nginx.ingress.kubernetes.io/proxy-stream-timeout: {{ . | quote }}
109+
nginx.ingress.kubernetes.io/upstream-keepalive-timeout: {{ . | quote }}
110+
nginx.ingress.kubernetes.io/ssl-session-timeout: {{ . | quote }}
110111
{{- end }}
111112
{{- with .proxyBuffer }}
112113
nginx.ingress.kubernetes.io/proxy-request-buffering: "on"
@@ -129,6 +130,7 @@ nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
129130
{{- end }}
130131
{{- end }}
131132
{{- if eq (include "seleniumGrid.ingress.secureConnection" $) "true" }}
133+
nginx.ingress.kubernetes.io/use-http2: {{ .useHttp2 | quote }}
132134
{{- if not (empty .sslSecret) }}
133135
nginx.ingress.kubernetes.io/proxy-ssl-secret: {{ tpl .sslSecret $ | quote }}
134136
{{- else if (empty $.Values.ingress.tls) }}
@@ -137,6 +139,17 @@ nginx.ingress.kubernetes.io/proxy-ssl-secret: {{ tpl (printf "%s/%s" $.Release.N
137139
nginx.ingress.kubernetes.io/proxy-ssl-secret: {{ tpl (printf "%s/%s" $.Release.Namespace (index $.Values.ingress.tls 0).secretName) $ | quote }}
138140
{{- end }}
139141
{{- end }}
142+
{{- with .upstreamKeepalive }}
143+
{{- with .connections }}
144+
nginx.ingress.kubernetes.io/upstream-keepalive-connections: {{ . | quote }}
145+
{{- end }}
146+
{{- with .requests }}
147+
nginx.ingress.kubernetes.io/upstream-keepalive-request: {{ . | quote }}
148+
{{- end }}
149+
{{- with .time }}
150+
nginx.ingress.kubernetes.io/upstream-keepalive-time: {{ . | quote }}
151+
{{- end }}
152+
{{- end }}
140153
{{- end }}
141154
{{- end -}}
142155

Diff for: charts/selenium-grid/values.yaml

+8-1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,13 @@ ingress:
123123
number: 4
124124
sslPassthrough: true
125125
sslSecret: ""
126+
# Enables or disables HTTP/2 support in secure connections
127+
useHttp2: true
128+
# Apply upstream keepalive settings once HTTP/2 is enabled
129+
upstreamKeepalive:
130+
connections: 10000
131+
time: 1h
132+
requests: 10000
126133
ports:
127134
http: 80
128135
https: 443
@@ -248,7 +255,7 @@ loggingConfigMap:
248255
serverConfigMap:
249256
# nameOverride:
250257
env:
251-
SE_JAVA_OPTS: "-XX:+UseZGC"
258+
SE_JAVA_OPTS: "-Djdk.httpclient.keepalive.timeout=300 -Djdk.httpclient.maxstreams=10000 -XX:+UseZGC"
252259
# Log level of supervisord. Accept values: critical, error, warn, info, debug, trace, blather (http://supervisord.org/logging.html)
253260
SE_SUPERVISORD_LOG_LEVEL: "info"
254261
# Custom annotations for configmap

Diff for: tests/charts/make/chart_test.sh

+6
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,12 @@ if [ "${SECURE_INGRESS_ONLY_DEFAULT}" = "true" ]; then
204204
"
205205
fi
206206

207+
if [ "${INGRESS_DISABLE_USE_HTTP2}" = "true" ]; then
208+
HELM_COMMAND_SET_IMAGES="${HELM_COMMAND_SET_IMAGES} \
209+
--set ingress.nginx.useHttp2=false \
210+
"
211+
fi
212+
207213
if [ "${SECURE_CONNECTION_SERVER}" = "true" ]; then
208214
HELM_COMMAND_SET_IMAGES="${HELM_COMMAND_SET_IMAGES} \
209215
--set tls.enabled=true \

0 commit comments

Comments
 (0)