You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();
}

需要解决两个核心问题:

  1. 确保每条命令严格按顺序执行,前一条执行完成后再执行下一条
  2. 等待Docker Desktop完全启动就绪后再继续后续操作
  3. 程序和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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 18:23:17