通过 PowerShell 脚本以编程方式设置 docker-desktop 的配置

问题描述 投票:0回答:1

我又来了,看看你能不能帮我...

通常当你从0开始安装docker-desktop时,一些配置文件被设置为:

C:\Users\AppData\Roaming\Docker\setting.json

几乎总是需要执行手动步骤:打开应用程序,进行调查,然后更改设置,保存并应用,然后关闭...并再次登录。

我更喜欢从终端使用 docker-desktop,我通常执行命令来创建网络并基于

docker-compose

启动容器

问题或更确切地说我正在寻找的帮助是您是否可以帮助我完成更新设置以及关闭和重新打开桌面应用程序的编程部分:

docker-desktop

在来到这里之前,我尝试用 C# 做一些事情,但结果不稳定:

检查/等待调用的应用程序打开

我确信这可以通过 PowerShell 实现,但我对此了解不多,在 powershell 中我已经做到了这一点:


# Defines the configuration dictionary
$settingsToReplace = @{
    '"exposeDockerAPIOnTCP2375": false,' = '"exposeDockerAPIOnTCP2375": true,'
    '"updateHostsFile": false,' = '"updateHostsFile": true,'
    '"licenseTermsVersion": 0,' = '"licenseTermsVersion": 2,'
}

# Defines the path to the configuration file
$settingsPath = "$env:APPDATA\Docker\settings.json"

# Read the contents of the configuration file
$settingsContent = Get-Content $settingsPath -Raw

# Replaces the values in the file content
foreach ($key in $settingsToReplace.Keys) {
    $settingsContent = $settingsContent -replace [regex]::Escape($key), $settingsToReplace[$key]
}

# Write the modified content back to the file
$settingsContent | Set-Content $settingsPath

# Close Docker Desktop
Stop-Process -Name "Docker Desktop*" -ErrorAction SilentlyContinue

# Wait until Docker Desktop has completely closed
$timeout = 60  # seconds
$processName = "Docker Desktop"
$timeoutReached = $false
$startTime = Get-Date

# Wait until Docker Desktop has completely closed or the timeout has been reached
while ((Get-Process -Name $processName -ErrorAction SilentlyContinue) -and (-not $timeoutReached)) {
    # Verifica si el proceso de Docker Desktop se ha cerrado
    if (-not (Get-Process -Name $processName -ErrorAction SilentlyContinue)) {
        Write-Host "Docker Desktop has closed before the time limit was reached."
        break
    }

    # Check if the time limit has been reached
    if ((Get-Date) - $startTime -ge [TimeSpan]::FromSeconds($timeout)) {
        $timeoutReached = $true
    }

    # Wait 1 second before checking again
    Start-Sleep -Seconds 1
}

# Check if the timeout has been reached
if ($timeoutReached) {
    Write-Host "Docker Desktop did not close properly. Please manually close the application and run the script again."
} else {
    Write-Host "Docker Desktop has closed successfully. Continuing..."
}

# Open Docker Desktop

$docker = [System.Environment]::GetEnvironmentVariable('ProgramFiles') + '\Docker\Docker\Docker Desktop.exe'
Start-Process -FilePath $docker

# Wait until Docker Desktop has fully opened
$processName = "Docker Desktop"
while (-not (Get-Process -Name $processName -ErrorAction SilentlyContinue)) {
    Start-Sleep -Seconds 1
}

Write-Host "continue"

但是我检测到 docker-desktop 再次变得不稳定...并且设置更新文件应用于setting.json,但在重新打开时不会向 docker-desktop 收费..

Docker 帖子论坛相关:https://forums.docker.com/t/programmatic-manipulation-and-management-of-docker-desktop/140018

更新:

“不稳定”的具体症状是什么? 答案: 使用脚本打开 Docker-Desktop 时,Docker-Desktop 用户界面慢慢变慢,直至卡住,鼠标点击无响应。

什么以及如何在重新启动 Docker 桌面后测试更改是否已应用? 答案: 设置选项卡在 docker-desktop 中打开,并且它们会继续,就像未进行更改一样。但更改会反映在setting.json 文件中。

docker powershell scripting docker-desktop windows-11
1个回答
2
投票

以下步骤顺序适用于 Windows 上的 Docker Desktop 4.3 和 Docker Engine 20.10:

  1. 停止 Docker 桌面
  2. 更新
    settings.json
  3. 重启Docker引擎服务
  4. 启动 Docker 桌面
  5. 等待
    • 创建
      docker_engine
      IPC管道,并用于
    • 响应
      docker info
      查询的服务

