New to Voyager? Please start here.

Configure HTTP/2 and GRPC

You can configure HTTP/2 by configuring proto or, alpn under rules.http section (for frontend) or, backend section (for specific backend). If you want to use only HTTP/2.0, then you can specify it using proto: h2. However, if you like to use both HTTP/2.0 and HTTP/1.1 in a preferred order, then you need to specify the order using ALPN.

Please note the followings: - TLS needed to be configured for using ALPN. - A single rule/backend can’t use both ALPN and proto. - Multiple rules pointing the same frontend can’t use different ALPN or, proto configurations.

Example: gRPC Without TLS

First create demo namespace for this example.

$ kubectl create namespace demo
namespace/demo created

Deploy gRPC Test Server

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    run: grpc-server
  name: grpc-server
  namespace: demo
spec:
  selector:
    matchLabels:
      run: grpc-server
  template:
    metadata:
      labels:
        run: grpc-server
    spec:
      containers:
      - image: appscode/hello-grpc:0.1.0
        args:
        - run
        - --v=3
        name: grpc-server
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  labels:
    run: grpc-server
  name: grpc-server
  namespace: demo
spec:
  ports:
  - port: 3000
    targetPort: 8080
    name: h2c
  selector:
    run: grpc-server

Create Ingress

apiVersion: voyager.appscode.com/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  namespace: demo
spec:
  rules:
  - host: "*"
    http:
      port: 3001
      proto: h2
      paths:
      - path: /
        backend:
          serviceName: grpc-server
          servicePort: 3000
          proto: h2

Generated haproxy.cfg

# HAProxy configuration generated by https://github.com/appscode/voyager
# DO NOT EDIT!
global
  daemon
  stats socket /var/run/haproxy.sock level admin expose-fd listeners
  server-state-file global
  server-state-base /var/state/haproxy/
  # log using a syslog socket
  log /dev/log local0 info
  tune.ssl.default-dh-param 2048
  ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK
  lua-load /etc/auth-request.lua
defaults
  log global
  # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose
  # https://github.com/appscode/voyager/pull/403
  option dontlognull
  option http-server-close
  option http-use-htx
  option logasap
  # Timeout values
  timeout client 50s
  timeout client-fin 50s
  timeout connect 50s
  timeout server 50s
  timeout tunnel 50s
  # Configure error files
  # default traffic mode is http
  # mode is overwritten in case of tcp services
  mode http
frontend http-0_0_0_0-3001
  bind *:3001  proto h2
  mode http
  option httplog
  option forwardfor
  acl is_proxy_https hdr(X-Forwarded-Proto) https
  acl is_proxy_https ssl_fc
  http-request set-var(req.scheme) str(https) if is_proxy_https
  http-request set-var(req.scheme) str(http) if ! is_proxy_https
  acl acl_: path_beg /
  use_backend grpc-server.demo:3000 if  acl_:
backend grpc-server.demo:3000
  server pod-grpc-server-6c7f686bbb-jhngb 172.17.0.6:8080        proto h2

Check Response

$ minikube service --url voyager-test-ingress -n demo
http://192.168.99.100:30652

Run gRPC client using docker.

$ docker run -it appscode/hello-grpc:0.1.0 client --address=192.168.99.100:30652 --name=Voyager
2019/02/05 08:01:18 192.168.99.100:30652
2019/02/05 08:01:18 intro:"hello, Voyager!"

Cleanup

$ kubectl delete ns demo
namespace "demo" deleted

Example: gRPC With TLS

First create demo namespace for this example.

$ kubectl create namespace demo
namespace/demo created

Create Secrets

Generate certs and create secret for backend server. Here we are using onessl. You can use openssl or any other tools to generate the certificates.

$ mkdir server-certs; cd server-certs
$ onessl create ca-cert
$ onessl create server-cert --domains ssl.appscode.test --ips 192.168.99.100,127.0.0.1
$ cat {server.crt,ca.crt} > bundle.crt
$ kubectl create secret tls server-secret -n demo --cert=bundle.crt --key=server.key

Generate certs and create secret for haproxy:

$ mkdir haproxy-certs; cd haproxy-certs
$ onessl create ca-cert
$ onessl create server-cert --domains ssl.appscode.test --ips 192.168.99.100,127.0.0.1
$ cat {server.crt,ca.crt} > bundle.crt
$ kubectl create secret tls haproxy-secret -n demo --cert=bundle.crt --key=server.key

Deploy gRPC Test Server

