@@ -662,10 +662,21 @@ private void startNativeDocker() throws IOException, InterruptedException {
662662 }
663663
664664 private int dockerPort ;
665+ private boolean usingExistingDaemon = false ;
666+ private static final Object EXISTING_DAEMON_LOCK = new Object ();
667+ private static volatile boolean existingDaemonSetup = false ;
668+ private static volatile int sharedDaemonPort = 0 ;
669+ private static volatile String sharedWslIp = null ;
665670
666671 private void startWsl2Docker () throws IOException , InterruptedException {
667672 ensureInstalled ();
668673
674+ if (tryConnectToExistingDaemon ()) {
675+ log .info ("Connected to existing Docker daemon in WSL2" );
676+ usingExistingDaemon = true ;
677+ return ;
678+ }
679+
669680 dockerPort = 2375 + Math .abs (instanceId .hashCode () % 1000 );
670681 wslSocketPath = "tcp://0.0.0.0:" + dockerPort ;
671682 String wslLogFile = "/tmp/docker-java-" + instanceId + ".log" ;
@@ -731,7 +742,7 @@ private void startWsl2Docker() throws IOException, InterruptedException {
731742 String isolationFlags = "" ;
732743 if (otherDockerdRunning ) {
733744 log .info ("Another Docker daemon detected, using isolation flags to avoid conflicts" );
734- isolationFlags = " --iptables=false --bridge=none " ;
745+ isolationFlags = " --iptables=false" ;
735746 }
736747
737748 log .debug ("Starting dockerd directly..." );
@@ -830,6 +841,150 @@ private void printDockerdSudoManualInstructions() {
830841 log .error ("" );
831842 }
832843
844+ /**
845+ * Try to connect to an existing Docker daemon running in WSL2.
846+ * This checks if Docker is running, starts it if needed, and exposes it on TCP.
847+ * Uses synchronization to prevent race conditions when multiple threads call this.
848+ */
849+ private boolean tryConnectToExistingDaemon () {
850+ synchronized (EXISTING_DAEMON_LOCK ) {
851+ if (existingDaemonSetup && sharedDaemonPort > 0 && sharedWslIp != null ) {
852+ dockerPort = sharedDaemonPort ;
853+ wslIpAddress = sharedWslIp ;
854+ log .info ("Using existing Docker daemon connection on port {}" , dockerPort );
855+ return true ;
856+ }
857+
858+ try {
859+ String socketCheck = runWslCommand ("test -S /var/run/docker.sock && echo yes || echo no" , false , 5 );
860+ if (!"yes" .equals (socketCheck .trim ())) {
861+ log .debug ("Docker socket /var/run/docker.sock does not exist" );
862+
863+ log .info ("Docker daemon not running, attempting to start it..." );
864+ String startResult = runWslCommand ("sudo service docker start 2>&1" , false , 30 );
865+ log .debug ("Docker service start result: {}" , startResult );
866+
867+ Thread .sleep (3000 );
868+
869+ socketCheck = runWslCommand ("test -S /var/run/docker.sock && echo yes || echo no" , false , 5 );
870+ if (!"yes" .equals (socketCheck .trim ())) {
871+ log .debug ("Docker socket still doesn't exist after service start" );
872+ return false ;
873+ }
874+ }
875+
876+ log .info ("Found Docker daemon in WSL2, setting up TCP forwarding..." );
877+
878+ String wslIp = runWslCommand ("hostname -I | awk '{print $1}'" , false , 5 ).trim ();
879+ if (wslIp .isEmpty ()) {
880+ log .info ("Could not get WSL2 IP address, will use isolated daemon" );
881+ return false ;
882+ }
883+ wslIpAddress = wslIp ;
884+ log .info ("WSL2 IP: {}" , wslIp );
885+
886+ String socatPath = runWslCommand ("command -v socat 2>/dev/null || echo ''" , false , 5 ).trim ();
887+ if (socatPath .isEmpty ()) {
888+ log .info ("Installing socat for TCP forwarding..." );
889+ runWslCommand ("sudo apt-get update -qq && sudo apt-get install -y -qq socat 2>&1" , false , 120 );
890+ socatPath = runWslCommand ("command -v socat 2>/dev/null || echo ''" , false , 5 ).trim ();
891+ if (socatPath .isEmpty ()) {
892+ log .info ("Failed to install socat, will use isolated daemon" );
893+ return false ;
894+ }
895+ }
896+
897+ dockerPort = 2375 ;
898+
899+ runWslCommand ("sudo pkill -9 -f 'socat.*:" + dockerPort + "' 2>/dev/null; sleep 1" , false , 10 );
900+
901+ String socketPerms = runWslCommand ("ls -la /var/run/docker.sock 2>&1" , false , 5 );
902+ log .info ("Docker socket: {}" , socketPerms .trim ());
903+
904+ String socatCmd = String .format (
905+ "sudo nohup socat TCP-LISTEN:%d,bind=0.0.0.0,reuseaddr,fork UNIX-CONNECT:/var/run/docker.sock </dev/null >/tmp/socat-%d.log 2>&1 &" ,
906+ dockerPort , dockerPort );
907+ runWslCommand (socatCmd , false , 5 );
908+
909+ Thread .sleep (2000 );
910+
911+ String socatPid = runWslCommand ("pgrep -f 'socat.*:" + dockerPort + "' 2>/dev/null | head -1 || echo ''" , false , 5 ).trim ();
912+ if (socatPid .isEmpty ()) {
913+ String socatLog = runWslCommand ("cat /tmp/socat-" + dockerPort + ".log 2>/dev/null | head -20 || echo '(no log)'" , false , 5 );
914+ log .info ("socat failed to start. Log: {}" , socatLog );
915+ return false ;
916+ }
917+ log .info ("socat running with PID: {}" , socatPid );
918+
919+ String listenCheck = runWslCommand ("ss -tlnp 2>/dev/null | grep ':" + dockerPort + " ' || echo 'not listening'" , false , 5 );
920+ log .info ("Port {} status: {}" , dockerPort , listenCheck .trim ());
921+
922+ boolean connected = testDockerConnection (wslIp , dockerPort );
923+ if (!connected ) {
924+ connected = testDockerConnection ("localhost" , dockerPort );
925+ if (connected ) {
926+ wslIpAddress = "localhost" ;
927+ }
928+ }
929+
930+ if (connected ) {
931+ sharedDaemonPort = dockerPort ;
932+ sharedWslIp = wslIpAddress ;
933+ existingDaemonSetup = true ;
934+ log .info ("Connected to Docker daemon via TCP at {}:{}" , wslIpAddress , dockerPort );
935+ return true ;
936+ }
937+
938+ String socatLog = runWslCommand ("cat /tmp/socat-" + dockerPort + ".log 2>/dev/null | tail -10 || echo '(no log)'" , false , 5 );
939+ log .info ("Connection failed, socat log: {}" , socatLog );
940+ return false ;
941+ } catch (Exception e ) {
942+ log .info ("Failed to connect to existing daemon: {}" , e .getMessage ());
943+ return false ;
944+ }
945+ }
946+ }
947+
948+ /**
949+ * Test Docker connection from Windows by attempting a TCP socket connection and HTTP request.
950+ */
951+ private boolean testDockerConnection (String host , int port ) {
952+ try {
953+ log .info ("Testing Docker connection to {}:{}..." , host , port );
954+
955+ java .net .Socket socket = new java .net .Socket ();
956+ socket .connect (new java .net .InetSocketAddress (host , port ), 3000 );
957+ socket .close ();
958+ log .info ("TCP socket connection successful to {}:{}" , host , port );
959+
960+ java .net .URL url = new java .net .URL ("http://" + host + ":" + port + "/version" );
961+ java .net .HttpURLConnection conn = (java .net .HttpURLConnection ) url .openConnection ();
962+ conn .setConnectTimeout (3000 );
963+ conn .setReadTimeout (3000 );
964+ int responseCode = conn .getResponseCode ();
965+ conn .disconnect ();
966+
967+ if (responseCode == 200 ) {
968+ log .info ("Docker API responding at {}:{}" , host , port );
969+ return true ;
970+ }
971+ log .info ("Docker API returned HTTP {} at {}:{}" , responseCode , host , port );
972+ return false ;
973+ } catch (java .net .ConnectException e ) {
974+ log .info ("Connection refused to {}:{} - socat may not be forwarding correctly" , host , port );
975+ return false ;
976+ } catch (java .net .SocketTimeoutException e ) {
977+ log .info ("Connection timeout to {}:{}" , host , port );
978+ return false ;
979+ } catch (IOException e ) {
980+ log .info ("Connection test failed for {}:{} - {}: {}" , host , port , e .getClass ().getSimpleName (), e .getMessage ());
981+ return false ;
982+ }
983+ }
984+
985+ /**
986+ * Check if passwordless sudo is available for dockerd.
987+ */
833988 private boolean checkPasswordlessSudo () {
834989 try {
835990 ProcessBuilder pb = new ProcessBuilder ("wsl" , "-d" , wslDistro , "-e" , "bash" , "-c" ,
@@ -1023,6 +1178,18 @@ public DockerClient getClient() {
10231178 public void stop () {
10241179 log .info ("Stopping Docker daemon (instance: {})..." , instanceId );
10251180
1181+ if (usingExistingDaemon && usingWsl2 && wslDistro != null ) {
1182+ try {
1183+ ProcessBuilder pb = new ProcessBuilder ("wsl" , "-d" , wslDistro , "-e" , "bash" , "-c" ,
1184+ "sudo -n pkill -f 'socat.*:" + dockerPort + "' 2>/dev/null || true" );
1185+ pb .start ().waitFor (5 , TimeUnit .SECONDS );
1186+ log .info ("Stopped socat TCP forwarder" );
1187+ } catch (IOException | InterruptedException e ) {
1188+ log .debug ("Failed to stop socat: {}" , e .getMessage ());
1189+ }
1190+ return ;
1191+ }
1192+
10261193 if (dockerProcess != null ) {
10271194 if (usingWsl2 && wslDistro != null ) {
10281195 try {
0 commit comments