> ## Documentation Index
> Fetch the complete documentation index at: https://felimet-hub.jmcores.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 在 Windows 安裝 Docker（WSL 2 後端）

> Docker 筆記的起點：在 Windows 以 WSL 2 安裝 Docker，並通往指令、設定、Compose 與 Dockerfile 各章。

export const TerminalDemo = ({lang = "zh", title, prompt, commands}) => {
  const L = ({
    zh: {
      play: "播放",
      pause: "暫停",
      step: "下一步",
      replay: "重新播放",
      reset: "重設",
      winTitle: "Windows PowerShell",
      hint: "點播放，逐行看驗證流程實際跑出來的樣子"
    },
    en: {
      play: "Play",
      pause: "Pause",
      step: "Step",
      replay: "Replay",
      reset: "Reset",
      winTitle: "Windows PowerShell",
      hint: "Press play to watch the verification run line by line"
    }
  })[lang] || ({});
  const defaultCmds = [{
    cmd: "nvidia-smi",
    output: ["Mon Jun  8 14:30:12 2026", "+-----------------------------------------------------------------------------+", "| NVIDIA-SMI 552.22       Driver Version: 552.22       CUDA Version: 12.4     |", "|-------------------------------+----------------------+----------------------+", "| GPU  Name           TCC/WDDM  | Bus-Id        Disp.A | Volatile Uncorr. ECC |", "| Fan  Temp Perf Pwr:Usage/Cap  | Memory-Usage         | GPU-Util  Compute M. |", "|===============================+======================+======================|", "|   0  GeForce RTX 3080  WDDM   | 00000000:01:00.0  On |                  N/A |", "| 30%   42C  P8    21W / 320W   |    842MiB / 10240MiB |      2%      Default |", "+-------------------------------+----------------------+----------------------+"]
  }, {
    cmd: "nvcc -V",
    output: ["nvcc: NVIDIA (R) Cuda compiler driver", "Copyright (c) 2005-2024 NVIDIA Corporation", "Built on Tue_Feb_27_16:28:36_2024", "Cuda compilation tools, release 12.4, V12.4.99", "Build cuda_12.4.r12.4/compiler.34097967_0"]
  }, {
    cmd: "python gpu_test.py",
    output: ["========================================", "PyTorch Version: 2.6.0+cu124", "CUDA Available:  True", "Device Name:     NVIDIA GeForce RTX 3080", "CUDA Version:    12.4", "✓ cuDNN Test Passed! Convolution executed successfully.", "========================================"]
  }];
  const raw = commands && commands.length ? commands : defaultCmds;
  const cmds = raw.map(c => ({
    cmd: c.cmd,
    lines: Array.isArray(c.output) ? c.output : String(c.output || "").split("\n")
  }));
  const PROMPT = prompt || "PS C:\\Users\\dev>";
  const TITLE = title || L.winTitle;
  const [idx, setIdx] = useState(0);
  const [typed, setTyped] = useState(0);
  const [outN, setOutN] = useState(0);
  const [stage, setStage] = useState("cmd");
  const [running, setRunning] = useState(false);
  const [done, setDone] = useState(false);
  useEffect(() => {
    if (!running || done) return;
    const cur = cmds[idx];
    if (!cur) {
      setRunning(false);
      setDone(true);
      return;
    }
    if (stage === "cmd") {
      if (typed < cur.cmd.length) {
        const id = setTimeout(() => setTyped(typed + 1), 28);
        return () => clearTimeout(id);
      }
      const id = setTimeout(() => setStage("out"), 200);
      return () => clearTimeout(id);
    }
    if (stage === "out") {
      if (outN < cur.lines.length) {
        const id = setTimeout(() => setOutN(outN + 1), 70);
        return () => clearTimeout(id);
      }
      const id = setTimeout(() => {
        if (idx + 1 < cmds.length) {
          setIdx(idx + 1);
          setTyped(0);
          setOutN(0);
          setStage("cmd");
        } else {
          setRunning(false);
          setDone(true);
        }
      }, 360);
      return () => clearTimeout(id);
    }
  }, [running, done, idx, typed, outN, stage]);
  const reset = () => {
    setRunning(false);
    setDone(false);
    setIdx(0);
    setTyped(0);
    setOutN(0);
    setStage("cmd");
  };
  const playPause = () => {
    if (done) {
      reset();
      setRunning(true);
      return;
    }
    setRunning(!running);
  };
  const step = () => {
    setRunning(false);
    if (done) return;
    if (idx + 1 < cmds.length) {
      setIdx(idx + 1);
      setTyped(0);
      setOutN(0);
      setStage("cmd");
    } else {
      const cur = cmds[idx];
      setTyped(cur.cmd.length);
      setOutN(cur.lines.length);
      setStage("out");
      setDone(true);
    }
  };
  const css = `
.td-root{--bg:#f4eee4;--bd:#e2d7c6;--ink:#5b5048;--accent:#bf7551;--accent-l:#cf8a68;
  --scr:#1c1815;--scr-fg:#e9e1d4;--scr-prompt:#cf8a68;--scr-dim:#8d8478;--scr-ok:#8fb573;--scr-err:#d98a72;
  border:1px solid var(--bd);border-radius:14px;overflow:hidden;background:var(--bg);
  font-family:ui-sans-serif,system-ui,"Noto Sans TC",sans-serif;margin:1.25rem 0;box-shadow:0 1px 2px rgba(60,40,25,.06);}
.dark .td-root{--bg:#26221e;--bd:#3a332c;--ink:#cabfb2;}
.td-bar{display:flex;align-items:center;gap:.6rem;padding:.55rem .8rem;background:linear-gradient(var(--bg),color-mix(in srgb,var(--bg) 90%,#000));border-bottom:1px solid var(--bd);}
.td-dots{display:flex;gap:.4rem;}
.td-dots i{width:11px;height:11px;border-radius:50%;display:block;}
.td-dots i:nth-child(1){background:#d98a72;} .td-dots i:nth-child(2){background:#dcb46a;} .td-dots i:nth-child(3){background:#8fb573;}
.td-title{font-size:.78rem;color:var(--ink);font-weight:600;letter-spacing:.01em;flex:1;text-align:center;opacity:.85;}
.td-ctrl{display:flex;align-items:center;gap:.3rem;}
.td-btn{display:inline-flex;align-items:center;gap:.32rem;border:1px solid var(--bd);background:transparent;color:var(--ink);
  border-radius:8px;padding:.3rem .55rem;font-size:.74rem;font-weight:600;cursor:pointer;transition:all .15s ease;line-height:1;}
.td-btn:hover{border-color:var(--accent);color:var(--accent);background:color-mix(in srgb,var(--accent) 10%,transparent);}
.td-btn svg{width:13px;height:13px;}
.td-btn--primary{background:var(--accent);border-color:var(--accent);color:#fff;}
.dark .td-btn--primary{background:var(--accent-l);border-color:var(--accent-l);}
.td-btn--primary:hover{background:var(--accent-l);color:#fff;}
.td-count{font-size:.72rem;color:var(--ink);opacity:.6;font-variant-numeric:tabular-nums;margin-left:.2rem;}
.td-screen{background:var(--scr);color:var(--scr-fg);padding:.85rem 1rem 1.05rem;font-family:ui-monospace,"Cascadia Code","Consolas",monospace;
  font-size:.8rem;line-height:1.55;overflow-x:auto;min-height:120px;}
.td-block{margin-bottom:.5rem;}
.td-cmdline{white-space:pre;}
.td-prompt{color:var(--scr-prompt);font-weight:600;}
.td-cmd{color:#f3ecdf;}
.td-out{white-space:pre;color:var(--scr-fg);opacity:.92;}
.td-out.ok{color:var(--scr-ok);font-weight:600;}
.td-out.err{color:var(--scr-err);font-weight:600;}
.td-cursor{display:inline-block;width:8px;height:1em;background:var(--scr-prompt);margin-left:1px;vertical-align:text-bottom;
  animation:tdblink 1s steps(2,start) infinite;}
@keyframes tdblink{to{opacity:0;}}
.td-hint{padding:.5rem .9rem;font-size:.72rem;color:var(--ink);opacity:.6;border-top:1px solid var(--bd);background:var(--bg);}
@media (max-width:600px){.td-screen{font-size:.68rem;} .td-title{display:none;} .td-btn{padding:.28rem .42rem;}}
`;
  const PlayIcon = () => <svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M7 5.5v13l11-6.5z" /></svg>;
  const PauseIcon = () => <svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><rect x="6.5" y="5" width="4" height="14" rx="1" /><rect x="13.5" y="5" width="4" height="14" rx="1" /></svg>;
  const StepIcon = () => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 4l10 8-10 8z" /><line x1="19" y1="5" x2="19" y2="19" /></svg>;
  const ResetIcon = () => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7L3 8" /><path d="M3 3v5h5" /></svg>;
  const shown = Math.min(idx + (done ? 1 : 0), cmds.length);
  return <div className="td-root">
      <style>{css}</style>
      <div className="td-bar">
        <span className="td-dots"><i /><i /><i /></span>
        <span className="td-title">{TITLE}</span>
        <span className="td-ctrl">
          <button className="td-btn td-btn--primary" onClick={playPause}>
            {running ? <PauseIcon /> : <PlayIcon />}
            {done ? L.replay : running ? L.pause : L.play}
          </button>
          <button className="td-btn" onClick={step} disabled={done}><StepIcon />{L.step}</button>
          <button className="td-btn" onClick={reset}><ResetIcon />{L.reset}</button>
          <span className="td-count">{shown}/{cmds.length}</span>
        </span>
      </div>
      <div className="td-screen">
        {Array.from({
    length: idx + 1
  }).map((_, i) => {
    const c = cmds[i];
    if (!c) return null;
    const isCur = i === idx;
    const cmdText = isCur ? c.cmd.slice(0, typed) : c.cmd;
    const lines = isCur ? c.lines.slice(0, outN) : c.lines;
    const cursor = isCur && !done && stage === "cmd";
    return <div className="td-block" key={i}>
              <div className="td-cmdline">
                <span className="td-prompt">{PROMPT}</span> <span className="td-cmd">{cmdText}</span>
                {cursor && <span className="td-cursor" />}
              </div>
              {lines.map((ln, j) => {
      const tr = ln.trim();
      const cls = tr.startsWith("✓") ? "ok" : tr.startsWith("✗") || tr.startsWith("✘") ? "err" : "";
      return <div className={"td-out " + cls} key={j}>{ln.length ? ln : " "}</div>;
    })}
            </div>;
  })}
      </div>
      <div className="td-hint">{L.hint}</div>
    </div>;
};

