C# WinForm程序如何等待Docker Desktop完全启动并按序执行启停命令
问题:C# WinForm中Docker Desktop重启命令执行顺序混乱,无法等待完全启动
我基于.NET 8开发C# WinForm自动化部署工具,用来配置LAMP服务器的Docker环境,已经完成了Docker Desktop配置文件C:\Users\<USERNAME>\AppData\Roaming\Docker\setting.json的修改:
Dictionary<string, string> settingsToReplace = new() { { "\"exposeDockerAPIOnTCP2375\": false,", "\"exposeDockerAPIOnTCP2375\": true," }, { "\"updateHostsFile\": false,", "\"updateHostsFile\": true," }, { "\"displayedOnboarding\": false,", "\"displayedOnboarding\": true," }, { "\"licenseTermsVersion\": 0,", "\"licenseTermsVersion\": 2," }, { "\"noWindowsContainers\": true,", "\"noWindowsContainers\": false," }, { "\"runWinServiceInWslMode\": false,", "\"runWinServiceInWslMode\": true," } }; foreach (var setting in settingsToReplace) { if (jsonContent.Contains(setting.Key)) { jsonContent = jsonContent.Replace(setting.Key, setting.Value); update = true; } }
现在需要重启Docker Desktop及相关服务让配置生效,但执行以下PowerShell命令时出现顺序混乱、执行重叠的问题,导致Docker启动不稳定:
string dockerDesktopPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Docker\Docker\Docker Desktop.exe"); await run.RunCommand("Stop-Process -Name \"Docker Desktop\"", "powershell",true); await run.RunCommand("Stop-Service -Name \"com.docker.service\"", "powershell",true); await run.RunCommand("Start-Service -Name \"com.docker.service\"", "powershell",true); await run.RunCommand($"Start-Process -FilePath \"{dockerDesktopPath}\"", "powershell",true);
调用命令的C#方法:
public async Task RunCommand(string script, string command = "powershell", Boolean show = false, string? workDirectory = null) { string arguments = $"-Command \"Set-ExecutionPolicy -Scope Process -ExecutionPolicy Unrestricted -Force ; {script}\""; ProcessStartInfo processStartInfo = new(command) { Arguments = arguments, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, Verb = "runas", CreateNoWindow = true }; Process process = new() { StartInfo = processStartInfo }; process.OutputDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) { // 日志输出逻辑 } }; process.ErrorDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) { // 错误日志输出逻辑 } }; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); await process.WaitForExitAsync(); }
需要解决两个核心问题:
- 确保每条命令严格按顺序执行,前一条执行完成后再执行下一条
- 等待Docker Desktop完全启动就绪后再继续后续操作
- 程序和VS2022已以管理员权限运行
解决方案
1. 修复命令执行顺序问题
当前RunCommand方法虽然用了await process.WaitForExitAsync(),但部分PowerShell命令(比如Stop-Process)可能会在进程还没完全终止时就返回。需要给每个操作添加明确的等待逻辑:
优化停止Docker进程和服务的逻辑
// 停止Docker Desktop进程,等待进程完全退出 await run.RunCommand(@" $process = Get-Process -Name ""Docker Desktop"" -ErrorAction SilentlyContinue if ($process) { $process | Stop-Process -Force Wait-Process -Name ""Docker Desktop"" -Timeout 30 -ErrorAction SilentlyContinue } ", "powershell", true); // 停止Docker服务,等待服务状态变为Stopped await run.RunCommand(@" $count = 0 $service = Get-Service -Name com.docker.service -ErrorAction SilentlyContinue if ($service -and $service.Status -ne 'Stopped') { Stop-Service -Name com.docker.service -Force do { Start-Sleep -Seconds 1 $service.Refresh() } while ($service.Status -ne 'Stopped' -and $count++ -lt 30) } ", "powershell", true);
优化启动服务和Docker Desktop的逻辑
// 启动Docker服务,等待服务状态变为Running await run.RunCommand(@" $count = 0 $service = Get-Service -Name com.docker.service -ErrorAction SilentlyContinue if ($service -and $service.Status -ne 'Running') { Start-Service -Name com.docker.service do { Start-Sleep -Seconds 1 $service.Refresh() } while ($service.Status -ne 'Running' -and $count++ -lt 30) } ", "powershell", true); // 启动Docker Desktop并等待其就绪(通过2375端口检测) await run.RunCommand($@" Start-Process -FilePath ""{dockerDesktopPath}"" -NoNewWindow $timeout = 120 $startTime = Get-Date do { Start-Sleep -Seconds 2 $test = Test-NetConnection -ComputerName localhost -Port 2375 -ErrorAction SilentlyContinue } while ($test.TcpTestSucceeded -ne $true -and ((Get-Date) - $startTime).TotalSeconds -lt $timeout) ", "powershell", true);
2. 优化RunCommand方法的可靠性
给方法添加超时控制,避免命令无限等待:
public async Task<bool> RunCommand(string script, string command = "powershell", bool show = false, string? workDirectory = null, int timeoutSeconds = 120) { string arguments = $"-Command \"Set-ExecutionPolicy -Scope Process -ExecutionPolicy Unrestricted -Force ; {script}\""; using Process process = new Process(); ProcessStartInfo processStartInfo = new(command) { Arguments = arguments, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, Verb = "runas", CreateNoWindow = !show, WorkingDirectory = workDirectory ?? Environment.CurrentDirectory }; process.StartInfo = processStartInfo; StringBuilder output = new StringBuilder(); StringBuilder error = new StringBuilder(); process.OutputDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) output.AppendLine(e.Data); }; process.ErrorDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) error.AppendLine(e.Data); }; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); // 等待进程退出或超时 var waitTask = process.WaitForExitAsync(); if (await Task.WhenAny(waitTask, Task.Delay(TimeSpan.FromSeconds(timeoutSeconds))) == waitTask) { // 进程正常退出 return process.ExitCode == 0; } else { // 超时,终止进程 process.Kill(); return false; } }
3. 调用优化后的命令
string dockerDesktopPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Docker\Docker\Docker Desktop.exe"); // 按顺序执行,每个步骤都等待完成并检查结果 bool stopProcessOk = await run.RunCommand(@" $process = Get-Process -Name ""Docker Desktop"" -ErrorAction SilentlyContinue if ($process) { $process | Stop-Process -Force Wait-Process -Name ""Docker Desktop"" -Timeout 30 -ErrorAction SilentlyContinue } ", "powershell", true); if (!stopProcessOk) { // 处理停止进程失败的情况,比如弹窗提示或日志记录 } bool stopServiceOk = await run.RunCommand(@" $count = 0 $service = Get-Service -Name com.docker.service -ErrorAction SilentlyContinue if ($service -and $service.Status -ne 'Stopped') { Stop-Service -Name com.docker.service -Force do { Start-Sleep -Seconds 1 $service.Refresh() } while ($service.Status -ne 'Stopped' -and $count++ -lt 30) } ", "powershell", true); if (!stopServiceOk) { // 处理停止服务失败的情况 } bool startServiceOk = await run.RunCommand(@" $count = 0 $service = Get-Service -Name com.docker.service -ErrorAction SilentlyContinue if ($service -and $service.Status -ne 'Running') { Start-Service -Name com.docker.service do { Start-Sleep -Seconds 1 $service.Refresh() } while ($service.Status -ne 'Running' -and $count++ -lt 30) } ", "powershell", true); if (!startServiceOk) { // 处理启动服务失败的情况 } bool startDockerOk = await run.RunCommand($@" Start-Process -FilePath ""{dockerDesktopPath}"" -NoNewWindow $timeout = 120 $startTime = Get-Date do { Start-Sleep -Seconds 2 $test = Test-NetConnection -ComputerName localhost -Port 2375 -ErrorAction SilentlyContinue } while ($test.TcpTestSucceeded -ne $true -and ((Get-Date) - $startTime).TotalSeconds -lt $timeout) ", "powershell", true); if (!startDockerOk) { // 处理Docker启动超时的情况 }
内容的提问来源于stack exchange,提问作者user22473069
相关产品推荐
相关产品推荐

