目錄
docker init:自動產生 Dockerfile 與 compose.yaml
寫 Dockerfile 對新手來說最難的是「不知道從哪裡開始」。docker init 會偵測專案的語言,問你幾個問題,然後產生一套可以直接執行的 Docker 檔案。這一節用 Node.js 應用 的 Express 專案實測整個流程,並逐行檢查它產生了什麼。
docker init是 Docker Desktop 內建的外掛。只安裝 Docker Engine 的 Linux 主機沒有這個指令,但產生的檔案可以在任何地方使用。
準備專案
資料夾 init-demo 中只有三個檔案,還沒有任何 Docker 相關檔案:
init-demo/
├── package.json
├── package-lock.json
└── server.js
server.js 是一個監聽 3000 埠的 Express 程式,內容與 Node.js 應用 相同。
執行 docker init
在專案資料夾中執行:
$ docker init
Welcome to the Docker Init CLI!
This utility will walk you through creating the following files with sensible defaults for your project:
- .dockerignore
- Dockerfile
- compose.yaml
- README.Docker.md
Let's get started!
? What application platform does your project use? [Use arrows to move, type to filter]
> Node - (detected) suitable for a Node server application
Go - suitable for a Go server application
Python - suitable for a Python server application
Rust - suitable for a Rust server application
ASP.NET Core - suitable for an ASP.NET Core application
PHP with Apache - suitable for a PHP web application
Java - suitable for a Java application that uses Maven and packages as an uber jar
Other - general purpose starting point for containerizing your application
Don't see something you need? Let us know!
Quit
docker init 發現了 package.json,自動把 Node 標為 (detected) 並選好。用方向鍵選擇、Enter 確認。接下來會依序詢問:
? What application platform does your project use? Node
? What version of Node do you want to use? 24
? Which package manager do you want to use? npm
? What command do you want to use to start the app? npm start
? What port does your server listen on? 3000
✔ Created → .dockerignore
✔ Created → Dockerfile
✔ Created → compose.yaml
✔ Created → README.Docker.md
→ Your Docker files are ready!
Review your Docker files and tailor them to your application.
Consult README.Docker.md for information about using the generated files.
What's next?
Start your application by running → docker compose up --build
Your application will be available at http://localhost:3000
| 問題 | 本例的回答 | 說明 |
|---|---|---|
| application platform | Node | 偵測到 package.json,直接按 Enter |
| version of Node | 24 | 沒有預設值,必須輸入,否則出現 Value is required |
| package manager | npm | 偵測到 package-lock.json,預設就是 npm |
| command to start the app | npm start | 預設值取自 package.json 的 scripts.start |
| port | 3000 | 程式監聽的連接埠,沒有預設值 |
Node 版本沒有輸入就按 Enter,會看到:
? What application platform does your project use? Node
X Sorry, your reply was invalid: Value is required
? What version of Node do you want to use?
專案中有
.nvmrc或package.json的engines.node時,docker init會用它們當預設值。
最後產生了四個檔案:.dockerignore、Dockerfile、compose.yaml、README.Docker.md。
產生的 Dockerfile
去掉說明註解後的內容(原檔每一段都有英文註解):
# syntax=docker/dockerfile:1
ARG NODE_VERSION=24
FROM node:${NODE_VERSION}-alpine
# Use production node environment by default.
ENV NODE_ENV production
WORKDIR /usr/src/app
RUN --mount=type=bind,source=package.json,target=package.json \
--mount=type=bind,source=package-lock.json,target=package-lock.json \
--mount=type=cache,target=/root/.npm \
npm ci --omit=dev
USER node
COPY . .
EXPOSE 3000
CMD npm start
| 寫法 | 作用 |
|---|---|
# syntax=docker/dockerfile:1 | 使用最新的 Dockerfile 語法版本(建置時會先下載 docker/dockerfile:1) |
ARG NODE_VERSION=24 | 版本寫成變數,可以用 --build-arg NODE_VERSION=22 換版本 |
--mount=type=bind,source=package.json | 不用 COPY,建置時直接掛載 package.json,少一層映像檔 |
--mount=type=cache,target=/root/.npm | npm 的下載快取在多次建置之間共用,但不會進入映像檔 |
npm ci --omit=dev | 只安裝正式環境套件 |
USER node | 以非 root 使用者執行 |
整體上已經符合 Node.js 應用 介紹的最佳實務。
用 docker build --check 檢查
docker build --check 只檢查 Dockerfile 的寫法,不真的建置。對產生的 Dockerfile 執行:
$ docker build --check .
#0 building with "default" instance using docker driver
#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 1.20kB done
#1 DONE 0.0s
#2 resolve image config for docker-image://docker.io/docker/dockerfile:1
#2 DONE 0.2s
#3 docker-image://docker.io/docker/dockerfile:1@sha256:4edf897a3ffa55b89f906fc8cc78afdb3f1834cc9c7083565e611a8a7d5fe99e
#3 resolve docker.io/docker/dockerfile:1@sha256:4edf897a3ffa55b89f906fc8cc78afdb3f1834cc9c7083565e611a8a7d5fe99e done
#3 CACHED
#4 [internal] load metadata for docker.io/library/node:24-alpine
#4 DONE 0.2s
#5 [internal] load .dockerignore
#5 transferring context: 663B done
#5 DONE 0.0s
Check complete, 2 warnings have been found!
WARNING: LegacyKeyValueFormat - https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/
"ENV key=value" should be used instead of legacy "ENV key value" format
Dockerfile:14
--------------------
12 |
13 | # Use production node environment by default.
14 | >>> ENV NODE_ENV production
15 |
16 |
--------------------
WARNING: JSONArgsRecommended - https://docs.docker.com/go/dockerfile/rule/json-args-recommended/
JSON arguments recommended for CMD to prevent unintended behavior related to OS signals
Dockerfile:38
--------------------
36 |
37 | # Run the application.
38 | >>> CMD npm start
39 |
--------------------
範本本身有兩個警告:
- LegacyKeyValueFormat:
ENV NODE_ENV production是舊寫法,應改成ENV NODE_ENV=production。 - JSONArgsRecommended:
CMD npm start是 shell 格式,建議改成 JSON 陣列格式,否則可能影響停止訊號的傳遞,原因見 Dockerfile 指令詳解。
修改這兩行:
ENV NODE_ENV=production
CMD ["node", "server.js"]
CMD 順便改成直接執行 node,少一個 npm 程序,理由見 Node.js 應用 的實測。docker build --check 很適合加進 CI 流程,在建置前就攔下有問題的寫法。
產生的 compose.yaml
去掉註解後只有幾行:
services:
server:
build:
context: .
environment:
NODE_ENV: production
ports:
- 3000:3000
原檔的下半部是一大段被註解掉的 PostgreSQL 範例。如果要取消註解使用,請注意兩個問題:
# db:
# image: postgres
# ...
# volumes:
# - db-data:/var/lib/postgresql/data
# ...
# healthcheck:
# test: [ "CMD", "pg_isready" ]
image: postgres沒有指定版本,現在拉到的是 18 版。18 版的 Volume 要掛載在/var/lib/postgresql,掛在/var/lib/postgresql/data會啟動失敗,見 PostgreSQL。pg_isready沒有加-h 127.0.0.1,資料庫初始化還沒完成就會被判定為 healthy。
.dockerignore 與 README.Docker.md
產生的 .dockerignore 排除了常見的不需要的檔案,包括 **/node_modules、**/.env、**/.git、**/Dockerfile*、**/compose.y*ml 等,比本教學前面手寫的版本更完整,可以直接沿用。
README.Docker.md 是簡短的英文說明:如何用 docker compose up --build 啟動,以及建置給不同 CPU 架構的提醒(見 多平台映像檔)。
啟動
照著提示執行 docker compose up --build。這裡加上 -d 在背景執行,並確認結果:
$ docker compose up -d --build
[+] Building 15.1s (13/13) FINISHED
=> [internal] load local bake definitions 0.0s
=> => reading from stdin 486B 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 1.20kB 0.0s
=> resolve image config for docker-image://docker.io/docker/dockerfile:1 1.1s
=> docker-image://docker.io/docker/dockerfile:1@sha256:4edf897a3ffa55b89f906fc8cc78afdb3f1834cc9c7083565e611a8a7d5fe99e 3.9s
=> => resolve docker.io/docker/dockerfile:1@sha256:4edf897a3ffa55b89f906fc8cc78afdb3f1834cc9c7083565e611a8a7d5fe99e 0.0s
=> => sha256:9d2b4f57f9e20f33279375ce25c6ff14f30f64270ed5c7b613b2b30256754f62 14.28MB / 14.28MB 3.5s
=> => extracting sha256:9d2b4f57f9e20f33279375ce25c6ff14f30f64270ed5c7b613b2b30256754f62 0.4s
=> [internal] load metadata for docker.io/library/node:24-alpine 0.9s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 663B 0.0s
=> [stage-0 1/4] FROM docker.io/library/node:24-alpine@sha256:ebfe2f90462722a7a4de65e91990e97fe0d401c70e0e762c5b53302f905ec1c1 3.2s
=> => resolve docker.io/library/node:24-alpine@sha256:ebfe2f90462722a7a4de65e91990e97fe0d401c70e0e762c5b53302f905ec1c1 0.0s
=> => extracting sha256:e2de96513ba9eb53b431787ec8a65cdde380ac4772a3e4c4b714dcfde2a102b5 0.2s
=> => sha256:02f40d53b06f6b91fec0cd6a6719656da99270bff8ee54ed8dcdf4c157763fc1 1.26MB / 1.26MB 0.8s
=> => sha256:7ce7dcbafb7f750cf0c6be3c30e34372b06dd1182fa67f6ae30782c8150c5444 444B / 444B 0.2s
=> => sha256:3c504d5a797be28f9de43147d49cd8ecb2eea46dfaf7beb8715db695d5f0a7f0 56.52MB / 56.52MB 1.1s
=> => extracting sha256:3c504d5a797be28f9de43147d49cd8ecb2eea46dfaf7beb8715db695d5f0a7f0 1.9s
=> => extracting sha256:02f40d53b06f6b91fec0cd6a6719656da99270bff8ee54ed8dcdf4c157763fc1 0.1s
=> => extracting sha256:7ce7dcbafb7f750cf0c6be3c30e34372b06dd1182fa67f6ae30782c8150c5444 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 31.23kB 0.0s
=> [stage-0 2/4] WORKDIR /usr/src/app 0.1s
=> [stage-0 3/4] RUN --mount=type=bind,source=package.json,target=package.json --mount=type=bind,source=package-lock.json,target=package-l 2.6s
=> [stage-0 4/4] COPY . . 0.0s
=> exporting to image 2.7s
=> => exporting layers 0.3s
=> => exporting manifest sha256:1278071dc9c5842ea834d9abc8c01262b999118ef6903ed4998b8cc8ccc5aaba 0.0s
=> => exporting config sha256:879a23594d9f079707b7b35c022fb427cebaaa18db9701eb78b1fbaf82efed06 0.0s
=> => exporting attestation manifest sha256:012342031ad01079856bb6ebf257f096c2d8f9ff12d448ed86a58a645d64bb5d 0.0s
=> => exporting manifest list sha256:19aee69cf5d970c251d176f2f533bb918f9e72edf675b109b569ae2ff25cb4f3 0.0s
=> => naming to docker.io/library/init-demo-server:latest 0.0s
=> => unpacking to docker.io/library/init-demo-server:latest 2.3s
=> resolving provenance for metadata file 0.0s
[+] up 3/3
✔ Image init-demo-server Built 15.2s
✔ Network init-demo_default Created 0.0s
✔ Container init-demo-server-1 Started 0.4s
$ curl -s http://localhost:3000
{"message":"Hello from Express","node":"v24.21.0"}
$ docker compose exec server ps
PID USER TIME COMMAND
1 node 0:00 npm start
18 node 0:00 {MainThread} node server.js
25 node 0:00 ps
$ time docker compose stop
Container init-demo-server-1 Stopping
Container init-demo-server-1 Stopped
real 0m 0.21s
user 0m 0.04s
sys 0m 0.02s
$ docker compose logs server
server-1 |
server-1 | > express-app@1.0.0 start
server-1 | > node server.js
server-1 |
server-1 | Listening on port 3000
server-1 | SIGTERM received, closing server
server-1 | npm notice
server-1 | npm notice New major version of npm available! 11.19.0 -> 12.2.0
server-1 | npm notice Changelog: https://github.com/npm/cli/releases/tag/v12.2.0
server-1 | npm notice To update run: npm install -g npm@12.2.0
server-1 | npm notice
- 建置過程的第一步是下載
docker/dockerfile:1,這是# syntax=那一行的效果。 - 服務名稱是
server,網站正常回應。 ps顯示 PID 1 是npm start,node 是它的子程序;docker compose stop在 0.21 秒內完成,npm 有把停止訊號轉給 node。
什麼時候用 docker init
- 新專案、不熟 Dockerfile:用它產生起點,再對照本教學逐行理解並修改。
- 已有 Dockerfile 的專案:可以在另一個資料夾產生一份,參考它的寫法(例如快取掛載)。
- 它不會做的事:不會幫你處理資料庫遷移、環境變數、HTTPS、多階段建置的細節。產生的檔案只是開始。
重點回顧
docker init偵測專案語言,問幾個問題後產生Dockerfile、compose.yaml、.dockerignore、README.Docker.md。- Node 版本與連接埠沒有預設值,必須輸入。
- 產生的 Dockerfile 用了 BuildKit 的 bind 與 cache 掛載,寫法很好,但仍有舊語法警告。
- 用
docker build --check檢查任何 Dockerfile。 - 範本中被註解的 PostgreSQL 範例需要修改才能用在
postgres:18。
動手練習
練習 1:對你自己寫過的 Dockerfile(例如 Dockerfile 入門 的範例)執行 docker build --check .,看看有沒有警告。
提示
沒有任何問題時會顯示 Check complete, no warnings found.。最常見的警告是 JSONArgsRecommended(CMD、ENTRYPOINT 用了 shell 格式)和 LegacyKeyValueFormat(ENV 沒有用 =)。
練習 2:修改產生的 Dockerfile,把 Node 版本改成 22 而不修改檔案內容。
答案
NODE_VERSION 是 ARG,建置時傳入即可:
docker build --build-arg NODE_VERSION=22 -t init-demo:node22 .
Compose 中則寫在 build.args:
services:
server:
build:
context: .
args:
NODE_VERSION: "22"
練習 3:照本章的說明修正 ENV 和 CMD 兩行,再執行一次 docker build --check .,確認警告消失。
常見問題
docker init 在 Linux 的 Docker Engine 上可以用嗎?
docker init 是 Docker Desktop 內建的 CLI 外掛(Windows、macOS、Linux 版的 Docker Desktop 都有),只安裝 Docker Engine 的 Linux 主機預設沒有這個指令,執行會出現 docker: unknown command: docker init。
已經有 Dockerfile 的專案可以執行 docker init 嗎?
可以,但它會詢問是否覆蓋已存在的檔案。建議先提交到 Git,或在另一個資料夾試用,比較產生的內容後再決定要不要採用。
docker init 支援哪些語言?
實測 v1.4.0 的選單有 Node、Go、Python、Rust、ASP.NET Core、PHP with Apache、Java,以及通用的 Other。它會偵測專案中的檔案(例如 package.json)自動選好預設值。
產生的檔案可以直接用在正式環境嗎?
可以當作起點,但要自己檢查:例如本章實測的範本用了舊的 ENV key value 寫法和 shell 格式的 CMD,docker build --check 會提出警告;範本中被註解的 PostgreSQL 範例也不適用 postgres:18。
更新於 2026年10月13日