`Docker` `WSL 2` `Windows`

Docker 是開源的應用程式容器引擎，把應用程式與其相依套件打包進可移植的容器，發佈到任何支援的環境執行。容器以沙箱機制相互隔離，效能開銷極低。這份筆記在 Windows 以 WSL 2 為基礎，從 WSL 安裝走到 Docker 裝好、第一次跑起來。裝好之後的指令、設定與 Compose 從 [核心概念](/notes/docker/guide/concepts/) 一路看下去，建自己的映像看 [如何撰寫 Dockerfile](/notes/docker/dockerfile/basics/)。

<Tip>
  **建議使用 Windows 專業版（Pro）或企業版（Enterprise）**：具備 Hyper-V 與完整虛擬化功能，Docker Desktop 體驗最完整、設定最少踩雷。家用版（Home）仍可透過 WSL 2 後端執行 Docker，但缺少 Hyper-V 等部分功能，遇到進階虛擬化需求時較受限。
</Tip>

## WSL 安裝

WSL（Windows Subsystem for Linux）讓你在 Windows 上執行 Linux 環境，是 Docker 在 Windows 的最佳運行基礎。

<Note>
  現代的 `wsl --install` 會自動啟用所需的 Windows 功能並安裝預設發行版，多數情況下不必手動逐項開啟功能。下方步驟 1 的手動開啟適用於需要精細控制或自動安裝失敗時。WSL 2 實際只需要「Virtual Machine Platform」與「Windows 子系統 Linux 版」兩項；Hyper-V 與 Windows Hypervisor Platform 並非必需（且 Windows 家用版沒有 Hyper-V）。
