<p>I have multiple services that need to be exposed to the internet, but I'd like to use a single ALB for them.</p>
<p>I am using the latest <a href="https://github.com/kubernetes-sigs/aws-load-balancer-controller" rel="nofollow noreferrer">AWS Load Balancer Controller</a>, and I've been reading the documentation here (<a href="https://kubernetes-sigs.github.io/aws-load-balancer-controller/guide/ingress/annotations/#traffic-routing" rel="nofollow noreferrer">https://kubernetes-sigs.github.io/aws-load-balancer-controller/guide/ingress/annotations/#traffic-routing</a>), but I haven't found a clear explanation on how to achieve this.</p>
<p>Here's the setup:</p>
<p>I have service-a.example.com <em>-and-</em> service-b.example.com. They each have their own certificates within Amazon Certificate Manager.</p>
<p>Within Kubernetes, each has its own service object defined as follows (each unique):</p>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: v1
kind: Service
metadata:
  name: svc-a-service
  annotations:
    alb.ingress.kubernetes.io/healthcheck-protocol: HTTP
    alb.ingress.kubernetes.io/healthcheck-port: traffic-port
    alb.ingress.kubernetes.io/healthy-threshold-count: '5'
    alb.ingress.kubernetes.io/unhealthy-threshold-count: '2'
    alb.ingress.kubernetes.io/healthcheck-path: /index.html
    alb.ingress.kubernetes.io/healthcheck-interval-seconds: '30'
    alb.ingress.kubernetes.io/healthcheck-timeout-seconds: '5'
    alb.ingress.kubernetes.io/success-codes: '200'
    alb.ingress.kubernetes.io/tags: Environment=Test,App=ServiceA
spec:
  selector:
    app: service-a
  ports:
  - port: 80
    targetPort: 80
  type: NodePort
</code></pre>
<p>And each service has it's own Ingress object defined as follows (again, unique to each and with the correct certificates specified for each service):</p>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: svc-a-ingress
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/group.name: services
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/security-groups: sg-01234567898765432
    alb.ingress.kubernetes.io/ip-address-type: ipv4
    alb.ingress.kubernetes.io/listen-ports: '[{&quot;HTTP&quot;: 80}, {&quot;HTTPS&quot;: 443}]'
    alb.ingress.kubernetes.io/actions.ssl-redirect: '{&quot;Type&quot;: &quot;redirect&quot;, &quot;RedirectConfig&quot;: { &quot;Protocol&quot;: &quot;HTTPS&quot;, &quot;Port&quot;: &quot;443&quot;, &quot;StatusCode&quot;: &quot;HTTP_301&quot;}}'
    alb.ingress.kubernetes.io/actions.response-503: &gt;
      {&quot;type&quot;:&quot;fixed-response&quot;,&quot;fixedResponseConfig&quot;:{&quot;contentType&quot;:&quot;text/plain&quot;,&quot;statusCode&quot;:&quot;503&quot;,&quot;messageBody&quot;:&quot;Unknown Host&quot;}}
    alb.ingress.kubernetes.io/target-type: instance
    alb.ingress.kubernetes.io/load-balancer-attributes: routing.http2.enabled=true,idle_timeout.timeout_seconds=600
    alb.ingress.kubernetes.io/tags: Environment=Test
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-east-2:555555555555:certificate/33333333-2222-4444-AAAA-EEEEEEEEEEEE
    alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-2016-08
