Ingress is used as entry point for clients to publicly access the services on a kubernetes cluster. In a absence of an ingress the services are typically exposed to outside via a kubernetes resoure of the type loadbalancer. Loadbalancers are expensive resources in cloud and using them for every service is just not practicle even in your on-premises private cloud. Ingress controllers not only solve this problem but also provide additional features like SSL termination, host based or path based routing and the list goes on and on. Ingress controller can typically do both host based and path based routing to kubernetes services.
Ingress overcome restrictions with using kubernetes serivices like nodePort where one is restricted to use port number 30000 and above. Cloud loadbalancers also overcomes this restriction but at higher cost as the services that are exposed grow the number of load balancers that required also keep growing. Cloud load balancers are expensive items. This is where an ingress controller has an advantage as it can expose multiple services using a single cloud loadbalancer.
The cloud loadbalancer talks with ingress which in turn routes the traffic to an underlying service on kubernetes. In kubernetes both loadbalancer and ingress have service endpoints connected with each other. On public cloud ingress controller can provision cloud loadbalancer for themselves whereas on private cloud clusters use metallb as loadbalancer.