</Note>

<Steps>
  <Step title="啟用必要功能（選用，自動安裝失敗時）">
    「控制台 → 程式集 → 開啟或關閉 Windows 功能」，勾選：

    * Virtual Machine Platform（虛擬機器平台，**必要**）
    * Windows 子系統 Linux 版（**必要**）
    * Hyper-V、Windows Hypervisor Platform（選用，非 WSL 2 必需）

    按「確定」後重新啟動電腦。
  </Step>

  <Step title="安裝 WSL">
    以系統管理員開啟 PowerShell 或命令提示字元，執行：

    ```powershell theme={null}
    wsl --update
    wsl --install
    ```

    此指令啟用 WSL 所需功能並安裝預設 Linux 發行版（Ubuntu）。完成後重新啟動電腦。
  </Step>

  <Step title="設定 Linux 使用者">
    首次啟動新發行版時會開啟主控台，等待檔案解壓縮（之後啟動更快），並建立使用者帳號與密碼。
  </Step>

  <Step title="驗證 WSL 安裝">
    檢查 WSL 版本與已安裝發行版：

    ```powershell theme={null}
    wsl -l -v
    ```
  </Step>

  <Step title="設定 WSL 2 為預設版本">
    WSL 2 是執行 Docker 的推薦環境：

    ```powershell theme={null}
    wsl --set-default-version 2
    ```
  </Step>

  <Step title="更改預設發行版（選用）">
    列出可下載的發行版，並以 `-d` 安裝指定版本：

    ```powershell theme={null}
    wsl --list --online
    wsl --install -d <發行版本名稱>
    ```
  </Step>

  <Step title="以 root 啟動（步驟 3 未設定使用者時）">
    若 `wsl --install` 後未出現設定使用者名稱與密碼的提示，可先以 root 進入再手動建立帳號：

    ```powershell theme={null}
    wsl.exe --user root
    ```
  </Step>

  <Step title="最佳化 WSL 2 資源（選用）">
    編輯 `C:\Users\<你的使用者名稱>\.wslconfig` 限制 WSL 2 的記憶體與處理器。**`[wsl2]` 區段標頭不可省略**，否則設定不生效：

    ```ini theme={null}
    [wsl2]
    memory=8GB      # WSL 2 虛擬機器記憶體上限
    processors=16   # WSL 2 虛擬機器可用的虛擬處理器數
    swap=8GB        # swap 空間大小
    ```

    改完以 `wsl --shutdown` 重啟 WSL 套用。Docker 在 WSL 2 後端的 CPU 與記憶體就是由這個檔控制（不在 Docker Desktop GUI 設），細節見 [效能設定](/notes/docker/guide/config/)。
  </Step>

  <Step title="整合 VS Code 與 Windows Terminal（選用）">
    VS Code 安裝後會自動與 WSL 整合，可在 WSL 中編輯與編譯。Windows Terminal 則方便在多個 Linux 終端機與 PowerShell 間切換。
  </Step>
