@@ -439,10 +439,21 @@ private void startNativeDocker() throws IOException, InterruptedException {
439439 }
440440
441441 private int dockerPort ;
442+ private boolean usingExistingDaemon = false ;
443+ private static final Object EXISTING_DAEMON_LOCK = new Object ();
444+ private static volatile boolean existingDaemonSetup = false ;
445+ private static volatile int sharedDaemonPort = 0 ;
446+ private static volatile String sharedWslIp = null ;
442447
443448 private void startWsl2Docker () throws IOException , InterruptedException {
444449 ensureInstalled ();
445450
451+ if (tryConnectToExistingDaemon ()) {
452+ log .info ("Connected to existing Docker daemon in WSL2" );
453+ usingExistingDaemon = true ;
454+ return ;
455+ }
456+
446457 dockerPort = 2375 + Math .abs (instanceId .hashCode () % 1000 );
447458 wslSocketPath = "tcp://0.0.0.0:" + dockerPort ;
448459 String wslLogFile = "/tmp/docker-java-" + instanceId + ".log" ;
@@ -492,7 +503,7 @@ private void startWsl2Docker() throws IOException, InterruptedException {
492503 String isolationFlags = "" ;
493504 if (otherDockerdRunning ) {
494505 log .info ("Another Docker daemon detected, using isolation flags to avoid conflicts" );
495- isolationFlags = " --iptables=false --bridge=none " ;
506+ isolationFlags = " --iptables=false" ;
496507 }
497508
498509 log .debug ("Starting dockerd directly..." );
@@ -582,6 +593,147 @@ private void startWsl2Docker() throws IOException, InterruptedException {
582593 log .info ("Docker daemon started in WSL2 (instance: {}, port: {})" , instanceId , dockerPort );
583594 }
584595
596+ /**
597+ * Try to connect to an existing Docker daemon running in WSL2.
598+ * This checks if Docker is running, starts it if needed, and exposes it on TCP.
599+ * Uses synchronization to prevent race conditions when multiple threads call this.
600+ */
601+ private boolean tryConnectToExistingDaemon () {
602+ synchronized (EXISTING_DAEMON_LOCK ) {
603+ if (existingDaemonSetup && sharedDaemonPort > 0 && sharedWslIp != null ) {
604+ dockerPort = sharedDaemonPort ;
605+ wslIpAddress = sharedWslIp ;
606+ log .info ("Using existing Docker daemon connection on port {}" , dockerPort );
607+ return true ;
608+ }
609+
610+ try {
611+ String socketCheck = runWslCommand ("test -S /var/run/docker.sock && echo yes || echo no" , false , 5 );
612+ if (!"yes" .equals (socketCheck .trim ())) {
613+ log .debug ("Docker socket /var/run/docker.sock does not exist" );
614+
615+ log .info ("Docker daemon not running, attempting to start it..." );
616+ String startResult = runWslCommand ("sudo service docker start 2>&1" , false , 30 );
617+ log .debug ("Docker service start result: {}" , startResult );
618+
619+ Thread .sleep (3000 );
620+
621+ socketCheck = runWslCommand ("test -S /var/run/docker.sock && echo yes || echo no" , false , 5 );
622+ if (!"yes" .equals (socketCheck .trim ())) {
623+ log .debug ("Docker socket still doesn't exist after service start" );
624+ return false ;
625+ }
626+ }
627+
628+ log .info ("Found Docker daemon in WSL2, setting up TCP forwarding..." );
629+
630+ String wslIp = runWslCommand ("hostname -I | awk '{print $1}'" , false , 5 ).trim ();
631+ if (wslIp .isEmpty ()) {
632+ log .info ("Could not get WSL2 IP address, will use isolated daemon" );
633+ return false ;
634+ }
635+ wslIpAddress = wslIp ;
636+ log .info ("WSL2 IP: {}" , wslIp );
637+
638+ String socatPath = runWslCommand ("command -v socat 2>/dev/null || echo ''" , false , 5 ).trim ();
639+ if (socatPath .isEmpty ()) {
640+ log .info ("Installing socat for TCP forwarding..." );
641+ runWslCommand ("sudo apt-get update -qq && sudo apt-get install -y -qq socat 2>&1" , false , 120 );
642+ socatPath = runWslCommand ("command -v socat 2>/dev/null || echo ''" , false , 5 ).trim ();
643+ if (socatPath .isEmpty ()) {
644+ log .info ("Failed to install socat, will use isolated daemon" );
645+ return false ;
646+ }
647+ }
648+
649+ dockerPort = 2375 ;
650+
651+ runWslCommand ("sudo pkill -9 -f 'socat.*:" + dockerPort + "' 2>/dev/null; sleep 1" , false , 10 );
652+
653+ String socketPerms = runWslCommand ("ls -la /var/run/docker.sock 2>&1" , false , 5 );
654+ log .info ("Docker socket: {}" , socketPerms .trim ());
655+
656+ String socatCmd = String .format (
657+ "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 &" ,
658+ dockerPort , dockerPort );
659+ runWslCommand (socatCmd , false , 5 );
660+
661+ Thread .sleep (2000 );
662+
663+ String socatPid = runWslCommand ("pgrep -f 'socat.*:" + dockerPort + "' 2>/dev/null | head -1 || echo ''" , false , 5 ).trim ();
664+ if (socatPid .isEmpty ()) {
665+ String socatLog = runWslCommand ("cat /tmp/socat-" + dockerPort + ".log 2>/dev/null | head -20 || echo '(no log)'" , false , 5 );
666+ log .info ("socat failed to start. Log: {}" , socatLog );
667+ return false ;
668+ }
669+ log .info ("socat running with PID: {}" , socatPid );
670+
671+ String listenCheck = runWslCommand ("ss -tlnp 2>/dev/null | grep ':" + dockerPort + " ' || echo 'not listening'" , false , 5 );
672+ log .info ("Port {} status: {}" , dockerPort , listenCheck .trim ());
673+
674+ boolean connected = testDockerConnection (wslIp , dockerPort );
675+ if (!connected ) {
676+ connected = testDockerConnection ("localhost" , dockerPort );
677+ if (connected ) {
678+ wslIpAddress = "localhost" ;
679+ }
680+ }
681+
682+ if (connected ) {
683+ sharedDaemonPort = dockerPort ;
684+ sharedWslIp = wslIpAddress ;
685+ existingDaemonSetup = true ;
686+ log .info ("Connected to Docker daemon via TCP at {}:{}" , wslIpAddress , dockerPort );
687+ return true ;
688+ }
689+
690+ String socatLog = runWslCommand ("cat /tmp/socat-" + dockerPort + ".log 2>/dev/null | tail -10 || echo '(no log)'" , false , 5 );
691+ log .info ("Connection failed, socat log: {}" , socatLog );
692+ return false ;
693+ } catch (Exception e ) {
694+ log .info ("Failed to connect to existing daemon: {}" , e .getMessage ());
695+ return false ;
696+ }
697+ }
698+ }
699+
700+ /**
701+ * Test Docker connection from Windows by attempting a TCP socket connection and HTTP request.
702+ */
703+ private boolean testDockerConnection (String host , int port ) {
704+ try {
705+ log .info ("Testing Docker connection to {}:{}..." , host , port );
706+
707+ java .net .Socket socket = new java .net .Socket ();
708+ socket .connect (new java .net .InetSocketAddress (host , port ), 3000 );
709+ socket .close ();
710+ log .info ("TCP socket connection successful to {}:{}" , host , port );
711+
712+ java .net .URL url = new java .net .URL ("http://" + host + ":" + port + "/version" );
713+ java .net .HttpURLConnection conn = (java .net .HttpURLConnection ) url .openConnection ();
714+ conn .setConnectTimeout (3000 );
715+ conn .setReadTimeout (3000 );
716+ int responseCode = conn .getResponseCode ();
717+ conn .disconnect ();
718+
719+ if (responseCode == 200 ) {
720+ log .info ("Docker API responding at {}:{}" , host , port );
721+ return true ;
722+ }
723+ log .info ("Docker API returned HTTP {} at {}:{}" , responseCode , host , port );
724+ return false ;
725+ } catch (java .net .ConnectException e ) {
726+ log .info ("Connection refused to {}:{} - socat may not be forwarding correctly" , host , port );
727+ return false ;
728+ } catch (java .net .SocketTimeoutException e ) {
729+ log .info ("Connection timeout to {}:{}" , host , port );
730+ return false ;
731+ } catch (IOException e ) {
732+ log .info ("Connection test failed for {}:{} - {}: {}" , host , port , e .getClass ().getSimpleName (), e .getMessage ());
733+ return false ;
734+ }
735+ }
736+
585737 /**
586738 * Check if passwordless sudo is available for dockerd.
587739 */
@@ -771,6 +923,18 @@ public DockerClient getClient() {
771923 public void stop () {
772924 log .info ("Stopping Docker daemon (instance: {})..." , instanceId );
773925
926+ if (usingExistingDaemon && usingWsl2 && wslDistro != null ) {
927+ try {
928+ ProcessBuilder pb = new ProcessBuilder ("wsl" , "-d" , wslDistro , "-e" , "bash" , "-c" ,
929+ "sudo -n pkill -f 'socat.*:" + dockerPort + "' 2>/dev/null || true" );
930+ pb .start ().waitFor (5 , TimeUnit .SECONDS );
931+ log .info ("Stopped socat TCP forwarder" );
932+ } catch (IOException | InterruptedException e ) {
933+ log .debug ("Failed to stop socat: {}" , e .getMessage ());
934+ }
935+ return ;
936+ }
937+
774938 if (dockerProcess != null ) {
775939 if (usingWsl2 && wslDistro != null ) {
776940 try {
0 commit comments