要停止进程,请使用

Get-Process ... |Stop-Process
让生活变得更轻松 - 这允许您忽略解决现有正在运行的进程的失败,但仍会在无法终止任何现有进程时停止:

$ErrorActionPreference = 'Continue'

Get-Process 'Docker Desktop' -ErrorAction Ignore |Stop-Process -Force -ErrorAction Stop

现在您可以删除所有丑陋的代码来检测进程是否停止 - 它要么完全符合您的预期,要么最终失败!

接下来,让我们看看更新设置文件。您的正则表达式替换策略可能在大多数情况下都有效,但更强大的方法是:

  • 将文档解析为 JSON
  • 修改生成的对象
  • 将其转换回 JSON 并保存
# define settings to update
$settingsToUpdate = @{
    exposeDockerAPIOnTCP2375 = $true
    updateHostsFile = $true
    licenseTermsVersion = 2
}

# read settings file from disk (save for later), and then parse with ConvertFrom-Json
$settingsPath = "$env:APPDATA\Docker\settings.json"
$settingsContent = Get-Content $settingsPath -Raw 
$settingsObject  = $settingsContent |ConvertFrom-Json

# update relevant settings
$trackUpdates = 0
foreach ($update in $settingsToUpdate.GetEnumerator()) {
  if ($target = $settingsObject.psobject.Properties.Match($update.Key)) {
    if ($target.Value -ne $update.Value) {
      # update existing entry
      $target.Value = $newValue.Value

      $trackUpdates++
    }
  }
  else {
    # add new entry
    #
    # this is a good place to emit or log warnings if 
    # you expect the file to always be pre-populated
    # 
    Add-Member -InputObject $settingsObject -Name $newValue.Key -Value $new

    $trackUpdates++
  }
}

if ($trackUpdates -eq 0) {
  # no updates applied? nothing more to be done
  Write-Host "No new settings applied"
  return
}

# serialize and write settings to disk
$settingsObject |ConvertTo-Json |Set-Content $settingsPath

第 3 步和第 4 步是最简单的 -

Restart-Service
重新启动引擎服务,
Start-Process
启动 Docker Desktop:

# restart engine service
Restart-Service -Name com.docker.service

# start docker desktop
$dockerDesktopFilePath = $env:ProgramFiles |Join-Path -ChildPath 'Docker\Docker\Docker Desktop.exe'
Start-Process -FilePath $dockerDesktopFilePath

如果您想在此时重新启动 docker 引擎失败时恢复设置更改,请考虑使用简单的

try
/
catch
来重新应用原始文档内容:

try {
  Restart-Service -Name com.docker.service
}
catch {
  # roll-back settings changes and quit
  $settingsContent |Set-Content $settingsPath -Force
  # replace `throw` with `return` if you want to fail silently here
  throw
}

现在我们只需要等待 docker 桌面变得响应 - 以下内容似乎对我来说始终有效:

# let's give it 20 seconds 
$ipcTimeout = New-TimeSpan -Seconds 20
$waitUntil = [datetime]::Now.Add($ipcTimeout)
$pipeOpen = $false
Write-Host 'Probing docker engine I/O pipe'
do {
  # stat for a named pipe is pretty 
  # low-overhead, retry every 100ms
  Start-Sleep -Milliseconds 100
  $pipeOpen = Test-Path -LiteralPath \\.\pipe\docker_engine
} until ($pipeOpen -or ($waitUntil -le [datetime]::Now))

if (-not $pipeOpen) {
  # not responding, time to quit
  Write-Warning "Failed to observe named IPC pipe docker_engine within timeout"
  return
}

# let's give it another 10 seconds to respond to client requests
$responseTimeout = New-TimeSpan -Seconds 5
$waitUntil = [datetime]::Now.Add($responseTimeout)

Write-Host 'Querying docker server info'
do {
  # much more expensive probe than 
  # the pipe test, retry only every 500ms
  Start-Sleep -Milliseconds 500
  $dockerInfoOutput = docker info 2>&1 
  $dockerInfoSuccess = $?
} until ($dockerInfoSuccess -or ($waitUntil -le [datetime]::Now))

if (-not $dockerInfoSuccess) {
  Write-Warning "docker info failed within timeout"
  return
}

希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.