以程式設計方式設定 docker-desktop 的配置

以程式設計方式設定 docker-desktop 的配置

我又來了,看看你能不能幫我一把…

通常當你從 0 安裝 docker-desktop 時,一些設定檔被設定為:

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

幾乎總是需要執行手動步驟:打開應用程序,進行調查,然後更改設置,保存並應用,然後關閉...並再次登入。

我更喜歡從終端使用 docker-desktop,我通常會執行命令來建立網路並基於以下內容啟動容器docker-compose

問題或更確切地說我正在尋找的幫助是您是否可以幫助我完成更新設定以及關閉和重新開啟桌面應用程式:docker-desktop 的程式設計部分。

在來到這裡之前,我嘗試用 C# 做一些事情,但結果不穩定:

https://stackoverflow.com/questions/78048247/check-wait-for-the-invoked-application-to-be-open

我確信這可以透過 PowerShell 實現,但我對此了解不多。

Docker貼文論壇相關:https://forums.docker.com/t/programmatic-manipulation-and-management-of-docker-desktop/140018

在 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 再次變得不穩定...並且更新 Hosts 檔案的設定套用到setting.json,但未與 docker-desktop 聊天。

更新:

「不穩定」的具體症狀是什麼?

答:使用腳本開啟 Docker-Desktop 時,Docker-Desktop 使用者介面會慢慢變慢直到被阻止,對滑鼠點選沒有回應。

什麼以及如何測試重新啟動 Docker 桌面後更改是否已套用?

答:設定選項卡在 docker-desktop 中打開,並且它們會繼續,就像未進行更改一樣。但更改會反映在setting.json 檔案中。

更新#2

讓我們總結一下我正在做的事情,我把C# 放在一邊來評估是什麼導致了docker 桌面不穩定,這是我正在部署的完整powershell 腳本,經過我需要在settings.json 中進行的更改,該腳本可以正常工作,但是一旦 docker-desktop UI 在 30 秒後打開,當嘗試單擊任何 UI 控制項時,它會完全不穩定/有些閃爍:

$ErrorActionPreference = 'Continue'
Set-Service -Name "com.docker.service" -StartupType Automatic -ErrorAction SilentlyContinue
Stop-Service -Name "com.docker.service" -ErrorAction SilentlyContinue
Get-Process 'Docker Desktop' -ErrorAction Ignore | Stop-Process -Force -ErrorAction Stop
Wait-Process -Name 'Docker Desktop' -ErrorAction SilentlyContinue
$settingsToUpdate = @{
    exposeDockerAPIOnTCP2375 = $true
    updateHostsFile = $true
    licenseTermsVersion = 2
    noWindowsContainers = $true
    runWinServiceInWslMode = $false
    useResourceSaver = $false
}

$settingsPath = "$env:APPDATA\Docker\settings.json"
$settingsContent = Get-Content $settingsPath -Raw 
$settingsObject  = $settingsContent | ConvertFrom-Json

$trackUpdates = 0
foreach ($update in $settingsToUpdate.GetEnumerator()) {
    if ($target = $settingsObject.psobject.Properties.Match($update.Key)) {
        if ($target.Value -ne $update.Value) {
            Add-Member -InputObject $settingsObject -MemberType NoteProperty -Name $update.Key -Value $update.Value -Force
            $trackUpdates++
        }
    }
}

if ($trackUpdates -eq 0) {
    Write-Host "No new settings applied"
} else {
    $settingsObject | ConvertTo-Json | Set-Content $settingsPath
    Write-Host "Settings updated and saved successfully"
}

Start-Service -Name "com.docker.service" -ErrorAction SilentlyContinue

while ((Get-Service -Name "com.docker.service").Status -ne "Running") {
    Write-Host (Get-Service -Name "com.docker.service").Status
    Start-Sleep -Seconds 1
}

if((Get-Service -Name "com.docker.service").Status -eq "Running"){
    Write-Host (Get-Service -Name "com.docker.service").Status
}

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

$ipcTimeout = New-TimeSpan -Seconds 20
$waitUntil = [datetime]::Now.Add($ipcTimeout)
$pipeOpen = $false
Write-Host 'Probing docker engine I/O pipe'
do {
  Start-Sleep -Milliseconds 100
  $pipeOpen = Test-Path -LiteralPath \\.\pipe\docker_engine
} until ($pipeOpen -or ($waitUntil -le [datetime]::Now))

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

$responseTimeout = New-TimeSpan -Seconds 5
$waitUntil = [datetime]::Now.Add($responseTimeout)

Write-Host 'Querying docker server info'
do {
  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
}

Write-Host 'Docker Desktop Is Runing Now'

更新#3

所以問題不在於應用程式如何打開,而是如何關閉應用程式...

一位朋友嘗試執行這個腳本:

$ServiceName = "com.docker.service"
$ProcessName = "Docker Desktop"

$arrService = Get-Service -Name $ServiceName
if ($arrService.Status -ne 'Running') {
    Stop-Service -Name $ServiceName
}