</Steps>

## Docker 安裝

在 Windows 以 Docker Desktop 搭配 WSL 2 引擎使用 Docker。

<Steps>
  <Step title="安裝 Docker Desktop">
    從 [Docker 官方](https://docs.docker.com/desktop/setup/install/windows-install/) 下載安裝程式並依指示安裝，留意[系統需求](https://docs.docker.com/desktop/setup/install/windows-install/#system-requirements)。
  </Step>

  <Step title="啟動 Docker Desktop">
    安裝完成後從 Windows「開始」選單啟動。
  </Step>

  <Step title="啟用 WSL 2 引擎與整合">
    設定（右上齒輪）→「General」勾選「Use the WSL 2 based engine」；「Resources → WSL Integration」選擇要啟用 Docker 整合的發行版，按「Apply & Restart」。
  </Step>

  <Step title="驗證 Docker">
    在 WSL 的 Linux 終端機執行：

    ```bash theme={null}
    docker run hello-world
    docker version
    ```
  </Step>
</Steps>

裝好後在 WSL 終端機跑驗證，成功時應該看到這樣的輸出：

<TerminalDemo
  lang="zh"
  title="Ubuntu (WSL 2)"
  prompt="user@wsl:~$"
  commands={[
{
  cmd: "docker run hello-world",
  output: [
    "Unable to find image 'hello-world:latest' locally",
    "latest: Pulling from library/hello-world",
    "c1ec31eb5944: Pull complete",
    "Status: Downloaded newer image for hello-world:latest",
    "",
    "Hello from Docker!",
    "This message shows that your installation appears to be working correctly.",
  ],
},
{
  cmd: "docker version",
  output: [
    "Client:",
    " Version:        27.3.1",
    " API version:    1.47",
    " OS/Arch:        linux/amd64",
    "Server: Docker Desktop",
    " Engine:",
    "  Version:       27.3.1",
    "  API version:   1.47 (minimum version 1.24)",
  ],
},
]}
/>

<Warning>
  Docker Desktop 對大型企業（員工數或營收超過官方門檻）需付費訂閱授權，個人與小型團隊可免費使用。詳見 Docker 官方授權條款。
</Warning>

## 下一步

裝好之後，從這裡接著看。**使用與設定**：

* [核心概念](/notes/docker/guide/concepts/)：Image、Container、Volume 與兩種介面。
* [CLI 指令](/notes/docker/guide/cli/)：每天會用到的指令。
* [Docker Hub](/notes/docker/guide/hub/)：映像從哪來、怎麼判斷可不可信。
* [效能設定](/notes/docker/guide/config/)：WSL 2 後端資源與 daemon.json。
* [資料落點](/notes/docker/guide/storage/)：volume、bind mount、tmpfs 與不掛載。
* [Docker Compose](/notes/docker/guide/compose/)：多容器一次拉起。

**Dockerfile**（建自己的映像）：

* [是什麼與從零搭建](/notes/docker/dockerfile/basics/)、[指令逐一](/notes/docker/dockerfile/instructions/)、[配合 Python](/notes/docker/dockerfile/python/)、[選擇映像](/notes/docker/dockerfile/images/)、[Layer cache 與最佳實踐](/notes/docker/dockerfile/caching/)。

## 相關連結

* Docker 官方文件：[docs.docker.com](https://docs.docker.com/)
* WSL 官方文件：[learn.microsoft.com/windows/wsl](https://learn.microsoft.com/windows/wsl/)