Deploy the gRPC server and mount the server-secret.

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    run: grpc-server
  name: grpc-server
  namespace: demo
spec:
  selector:
    matchLabels:
      run: grpc-server
  template:
    metadata:
      labels:
        run: grpc-server
    spec:
      volumes:
      - name: secret-vol
        secret:
          secretName: server-secret
      containers:
      - image: appscode/hello-grpc:0.1.0
        args:
        - run
        - --tls-cert-file=/etc/certs/tls.crt
        - --tls-private-key-file=/etc/certs/tls.key
        - --v=3
        name: grpc-server
        imagePullPolicy: Always
        ports:
        - containerPort: 8443
        volumeMounts:
        - name: secret-vol
          mountPath: "/etc/certs"
          readOnly: true
---
apiVersion: v1
kind: Service
metadata:
  labels:
    run: grpc-server
  name: grpc-server
  namespace: demo
  annotations:
    ingress.appscode.com/backend-tls: ssl ca-file /tmp/certs/tls.crt
spec:
  ports:
  - port: 3000
    targetPort: 8443
    name: h2
  selector:
    run: grpc-server

Here, ingress.appscode.com/backend-tls will be used by voyager to configure backend TLS.

Create Ingress

Create ingress and specify the spec.tls and spec.configVolumes.

apiVersion: voyager.appscode.com/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  namespace: demo
spec:
  tls:
  - secretName: haproxy-secret
    hosts:
    - "*"
  configVolumes:
  - name: server-certs-vol
    secret:
      secretName: server-secret
    mountPath: /tmp/certs
  rules:
  - host: "*"
    http:
      port: 3001
      alpn:
      - h2
      - http/1.1
      paths:
      - path: /
        backend:
          serviceName: grpc-server
          servicePort: 3000
          alpn:
          - h2
          - http/1.1

Generated haproxy.cfg

# HAProxy configuration generated by https://github.com/appscode/voyager
# DO NOT EDIT!
global
  daemon
  stats socket /var/run/haproxy.sock level admin expose-fd listeners
  server-state-file global
  server-state-base /var/state/haproxy/
  # log using a syslog socket
  log /dev/log local0 info
  tune.ssl.default-dh-param 2048
  ssl-default-bind-ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK
  lua-load /etc/auth-request.lua
defaults
  log global
  # https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-option%20abortonclose
  # https://github.com/appscode/voyager/pull/403
  option dontlognull
  option http-server-close
  option http-use-htx
  option logasap
  # Timeout values
  timeout client 50s
  timeout client-fin 50s
  timeout connect 50s
  timeout server 50s
  timeout tunnel 50s
  # Configure error files
  # default traffic mode is http
  # mode is overwritten in case of tcp services
  mode http
frontend http-0_0_0_0-3001
  bind *:3001  ssl no-sslv3 no-tlsv10 no-tls-tickets crt /etc/ssl/private/haproxy/tls/  alpn h2,http/1.1 
  # Mark all cookies as secure
  rsprep ^Set-Cookie:\ (.*) Set-Cookie:\ \1;\ Secure
  # Add the HSTS header with a 6 month default max-age
  http-response set-header Strict-Transport-Security max-age=15768000
  mode http
  option httplog
  option forwardfor
  acl is_proxy_https hdr(X-Forwarded-Proto) https
  acl is_proxy_https ssl_fc
  http-request set-var(req.scheme) str(https) if is_proxy_https
  http-request set-var(req.scheme) str(http) if ! is_proxy_https
  acl acl_: path_beg /
  use_backend grpc-server.demo:3000 if  acl_:
backend grpc-server.demo:3000
  server pod-grpc-server-7578bf9696-rbq49 172.17.0.7:8443     ssl ca-file /tmp/certs/server.crt    alpn h2,http/1.1

Check Response

$ minikube service --url voyager-test-ingress -n demo
http://192.168.99.100:30446

Run gRPC client using docker and specify the haproxy certs.

$ docker run -v $(pwd)/haproxy-certs:/tmp/certs -it appscode/hello-grpc:0.1.0 client --address=192.168.99.100:30446 --crt=/tmp/certs/bundle.crt --name=Voyager
2019/02/05 12:11:13 192.168.99.100:30446
2019/02/05 12:11:13 intro:"hello, Voyager!"

Cleanup

$ kubectl delete ns demo
namespace "demo" deleted

Reference

Take your team where it needs to go.

Create your cluster in minutes. Our team is here to help and would be happy to chat with you.