if (Get-Process $ProcessName -ErrorAction SilentlyContinue) {  
  Stop-Process -Name $ProcessName
  Wait-Process -Name $ProcessName
}

就我而言,該服務不會運行,因此程式碼的上半部分並不重要。在任務管理器中,我可以看到 4 個或 6 個與 Docker 桌面相關的進程正在運行。這樣 Stop-Process 指令立即終止了「Docker Desktop」進程。但「Docker Desktop Backend」和「Docker Desktop Extensions」這兩個進程仍在運作。我透過雙擊快捷方式啟動了 Docker Desktop,然後可以看到 Docker 引擎已暫停,並且應用程式運行不穩定。然後我終止了所有進程並能夠再次開啟 Docker Desktop,沒有任何問題。從現在開始,其他的一切都需要你自己去尋找。

我不清楚關閉 Docker-Desktop 時必須關閉多少進程,似乎關閉需要通配符:"Docker-Desktop*""Docker Desktop*"或,"*Docker*"但這可能會導致應保持運行的進程關閉。

另一方面,昨晚當我從 0 開始安裝 #64 時,我發現了一些奇怪的事情。

事實證明,如果您執行了 docker,並且第一次進入設定並選取更新主機檔案的選項,則 updateHostsFile 屬性並不是唯一變更的屬性;如果您使用的是Windows 11/10 家庭版,那麼其他2 個選項也會改變:noWindowsContainers、runWinServiceInWslMode 並搞砸一般的docker 配置,因為只有在您使用具有Hiper-V 的PRO 版本時才應啟用這些選項。

因此,出於這個原因,如果您以程式設計方式啟動 updateHostsFile 它將不會產生任何效果...除非您啟動其他兩個...這也不會產生正面的結果...

事情很複雜…透過 PowerShell 來管理應該更簡單…

答案1

最終的腳本以編程方式:

  • 停止docker服務和進程。
  • 更新setting.json。
  • 重新開啟docker桌面在這裡:

https://gist.github.com/arcanisgk/d78acd5d51ab263d9467fb2da97781ca

不穩定的問題是因為docker合併的進程並不是全部都關閉了,顯然還有一系列額外的進程(不是服務)必須同樣關閉,否則會造成不穩定。

$ErrorActionPreference = 'Continue'

Stop-Service -Name "com.docker.*" -ErrorAction SilentlyContinue
Set-Service -Name "com.docker.service" `
  -StartupType Automatic `
  -ErrorAction SilentlyContinue

$processesToStop = @(
  'Docker Desktop',
  'com.docker.backend',
  'com.docker.extensions'
)
$processesToStop | ForEach-Object {
  Get-Process -Name $_ -ErrorAction Ignore |
    Stop-Process -Force -ErrorAction Ignore
}

$settingsToUpdate = @{
  exposeDockerAPIOnTCP2375 = $true
  updateHostsFile = $true
  licenseTermsVersion = 2
  noWindowsContainers = $false    # Required to enable read updateHostsFile
  runWinServiceInWslMode = $true  # Required to enable read updateHostsFile
  useResourceSaver = $false
}

$settingsPath    = "$env:APPDATA\Docker\settings.json"
$settingsContent = Get-Content $settingsPath -Raw 
$settingsObject  = $settingsContent | ConvertFrom-Json

$trackUpdates = 0
foreach ($update in $settingsToUpdate.GetEnumerator()) {
  if ($target = $settingsObject.psobject.Properties.Match($update.Key)) {
    if ($target.Value -ne $update.Value) {
      Write-Host $update.Key
      Add-Member `
        -InputObject $settingsObject `
        -MemberType NoteProperty `
        -Name $update.Key `
        -Value $update.Value `
        -Force
      $trackUpdates++
    }
  }
}

if ($trackUpdates -eq 0) {
  Write-Host "No new settings applied"
} else {
  $settingsObject | ConvertTo-Json | Set-Content $settingsPath
  Write-Host "Settings updated and saved successfully"
}

Start-Service -Name "com.docker.service" -ErrorAction SilentlyContinue

while ((Get-Service -Name "com.docker.service").Status -ne "Running") {
  Write-Host (Get-Service -Name "com.docker.service").Status
  Start-Sleep -Seconds 1
}

if((Get-Service -Name "com.docker.service").Status -eq "Running"){
  Write-Host "Service: com.docker.service is now:"
  Write-Host (Get-Service -Name "com.docker.service").Status
}

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

$ipcTimeout = New-TimeSpan -Seconds 20
$waitUntil = [datetime]::Now.Add($ipcTimeout)
$pipeOpen = $false
Write-Host 'Probing docker engine I/O pipe'
do {
  Start-Sleep -Milliseconds 100
  $pipeOpen = Test-Path -LiteralPath \\.\pipe\docker_engine
}
until ($pipeOpen -or ($waitUntil -le [datetime]::Now))

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

$responseTimeout = New-TimeSpan -Seconds 5
$waitUntil = [datetime]::Now.Add($responseTimeout)

Write-Host 'Querying docker server info'
do {
  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
}

Write-Host 'Docker Desktop Is Runing Now'

相關內容