<p>Currently, I'm trying to create a Kubernetes cluster on Google Cloud with two <strong>load balancers</strong>: one for backend (in Spring boot) and another for frontend (in Angular), where each service (load balancer) communicates with 2 replicas (pods). To achieve that, I created the following ingress:</p>

<pre><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: sample-ingress
spec:
  rules:
    - http:
        paths:
          - path: /rest/v1/*
            backend:
              serviceName: sample-backend
              servicePort: 8082
          - path: /*
            backend:
              serviceName: sample-frontend
              servicePort: 80
</code></pre>

<p>The ingress above mentioned can make the frontend app communicate with the REST API made available by the backend app. However, I have to create <strong>sticky sessions</strong>, so that every user communicates with the same POD because of the authentication mechanism provided by the backend. To clarify, if one user authenticates in POD #1, the cookie will not be recognized by POD #2.</p>

<p>To overtake this issue, I read that the <strong>Nginx-ingress</strong> manages to deal with this situation and I installed through the steps available here: <a href="https://kubernetes.github.io/ingress-nginx/deploy/" rel="noreferrer">https://kubernetes.github.io/ingress-nginx/deploy/</a> using Helm. </p>

<p>You can find below the diagram for the architecture I'm trying to build:</p>

<p><a href="https://i.stack.imgur.com/iZeHX.png" rel="noreferrer"><img src="https://i.stack.imgur.com/iZeHX.png" alt="enter image description here"></a></p>

<p>With the following services (I will just paste one of the services, the other one is similar):</p>

<pre><code>apiVersion: v1
kind: Service
metadata:
  name: sample-backend
spec:
  selector:
    app: sample
    tier: backend
  ports:
    - protocol: TCP
      port: 8082
      targetPort: 8082
  type: LoadBalancer
</code></pre>

<p>And I declared the following ingress:</p>

<pre><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: sample-nginx-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/affinity: cookie
    nginx.ingress.kubernetes.io/affinity-mode: persistent
    nginx.ingress.kubernetes.io/session-cookie-hash: sha1
    nginx.ingress.kubernetes.io/session-cookie-name: sample-cookie
spec:
  rules:
    - http:
        paths:
          - path: /rest/v1/*
            backend:
              serviceName: sample-backend
              servicePort: 8082
          - path: /*
            backend:
              serviceName: sample-frontend
              servicePort: 80
</code></pre>

<p>After that, I run <code>kubectl apply -f sample-nginx-ingress.yaml</code> to apply the ingress, it is created and its status is OK. However, when I access the URL that appears in "Endpoints" column, the browser can't connect to the URL.
Am I doing anything wrong?</p>

<h1>Edit 1</h1>

<p>** Updated service and ingress configurations **</p>

<p>After some help, I've managed to access the services through the Ingress Nginx. Above here you have the configurations:</p>

<h2>Nginx Ingress</h2>

<p>The paths shouldn't contain the "<em>", unlike the default Kubernetes ingress that is mandatory to have the "</em>" to route the paths I want.</p>

<pre><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: sample-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "sample-cookie"
    nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"

spec:
  rules:
    - http:
        paths:
          - path: /rest/v1/
            backend:
              serviceName: sample-backend
              servicePort: 8082
          - path: /
            backend:
              serviceName: sample-frontend
              servicePort: 80
</code></pre>

<h2>Services</h2>

<p>Also, the services shouldn't be of type "LoadBalancer" but "<strong>ClusterIP</strong>" as below:</p>

<pre><code>apiVersion: v1
kind: Service
metadata:
  name: sample-backend
spec:
  selector:
    app: sample
    tier: backend
  ports:
    - protocol: TCP
      port: 8082
      targetPort: 8082
  type: ClusterIP
</code></pre>

<p>However, I still can't achieve sticky sessions in my Kubernetes Cluster, once I'm still getting 403 and even the cookie name is not replaced, so I guess the annotations are not working as expected.</p>

<p>I looked into this matter and I have found solution to your issue. </p>

<p><strong>To achieve sticky session for both paths you will need two definitions of ingress.</strong></p>

<p>I created example configuration to show you the whole process: </p>

<p><strong>Steps to reproduce:</strong> </p>

<ul>
<li>Apply Ingress definitions </li>
<li>Create deployments</li>
<li>Create services</li>
<li>Create Ingresses </li>
<li>Test </li>
</ul>

<p>I assume that the cluster is provisioned and is working correctly. </p>

<h2>Apply Ingress definitions</h2>

<p>Follow this <a href="https://kubernetes.github.io/ingress-nginx/deploy/" rel="noreferrer">Ingress link </a> to find if there are any needed prerequisites before installing Ingress controller on your infrastructure.  </p>

<p>Apply below command to provide all the mandatory prerequisites: </p>

<pre><code>kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
</code></pre>

<p>Run below command to apply generic configuration to create a service: </p>

<pre><code>kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/cloud-generic.yaml
</code></pre>

<h2>Create deployments</h2>

<p>Below are 2 example deployments to respond to the Ingress traffic on specific services: </p>

<p><strong>hello.yaml:</strong> </p>

<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
spec:
  selector:
    matchLabels:
      app: hello
      version: 1.0.0
  replicas: 5
  template:
    metadata:
      labels:
        app: hello
        version: 1.0.0
    spec:
      containers:
      - name: hello
        image: "gcr.io/google-samples/hello-app:1.0"
        env:
        - name: "PORT"
          value: "50001"
</code></pre>

<p>Apply this first deployment configuration by invoking command:</p>

<p><code>$ kubectl apply -f hello.yaml</code></p>

<p><strong>goodbye.yaml:</strong> </p>

<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: goodbye
spec:
  selector:
    matchLabels:
      app: goodbye
      version: 2.0.0
  replicas: 5
  template:
    metadata:
      labels:
        app: goodbye
        version: 2.0.0
    spec:
      containers:
      - name: goodbye 
        image: "gcr.io/google-samples/hello-app:2.0"
        env:
        - name: "PORT"
          value: "50001"
</code></pre>

<p>Apply this second deployment configuration by invoking command:</p>

<p><code>$ kubectl apply -f goodbye.yaml</code></p>

<p>Check if deployments configured pods correctly: </p>

<p><code>$ kubectl get deployments</code></p>

<p>It should show something like that: </p>

<pre><code>NAME      READY   UP-TO-DATE   AVAILABLE   AGE
goodbye   5/5     5            5           2m19s
hello     5/5     5            5           4m57s
</code></pre>

<h2>Create services</h2>

<p>To connect to earlier created pods you will need to create services. Each service will be assigned to one deployment. Below are 2 services to accomplish that:</p>

<p><strong>hello-service.yaml:</strong> </p>

<pre><code>apiVersion: v1
kind: Service
metadata:
  name: hello-service
spec:
  type: NodePort
  selector:
    app: hello
    version: 1.0.0
  ports:
  - name: hello-port
    protocol: TCP
    port: 50001
    targetPort: 50001
</code></pre>

<p>Apply first service configuration by invoking command:</p>

<p><code>$ kubectl apply -f hello-service.yaml</code></p>

<p><strong>goodbye-service.yaml:</strong></p>

<pre><code>apiVersion: v1
kind: Service
metadata:
  name: goodbye-service
spec:
  type: NodePort
  selector:
    app: goodbye
    version: 2.0.0
  ports:
  - name: goodbye-port
    protocol: TCP
    port: 50001
    targetPort: 50001
</code></pre>

<p>Apply second service configuration by invoking command:</p>

<p><code>$ kubectl apply -f goodbye-service.yaml</code></p>

<p><strong>Take in mind that in both configuration lays type: <code>NodePort</code></strong></p>

<p>Check if services were created successfully: </p>

<p><code>$ kubectl get services</code> </p>

<p>Output should look like that:</p>

<pre><code>NAME              TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)           AGE
goodbye-service   NodePort    10.0.5.131   &lt;none&gt;        50001:32210/TCP   3s
hello-service     NodePort    10.0.8.13    &lt;none&gt;        50001:32118/TCP   8s
</code></pre>

<h2>Create Ingresses</h2>

<p>To achieve sticky sessions you will need to create 2 ingress definitions. </p>

<p>Definitions are provided below: </p>

<p><strong>hello-ingress.yaml:</strong></p>

<pre><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "hello-cookie"
    nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/affinity-mode: persistent
    nginx.ingress.kubernetes.io/session-cookie-hash: sha1
spec:
  rules:
  - host: DOMAIN.NAME
    http:
      paths:
      - path: /
        backend:
          serviceName: hello-service
          servicePort: hello-port

</code></pre>

<p><strong>goodbye-ingress.yaml:</strong> </p>

<pre><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: goodbye-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "goodbye-cookie"
    nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/affinity-mode: persistent
    nginx.ingress.kubernetes.io/session-cookie-hash: sha1
spec:
  rules:
  - host: DOMAIN.NAME
    http:
      paths:
      - path: /v2/
        backend:
          serviceName: goodbye-service
          servicePort: goodbye-port
</code></pre>

<p>Please change <code>DOMAIN.NAME</code>  in both ingresses to appropriate to your case. 
I would advise to look on this <a href="https://kubernetes.github.io/ingress-nginx/examples/affinity/cookie/" rel="noreferrer">Ingress Sticky session </a> link. 
Both Ingresses are configured to HTTP only traffic. </p>

<p>Apply both of them invoking command: </p>

<p><code>$ kubectl apply -f hello-ingress.yaml</code></p>

<p><code>$ kubectl apply -f goodbye-ingress.yaml</code></p>

<p>Check if both configurations were applied: </p>

<p><code>$ kubectl get ingress</code></p>

<p>Output should be something like this: </p>

<pre class="lang-sh prettyprint-override"><code>NAME              HOSTS        ADDRESS          PORTS   AGE
goodbye-ingress   DOMAIN.NAME   IP_ADDRESS      80      26m
hello-ingress     DOMAIN.NAME   IP_ADDRESS      80      26m
</code></pre>

<h2>Test</h2>

<p>Open your browser and go to <code>http://DOMAIN.NAME</code>
Output should be like this: </p>

<pre><code>Hello, world!
Version: 1.0.0
Hostname: hello-549db57dfd-4h8fb
</code></pre>

<p><code>Hostname: hello-549db57dfd-4h8fb</code> is the name of the pod. Refresh it a couple of times. </p>

<p>It should stay the same. </p>

<p>To check if another route is working go to <code>http://DOMAIN.NAME/v2/</code>
Output should be like this: </p>

<pre><code>Hello, world!
Version: 2.0.0
Hostname: goodbye-7b5798f754-pbkbg
</code></pre>

<p><code>Hostname: goodbye-7b5798f754-pbkbg</code> is the name of the pod. Refresh it a couple of times. </p>

<p>It should stay the same. </p>

<p>To ensure that cookies are not changing open developer tools (probably F12) and navigate to place with cookies. You can reload the page to check if they are not changing. </p>

<p><a href="https://i.stack.imgur.com/Odr0O.png" rel="noreferrer"><img src="https://i.stack.imgur.com/Odr0O.png" alt="Cookies"></a></p>
