Docker 完全入门指南:从零理解容器到多服务编排实战

面向零基础读者的 Docker 详细教程,覆盖核心概念、安装、镜像与容器操作、数据卷与网络、Dockerfile 编写、docker-compose 多容器编排、镜像构建发布、常见坑与速查表

一、前言:为什么我们需要 Docker

如果你写过 Web 应用、跑过数据库、部署过服务,大概率遇到过这些头疼事:

"在我电脑上明明能跑啊,怎么到你那就不行了?"
"这个项目要装 Python 3.11,另一个要 3.9,冲突了。"
"新同事入职花了三天配环境,最后还是少装了某个 so 库。"
"服务器一升级,原来跑得好好的服务全挂了。"

这些问题的根源,是 “运行环境不一致”。代码本身可能没变,但围绕它的操作系统、依赖库、运行时版本、环境变量、网络配置一旦变化,行为就可能天差地别。

Docker 的核心思想,就是把代码和它运行所需的一切,打包进一个标准化的"集装箱"——镜像(Image),然后在任何支持 Docker 的机器上,原样启动出一模一样的运行环境。

一旦你用过 Docker 部署过哪怕一个 Nginx,你会立刻意识到这套思路的价值:

  • 环境一致:开发、测试、生产用同一个镜像,不会"我电脑能跑你电脑跑不了"。
  • 秒级启动:容器是进程级别的隔离,启动速度远快于虚拟机。
  • 资源占用低:共用宿主机内核,不需要为每个应用分配一套完整的操作系统。
  • 易于迁移与扩展:Kubernetes、Swarm、各家云厂商都能直接调度 Docker 镜像。

这篇文章会带你从零开始,系统学完 Docker 的核心概念与日常实战。

二、核心概念:先把术语搞清楚

Docker 的世界里,最重要的概念只有五个。把它们理解清楚,后面的命令就是水到渠成。

01 镜像(Image)

镜像是一个只读模板,可以理解为"类的定义"或者"系统安装盘的镜像文件"。

它里面包含了:

  • 操作系统的基础层(通常是精简版 Linux,如 alpineubuntudebian
  • 应用程序代码与可执行文件
  • 运行时依赖(Node.js、Python、Java、Nginx 等)
  • 环境变量、配置文件、启动脚本

镜像采用**分层(layer)**结构,每一行 Dockerfile 指令都生成一个只读层,所有层叠加在一起形成最终镜像。这种设计让镜像可以被多个不同镜像复用,节省存储与下载时间。

镜像本身是静态的,不能直接运行。

02 容器(Container)

容器是镜像的运行实例——相当于"根据类 new 出来的对象"。

当你用 docker run 启动一个镜像,Docker 会在镜像的最上层添加一个可写层(writable layer),容器内所有运行时的改动(新建文件、修改配置、写入日志)都发生在这层。删除容器后,可写层一并销毁,数据不会保留。

容器之间相互独立,每个容器都有自己的文件系统、进程空间、网络接口,看起来就像一台独立的"小电脑"。

03 仓库(Registry / Repository)

仓库是存放和分发镜像的地方,最知名的公共仓库是 Docker Hub

镜像的完整名称由三部分组成:

[仓库地址/]镜像名[:标签]

例如:

  • nginx:默认从 Docker Hub 下载官方 nginx 镜像,latest 标签
  • nginx:1.27:指定 1.27 版本
  • registry.cn-hangzhou.aliyuncs.com/myteam/myapp:v1:从阿里云私有仓库拉取 myapp:v1

你可以把它类比成 Git:镜像 = 代码提交,仓库 = 代码托管平台,标签 = 某个版本号。

04 Dockerfile

Dockerfile 是一个文本文件,用几行声明式指令描述"如何镜像一个镜像"。

例如:

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

配合 docker build 命令,就能把这份描述变成一个可分发的镜像。

Dockerfile 是 Docker 生态的核心自动化工具,所有可复现的镜像都应该从 Dockerfile 构建,而不是手动"容器里装好再导出"。

05 Volume(数据卷)

容器默认是无状态的——删掉容器,里面的数据也没了。

Volume 是 Docker 提供的持久化存储机制,把容器内的某个目录映射到宿主机上,使数据独立于容器生命周期。后面我们会详细讲它的用法。

一张图理解 Docker 全貌

三、安装 Docker

01 Windows

推荐安装 Docker Desktop,自带 Docker Engine 与可视化界面。

  1. 访问 docker.com/products/docker-desktop 下载安装包
  2. 双击安装,按提示一路 Next(会提示启用 WSL 2,按提示操作)
  3. 安装完成后重启电脑
  4. 打开 PowerShell,执行:
docker --version
docker run hello-world

看到 Hello from Docker! 字样即表示安装成功。

注意:Docker Desktop 对个人与小公司(少于 250 人、年收入低于 1000 万美元)是免费的,企业大规模使用需付费订阅。

02 macOS

同样推荐 Docker Desktop,下载 Apple Silicon 或 Intel 对应版本,安装即用。

也可以用 brew install --cask docker 一行命令搞定。

03 Linux

以 Ubuntu 为简示例:

# 卸载旧版本(如有)
sudo apt-get remove docker docker-engine docker.io containerd runc

# 安装依赖
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg

# 添加 Docker 官方 GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# 添加仓库
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 安装
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 验证
sudo docker run hello-world

04 配置镜像加速(国内强烈建议)

国内访问 Docker Hub 经常超时,建议配置镜像加速器。

Linux 下编辑 /etc/docker/daemon.json

{
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com",
    "https://mirror.baidubce.com"
  ]
}

