Kubernetes: Ingress: Allow for multiple hosts

Created on 24 Mar 2017  ·  38Comments  ·  Source: kubernetes/kubernetes

Is this a request for help?
No

What keywords did you search in Kubernetes issues before filing this one?
Ingress controller, "hosts", multiple host.

I found this issue: https://github.com/kubernetes/ingress/issues/87 but it was closed as it was in the wrong repo.


Is this a BUG REPORT or FEATURE REQUEST? (choose one):
FEATURE REQUEST

With the current implementation, if you have a few sub-/domains which need to point to the same service, you get a "lot" of duplicated code.

Example:

spec:
  rules:
  - host: foobar.com
    http:
      paths:
      - backend:
          serviceName: foobar
          servicePort: 80
  - host: api.foobar.com
    http:
      paths:
      - backend:
          serviceName: foobar
          servicePort: 80
  - host: admin.foobar.com
    http:
      paths:
      - backend:
          serviceName: foobar
          servicePort: 80
  - host: status.foobar.com
    http:
      paths:
      - backend:
          serviceName: foobar
          servicePort: 80

So I propose that the Host field get changed from a single FQDN to a array of FQDN.
So I could do something like:

spec:
  rules:
  - host: ["foobar.com", "api.foobar.com", "admin.foobar.com", "status.foobar.com"]
    http:
      paths:
      - backend:
          serviceName: foobar
          servicePort: 80

It save me 18 lines and makes the config more clear.

Maybe dup of: https://github.com/kubernetes/kubernetes/issues/41881 , but this seems easier to implement.

cc @aledbf (you closed the last issues, not sure if you "work" in this part of k8s)

Kubernetes version (use kubectl version):

Client Version: version.Info{Major:"1", Minor:"5", GitVersion:"v1.5.4", GitCommit:"7243c69eb523aa4377bce883e7c0dd76b84709a1", GitTreeState:"clean", BuildDate:"2017-03-07T23:53:09Z", GoVersion:"go1.7.4", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"5", GitVersion:"v1.5.4+coreos.0", GitCommit:"97c11b097b1a2b194f1eddca8ce5468fcc83331c", GitTreeState:"clean", BuildDate:"2017-03-08T23:54:21Z", GoVersion:"go1.7.4", Compiler:"gc", Platform:"linux/amd64"}

Environment:
DigitalOcean, CoreOS.

sinetwork triagunresolved

Most helpful comment

I also would like to see this feature, but as a workaround, I use YAML ids. Here is how it would look for given example.

spec:
  rules:
  - host: foobar.com
    http: &http_rules
      paths:
      - backend:
          serviceName: foobar
          servicePort: 80
  - host: api.foobar.com
    http: *http_rules
  - host: admin.foobar.com
    http: *http_rules
  - host: status.foobar.com
    http: *http_rules

All 38 comments

+1 for this as well. As referenced by both @klausenbusk and me at https://github.com/kubernetes/kubernetes/issues/41881 , this would go a long way.

I prefer to have a wildcard or a subdomain-only option, so I can specify host: web.* or host: api.web.* and have anything that _starts_ with that pattern pass through, leaving the service ignorant as to its final domain (is it running in .example.com? .prod.example.com? .beta.example.com? .it.internal?), but anything that moves it past the current monolithic "must list entire single domain in host: is a big step forward.

Personally, I also think the ingress controller (which usually is deployed by cluster admins) should have a restriction that says, "only service the following domains or subdomains of them...", but that is a separate issue.

Another +1. I think almost anyone with a non-trivial ingress use-case will benefit from this.

+1

+1

Issues go stale after 90d of inactivity.
Mark the issue as fresh with /remove-lifecycle stale.
Stale issues rot after an additional 30d of inactivity and eventually close.

Prevent issues from auto-closing with an /lifecycle frozen comment.

If this issue is safe to close now please do so with /close.

Send feedback to sig-testing, kubernetes/test-infra and/or @fejta.
/lifecycle stale

