Humberto
Humberto

Reputation: 13

Using HTTP/2 with nginx Ingress on GKE

We have configured a cluster on GKE and installed nginx-ingress. Using our ingress rule it works, but I can't make it work with HTTP/2. We set the data information on the ConfigMap but it will always fallback to http/1.1. This exact setup was running fine on DigitalOcean. Can anyone provide some guidance?

Thanks

Install Nginx-Ingress

kubectl create ns ingress-nginx
helm repo add nginx-stable https://helm.nginx.com/stable
helm repo update
helm install nginx-ingress nginx-stable/nginx-ingress --namespace ingress-nginx

My Ingress file:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    kubernetes.io/ingress.global-static-ip-name: "mylocalip"
spec:
  rules:
  - host: test.mydomain.com
    http:
      paths:
      - path: /hello
        backend:
          serviceName: hello-server
          servicePort: 80
      - backend:
          serviceName: default-server
          servicePort: 80

My ConfigMap data applied to nginx-ingress-nginx-ingress configmap

data:
  use-http2: "true"

EDIT (05/11/2021):

We changed the ingress to work with certificates, now we connect using HTTPS. But still, all connections are established using http/1.1

Hi, thanks for the reply. But I've changed my ingress to use cert-manager and LetEncrypt, below is the updated Ingress.

INGRESS

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress
  namespace: mynamespace
  annotations:
    kubernetes.io/ingress.class: nginx
    kubernetes.io/ingress.global-static-ip-name: "myip"
spec:
  tls:
  - hosts:
    - test.mydomain.com
    secretName: my-cert
  rules:
  - host: test.mydomain.com
    http:
      paths:
      - backend:
          serviceName: myweb
          servicePort: 80

EDIT 2 (05/14/2021)

Current version: 1.19.9-gke.1400 Test using curl and https://http2.pro/ (both indicate it's not available)

This same setup works using k8s on DigitalOcean.

Here are my install and config files:

INSTALL INGRESS-NGINX

kubectl create ns ingress-nginx
helm repo add nginx-stable https://helm.nginx.com/stable
helm repo update
helm install nginx-ingress nginx-stable/nginx-ingress --namespace ingress-nginx --set controller.service.loadBalancerIP=x.x.x.x

INGRESS

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress
  namespace: mynamespace
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  tls:
  - hosts:
    - test.mydomain.com
    secretName: my-cert
  rules:
  - host: test.mydomain.com
    http:
      paths:
      - backend:
          serviceName: myweb
          servicePort: 80

CONFIGMAP

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: ingress-nginx
  name: nginx-ingress-nginx-ingress
data:
  proxy-buffering: "false"
  ssl-ciphers: EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA256:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EDH+aRSA+AESGCM:EDH+aRSA+SHA256:EDH+aRSA:EECDH:!aNULL:!eNULL:!MEDIUM:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4:!SEED
  ssl-protocols: TLSv1.2 TLSv1.3
  ssl-redirect: "true"
  use-forward-headers: "true"
  use-http2: "true"
  
  

Upvotes: 1

Views: 18266

Answers (1)

Dawid Kruk
Dawid Kruk

Reputation: 9877

EDIT


After further reproduction I've noticed that in the question there is a miss-match between the NGINX Ingress controllers.

There are 2 similarly named Ingress controllers:

This are 2 separate products where the differences are explained here:

Due to this Configmap key:

  • use-http2: "true"

I've incorrectly assumed that we are talking about the nginx where in fact it was the nginx-inc (I've missed the link of $ helm repo add). This field is specific to the nginx and will not work with the nginx-inc.

I've managed to find a way to enable the HTTP/2 support with the nginx-inc. Change:

  • from: use-http2: "true"
  • to: http2: "true"

More explanation can be found here:



Below part is more of a general approach to the support of HTTP/2 on GKE with Ingress.

A side note!

Even without the tls part in the YAML manifest it's possible to use HTTPS due to the Fake Ingress Controller certificate


As pointed in the following github issue:

aledbf commented on 28 Mar 2019


NGINX does not support HTTP/1.x and HTTP/2 at the same time on a cleartext (non-TLS) port. That's the reason why it works only when HTTPS is used.

-- Github.com: Kubernetes: Ingress nginx: Issue: HTTP2 support

As stated to enable HTTP/2 you will need to have the tls part (certificate) configured in your Ingress resource.

Here you can find the documentation to help you with the process:


I've used your setup on the GKE version 1.20.5-gke.2000 (the Helm part) and here is what I found.

Querying the external IP of your Ingress controller with HTTP request will allow you to use HTTP/1.1.

After I've configured the certificate to use with the Ingress resource (and domain name), I could get the response stating that I'm using HTTP/2:

You can check it with various measures like cURL or online HTTP/2 test sites:

  • curl -v -k https://DOMAIN.NAME
* Trying IP_ADRESS
* TCP_NODELAY set
* Connected to DOMAIN.NAME ( IP_ADRESS) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/cert.pem
< <-- REDACTED --> 
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7fa5b300e800)
> GET / HTTP/2
> Host: DOMAIN.NAME
> User-Agent: curl/7.64.1
> Accept: */*
> 
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200 
< <-- REDACTED --> 
< 
< <-- NGINX WELCOME SITE --> 
* Connection #0 to host DOMAIN.NAME left intact
* Closing connection 0

You can also go for more of a one line solution:

  • curl -k -sI https://DOMAIN.NAME -o/dev/null -w '%{http_version}\n'

where the output should be 2. More reference:


Also, adding to whole answer on the modified part of the Configmap of your nginx-ingress:

data:
  use-http2: "true"

use-http2

Enables or disables HTTP/2 support in secure connections.

-- Kubernetes.github.io: Ingress nginx: User guide: Nginx configuration: Configmap: Use HTTP/2

I'm not also sure about the usage of this annotation:

  • kubernetes.io/ingress.global-static-ip-name: "mylocalip"

as it's valid only for the Ingress resource for GKE Ingress and not ingress-nginx.


Additional resources:

Upvotes: 5

Related Questions