容器运行

14 分钟阅读 · 23 组命令示例

Docker 基础指南:镜像 / 容器 / Compose

适用场景:本地开发环境容器化、数据库快速启动、项目部署、CI/CD 流水线。

适用版本:Docker Engine 24+、Docker Compose 2.22+;Node.js 示例使用 24 LTS。

最后核对:2026-07-30

30 秒快速路径

bash
docker compose up -d --wait
docker compose ps
docker compose logs -f app

目录

  1. 核心概念
  2. 镜像操作
  3. 容器操作
  4. 端口映射与数据卷
  5. Dockerfile — 构建自定义镜像
  6. Docker Compose — 多容器编排
  7. 日志与调试
  8. 清理空间
  9. 前端常用场景
  10. 常见问题

核心概念

镜像 vs 容器

text
镜像 (Image)          容器 (Container)
  模板/蓝图    ──run──→   运行中的实例
  只读                    可读写
  可共享                  独立隔离
  类比:类               类比:对象

关键术语

术语 含义
镜像 (Image) 打包好的文件系统 + 运行环境,只读模板
容器 (Container) 镜像的运行实例,有自己的进程/网络/文件系统
Dockerfile 构建镜像的脚本
Registry 镜像仓库(Docker Hub、GitHub Container Registry)
Volume 持久化数据卷(容器删了数据还在)
Network 容器间通信的虚拟网络
Compose 多容器应用的编排工具

镜像操作

bash
# 搜索镜像
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。


容器操作

bash
# ═══ 运行容器 ═══

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)

bash
# 格式:-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)

bash
# 格式:-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)

bash
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 项目示例

dockerfile
# 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

dockerfile
# 多阶段构建:构建阶段 + 运行阶段
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

text
node_modules
dist
.git
.env
*.log

构建与运行

bash
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 示例

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 命令

bash
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             # 重启某服务

日志与调试

bash
# 查看容器日志
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 长期使用会占大量磁盘。

bash
# 查看空间占用
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                   # 清理构建缓存

前端常用场景

快速起一个数据库

bash
# 先在当前会话设置强密码;不要把真实值写进脚本或 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

测试生产构建

bash
# 把 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 验证

统一团队开发环境

yaml
# 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:
bash
docker compose -f compose.dev.yaml up

大型项目可进一步使用 Compose Watch,只同步源码并在依赖声明变化时重建,避免整棵目录绑定挂载:docker compose up --watch


常见问题

"port is already allocated"

bash
docker ps --format 'table {{.Names}}\t{{.Ports}}'  # 查看 Docker 发布的端口
docker stop my-container               # 用实际容器名替换 my-container
# 或者换个端口:-p 8081:80

docker ps 只能看到 Docker 容器。若没有匹配项,还要使用宿主机的 Get-NetTCPConnectionsslsof 检查普通进程。

"no space left on device"

bash
docker system df -v                    # 先判断是镜像、卷还是构建缓存
docker builder prune                   # 示例:确认主要是构建缓存后定向清理
docker system df                       # 再确认释放量

容器内网络不通

bash
# 进入容器检查
docker exec -it my-container sh
getent hosts example.com               # 镜像包含 getent 时检查 DNS
curl http://other-service:3000         # 容器间通信用服务名

# Compose 中各服务可以用服务名互相访问
# 例如 app 容器通过服务名 db 连接 PostgreSQL 的 5432 端口

Alpine 和其他精简镜像通常不预装 pingcurlnslookup。不要把“命令不存在”误判成网络故障,可按镜像包管理器临时安装诊断工具,或使用专门的调试容器。

镜像构建慢

dockerfile
# 优化:把不常变的放前面(利用缓存)
COPY package.json package-lock.json ./  # 依赖声明不常变
RUN npm ci                              # 这一层被缓存
COPY . .                                # 源代码常变,放后面
RUN npm run build

Windows/macOS 性能问题

Docker Desktop 在 Windows/macOS 上用虚拟机跑 Linux,挂载大量文件(如 node_modules)时性能差。

yaml
# 解决方案 1:源码绑定挂载,但 node_modules 使用容器卷
volumes:
  - .:/app
  - node_modules:/app/node_modules

如果容器启动命令依赖 node_modules,必须在启动前通过镜像构建或启动脚本完成安装;不要等容器已经因缺少依赖退出后再运行 docker compose exec。Compose 2.22+ 还可使用 develop.watch 精确同步源码,并排除 node_modules


官方参考