nginxinc / kubernetes-ingress

NGINX and NGINX Plus Ingress Controllers for Kubernetes
https://docs.nginx.com/nginx-ingress-controller
Apache License 2.0
4.68k stars 1.97k forks source link

Support for not setting explicit host #209

Open kbirger opened 7 years ago

kbirger commented 7 years ago

According to the K8S Ingress spec, I should be able to either set a rule with no host, or an ingress with no rules, and be able to have a default backend.

In the first case, the controller rejects the ingress because it has a rule with no host, and in the second case, it fails to create a server entry that has a proxy_pass to the default backend of the rule.

Is this a bug, or is this intentional? (if so, why?)

I'd like to see support for both of these cases as they are in the documentation: https://kubernetes.io/docs/concepts/services-networking/ingress/

If there is some reason why they cannot be supported organically, I'd like to see a way to override the server_name directive that gets generated so that I can have a server that listens to all hosts.

Aha! Link: https://nginx.aha.io/features/IC-111

pleshakov commented 7 years ago

@kbirger this restriction is intentional. While the Ingress spec allows rules with no hosts or an Ingress with no rules but with the default backend, this Ingress controller doesn't support those.

The reason such rules are not supported is that it is possible to create multiple Ingress rules with no hosts, however, NGINX can only handle one such rule.

What is your use-case? Do you only need a single server with no host?

kbirger commented 7 years ago

Thanks @pleshakov. Sometimes I'm working with an internal environment where the worker nodes have no machine name. We are still working to see if we can connect our load balancer (F5 Big-IP) to talk to K8S. It would be useful to set up a single server with no host so that regardless of which node the ingress controller is running on and regardless of which node you address, you could access applications on a standard port (80/443).

Right now I'm getting around it by using xip and creating a rule for each worker node, but this of course means I need to reference the node IPs from my ingress configuration.

So instead of having to do:

spec:
  rules:
    - host: 10.74.151.67.xip.io
      http:
        paths:
          - path: /
            backend:
              serviceName: my-service
              servicePort: 80
    - host: 10.74.151.70.xip.io
      http:
        paths:
          - path: /
            backend:
              serviceName: my-service
              servicePort: 80

I'd rather be able to write:

spec:
  rules:
    - http:
        paths:
          - path: /
            backend:
              serviceName: my-service
              servicePort: 80
pleshakov commented 7 years ago

@kbirger if you need to expose only one application, regardless of its DNS name, I recommend deploying NGINX without the Ingress controller, and configure NGINX using its native configuration. You can put that configuration into a ConfigMap resources(https://kubernetes.io/docs/tasks/configure-pod-container/configmap/) and mount that configuration on the filesystem of NGINX container. A simplified config for your case is below:

upstream backend {
    server my-service;
}

server {
    listen 80 default_server;

    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;
    }
}

Also, for the Ingress resource you attached above, you can use a wildcard host. For example, - host: *.xip.io

kbirger commented 7 years ago

I do want multiple applications, though I didn't include it in this example. My understanding is that you may have multiple applications on the same host, and thus on the same server.

The following is what I would like to represent:

upstream service-one { 
    server service-one;
}

upstream service-two {
    server service-two;
}

server { 
    listen 80 default_server; # underscore causes nginx to match any host

    location /one {
        proxy_pass http://service-one;
        proxy_set_header Host $host;
    }

    location /two {
        proxy_pass http://service-two;
        proxy_set_header Host $host;
    }
}

Also, host: *.xip.io violates the schema for that field. At least in K8S 1.6, which is what I am currently on (soon upgrading to 1.7, if that makes any difference)

pleshakov commented 7 years ago

@kbirger Yes, that is a valid case. However, what I meant by an application is that an application has a unique DNS name. This Ingress controller is designed for load balancing several applications, each with a unique DNS name. The case when you only need to load balance one application (with possible path-based routing across multiple k8s services, as in your second example), regardless of the application DNS name, is far less common. Even for a single application, it is common to have a DNS name. That is why it is not supported in this Ingress controller.

Could you try like this : host: "*.xip.io"? My mistake, I gave you an invalid example.

alvgarvilla commented 6 years ago

Is there any new about this Issue? What if I want to call my ingress service from javascript for example? I cannot set Host header from it. As @kbirger says, documentation says it is possible to set a rule without host, but then it is mandatory to add Host to the header...

pleshakov commented 6 years ago

@alvgarvilla we are not planning to support rules without hosts, as (1) this use case is not common and (2) NGINX can only handle one rule without host, because one NGINX is used for all Ingress rules.

benmathews commented 6 years ago

I've a case with a client that I don't control that is calling me via an IP. There is no hostname. This bug makes it impossible to serve the content through a nginx ingress controller.

pleshakov commented 6 years ago

@benmathews Thanks for sharing. Unfortunately, we don't have any plans to support that use case. For cases when clients don't use the DNS name, we recommend using NGINX without the Ingress controller. Please see https://github.com/nginxinc/kubernetes-ingress/issues/209#issuecomment-341196060 Can that approach solve your problem?

benmathews commented 6 years ago

We have lots of applications, this is just one of them. Ingress is certainly wanted and needed. There are always workarounds, but I'd wish to avoid them if possible. In our case, I'll probably put some code on our load balancer to add a host name header.

pleshakov commented 6 years ago