spec:
  rules:
    - http:
        paths:
          - path: /*
            backend:
              serviceName: ssl-redirect
              servicePort: use-annotation
          - path: /*
            backend:
              serviceName: svc-a-service
              servicePort: 80
          - path: /*
            backend:
              serviceName: response-503
              servicePort: use-annotation

</code></pre>
<p>The HTTP to HTTPS redirection works as expected.</p>
<p>However -- there is no differentiation between my two apps for the load balancer to be able to know that traffic destined for service-a.example.com and service-b.example.com should be routed to two different target groups.</p>
<p>In the HTTP:443 listener rules in the console, it shows:</p>
<ol>
<li>IF Path is /* THEN Forward to ServiceATargetGroup</li>
<li>IF Path is /* THEN Return fixed 503</li>
<li>IF Path is /* THEN Forward to ServiceBTargetGroup</li>
<li>IF Path is /* THEN Return fixed 503</li>
<li>IF Request otherwise not routed THEN Return fixed 404</li>
</ol>
<p>So the important question here is:
<strong>How should the ingress be defined to force traffic destined for service-a.example.com to ServiceATargetGroup - and traffic destined for service-b.example.com to ServiceBTargetGroup?</strong></p>
<p>And secondarily, I need the &quot;otherwise not routed&quot; to return a 503 instead of 404. I was expecting this to appear only once in the rules (be merged) - yet it is created for each ingress. How should my yaml be structured to achieve this?</p>

<p>I eventually figured this out -- so for anyone else stumbling onto this post, here's how I resolved it:</p>
<p>The trick was not relying on merging between the Ingress objects. Yes, it can handle a certain degree of merging, but there's not really a one-to-one relationship between Services as TargetGroups and Ingress as ALB. So you have to be very cautious and aware of what's in each Ingress object.</p>
<p>Once I combined all of my ingress into a single object definition, I was able to get it working exactly as I wanted with the following YAML:</p>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: svc-ingress
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/group.name: services
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/security-groups: sg-01234567898765432
    alb.ingress.kubernetes.io/ip-address-type: ipv4
    alb.ingress.kubernetes.io/listen-ports: '[{&quot;HTTP&quot;: 80}, {&quot;HTTPS&quot;: 443}]'
    alb.ingress.kubernetes.io/actions.ssl-redirect: '{&quot;Type&quot;: &quot;redirect&quot;, &quot;RedirectConfig&quot;: { &quot;Protocol&quot;: &quot;HTTPS&quot;, &quot;Port&quot;: &quot;443&quot;, &quot;StatusCode&quot;: &quot;HTTP_301&quot;}}'
    alb.ingress.kubernetes.io/actions.response-503: &gt;
      {&quot;type&quot;:&quot;fixed-response&quot;,&quot;fixedResponseConfig&quot;:{&quot;contentType&quot;:&quot;text/plain&quot;,&quot;statusCode&quot;:&quot;503&quot;,&quot;messageBody&quot;:&quot;Unknown Host&quot;}}
    alb.ingress.kubernetes.io/actions.svc-a-host: &gt;
      {&quot;type&quot;:&quot;forward&quot;,&quot;forwardConfig&quot;:{&quot;targetGroups&quot;:[{&quot;serviceName&quot;:&quot;svc-a-service&quot;,&quot;servicePort&quot;:80,&quot;weight&quot;:100}]}}
    alb.ingress.kubernetes.io/conditions.svc-a-host: &gt;
      [{&quot;field&quot;:&quot;host-header&quot;,&quot;hostHeaderConfig&quot;:{&quot;values&quot;:[&quot;svc-a.example.com&quot;]}}]
    alb.ingress.kubernetes.io/actions.svc-b-host: &gt;
      {&quot;type&quot;:&quot;forward&quot;,&quot;forwardConfig&quot;:{&quot;targetGroups&quot;:[{&quot;serviceName&quot;:&quot;svc-b-service&quot;,&quot;servicePort&quot;:80,&quot;weight&quot;:100}]}}
    alb.ingress.kubernetes.io/conditions.svc-b-host: &gt;
      [{&quot;field&quot;:&quot;host-header&quot;,&quot;hostHeaderConfig&quot;:{&quot;values&quot;:[&quot;svc-b.example.com&quot;]}}]
    alb.ingress.kubernetes.io/target-type: instance
    alb.ingress.kubernetes.io/load-balancer-attributes: routing.http2.enabled=true,idle_timeout.timeout_seconds=600
    alb.ingress.kubernetes.io/tags: Environment=Test
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-east-2:555555555555:certificate/33333333-2222-4444-AAAA-EEEEEEEEEEEE,arn:aws:acm:us-east-2:555555555555:certificate/44444444-3333-5555-BBBB-FFFFFFFFFFFF
    alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-2016-08
spec:
  backend:
    serviceName: response-503
    servicePort: use-annotation
  rules:
    - http:
        paths:
          - backend:
              serviceName: ssl-redirect
              servicePort: use-annotation
          - backend:
              serviceName: svc-a-host
              servicePort: use-annotation
          - backend:
              serviceName: svc-b-host
              servicePort: use-annotation
</code></pre>
<p><strong>Default Action:</strong></p>
<p>Set by specifying the serviceName and servicePort directly under <code>spec</code>:</p>
<pre class="lang-yaml prettyprint-override"><code>spec:
  backend:
    serviceName: response-503
    servicePort: use-annotation
</code></pre>
<p><strong>Routing:</strong></p>
<p>Because I'm using subdomains and paths won't work for me, I simply omitted the path and instead relied on hostname as a condition.</p>
<pre class="lang-yaml prettyprint-override"><code>metadata:
  alb.ingress.kubernetes.io/actions.svc-a-host: &gt;
      {&quot;type&quot;:&quot;forward&quot;,&quot;forwardConfig&quot;:{&quot;targetGroups&quot;:[{&quot;serviceName&quot;:&quot;svc-a-service&quot;,&quot;servicePort&quot;:80,&quot;weight&quot;:100}]}}
  alb.ingress.kubernetes.io/conditions.svc-a-host: &gt;
      [{&quot;field&quot;:&quot;host-header&quot;,&quot;hostHeaderConfig&quot;:{&quot;values&quot;:[&quot;svc-a.example.com&quot;]}}]
</code></pre>
<p><strong>End Result:</strong></p>
<p>The ALB rules were configured precisely how I wanted them:</p>
<ul>
<li>default action is a 503 fixed response</li>
<li>all http traffic is redirected to https</li>
<li>traffic is directed to TargetGroups based on the host header</li>
</ul>
