目录
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日