然后重启:

sudo systemctl daemon-reload
sudo systemctl restart docker

Windows / macOS 在 Docker Desktop 的 Settings -> Docker Engine 里直接编辑 JSON 即可。

四、镜像操作:拉取、查看、删除

01 搜索镜像

docker search nginx

02 拉取镜像

docker pull nginx                    # 默认 latest 标签
docker pull nginx:1.27               # 指定版本
docker pull ubuntu:22.04

03 查看本地镜像

docker images

输出示例:

REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        latest    4f0fcc4e60a4   2 weeks ago   188MB
nginx        1.27      4f0fcc4e60a4   2 weeks ago   188MB
ubuntu       22.04     2dc39ba59dc3   3 weeks ago   77.8MB

04 查看镜像详细信息

docker inspect nginx

会看到完整 JSON,包括镜像各层、配置、环境变量、入口点等。

05 删除镜像

docker rmi nginx:1.27                # 按名字:标签
docker rmi 4f0fcc4e60a4              # 按镜像 ID
docker image prune                   # 清理悬空镜像(无标签的)
docker image prune -a                # 清理所有未被使用的镜像

删除镜像前必须先删除基于它运行的所有容器。

06 给镜像打标签

docker tag nginx:latest mynginx:v1

这并不会复制镜像,只是给同一个镜像 ID 加了个别名,常用于推送到私有仓库前改名。

五、容器操作:日常最常用的部分

01 启动容器

docker run -d -p 8080:80 --name mynginx nginx

参数解释:

  • -d:后台运行(detached),不阻塞当前终端
  • -p 8080:80:把宿主机的 8080 端口映射到容器的 80 端口
  • --name mynginx:给容器起个名字,不指定会随机生成
  • nginx:使用的镜像

02 常用 run 参数一览

参数含义示例
-d后台运行docker run -d nginx
-it交互式终端(常用于 bash)docker run -it ubuntu bash
-p端口映射 宿主机:容器-p 8080:80
-P随机映射所有 EXPOSE 端口docker run -P nginx
--name容器名--name web
-e环境变量-e MYSQL_ROOT_PASSWORD=123456
-v挂载卷-v /host/path:/container/path
--restart自动重启策略--restart=always
--rm退出后自动删除容器docker run --rm alpine echo hi
-u指定用户-u root-u 1000:1000
--network加入网络--network mynet
--hostname设置容器内主机名--hostname node1

03 查看运行中的容器

docker ps

-a 查看所有(包括已停止的):

docker ps -a

输出字段含义:

CONTAINER ID   IMAGE     COMMAND       CREATED       STATUS       PORTS                  NAMES
4f0fcc4e60a4   nginx     "/docker…"   2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp   mynginx

04 停止 / 启动 / 重启 / 删除容器