as a workaround in the Ingress controller, you can create an Ingress resource for which NGINX will create a virtual server that will listen on a custom port. For example:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: cafe-ingress
  annotations:
     kubernetes.io/ingress.class: "nginx"
     nginx.org/listen-ports: "8080"

In the Ingress resource, you can use an arbitrary name as the value of the host.

In this case the generated virtual server will listen on port 8080. If you make a request to NGINX using its IP and port 8080, it will respond even if you don't specify the host header in the request.

Note that you can only have one Ingress resource with exactly one Ingress rule per port.

luispollo commented 6 years ago

@pleshakov I just came across this issue while researching a problem we were facing, where we previously had several ingresses using path-based rules and no hosts on the same ingress controller, and the controller would happily route traffic regardless of the hostname, and then suddenly it stopped doing that.

We found that, when there was at least one ingress object picked up by the same controller which did have a host specified, then routing with that particular hostname for other ingress objects which did not have a matching host would not work. However, when we removed the host rule from all the ingresses, leaving only the paths, the controller would route just fine.

I thought I should bring that up because it contradicts your and other statements above that this configuration is not supported... Or was there something I missed?

Hope this helps. (And I would ask the team to please not remove that capability. 😃)

pleshakov commented 6 years ago

@luispollo we don't support Ingress resources without hosts. It might be the case that you're using a different Ingress Controller https://github.com/kubernetes/ingress-nginx Could you possible double check?

luispollo commented 6 years ago

@pleshakov Oh, yes, I'm using the Ingress Controller hosted in the Kubernetes org. I assumed it was just a fork but can see the README clearly states it's a different implementation. My apologies.

delfer commented 5 years ago

In my case to avoid CORS I'm using path-based routing instead of host-based. And better have something like host: * to do not binds to stage or prod domains.

jjindrich commented 5 years ago

Fully agree, I don't want to care on my igress IP.

nfds89 commented 5 years ago

Is there any solution for this issue? I tried using the rule "hosts: ''" on the config file but got an error: range can't iterate over

clarktlaugh commented 5 years ago

we are not planning to support rules without hosts, as (1) this use case is not common and (2) NGINX can only handle one rule without host, because one NGINX is used for all Ingress rules.

Seems like it would be common when using path-based routing -- I don't care what the host name is. Or is there another simple way to do it?

htonkovac commented 5 years ago

Have in mind these are also valid wildcards: host: "*.elb.amazonaws.com" host: "*.com"

cseeger-epages commented 4 years ago

I have the same problem i'm using a setup which is later deployed on a system where i dont know (and dont want to care about) the hostname yet so i dont want to specify it. I just need a default vhost routing different paths to different services in different namespaces

Benjamin-Beeman commented 4 years ago

I agree not accepting all hosts is very limiting.

lokeshmadan commented 4 years ago

Any update on this issue ? Seems like a very common requirement.

pleshakov commented 4 years ago

There is a workaround that uses server snippet annotation:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: cafe-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.org/server-snippets: "server_name ~^.*$;"
spec:
  tls:
  - hosts:
    - cafe.example.com
    secretName: cafe-secret
  rules:
  - host: cafe.example.com
    http:
      paths:
      - path: /tea
        backend:
          serviceName: tea-svc
          servicePort: 80
      - path: /coffee
        backend:
          serviceName: coffee-svc
          servicePort: 80

As a result, requests that use IP addresses or random host names will be routed to that Ingress resource. For example, curl https://127.0.0.1/coffee -sk or curl https://bogus.example.com/coffee -sk

Note that you can only deploy one Ingress resource with such a server_name ~^.*$;. If you deploy multiple Ingresses like that , only one will catch requests with IP addresses or random host names.

skashyap7 commented 4 years ago

Any change of plans on this?

lubinson commented 4 years ago

can you support * similar to istio?

johnzeng2010 commented 3 years ago

The workaround posted on Feb 3, 2020 does not work for me.

github-actions[bot] commented 3 years ago

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.

congenica-peter-fox commented 3 years ago

I'm another me too. Trying to deploy the same application multiple times to the same Kubernetes cluster. I want to use the same host name. So

http://host.com/production routes to production deployment and http://host.com/preproduction routes to preproduction.

I want to use the same host so I can have one registration in external OpenId Connect provider

Using a similar set up in development with each team/branch having its down deployment with different path to route off. Actually I really want to use a wild card host so I have a DNS record *.myapp.mydomain.com points at the cluster. The wild carded host acts a way of picking a tenant and I route to deployment off path.

So

http://tenant1.myapp.mydomain.com/live routes as tenant1 (and tenant1 OIDC provider) to deployment live

and

http://tenant2.myapp.mydomain.com/test routes as tenant2 to deployment test

This means I can add new tenants by adding the OIDC configuration to the relevant application and I can deploy new environments (or applications) by deploying the app and deploying some ingress rules.

github-actions[bot] commented 3 years ago

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.

shaun-nx commented 3 months ago

Hi folks 👋 It's very clear from all of the comments that there are many use-cases for this. We are looking into re-evaluating the value, priority and effort of this request.

We encourage everyone to keep an eye on the existing Epic Roadmap and Prioritized Backlog for the project.

I am currently in the process of grooming our existing issues, starting with the oldest ones. As you look at the backlog now, know that it is very likely to change in the near future. Some issues may be added, and some removed 🙂