# 如何讓 Docker Desktop for Windows 在系統開機時自動啟動

我們公司內部有台 Windows 10 測試機，幾乎所有的環境都跑在 Docker 容器中，但這台 VM 每次重開的時候，都需要人工進入系統啟動 Docker Desktop 並且手動執行因為重開而被停止的容器。這篇文章我打算來分享一個小技巧，教你如何將現有正在執行的容器，可以在系統開機時就自動跑起來。

### 設定工作排程器

雖然說 Docker Desktop for Windows 本身就支援了可以在「登入時」自動啟動 Desktop Desktop 的設定，但我們的需求比較是希望可以在「啟動時」就直接啟動 Docker Desktop 服務。

![Docker Desktop > Settings](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/6fa6ea2bbb980804c10f-195645655-03e19bc5-645d-4e30-9721-81b0eb1c19d4.png)

我直接利用 Windows 內建的「工作排程器」來設定啟動時自動執行 Docker Desktop 應用程式，設定的過程直接用 PowerShell 自動化，只要複製貼上就能設定完成。

-   PowerShell 5.1
    
    由於 Windows 內建的 PowerShell 僅支援到 Windows PowerShell 5.1 版，之後的新版都需要額外安裝才行，這裡我先分享 PowerShell 5.1 的命令。
    
    請記得以系統管理人員身份執行 Windows PowerShell 命令提示字元。
    
    ```powershell
    $trigger = New-ScheduledTaskTrigger -AtStartup
    $trigger.Delay = 'PT1M'
    
    $action = New-ScheduledTaskAction -Execute 'C:\Program Files\Docker\Docker\Docker Desktop.exe'
    
    $settings = New-ScheduledTaskSettingsSet -Compatibility Win8 -StartWhenAvailable -RestartCount 999
    $settings.ExecutionTimeLimit = 'PT0S'
    $settings.RestartInterval = 'PT1M'
    
    $secureString = Read-Host -Prompt 'Password' -AsSecureString
    $ToBSTRString = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureString)
    $ToPlainText = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($ToBSTRString)
    
    Register-ScheduledTask `
        -Action $action `
        -Trigger $trigger `
        -TaskName Docker `
        -Settings $settings `
        -User $env:UserName `
        -Password $ToPlainText
    ```
    
-   PowerShell 7+
    
    較新版的 Windows 10 或 Windows 11 都已經內建 `winget` 套件管理器，你只要用一個命令就可以自動安裝好 PowerShell 7+ 版本：
    
    ```powershell
    winget install Microsoft.PowerShell
    ```
    
    請記得以系統管理人員身份執行 PowerShell 7 命令提示字元，你也可以輸入 `pwsh` 命令進入 PowerShell 7 環境。
    
    ```powershell
    $trigger = New-ScheduledTaskTrigger -AtStartup
    $trigger.Delay = 'PT1M'
    
    $action = New-ScheduledTaskAction -Execute 'C:\Program Files\Docker\Docker\Docker Desktop.exe'
    
    $settings = New-ScheduledTaskSettingsSet -Compatibility Win8 -StartWhenAvailable -RestartCount 999
    $settings.ExecutionTimeLimit = 'PT0S'
    $settings.RestartInterval = 'PT1M'
    
    $ToPlainText = ConvertFrom-SecureString (Read-Host -Prompt 'Password' -AsSecureString) -AsPlainText
    
    Register-ScheduledTask `
        -Action $action `
        -Trigger $trigger `
        -TaskName Docker `
        -Settings $settings `
        -User $env:UserName `
        -Password $ToPlainText
    ```
    

### 調整現有容器的重啟設定

由於我們的 Docker 容器都已經啟動，而且做了不少開發環境的設定，若要在不重建容器的情況下，讓 Docker Desktop 在成功啟動時自動啟動容器，那麼我們就需要透過以下命令，更新現有容器的 Restart Policy 設定值：

```powershell
docker update --restart unless-stopped websphere
docker update --restart unless-stopped sqlserver
```

> 假設我們有兩個容器，名稱分別為 `websphere` 與 `sqlserver`。

### 如何停止 Docker Desktop for Windows 服務

由於我們已經在系統啟動時，就自動啟動 Docker Desktop 應用程式，因此我們用相同帳號登入此系統時，就無法再次啟動，你會看到以下錯誤訊息：

![Docker failed to initialize](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/16f5872d49b9830e85b4-195644070-da327f88-8549-4441-b53e-b6b25b6a834a.png)

所以你無法透過桌面右下角的 System Tray 來關閉 Docker Desktop 運作。

我原本想，那我把「服務管理員」的 `com.docker.service` 服務關閉，會不會就能完全停止 Docker Desktop 運作了？結果是完全不行！就算你停止該服務，所有容器還是會繼續執行的。

```powershell
Stop-Service com.docker.service
```

> 以上命令無法關閉 Docker Desktop 喔！

如果你真的要停止 Docker Desktop 的話，可能要用比較暴力的方法了，如下命令：

```powershell
$isrunning = Get-Process "Docker Desktop" -ErrorAction SilentlyContinue
if ($isrunning) {
  $isrunning.CloseMainWindow()
  $isrunning | Stop-Process -Force
}
```

### 相關連結

-   [Start containers automatically | Docker Documentation](https://docs.docker.com/config/containers/start-containers-automatically/)
-   [How to start Docker daemon (windows service) at startup without the need to log-in? - Stack Overflow](https://stackoverflow.com/a/62033673/910074)
-   [How to quit Docker Desktop from command line or programatically? · Issue #11111 · docker/for-win](https://github.com/docker/for-win/issues/11111#issuecomment-831103720)
-   [PowerShell error when converting a SecureString back to plain text - Stack Overflow](https://stackoverflow.com/a/60010688/910074)