docker stop mynginx          # 优雅停止(发送 SIGTERM,10s 后 SIGKILL)
docker start mynginx         # 启动已存在的容器
docker restart mynginx       # 重启
docker rm mynginx            # 删除已停止的容器
docker rm -f mynginx         # 强制删除运行中的容器
docker container prune       # 删除所有已停止的容器

05 进入容器内部

容器已经在运行时,可以用以下命令进入交互终端:

docker exec -it mynginx bash

常见问题:很多精简镜像(如 alpinenginx)没有 bash,需要换成 sh

docker exec -it mynginx sh

如果只是想一次性执行命令:

docker exec mynginx ls /etc/nginx

06 查看容器日志

docker logs mynginx                  # 全部日志
docker logs -f mynginx               # 跟踪输出(类似 tail -f)
docker logs --tail 100 mynginx      # 最后 100 行
docker logs -t mynginx              # 显示时间戳

07 查看容器资源占用

docker stats                        # 所有运行中容器的实时资源
docker stats mynginx                # 指定容器

输出会显示 CPU、内存、网络、磁盘 IO 使用率。

08 在容器与宿主机之间复制文件

# 容器 -> 宿主机
docker cp mynginx:/etc/nginx/nginx.conf ./nginx.conf

# 宿主机 -> 容器
docker cp ./index.html mynginx:/usr/share/nginx/html/

09 查看容器内进程

docker top mynginx

六、数据持久化:Volume 与绑定挂载

容器天然是无状态的,但绝大多数应用都需要保存数据。Docker 提供两种主要方式。

01 Volume(推荐)

由 Docker 管理的持久化存储,位置由 Docker 决定(Linux 默认在 /var/lib/docker/volumes/)。

# 创建具名卷
docker volume create mydata

# 启动容器并挂载
docker run -d -p 8080:80 \
  -v mydata:/usr/share/nginx/html \
  --name web \
  nginx

# 查看卷
docker volume ls
docker volume inspect mydata

# 删除卷(需先删除使用它的容器)
docker volume rm mydata
docker volume prune          # 清理所有未被使用的卷

02 绑定挂载(Bind Mount)

直接把宿主机的任意目录挂到容器里。开发时常用——改宿主机代码,容器内立刻生效。

docker run -d -p 8080:80 \
  -v /home/user/code:/usr/share/nginx/html:ro \
  --name web \
  nginx

-v 宿主路径:容器路径:ro,末尾的 ro 表示只读。

03 tmpfs 挂载

只在内存中,不写磁盘,适合存敏感临时数据(如密钥、token):

docker run --tmpfs /tmp alpine

三种方式对比

方式位置适用场景
Volume(默认)Docker 目录生产数据库、长期存储
Bind Mount任意宿主机目录开发环境、调试
tmpfs内存临时敏感数据

七、网络:从端口映射到自定义网络

01 Docker 默认网络

docker network ls

默认会有三个:

  • bridge:默认网络,容器通过它互联
  • host:容器直接使用宿主机网络(无网络隔离)
  • none:完全无网络

02 端口映射

最常用的 -p 参数有三种写法:

docker run -p 8080:80 nginx        # 映射到 0.0.0.0:8080
docker run -p 127.0.0.1:8080:80 nginx   # 只本机访问
docker run -p 8080:80 nginx        # 同上,最常用

03 自定义网络(容器互联推荐)

默认 bridge 网络下,容器之间只能通过 IP 互访,不直观。自定义网络支持容器名直接互访

# 创建网络
docker network create mynet

# 启动两个容器加入同一网络
docker run -d --name db --network mynet \
  -e POSTGRES_PASSWORD=123456 \
  postgres:16

docker run -d --name app --network mynet \
  -e DATABASE_URL=postgres://postgres:123456@db:5432/postgres \
  myapp:latest

app 容器可以直接通过 db 这个名字访问数据库,Docker 内置 DNS 会自动解析。

04 网络常用命令

docker network ls                  # 列出所有网络
docker network inspect mynet     # 查看网络详情
docker network connect mynet web # 把运行中容器加入网络
docker network disconnect mynet web
docker network rm mynet

八、Dockerfile 详解:从零编写镜像构建脚本

01 一个最小可用的 Dockerfile

# 基础镜像
FROM node:20-alpine

# 设置工作目录
WORKDIR /app

