Docker 基础指南:镜像 / 容器 / Compose
适用场景:本地开发环境容器化、数据库快速启动、项目部署、CI/CD 流水线。
适用版本:Docker Engine 24+、Docker Compose 2.22+;Node.js 示例使用 24 LTS。
最后核对:2026-07-30
30 秒快速路径
docker compose up -d --wait
docker compose ps
docker compose logs -f app
目录
核心概念
镜像 vs 容器
镜像 (Image) 容器 (Container)
模板/蓝图 ──run──→ 运行中的实例
只读 可读写
可共享 独立隔离
类比:类 类比:对象
关键术语
| 术语 | 含义 |
|---|---|
| 镜像 (Image) | 打包好的文件系统 + 运行环境,只读模板 |
| 容器 (Container) | 镜像的运行实例,有自己的进程/网络/文件系统 |
| Dockerfile | 构建镜像的脚本 |
| Registry | 镜像仓库(Docker Hub、GitHub Container Registry) |
| Volume | 持久化数据卷(容器删了数据还在) |
| Network | 容器间通信的虚拟网络 |
| Compose | 多容器应用的编排工具 |
镜像操作
# 搜索镜像
docker search node
docker search postgres
# 拉取镜像
docker pull node:24-alpine # 指定版本+变体
docker pull postgres:16 # PostgreSQL 16
docker pull redis:7-alpine # Redis 7
# 查看本地镜像
docker images
docker images | grep node
# 删除指定镜像
docker rmi node:24-alpine
# 清理前先看占用;优先只删除 dangling 镜像
docker system df
docker image prune
# 查看镜像详情
docker inspect node:24-alpine
# 镜像标签
docker tag myapp:latest myapp:v1.0.0
常用基础镜像
| 镜像 | 用途 | 特点 |
|---|---|---|
node:24-alpine |
Node.js 24 LTS 运行环境 | 较小,但基于 musl,部分原生依赖需要额外处理 |
node:24 |
Node.js 24 LTS 完整版 | 兼容性通常更好,体积较大 |
nginx:alpine |
Web 服务器 | 精简 Nginx |
postgres:16 |
PostgreSQL 数据库 | 官方 PostgreSQL 镜像 |
redis:7-alpine |
Redis 缓存 | 精简 Redis |
mongo:7 |
MongoDB | 官方 MongoDB 镜像 |
镜像大小会随架构、具体 tag 和发布时间变化,应以 docker images 或 registry 页面为准;生产环境还应固定更精确的版本或 digest。
容器操作
# ═══ 运行容器 ═══
docker run nginx # 前台运行(Ctrl+C 停止)
docker run -d nginx # -d 后台运行(detach)
docker run -d --name my-nginx nginx # 给容器命名
docker run --rm nginx # 用完自动删除容器
docker run -it node:24-alpine sh # -it 交互模式(进入 shell)
# ═══ 查看容器 ═══
docker ps # 运行中的容器
docker ps -a # 所有容器(含已停止)
# ═══ 停止/启动/重启 ═══
docker stop my-nginx # 优雅停止
docker start my-nginx # 启动已停止的
docker restart my-nginx # 重启
docker kill my-nginx # 强制停止
# ═══ 删除容器 ═══
docker rm my-nginx # 删除已停止的容器
docker rm -f my-nginx # 强制删除(运行中也杀)
docker container prune # 确认后删除所有已停止容器
# ═══ 进入容器 ═══
docker exec -it my-nginx sh # 进入容器的 shell
docker exec -it my-nginx bash # 如果有 bash
docker exec my-nginx cat /etc/hosts # 在容器内执行单条命令
端口映射与数据卷
端口映射 (-p)
# 格式:-p 主机地址:主机端口:容器端口
# 本地开发显式绑定 127.0.0.1,避免暴露到局域网
docker run -d -p 127.0.0.1:8080:80 nginx
docker run -d -p 127.0.0.1:3000:3000 myapp
# 多端口
docker run -d -p 127.0.0.1:8080:80 -p 127.0.0.1:8443:443 nginx
# 查看端口映射
docker port my-nginx
数据卷 (-v)
# 格式:-v 主机路径:容器路径
: "${POSTGRES_PASSWORD:?请先 export POSTGRES_PASSWORD}"
docker run -d -p 127.0.0.1:5432:5432 \
-e POSTGRES_PASSWORD="$POSTGRES_PASSWORD" \
-v ./pg-data:/var/lib/postgresql/data \
postgres:16
# → 数据库文件保存在主机 ./pg-data,容器删了数据不丢
# 挂载当前目录到容器(开发常用)
docker run -d -p 127.0.0.1:3000:3000 \
-v "$PWD:/app" \
-w /app \
node:24-alpine npm run dev
# -w 设置工作目录
# 命名卷(Docker 管理,不用关心主机路径)
docker run -d -v pgdata:/var/lib/postgresql/data postgres:16
docker volume ls # 查看所有卷
docker volume rm pgdata # 删除卷
环境变量 (-e)
docker run -d \
-e POSTGRES_USER=myuser \
-e POSTGRES_PASSWORD="$POSTGRES_PASSWORD" \
-e POSTGRES_DB=mydb \
-p 127.0.0.1:5432:5432 \
postgres:16
# 从文件读取环境变量
docker run --env-file .env -d myapp
容器环境变量可通过 docker inspect 被有权限访问 Docker 的用户看到。示例只适合本地开发;生产密码应使用平台提供的 secrets 机制,不要写进镜像、Compose 文件或 Git。
Dockerfile — 构建自定义镜像
Node.js 项目示例
# syntax=docker/dockerfile:1
# 构建阶段:安装完整依赖,确保构建工具可用
FROM node:24-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
# 生产依赖阶段
FROM node:24-alpine AS prod-deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
# 运行阶段:不携带源码和构建工具
FROM node:24-alpine AS runner
ENV NODE_ENV=production
WORKDIR /app
COPY --from=prod-deps --chown=node:node /app/node_modules ./node_modules
COPY --from=builder --chown=node:node /app/dist ./dist
COPY --chown=node:node package.json ./
USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]
前端静态站 + Nginx
# 多阶段构建:构建阶段 + 运行阶段
FROM node:24-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
.dockerignore
node_modules
dist
.git
.env
*.log
构建与运行
docker build -t myapp . # 构建镜像
docker build -t myapp:v1.0 . # 带标签
docker run -d -p 127.0.0.1:3000:3000 myapp # 仅本机访问
镜像标签可以被发布者更新。日常开发可固定主版本并定期重建;要求严格复现或供应链审计时,应进一步固定到不可变 digest,并配合自动更新工具主动升级。
Docker Compose — 多容器编排
compose.yaml 示例
# compose.yaml(正式运行示例)
services:
app:
build: .
ports:
- "127.0.0.1:3000:3000"
environment:
DATABASE_URL: postgres://user:${POSTGRES_PASSWORD}@db:5432/mydb
REDIS_URL: redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_healthy
db:
image: postgres:16
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?请先设置 POSTGRES_PASSWORD}
POSTGRES_DB: mydb
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
interval: 5s
timeout: 3s
retries: 10
cache:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10
volumes:
pgdata:
若密码包含 @、:、/ 等 URI 保留字符,写入 DATABASE_URL 前必须进行 URL 编码;生产环境优先使用 secrets 或应用支持的独立连接参数。
正式运行示例不要再把 .:/app 挂到应用容器:绑定挂载会遮住镜像中已经构建好的 /app/dist 和 /app/node_modules。开发环境请使用后面的独立配置。
Compose 命令
docker compose up # 启动所有服务(前台)
docker compose up -d # 后台启动
docker compose up -d --wait # 后台启动,并等待服务 running/healthy
docker compose up -d --wait --wait-timeout 60
docker compose down # 停止并删除容器
docker compose down -v # 同时永久删除项目数据卷;确认无需数据后才执行
docker compose ps # 查看状态
docker compose logs # 查看所有日志
docker compose logs -f app # 追踪某服务日志
docker compose exec app sh # 进入某服务的 shell
docker compose build # 重新构建镜像
docker compose up --build # 构建 + 启动
docker compose restart app # 重启某服务
日志与调试
# 查看容器日志
docker logs my-container # 全部日志
docker logs -f my-container # 实时追踪(-f = follow)
docker logs --tail 100 my-container # 最后 100 行
docker logs --since 1h my-container # 最近 1 小时
# 查看容器资源占用
docker stats # 实时 CPU/内存/网络
docker stats --no-stream # 快照一次
# 查看容器详情
docker inspect my-container
docker inspect --format '{{json .NetworkSettings.Networks}}' my-container
# 查看容器内进程
docker top my-container
# 拷贝文件进出容器
docker cp ./file.txt my-container:/app/
docker cp my-container:/app/data.json ./
清理空间
Docker 长期使用会占大量磁盘。
# 查看空间占用
docker system df
# 先详细检查哪些对象占空间
docker system df -v
# 一键清理会删除停止容器、未使用网络、dangling 镜像和构建缓存
docker system prune # 阅读清单并确认后执行
docker system prune -a # 还会删除所有未被容器使用的镜像
docker system prune -a --volumes # 还会删除未使用卷,可能永久丢失数据
# 精细清理
docker container prune # 删除所有停止的容器
docker image prune # 删除无标签镜像
docker volume prune # 删除未使用的卷;先用 docker volume ls/inspect 确认
docker builder prune # 清理构建缓存
前端常用场景
快速起一个数据库
# 先在当前会话设置强密码;不要把真实值写进脚本或 Git
: "${POSTGRES_PASSWORD:?请先 export POSTGRES_PASSWORD}"
: "${MYSQL_ROOT_PASSWORD:?请先 export MYSQL_ROOT_PASSWORD}"
# PostgreSQL
docker run -d --name pg -p 127.0.0.1:5432:5432 \
-e POSTGRES_PASSWORD="$POSTGRES_PASSWORD" \
postgres:16
# MySQL
docker run -d --name mysql -p 127.0.0.1:3306:3306 \
-e MYSQL_ROOT_PASSWORD="$MYSQL_ROOT_PASSWORD" \
mysql:8
# Redis(无认证示例,因此必须只绑定本机)
docker run -d --name redis -p 127.0.0.1:6379:6379 redis:7-alpine
# MongoDB(无认证示例,因此必须只绑定本机)
docker run -d --name mongo -p 127.0.0.1:27017:27017 mongo:7
测试生产构建
# 把 dist 目录用 nginx 跑起来看看
docker run --rm -p 127.0.0.1:8080:80 \
-v "$PWD/dist:/usr/share/nginx/html:ro" nginx:alpine
# 打开 http://localhost:8080 验证
统一团队开发环境
# compose.dev.yaml
services:
dev:
image: node:24
ports:
- "127.0.0.1:4321:4321"
volumes:
- .:/app
- node_modules:/app/node_modules
working_dir: /app
# 干净检出也能启动;依赖安装在容器卷中,不复用宿主机的原生模块
command: sh -c "npm ci && npm run dev -- --host 0.0.0.0"
volumes:
node_modules:
docker compose -f compose.dev.yaml up
大型项目可进一步使用 Compose Watch,只同步源码并在依赖声明变化时重建,避免整棵目录绑定挂载:docker compose up --watch。
常见问题
"port is already allocated"
docker ps --format 'table {{.Names}}\t{{.Ports}}' # 查看 Docker 发布的端口
docker stop my-container # 用实际容器名替换 my-container
# 或者换个端口:-p 8081:80
docker ps 只能看到 Docker 容器。若没有匹配项,还要使用宿主机的 Get-NetTCPConnection、ss 或 lsof 检查普通进程。
"no space left on device"
docker system df -v # 先判断是镜像、卷还是构建缓存
docker builder prune # 示例:确认主要是构建缓存后定向清理
docker system df # 再确认释放量
容器内网络不通
# 进入容器检查
docker exec -it my-container sh
getent hosts example.com # 镜像包含 getent 时检查 DNS
curl http://other-service:3000 # 容器间通信用服务名
# Compose 中各服务可以用服务名互相访问
# 例如 app 容器通过服务名 db 连接 PostgreSQL 的 5432 端口
Alpine 和其他精简镜像通常不预装 ping、curl、nslookup。不要把“命令不存在”误判成网络故障,可按镜像包管理器临时安装诊断工具,或使用专门的调试容器。
镜像构建慢
# 优化:把不常变的放前面(利用缓存)
COPY package.json package-lock.json ./ # 依赖声明不常变
RUN npm ci # 这一层被缓存
COPY . . # 源代码常变,放后面
RUN npm run build
Windows/macOS 性能问题
Docker Desktop 在 Windows/macOS 上用虚拟机跑 Linux,挂载大量文件(如 node_modules)时性能差。
# 解决方案 1:源码绑定挂载,但 node_modules 使用容器卷
volumes:
- .:/app
- node_modules:/app/node_modules
如果容器启动命令依赖 node_modules,必须在启动前通过镜像构建或启动脚本完成安装;不要等容器已经因缺少依赖退出后再运行 docker compose exec。Compose 2.22+ 还可使用 develop.watch 精确同步源码,并排除 node_modules。