建立第一個容器#
從這一章開始進入實作。本章使用最小的 Linux 映像 Alpine 啟動一個容器(Container),並逐步拆解 docker run 背後到底發生了什麼。
為什麼選 Alpine#
Alpine 是基於 musl libc 與 BusyBox 的極小 Linux 發行版:
- 映像體積約 5–8 MB
- 啟動極快,適合教學與實驗
- 預設 shell 是
ash(BusyBox 提供)而非 bash - 套件管理使用
apk
對於觀察容器生命週期與行程(Process)行為而言,Alpine 是非常理想的對象。
第一條指令:docker run#
最簡單的容器啟動指令:
docker run -it --name mybox alpine參數解析:
-i:保持 STDIN 開啟(interactive)-t:分配虛擬終端機(TTY)--name mybox:給這個容器一個名字,方便後續操作alpine:使用的映像名稱,預設從 Docker Hub 拉取alpine:latest
預期輸出(具體值依環境而異):第一次執行會看到 Docker 從 Docker Hub pull alpine:latest 的訊息(包含每個 layer 的下載進度),完成後直接進入容器內的 shell prompt(通常是 / #)。
docker run 的三個階段#
docker run 並不是一個原子指令,而是依序執行三件事。理解這個流程對後續除錯很重要:
docker run = docker pull (if needed) → docker create → docker start階段 1:pull#
Docker daemon 會檢查 host 上是否已經有該映像。如果沒有:
- 解析 image 名稱(例如
alpine→docker.io/library/alpine:latest) - 與 registry(預設 Docker Hub)建立 HTTPS 連線
- 下載映像的 manifest(描述 layer 結構)
- 平行下載每個 layer(壓縮 tarball)
- 解壓縮並寫入聯合檔案系統(Union File System,多半是 OverlayFS)
可以單獨執行:
docker pull alpine階段 2:create#
create 階段會:
- 為新容器產生唯一 ID 與 metadata
- 設定 cgroups(CPU、記憶體限額)
- 準備命名空間(Namespaces):PID、Mount、Network、UTS、IPC、User
- 透過 OverlayFS 建立可寫層(容器的 rootfs)
- 設定網路介面(連到預設的
bridge網路)
此時容器尚未執行任何行程。可以單獨執行:
docker create --name mybox alpine階段 3:start#
start 階段才是真正執行容器的進入點(entrypoint):
- fork / exec 出新行程,並將該行程放入前面準備好的命名空間與 cgroups
- 該行程在容器內成為 PID 1(init process)
- STDIO 視
-it等參數決定是否連回 host terminal
可以單獨執行:
docker start -ai mybox-ai 是 --attach --interactive 的縮寫。
容器內看到什麼#
進入容器後執行:
ps -ef
ls /
cat /etc/os-release
hostname預期輸出(具體值依環境而異):
ps -ef只會看到極少的行程,且第一個行程的 PID 是 1(也就是進入容器時啟動的ash)ls /看到典型的 Linux 根目錄結構(bin、etc、proc、sys、usr等)/etc/os-release顯示NAME="Alpine Linux"與版本號hostname顯示一段隨機英數字串(容器 ID 的前綴)
這些觀察驗證了容器是「被隔離的 Linux 行程」這個事實:它有自己的根目錄、自己的 PID 樹、自己的主機名稱。
從 host 看容器#
開另一個 terminal,執行:
docker ps預期輸出(具體值依環境而異):會看到一行紀錄,包含容器 ID、image(alpine)、command(/bin/sh 或 ash)、status(Up xx seconds)、name(mybox)。
接著查看實際的行程:
ps -ef | grep ash在 Linux host 上會直接看到 ash 行程,且該行程的 parent 多半是 containerd-shim 或類似的 runtime 元件。在 macOS 上要先進入 LinuxKit VM 才看得到(參見上一章)。
容器內的 PID 1 與 host 上看到的 PID 是同一個行程,只是在不同 PID Namespace 中有不同的編號。這就是「行程隔離」的核心。
退出容器與容器狀態#
在容器內輸入 exit 或按 Ctrl-D:
- 容器內的 PID 1(
ash)會結束 - 容器隨之停止(不是刪除)
docker ps看不到,但docker ps -a仍會列出
這個「停止 ≠ 刪除」的差別下一章會詳細說明。
一次性容器:–rm#
如果只想做一次性實驗,加上 --rm 讓容器結束時自動刪除:
docker run -it --rm alpine退出後,連 docker ps -a 都不會留下紀錄。對教學情境特別實用。
延伸閱讀#
- Docker Docs —
docker run: https://docs.docker.com/engine/reference/run/ ↗ - Alpine Linux 官方網站: https://alpinelinux.org/ ↗
- OCI Runtime Specification: https://github.com/opencontainers/runtime-spec ↗