# 先拷贝依赖文件(利用缓存)
COPY package*.json ./

# 安装依赖
RUN npm install --production

# 拷贝源代码
COPY . .

# 暴露端口(仅声明,不会真正发布)
EXPOSE 3000

# 容器启动命令
CMD ["node", "server.js"]

构建:

docker build -t myapp:v1 .

末尾的 . 是构建上下文(build context),即 Dockerfile 所在的目录。

02 核心指令详解

指令作用示例
FROM指定基础镜像FROM ubuntu:22.04
WORKDIR设置后续命令的工作目录WORKDIR /app
COPY从构建上下文拷贝文件COPY ./src /app/src
ADD类似 COPY,支持 URL 和自动解压ADD app.tar.gz /app/
RUN在镜像构建时执行命令RUN apt-get update && apt-get install -y curl
CMD容器启动默认命令(可被覆盖)CMD ["python", "app.py"]
ENTRYPOINT容器启动入口(不易被覆盖)ENTRYPOINT ["python"]
ENV设置环境变量ENV NODE_ENV=production
ARG构建参数(构建时传入)ARG VERSION=1.0
EXPOSE声明容器监听的端口EXPOSE 8080
VOLUME声明挂载点VOLUME /data
USER切换运行用户USER node
LABEL添加元数据LABEL version="1.0"
HEALTHCHECK健康检查HEALTHCHECK CMD curl -f http://localhost/ || exit 1
ONBUILD触发器,被当基础镜像时执行ONBUILD COPY . /app/src

03 CMD vs ENTRYPOINT

这是初学者最常困惑的:

  • CMD ["node", "server.js"]docker run myapp node debug.js 会改成跑 node debug.js
  • ENTRYPOINT ["node"] + CMD ["server.js"]:默认跑 node server.js,但 docker run myapp debug.js 会跑 node debug.js

如果命令以 shell 形式(不带中括号)写,Docker 会用 /bin/sh -c 包裹,行为略有不同,生产环境强烈建议使用 exec 形式(带中括号)

04 多阶段构建(强烈推荐)

构建前端 / Go / Rust 项目时,编译环境通常很大,而运行时只需要产物。多阶段构建可以让最终镜像极小

# 阶段 1:编译
FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN go build -o app

# 阶段 2:运行时
FROM alpine:3.20
COPY --from=builder /src/app /app
CMD ["/app"]

最终镜像可能只有十几 MB,而不用多阶段会带上整个 Go 工具链,接近 1 GB。

05 .dockerignore

.gitignore 类似,告诉 Docker 构建时排除哪些文件。必须创建,否则 node_modules.git*.log 会全被打进镜像:

.git
node_modules
*.log
.env
dist
.vscode
.idea

06 镜像构建实战:Node.js 项目

假设项目结构:

myapp/
├── Dockerfile
├── .dockerignore
├── package.json
└── server.js

Dockerfile:

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
USER node
CMD ["node", "server.js"]

server.js:

const http = require('http');
http.createServer((req, res) => {
  res.end('Hello from Docker!');
}).listen(3000);

构建并运行:

docker build -t myapp:v1 .
docker run -d -p 3000:3000 --name myapp myapp:v1
curl http://localhost:3000

07 镜像构建常用选项

docker build -t myapp:v1 .                          # 打标签
docker build -t myapp:v1 -f Dockerfile.dev .        # 指定 Dockerfile
docker build --build-arg VERSION=1.2 .              # 传入构建参数
docker build --no-cache .                           # 不使用缓存
docker build --progress=plain .                     # 显示完整构建日志

九、Docker Compose:多容器编排

现实项目通常不是一个应用——前端、后端、数据库、缓存、消息队列,每个都要单独的容器。手动一个一个 docker run 会非常痛苦。

Docker Compose 就是用一份 YAML 文件描述整个多容器应用,然后一条命令启动 / 停止 / 重建。

01 安装

  • Docker Desktop:自带
  • Linux:单独安装 docker-compose-plugin(新版 Compose V2 已集成进 Docker CLI)

02 一个完整示例:WordPress + MySQL

docker-compose.yml

version: '3.8'

