プログラムでdocker-desktopの設定をする

プログラムでdocker-desktopの設定をする

またここに来ました。手伝ってもらえませんか...

通常、docker-desktop を 0 からインストールすると、いくつかの構成ファイルは次のように設定されます。

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

私がやっていることをまとめると、docker デスクトップを不安定にする原因を評価するために C# は脇に置いておきました。これは私がデプロイしている完全な PowerShell スクリプトです。setting.json に必要な変更を加えると、スクリプトは正しく動作しますが、30 秒後に docker-desktop UI が開くと、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
}

私の場合、サービスは実行されていないため、コードの上部セクションは関係ありません。タスク マネージャーでは、Docker デスクトップに関連して 4 つまたは 6 つのプロセスが実行されていることがわかりました。そのため、Stop-Process コマンドはプロセス「Docker Desktop」をすぐに終了しました。ただし、2 つのプロセス「Docker Desktop Backend」と「Docker Desktop Extensions」はまだ実行されています。ショートカットをダブルクリックして Docker Desktop を起動すると、Docker Engine が一時停止し、アプリケーションが安定して実行されていないことがわかりました。その後、すべてのプロセスを終了し、問題なく Docker Desktop を再度開くことができました。ここから先は、他のすべてを自分で調べる必要があります。

Docker-Desktop を閉じるときにいくつのプロセスを閉じる必要があるのか​​はわかりません。閉じるにはワイルドカード"Docker-Desktop*"または"Docker Desktop*"またはが必要であるようですが、"*Docker*"これにより実行し続ける必要のあるプロセスが閉じられる可能性があります。

一方、昨夜、0 からインストール #64 を実行したときに、興味深いことが分かりました。

docker を実行していて、初めて設定に移動し、hosts ファイルを更新するオプションをチェックすると、updateHostsFile プロパティだけが変更されるのではなく、他の 2 つ (noWindowsContainers、runWinServiceInWslMode) も変更され、Windows 11/10 home を使用している場合は一般的な docker 構成が台無しになります。これらのオプションは、Hiper-V で PRO バージョンを使用している場合にのみ有効にする必要があるためです。

そのため、プログラムで updateHostsFile をアクティブ化しても効果はありません。他の 2 つをアクティブ化しない限り、効果はありません。他の 2 つをアクティブ化しても、良い結果は得られません。

状況は複雑で入り組んでいます…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'

関連情報