
Estoy aquí de nuevo, a ver si me podéis echar una mano...
Normalmente, cuando instalas docker-desktop desde 0, algunos archivos de configuración se configuran en:
C:\Usuarios\AppData\Roaming\Docker\setting.json
Casi siempre es necesario hacer pasos manuales: abrir la aplicación, hacer la encuesta, luego hacer cambios en la configuración, guardar y aplicar, luego cerrar… e iniciar sesión nuevamente.
Me gusta más usar docker-desktop desde la terminal, suelo ejecutar los comandos para crear la red y levantar los contenedores en función dedocker-compose
El problema o más bien la ayuda que busco es si me pueden ayudar a hacer la parte programática de actualizar la configuración y cerrar y volver a abrir la aplicación de escritorio: docker-desktop.
Intenté hacer algo antes de venir aquí en C# pero resultó ser inestable:
https://stackoverflow.com/questions/78048247/check-wait-for-the-invoked-application-to-be-open
Estoy seguro de que esto se podría lograr con PowerShell pero no sé mucho al respecto.
Foro de publicaciones de Docker relacionado:https://forums.docker.com/t/programmatic-manipulation-and-management-of-docker-desktop/140018
En powershell he hecho esto:
# 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"
Pero detecto que Docker-Desktop vuelve a ser inestable... y la configuración para actualizar el archivo Hosts se aplica a settings.json pero no se conversa con Docker-Desktop.
Actualizar:
¿Cuáles son los síntomas exactos de la "inestabilidad"?
respuesta:Al abrir Docker-Desktop usando el script, la interfaz de usuario de Docker-Desktop se ralentiza lentamente hasta el punto de bloquearse y no responde a los clics del mouse.
¿Qué y cómo se prueba si los cambios se han aplicado después de reiniciar el escritorio Docker?
respuesta:se abre la pestaña de configuración en docker-desktop y continúan como si no se hubieran realizado los cambios. pero los cambios se reflejan en el archivo settings.json.
Actualización #2
Resumamos lo que estoy haciendo, dejé C# a un lado para evaluar qué hace que el escritorio de Docker sea inestable, y este es el script de PowerShell completo que estoy implementando, con los cambios que necesito en settings.json, el script funciona correctamente, pero Una vez que la interfaz de usuario de Docker-Desktop se abre después de 30 segundos, es completamente inestable o parpadea cuando intenta hacer clic en cualquier control de la interfaz de usuario:
$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'
Actualización #3
Entonces el problema no es cómo se abre la aplicación, sino cómo se cierra…
un amigo intenta ejecutar este script:
$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
}
En mi caso, el servicio no estaría ejecutándose, por lo que la sección superior del código no importa. En el administrador de tareas pude ver que se están ejecutando 4 o 6 procesos respectivamente en relación con el escritorio Docker. De modo que el comando Stop-Process finalizó el proceso “Docker Desktop” inmediatamente. Pero 2 procesos "Docker Desktop Backend" y "Docker Desktop Extensions" todavía se están ejecutando. Inicié Docker Desktop haciendo doble clic en un acceso directo y luego pude ver que Docker Engine estaba en pausa y la aplicación no se ejecutaba de manera estable. Luego terminé todos los procesos y pude abrir Docker Desktop nuevamente sin ningún problema. A partir de ahora, todo lo demás lo tendrás que descubrir tú mismo.
No tengo claro cuántos procesos deben cerrarse al cerrar Docker-Desktop, parece que el cierre requiere un comodín: "Docker-Desktop*"
o "Docker Desktop*"
o "*Docker*"
pero esto puede provocar que se cierren procesos que deben mantenerse ejecutándose.
Por otro lado encontré algo curioso anoche cuando hice la instalación #64 desde 0.
Resulta que si tienes Docker ejecutándose y vas a configuración por primera vez y marcas la opción de actualizar el archivo hosts, la propiedad updateHostsFile no es la única que cambia; Estos otros 2 también cambian: noWindowsContainers, runWinServiceInWslMode y joden la configuración general de Docker, si estás usando Windows 11/10 home, ya que estas opciones solo deben estar habilitadas si estás usando la versión PRO con Hiper-V.
Entonces por esta razón, si activas programáticamente updateHostsFile no tendrá ningún efecto… a menos que actives los otros dos… lo cual tampoco tendrá resultados positivos…
La cosa es complicada y compleja… debería ser más sencillo gestionar esto a través de PowerShell…
Respuesta1
El script final para programación:
- Detenga el servicio y proceso de Docker.
- Actualice la configuración.json.
- Reabrir el escritorio de Docker está aquí:
https://gist.github.com/arcanisgk/d78acd5d51ab263d9467fb2da97781ca
El problema de la inestabilidad se dio porque no se cerraron todos los procesos que incorpora docker, al parecer hay una serie de procesos adicionales (no servicios) que se deben cerrar igualmente o causará inestabilidad.
$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'