Had the same problem for my work setup on Linux, where we’re also bound to an Ivanti gateway with PulseSecure as VPN client without split-tunneling. The issue with this is that the PulseSecure client puts itself as the default gateway for every route or local interface it encounters and overwrites any of your IP route changes immediately.
Since you’re speaking of Docker Desktop, I assume you’re on Windows. I have no experience with DD since I’m using Rancher Desktop, but as far as it concerns Rancher, it’s not an issue there, since it integrates itself already in the Hypervisor (network-wise), so no noticable issues there for me.
On Linux (in my case AlmaLinux), however, I had to craft my own solution. Since you have a bit more power over policy based routing on Linux, you can place your own routes in a routing table which sits higher in the priority list than the main routing table. Say, you want to put your Docker related routes in a custom routing table named ‘docker’ which is consulted before the ‘main’ routing table (which the PulseSecure client operates on). For this, you’d first create that named table:
$ cat /etc/iproute2/rt_tables
200 docker
The number doesn’t really matter, it’s just an ID you pick for yourself. IDs 253–255 are already taken by the default tables ‘local’, ‘main’ and ‘default’. The rest is free to chose.
After that, you create a new IP rule for that table which funnels all routing requests first through that table, but before the ‘main’ table:
ip rule add table docker
That’s already it. It automaticaly creates a new rule with a priority one higher than the priority of the ‘main’ table. But you can also specify a custom priority, say 1000, by adding priority 1000 to the above command. Your IP rules should look similar to this:
$ ip rule list
0: from all lookup local
32765: from all lookup docker
32766: from all lookup main
32767: from all lookup default
Notice that the priority of the ‘docker’ table is one higher than the ‘main’ table (lower numbers mean higher priority).
The only thing left to do now is to add your IP routes for your Docker networks to that table. Assuming the default subnet of your Docker is 172.17.0.0/16, you would do it like so:
$ ip route add 172.17.0.0/16 dev docker0 metric 1
At least for me it was important that I also added the metric, otherwise the PulseSecure client would constantly throw up and get confused. Of course it’s up to you now to figure out all the subnets and interface names that you might have, but these are the basic commands that you need to talk to your local containers while not messing around with the IP routes set up by the PulseSecure client.
I for one wrote a little helper script for myself which hooks into Systemd and watches for any changes on Docker networks and alters routes accordingly in real time. You can get creative with the tools you have at hand.