How do I apply session stickiness with nginx-ingress on just one backend service?

10/31/2019

I've got an Ingress object with multiple backends, like this:

kind: Ingress
apiVersion: extensions/v1beta1
metadata:
  name: my-app
  annotations:
    certmanager.k8s.io/issuer: letsencrypt-prod
    fabric8.io/generated-by: exposecontroller
    kubernetes.io/ingress.class: nginx
    kubernetes.io/tls-acme: 'true'
    nginx.ingress.kubernetes.io/affinity: cookie
    nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    nginx.ingress.kubernetes.io/proxy-body-size: 500m
    nginx.ingress.kubernetes.io/session-cookie-expires: '172800'
    nginx.ingress.kubernetes.io/session-cookie-max-age: '172800'
spec:
  tls:
    - hosts:
        - my-app.<tld>
      secretName: tls-my-app
  rules:
    - host: my-app.<tld>
      http:
        paths:
          - path: /_ui/
            backend:
              serviceName: ui
              servicePort: 443
          - backend:
              serviceName: api
              servicePort: 443

I only need session stickiness on my api service. But the nginx.ingress.kubernetes.io/affinity: cookie annotation applies to all backend services. Does someone know how I can accomplish what I need?

-- gazal
kubernetes
nginx-ingress

1 Answer

10/31/2019

Annotations are applied to every path (location) defined on your Ingress object. If you need different annotations for each path, you could create one different Ingress for each path:

  • Annotations are applied to all the paths in the Ingress.
  • Multiple Ingresses can define different annotations. These definitions are not shared between Ingresses.
  • If multiple Ingresses define different paths for the same host, the ingress controller will merge the definitions.

Nginx Ingress Controller will watch and collect those Ingress rules, applying them accordingly.

For example:

kind: Ingress
apiVersion: extensions/v1beta1
metadata:
  name: my-app-ui
  annotations:
    certmanager.k8s.io/issuer: letsencrypt-prod
    fabric8.io/generated-by: exposecontroller
    kubernetes.io/ingress.class: nginx
    kubernetes.io/tls-acme: 'true'
    # No session affinity here
    nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    nginx.ingress.kubernetes.io/proxy-body-size: 500m
    nginx.ingress.kubernetes.io/session-cookie-expires: '172800'
    nginx.ingress.kubernetes.io/session-cookie-max-age: '172800'
spec:
  tls:
    - hosts:
        - my-app.<tld>
      secretName: tls-my-app
  rules:
    - host: my-app.<tld>
      http:
        paths:
          - path: /_ui/
            backend:
              serviceName: ui
              servicePort: 443
---
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
  name: my-app-api
  annotations:
    certmanager.k8s.io/issuer: letsencrypt-prod
    fabric8.io/generated-by: exposecontroller
    kubernetes.io/ingress.class: nginx
    kubernetes.io/tls-acme: 'true'
    nginx.ingress.kubernetes.io/affinity: cookie  # <-- Session affiniy is here
    nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    nginx.ingress.kubernetes.io/proxy-body-size: 500m
    nginx.ingress.kubernetes.io/session-cookie-expires: '172800'
    nginx.ingress.kubernetes.io/session-cookie-max-age: '172800'
spec:
  tls:
    - hosts:
        - my-app.<tld>
      secretName: tls-my-app
  rules:
    - host: my-app.<tld>
      http:
        paths:
          - path: /_api/
            backend:
              serviceName: api
              servicePort: 443
---

Note: The API extensions/v1beta1 was deprecated on Kubernetes 1.16. Consider migrating to networking.k8s.io/v1beta1.

-- Eduardo Baitello
Source: StackOverflow