You can either put a dedicated load balancer to each of them (the expensive solution, but straight forward), or make your Ingress Controller to only accept requests with a hostname, and point each hostname to it's service, in its namespace (cheap solution but complicate).
Load Balancer Solution:
This one is easy, if you are with a cloud provider, so every time a client exposes the app, you just create a LoadBalancer type service pointing to his app. Since for each app you get a new load balancer, you have no problem of port collision. Now, the drawbacks are that this you can do only with a cloud provider, and it will be quite expensive.
Ingress Solution:
This one is the pro solution. It's cheap, but it's also more complex. So, you would create an Ingress resource like this:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
spec:
tls:
- secretName: tls
rules:
- host: site1.domain.com
http:
paths:
- path: /path1/
backend:
serviceName: service1
servicePort: 80
- host: site2.domain.com
http:
paths:
- backend:
serviceName: service1
servicePort: 80
...
Here, you just have one L7 load balancer, and that's Ingress Controller doing all the routing. Depending on Ingress Controller, you might get an L4 load balancer (e.g. nginx, Traefik), but still that's Ingres Controller doing the routing.
Complexity? You will have to figure out a way to update the Ingress Controller records without a downtime for other users. Also, on Kubernetes, an Ingress Controller can't pass a request from one namespace to another. So, the service needs to run in the same namespace that the Ingress resource has been created (Note, I'm saying Ingress resource, being the rules (like the yaml above); not Ingress Controller). This is a known limitation that Kubernetes team already announced that will never be changed, as it introduces a huge security hole.
You will need to create headless services without selectors in the same namespace that Ingress object, and separately create Endpoint objects pointing to the service in the other namespaces. It might look like cumbersome, but that's quite pro actually.