On the Nomad project we've taken a distinct approach to networking: treat the IP layer as an implementation detail and attempt to abstract it away. This has led to a few design decisions:
1. Global node addressing - Given a region + node ID you can query any node from any other node.
2. Global allocation (pod) addressing - Given a region + allocation ID you can interact with individual allocations and tasks (metrics, files, logs, remote exec, etc).
3. Global name-based service addressing (via Consul) - whether via Consul's DNS interface, catalog API, or Connect service mesh, services discover one another by name instead of by IP or port. The service's address (ip+port) is hopefully an opaque implementation detail that never needs to be externally observed.
With all 3 of these taken together there's no need for overlays, distinct subnets, or unique IPs-per-allocation. Datacenters may even have overlapping subnets and Consul Connect will still allow services to communicate via global name based addressing. Even without Consul, almost all Nomad commands will route to a remote region and execute on the correct node regardless of subnet overlapping.
This does cause some friction at the edge: when translating from external IP based routing to internal services (aka ingress). However, there are lots of load balancers that integrate with Consul and therefore translate between IP and name based routing adequately.
Really any service unhappy with our "route by name, not by ip" design is going to be a bit awkward to use, but routable IPs and ports are selected and exposed by Nomad's scheduler - or advertised in Consul if the address is overridden at runtime.