services:
  db:
    image: mysql:8.0
    restart: always
    volumes:
      - dbdata:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: examplepass
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
    networks:
      - wpnet

  wordpress:
    image: wordpress:latest
    restart: always
    depends_on:
      - db
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
    networks:
      - wpnet

volumes:
  dbdata:

networks:
  wpnet:

启动:

docker compose up -d

查看状态:

docker compose ps

查看日志:

docker compose logs -f

停止:

docker compose down            # 停止并删除容器
docker compose down -v         # 同时删除卷

03 常用 docker compose 命令

docker compose up -d              # 后台启动所有服务
docker compose down               # 停止并删除
docker compose ps                 # 查看服务状态
docker compose logs -f            # 跟踪日志
docker compose exec web bash      # 进入某个服务容器
docker compose restart web        # 重启某个服务
docker compose pull               # 拉取最新镜像
docker compose build              # 重新构建
docker compose config             # 验证并打印最终配置

04 与 Dockerfile 配合

Compose 也能直接基于 Dockerfile 构建:

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    depends_on:
      - redis

docker compose up --build 会先构建再启动。

05 实用模式:开发 + 生产两套配置

可以用 -f 指定多个文件叠加:

docker compose -f docker-compose.yml -f docker-compose.dev.yml up

开发环境 compose 覆盖默认配置,例如挂载源代码实现热更新。

十、镜像发布:从本地到仓库

01 推送到 Docker Hub

# 登录
docker login

# 打标签(必须包含用户名)
docker tag myapp:v1 yourusername/myapp:v1

# 推送
docker push yourusername/myapp:v1

02 推送到阿里云 / 腾讯云私有仓库

以阿里云为例:

# 登录(用户名是阿里云账号全名)
docker login registry.cn-hangzhou.aliyuncs.com

# 打标签
docker tag myapp:v1 registry.cn-hangzhou.aliyuncs.com/yourteam/myapp:v1

# 推送
docker push registry.cn-hangzhou.aliyuncs.com/yourteam/myapp:v1

03 自动构建(CI/CD 推荐)

更专业的做法是用 GitHub Actions / GitLab CI 在代码 push 时自动构建并推送镜像:

# .github/workflows/docker.yml 简化示例
name: Docker
on:
  push:
    branches: [main]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: 登录 Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      - name: 构建并推送
        uses: docker/build-push-action@v5
        with:
          push: true
          tags: yourusername/myapp:latest

十一、清理与维护

Docker 用久了,本机会堆积大量无用对象:

docker system df                # 查看占用
docker system prune             # 清理所有停止容器、无用网络、悬空镜像
docker system prune -a          # 包括所有未被使用的镜像(慎用)
docker volume prune             # 清理多余卷
docker container prune          # 清理停止的容器
docker image prune -a           # 清理镜像

十二、常见坑与排错

01 容器一启动就退出

原因:前台进程退出(CMD 命令跑完了)。

排查

docker logs container_name
docker ps -a           # 看 STATUS 列,常见 Exited (1) xxx ago

解决:确保 CMD / ENTRYPOINT 是前台运行的进程(Nginx、Node、Java 之类),不要用 shell 跑后台再退出。

2 修改了容器内文件,重启后没了

原因:容器可写层是临时的。

解决:用 -v 挂载卷,或在 Dockerfile 中固化配置。

3 时区不对

解决

ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

或在运行时挂载:

docker run -v /etc/localtime:/etc/localtime:ro ...

4 端口被占用

# Windows
netstat -ano | findstr :8080

# Linux / macOS
lsof -i :8080

或者换个端口:docker run -p 9090:80 ...

5 容器内网络访问不到外网

docker network inspect bridge      # 看配置
docker run --network host ...      # 临时用 host 网络排查

最常见原因是 DNS 配置。可以在 daemon.json 加:

{
  "dns": ["8.8.8.8", "1.1.1.1"]
}

6 镜像构建缓存失效

改了 COPY . . 之前的内容就重新跑 npm install,构建会变慢。把不常变化的依赖声明放在前面,常变的源码放在后面:

COPY package*.json ./
RUN npm install
COPY . .           # 这一层每次都会变,但 npm install 不会重跑

7 docker build 太慢

  • 配置镜像加速(前面讲过)
  • 启用 BuildKit:DOCKER_BUILDKIT=1 docker build .
  • .dockerignore 排除无关内容