/remove-lifecycle stale

Apparently, I cannot remove it from stale...

looks like it worked @deitch !

I also would like to see this feature, but as a workaround, I use YAML ids. Here is how it would look for given example.

spec:
  rules:
  - host: foobar.com
    http: &http_rules
      paths:
      - backend:
          serviceName: foobar
          servicePort: 80
  - host: api.foobar.com
    http: *http_rules
  - host: admin.foobar.com
    http: *http_rules
  - host: status.foobar.com
    http: *http_rules

I don't have much to add except to say this would be very welcome. Hopefully the rules for beta APIs still allow some flexibility to modify this.

same here - have to add multiple domains i.e.

*.foobar.com
*.foobar.net
*.foobar.biz

what is not really comfortable in the current implementation...

so, vote up...

Issues go stale after 90d of inactivity.
Mark the issue as fresh with /remove-lifecycle stale.
Stale issues rot after an additional 30d of inactivity and eventually close.

If this issue is safe to close now please do so with /close.

Send feedback to sig-testing, kubernetes/test-infra and/or fejta.
/lifecycle stale

/remove-lifecycle stale

This is much needed :((

+1 for this feature.

I also tried @kramarz suggested workaround, and I get the following error:
Error: YAML parse error on mysite-web/templates/ingress.yaml: error converting YAML to JSON: yaml: line 4: mapping values are not allowed in this context

+1 for this feature.

Issues go stale after 90d of inactivity.
Mark the issue as fresh with /remove-lifecycle stale.
Stale issues rot after an additional 30d of inactivity and eventually close.

If this issue is safe to close now please do so with /close.

Send feedback to sig-testing, kubernetes/test-infra and/or fejta.
/lifecycle stale

/remove-lifecycle stale

feature needed indeed

Use case I haven't seen yet, we have some domains that look like api[0-9].domain.io -- existing wildcard domains don't cover this case. The set is small enough to manage manually using yaml IDs, but would be ideal to not need that fallback (e.g., regex domain names)

We really need this feature

Another vote for this feature

another work around using range loop:

rules:
          {{- range .Values.ingress.hosts }}
    - host: {{ . }}
      http:
        paths:
          - path: /
            backend:
              serviceName: {{ $fullName }}
              servicePort: 80
              {{- end }}

and in values yaml:

ingress:
  hosts:
    - "bla.blub"
    - "foo.bar"

and set a variable fullName...

Still i'd prefer an array or regex or ... for the hosts element

This is almost certainly not happening in Ingress , but we should keep it in mind for the API to follow Ingress (proposals coming soon?)

API to follow Ingress, @thockin? Is there a replacement in the works?

This is almost certainly not happening in Ingress

No? Seems a frequently requested feature to avoid a lot of duplication. -- What's our alternatives?

Might be useful for someone, I use server-alias option on the nginx ingress to have multiple domains for a single ingress.

Might be useful for someone, I use server-alias option on the nginx ingress to have multiple domains for a single ingress.

@catalinpan how does it work on your end? My server-alias doesn't work with this config.

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: foobar-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/server-alias: "two-app.foobar.dev"
spec:
  tls:
  - secretName: tls-secret
  rules:
  - host: "one-app.foobar.dev"
    http:
      paths:
      - backend:
          serviceName: foobar
          servicePort: 80

@angelogwapo is worth checking if the nginx ingress version you have supports the alias implementation. If the version is newer check here how the rewrite-target syntax should look like.
There is a case where your alias will not work if there is another ingress which uses the same domain, here is the explanation.

As long as the above case doesn't apply to you and the DNS record for two-app.foobar.dev points to the same load balancer as one-app.foobar.dev your example should work.

I manage the server alias in Route 53 using terraform because of my specific use case, multiple deployments in different regions = multiple server alias CNAMEs pointing to multiple hosts with health checks and few more options.

example:
CNAME two-app.foobar.dev --> one-app-ew1.foobar.dev
CNAME two-app.foobar.dev --> one-app-ase1.foobar.dev

Below is an example of something I use.

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/server-alias: public_url
  name: app1
spec:
  tls:
  - hosts:
    - public_region_url
      secretName: my_wildcard
  rules:
    - host: public_region_url
      http:
        paths:
          - path: /
            backend:
              serviceName: app1
              servicePort: 80

This feature would be great to have for users of traefik who are also using the automated Let's Encrypt feature. Here, traefik expects a comma-separated list of domains as the Host (https://docs.traefik.io/v1.7/configuration/acme/#onhostrule), where the first domain will become the main domain of the certificate and all others will be SANs.

@catalinpan I am also struggling with the server-alias annotation.
I have almost the same config as @angelogwapo. I have two domains:

  • one-app.one-domain.dev
  • two-app.two-domain.dev

Both are pointing to the same loadbalancer. Both have a valid TLS certificate.
Below my config. I get directed to the correct page, but the TLS certificate is only valid for the domain mentioned as the host. When I browse to the other domain, I am presented the Kubernetes Ingress Controller Fake Certificate. And vice versa. Any help is appreciated...

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    app.kubernetes.io/instance: ngress-rules
    cert-manager.io/issuer: letsencrypt-prod
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/server-alias: two-app.two-domain.dev
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
  name: ingress-rules
  namespace: default
spec:
  rules:
  - host: one-app.one-domain.dev
    http:
      paths:
      - backend:
          serviceName: service1
          servicePort: 80
        path: /
      - backend:
          serviceName: service2
          servicePort: 80
        path: /portal/
  tls:
  - hosts:
    - one-app.one-domain.dev
    secretName: one-app-tls
  - hosts:
    - two-app.two-domain.dev
    secretName: two-app-tls

Btw, I am using version 0.27 which should contain this change: https://github.com/kubernetes/ingress-nginx/pull/4472/files#diff-9bba411a7c28f1ef63c3a5339db109d5

@jacqinthebox: Your Ingress configuration actually only configures one host (one-app.one-domain.dev). Sure, your tls configures both of them, but you still need one rule for each domain. Specifically see the array under spec.rules. Currently, there is nothing that tells NGINX which service that the 2nd domain should proxy to.

EDIT: My bad, I was too quick. I didn't realize you were talking about the server alias annotation.

@jacqinthebox

Both are pointing to the same loadbalancer. Both have a valid TLS certificate.

you may use multiple independent domains in one TLS secret
``` tls:

  • hosts:

    • one-app.one-domain.dev

    • two-app.two-domain.dev

      secretName: all-app-tls

      ```

You can always use a helm chart to create the dup config for each domain in an array. "If" you are using helm of course :)

+1

@kramarz , Thanks, this workround work for me.

The workaround works also perfectly with https://github.com/jetstack/cert-manager .
Here is my example

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
   name: site
   annotations:
      cert-manager.io/issuer: letsencrypt-prod
      nginx.ingress.kubernetes.io/server-alias: host2.com
spec:
   rules:
   - host: host1.com
     http:
      paths:
      - path: /
        backend:
           serviceName: site
           servicePort: 8080
   tls:
   - secretName: nice-name
     hosts:
     - host1.com
     - host2.com

@AndreKoepke thank you for this. It worked somewhat for me but after adding domain.com to spec.rules[0].host and www.domain.com,domain.se,www.domain.se to nginx.ingress.kubernetes.io/server-alias I get the following error: controller.go:1155] Conflicting hostname (domain.com) and alias (www.domain.se). Removing alias to avoid conflicts.

Any suggestions?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

montanaflynn picture montanaflynn  ·  3Comments

alexferl picture alexferl  ·  3Comments

zetaab picture zetaab  ·  3Comments

Seb-Solon picture Seb-Solon  ·  3Comments

theothermike picture theothermike  ·  3Comments