十三、实战小项目:把一个 Node 应用完整 Docker 化

我们串一下完整流程,把前面所有知识用一遍。

项目结构

hello-app/
├── Dockerfile
├── .dockerignore
├── package.json
├── server.js
└── public/
    └── index.html

01 写应用

package.json

{
  "name": "hello-app",
  "version": "1.0.0",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.19.0"
  }
}

server.js

const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

app.use(express.static('public'));

app.get('/api/hello', (req, res) => {
  res.json({
    message: 'Hello from Docker!',
    time: new Date().toISOString(),
    hostname: require('os').hostname()
  });
});

app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
});

public/index.html

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>Hello Docker</title></head>
<body>
  <h1>Hello Docker!</h1>
  <button onclick="fetch('/api/hello').then(r=>r.json()).then(d=>alert(JSON.stringify(d)))">
    调用 API
  </button>
</body>
</html>

02 Dockerfile

# 多阶段示例:本例单阶段即可,留作对比参考
FROM node:20-alpine

# 安装 curl 用于健康检查
RUN apk add --no-cache curl

WORKDIR /app

# 先装依赖
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

# 拷贝源码
COPY . .

# 用非 root 用户运行
USER node

EXPOSE 3000

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:3000/api/hello || exit 1

CMD ["node", "server.js"]

.dockerignore

node_modules
npm-debug.log
.git
.gitignore
.env
*.md

03 构建并运行

docker build -t hello-app:v1 .
docker run -d -p 3000:3000 --name hello hello-app:v1
curl http://localhost:3000/api/hello

04 用 docker compose 管理

docker-compose.yml

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - PORT=3000
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/api/hello"]
      interval: 30s
      timeout: 3s
      retries: 3

启动:

docker compose up -d
docker compose logs -f
docker compose down

十四、速查表

镜像

docker images                # 列出镜像
docker pull nginx            # 拉取
docker rmi nginx             # 删除
docker tag a b               # 打标签
docker inspect nginx         # 详情
docker history nginx         # 看各层
docker save -o a.tar nginx   # 导出
docker load -i a.tar         # 导入

容器

docker run -d -p 8080:80 nginx   # 启动
docker ps / docker ps -a          # 查看
docker stop / start / restart
docker rm / docker rm -f
docker logs -f
docker exec -it name bash
docker stats
docker top
docker cp

网络

docker network ls
docker network create mynet
docker network connect mynet web
docker network inspect mynet

docker volume ls
docker volume create mydata
docker volume rm mydata
docker volume inspect mydata

系统

docker system df
docker system prune
docker system info

Compose

docker compose up -d
docker compose down
docker compose ps
docker compose logs -f
docker compose exec app bash
docker compose build
docker compose pull

十五、学习路径建议

Docker 本身不难,但它的生态非常庞大。按这个路径学下来最稳:

  1. 本文内容——掌握镜像、容器、Volume、网络、Dockerfile、Compose
  2. 镜像优化——多阶段构建、镜像瘦身(distroless、scratch)
  3. 私有仓库——Harbor、registry 镜像
  4. 容器编排——Kubernetes(k8s)入门
  5. CI/CD——GitHub Actions / GitLab CI 自动构建推送镜像
  6. 安全——镜像扫描(Trivy)、运行时安全(Falco)、Rootless Docker

当你能在 30 分钟内把一个新项目从源码到 Dockerfile 到 Compose 一气呵成跑起来,Docker 才算真正"入门"了。

写在最后

Docker 不是银弹,它解决的是"环境一致性"这一类问题。它把软件打包成标准化、可分发的形态,让运维与协作的成本大幅下降。

刚开始学时,命令很多很容易忘,没关系——用多了自然会记住。先学会 docker rundocker psdocker logsdocker exec 四个命令,你就已经能解决 80% 的日常问题。

剩下的 20%,留给 Compose、Dockerfile、网络和卷。每一块单独看都不复杂,串起来才是 Docker 的全貌。

如果你看完这篇文章能写出一个能跑起来的 Dockerfile,那入门就完成了。


风险提示:本文涉及的命令与配置以 Docker 24+ 版本为准,不同版本细节可能略有差异。生产环境部署请结合实际网络与安全策略进行评估。