🐳 什么是 Docker?
Docker 是一个能让我们"打包 + 运输 + 运行"程序的工具。可以理解为就像现实中我们会用 集装箱 来运货,Docker 就是程序的集装箱
📦 举个超级通俗的例子:
假设你做了一个很好用的 Node.js 网站,别人想用它,但有问题:
• 别人电脑没有 Node.js ❌
• 别人系统是 Windows,你的是 Mac ❌
• 别人不会配置环境 ❌
你就会心累😩。
这时候你把整个项目打包成一个 Docker 镜像,别人只需要一行命令:
bash
docker run xxx
什么都不用装、跨平台、开箱即用,**运行效果 100% 跟你一模一样!**✅✅
🎁 Docker 三个核心概念
- 镜像 (image):(冷冻快餐)打包好的程序,里面包括代码、运行环境、依赖
- 容器 (container):(微波炉热好的饭)镜像运行起来就变成了容器,是你可以访问、操作的"活"程序
- Dockerfile:(菜谱)告诉 Docker 怎么做一份镜像(从哪下载,装啥依赖,复制啥文件等)
Docker 命令总览
🎁 小抄级总结 最常用的组合命令是:
bash
# 构建镜像
docker build -t myapp .
# 运行容器
docker run -p 3000:3000 myapp
# 停止容器
docker stop 容器名
# 启动 compose
docker compose up -d
🛠 举个完整例子:
bash
docker run -it --rm --name myweb -p 8080:80 nginx
这个命令的意思是:
• 启动一个 nginx 容器
• 映射端口:本地 8080 → 容器 80
• 容器名字叫 myweb
• 启动时是交互模式(-it)
• 退出时自动删除(--rm)
⚙️ docker run 命令常用参数(容器运行控制)
命名片段 | 作用 |
---|---|
-it |
用于调试或交互进容器 |
-d |
后台运行 |
--rm |
用完即焚 |
--name xxx |
容器好找 |
-p 端口映射 |
让服务暴露给本地访问 |
-v 卷挂载 |
数据不丢,代码同步 |
Dockerfile 和 Docker Compose
- Dockerfile:是 "造快餐" 的说明书(构建镜像),每一条指令(FROM、COPY、RUN)都是一步操作。Docker 会按照这个文件的内容,一步一步构建出镜像。
md
负责:定义单个服务的构建过程(怎么打包成镜像)
文件名固定:Dockerfile(没有后缀)
##运行你自己写的 Dockerfile 构建出来的镜像
# 先构建镜像,运行规则
docker build [-t=给构建出来的镜像起名字] [镜像名] [-f:指定一个非默认名字的 Dockerfile] [构建上下文路径, 代码+Dockerfile 所在目录]
docker build -t my-app -f Dockerfile.dev .
# 然后运行
docker run -p 3000:3000 my-app
示例Dockerfile
# 阶段1:使用 Node 镜像
FROM node:20
# 设置工作目录
WORKDIR /app
# 拷贝依赖文件并安装依赖(加缓存优化)
COPY package*.json yarn.lock ./
RUN yarn install
# 拷贝代码
COPY . .
# 设置环境变量
ENV NODE_ENV=development
# 开放开发端口(vite 默认 300)
EXPOSE 3001
# 默认执行开发命令
CMD ["yarn", "dev"]
- docker-compose.yml: 是 "如何安排这顿饭"的菜单(启动容器), 用来描述、定义、运行多个容器服务的组合。
md
# 文件名通常是:docker-compose.yml
# 运行指令:
(默认文件名):docker compose up -d (docker-compose.yml的运行方式)
非默认文件名):docker compose -f [文件名].yml up -d
## 🧱 顶级命令结构
docker compose -f docker-compose.dev.yml up --force-recreate
docker compose <一级子命令> [一级子命令参数] <二级子命令> [二级子命令参数]
⚙️ 一级子命令参数(Compose CLI 全局参数)
参数 | 示例 | 用途 | 说明 |
---|---|---|---|
-f |
-f docker-compose.dev.yml |
指定配置文件(可多个) | |
--env-file |
--env-file .env.dev |
加载额外的环境变量文件 | |
--project-name |
--project-name my-app |
自定义项目名(默认当前文件夹名) | |
--profile |
--profile debug |
启用指定的 profile(服务分组) | |
--compatibility |
--compatibility |
启用旧版 v2 行为兼容模式 | |
--ansi |
--ansi never |
控制颜色输出:auto / always / never | |
--no-ansi |
--no-ansi |
禁用彩色输出(等于 --ansi never ) |
|
--parallel |
--parallel 3 |
限制同时构建/拉取服务数量 | |
--log-level |
--log-level ERROR |
设置 CLI 日志级别:DEBUG / INFO / ERROR |
🧰 二级子命令参数(作用于 up
)
参数 | 示例 | 说明 |
---|---|---|
-d / --detach |
up -d |
后台运行容器 |
--build |
up --build |
启动前自动构建镜像 |
--force-recreate |
up --force-recreate |
强制重建容器 |
--no-build |
up --no-build |
禁止构建镜像 |
--no-recreate |
up --no-recreate |
禁止重建容器 |
--remove-orphans |
up --remove-orphans |
删除非当前文件定义的容器 |
--wait |
up --wait |
等待服务启动完毕才返回 |
--quiet-pull |
up --quiet-pull |
静默拉取镜像 |
🔻 二级子命令参数(作用于 down
)
参数 | 示例 | 说明 |
---|---|---|
--volumes |
down --volumes |
同时删除数据卷 |
--remove-orphans |
down --remove-orphans |
删除孤立容器 |
--timeout |
down --timeout 5 |
停止前等待时间(秒) |
📦 二级子命令参数(作用于 logs
)
参数 | 示例 | 说明 |
---|---|---|
-f / --follow |
logs -f |
实时日志 |
--tail |
logs --tail=100 |
查看末尾 N 行日志 |
--timestamps |
logs --timestamps |
显示时间戳 |
--no-color |
logs --no-color |
关闭颜色高亮 |
📋 二级子命令参数(作用于 ps
)
参数 | 示例 | 说明 |
---|---|---|
--services |
ps --services |
仅显示服务名 |
--quiet |
ps --quiet |
仅显示容器 ID |
🔧 二级子命令参数(作用于 build
)
参数 | 示例 | 说明 |
---|---|---|
--no-cache |
build --no-cache |
不使用缓存 |
--pull |
build --pull |
总是拉取镜像 |
--progress |
build --progress=plain |
控制构建日志格式 |
✅ 适合搭配 up
, down
, logs
, ps
, build
命令灵活组合使用!
Compose 文件是 启动多个容器时的一张"总布置图
它定义:
• 哪些服务(容器)要运行?
• 用哪个镜像或 Dockerfile?
• 启用哪些端口、挂载哪些目录?
• 它们之间的依赖关系是怎样?
一套通用的配置结构
完整docker-compose.yml 配置
docker-compose.yaml
version: '3.9'
services:
# -------------------------------
# 🌐 前端服务(React / Vite 项目)
# -------------------------------
web:
build: ./web # 使用当前目录下 ./web 的 Dockerfile 构建镜像
container_name: web_app # 自定义容器名,方便调试和识别
ports:
- "3000:3000" # 将本机 3000 端口映射到容器内 3000
depends_on:
- api # 等待 api 服务就绪再启动(只是顺序,不是就绪检测)
environment:
- NODE_ENV=development # 传入环境变量
volumes:
- ./web:/app # 挂载本地项目到容器,支持热更新(前提:框架支持)
networks:
- frontend
# -------------------------------
# 🧩 后端服务(Node.js API 项目)
# -------------------------------
api:
build: ./api
container_name: api_server
ports:
- "4000:4000"
depends_on:
- db
- redis
environment:
- DB_HOST=db # DB 容器的服务名作为主机名
- DB_PORT=5432
- DB_USER=user
- DB_PASSWORD=password
- DB_NAME=appdb
- REDIS_HOST=redis # Redis 容器的服务名
- REDIS_PORT=6379
volumes:
- ./api:/app
networks:
- frontend
- backend
# -------------------------------
# 🗃️ 数据库服务(PostgreSQL)
# -------------------------------
db:
image: postgres:14
container_name: postgres_db
restart: always # 容器异常退出时自动重启
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: appdb
volumes:
- db_data:/var/lib/postgresql/data # 持久化数据库数据
ports:
- "5432:5432" # 可选:方便用本地工具连接调试
networks:
- backend
# -------------------------------
# 🚀 缓存服务(Redis)
# -------------------------------
redis:
image: redis:6
container_name: redis_cache
restart: always
ports:
- "6379:6379" # 本地可访问 Redis
networks:
- backend
# -------------------------------
# 🧭 可视化工具(Adminer 管理 PostgreSQL)
# -------------------------------
adminer:
image: adminer
container_name: db_admin_ui
depends_on:
- db
ports:
- "8080:8080" # 访问 http://localhost:8080 使用图形界面
networks:
- backend
# -------------------------------
# 持久化卷:数据库数据(可扩展更多)
# -------------------------------
volumes:
db_data:
# -------------------------------
# 网络配置:隔离 + 通信通道
# -------------------------------
networks:
frontend:
backend:
Compose字段说明
字段 | 层级 | 分类 | 作用 | 示例 | 是否必填 | 推荐使用场景 |
---|---|---|---|---|---|---|
version | 顶级字段 | 基础结构 | 定义 Compose 文件的语法版本 | '3.9' | 是 | 所有 Compose 文件必需 |
services | 顶级字段 | 核心结构 | 定义多个容器服务 | services: web: | 是 | 定义服务入口点 |
volumes (root) | 顶级字段 | 数据卷声明 | 统一声明卷名用于挂载 | volumes: | 否 | 定义数据卷,如数据持久化 |
data-volume: | ||||||
networks (root) | 顶级字段 | 网络声明 | 统一声明网络名 | networks: | 否 | 多个服务互联时使用 |
my-network: | ||||||
build | 服务字段 | 构建镜像 | 使用 Dockerfile 构建镜像 | build: . | 否 | 需要自定义构建时使用,如修改代码、插件等 |
image | 服务字段 | 使用镜像 | 指定使用的镜像 | image: node:18 | 是(build 和 image 至少一个) | 直接使用官方或已有镜像时 |
container_name | 服务字段 | 容器命名 | 给容器指定名称 | container_name: myapp | 否 | 容器需指定名字便于识别、依赖或调试 |
ports | 服务字段 | 网络映射 | 映射主机端口到容器端口 | "3000:3000" | 否 | 服务对外暴露 HTTP、API、端口等 |
volumes | 服务字段 | 挂载数据 | 将主机目录挂载到容器 | - ./data:/app/data | 否 | 容器存本地缓存、数据卷、挂载需求时 |
environment | 服务字段 | 环境变量 | 设置容器内的环境变量 | - NODE_ENV=production | 否 | 设置注入环境变量,如 NODE_ENV、密钥 |
depends_on | 服务字段 | 依赖关系 | 设置容器启动顺序 | depends_on: | 否 | 确保按顺序、缓存先启动等场景 |
- db | ||||||
command | 服务字段 | 启动命令 | 覆盖镜像默认启动命令 | command: ["npm", "start"] | 否 | 更改默认启动命令 |
entrypoint | 服务字段 | 启动命令 | 覆盖默认入口脚本 | entrypoint: ["/start.sh"] | 否 | 替换默认入口脚本 |
restart | 服务字段 | 重启策略 | 定义容器失败后的重启行为 | restart: always | 否 | 服务异常重启自动重启 |
tty | 服务字段 | 控制台 | 分配终端 | tty: true | 否 | 运行交互型容器,如终端工具 |
stdin_open | 服务字段 | 控制台 | 保持标准输入打开 | stdin_open: true | 否 | 保持 stdin 打开,配合 tty 使用 |
extra_hosts | 服务字段 | 网络配置 | 额外 DNS 映射 | extra_hosts: | 否 | 需要自定义 host 映射,如 host-gateway |
- "host.docker.internal:host-gateway" | ||||||
logging | 服务字段 | 日志配置 | 配置容器日志驱动 | logging: | 否 | 服务大量日志需要管理时 |
driver: "json-file" | ||||||
networks | 服务字段 | 网络配置 | 指定容器所属网络 | networks: | 否 | 指定使用自定义网络名称 |
- my-network | ||||||
healthcheck | 服务字段 | 健康检查 | 容器运行健康检查 | healthcheck: | 否 | 对容器健康状态有监控要求 |
test: ["CMD", "curl", "-f", "http://localhost"] |
为什么别人可以只用一条 docker run 命令就跑起来,而我们却要写 Dockerfile 和 docker-compose.yml?
🎯 一句话解释:
docker run 是直接使用别人构建好的镜像 来启动服务(快速试玩)
Dockerfile 和 docker-compose.yml 是自己构建镜像 / 管理服务配置时用的工具(长期运行服务,可定制化)
🐳 Docker 使用方式:三种典型模式总览
🚀 使用方式一:拉取官方镜像直接运行(最快速)
无需 Dockerfile,适合使用已有服务(如 Redis、Nginx、Verdaccio)
bash
# 拉取镜像(可选,run 时会自动拉)
docker pull verdaccio/verdaccio:nightly-master
# 直接运行
docker run -it --rm --name verdaccio -p 4873:4873 verdaccio/verdaccio
✅ 适合:快速试用、已有服务、临时环境
🧱 使用方式二:自定义 Dockerfile 构建镜像再运行
适合自己项目,需要控制依赖、环境、命令
Dockerfile
# Dockerfile 示例
FROM node:18
WORKDIR /app
COPY . .
RUN yarn install
CMD ["yarn", "dev"]
bash
# 构建镜像
docker build -t my-app .
# 运行镜像
docker run -p 3000:3000 my-app
✅ 适合:Web 项目、自研服务、定制部署
📦 使用方式三:使用 Docker Compose 管理多个服务
适合项目多服务(前端+后端+数据库)、开发部署协同
yaml
# docker-compose.yml
version: "3.9"
services:
frontend:
build: .
ports:
- "3000:3000"
backend:
image: my-backend
ports:
- "5000:5000"
bash
# 一键构建并启动
docker compose up -d
✅ 适合:开发团队、微服务、多环境管理
🧠 总结对比
模式 | 是否需要 Dockerfile | 是否自定义镜像 | 是否适合多服务 | 场景推荐 |
---|---|---|---|---|
拉取镜像 + 运行 | ❌ 否 | ❌ 否 | ❌ 否 | 快速启动已有服务 |
构建镜像 + 运行 | ✅ 是 | ✅ 是 | ❌ 否 | 项目开发、部署 |
Compose 协同 | 可选 | ✅ 支持 | ✅ 是 | 团队协作、集成部署 |
✅ 推荐路径:先学 run → 再学 Dockerfile → 最后学 Compose
🔥 Docker 热更新 vs 镜像构建:开发流程对比
🎯 对比目的
帮助你理解在本地开发时,代码修改是否会自动反映到容器中,应该使用哪种方式更合适。
🧪 热更新模式(推荐开发)
使用 volumes 挂载本地代码,代码改动后容器实时生效(无需重启)
✅ 特点
项目 | 内容 |
---|---|
是否需要构建镜像 | ❌ 不需要 |
是否实时反映代码改动 | ✅ 是 |
适合场景 | 本地开发、调试 |
启动方式 | docker run -v $(pwd):/app or docker-compose.dev.yml |
是否依赖 Dockerfile | ❌ 可选 |
优点 | 快速开发、热更新 |
缺点 | 稍微依赖本地环境一致性 |
📦 镜像构建模式(推荐部署)
每次改动后都重新
docker build
构建镜像,改动后不会自动生效
✅ 特点
项目 | 内容 |
---|---|
是否需要构建镜像 | ✅ 是 |
是否实时反映代码改动 | ❌ 否(需重构建) |
适合场景 | 发布、线上部署 |
启动方式 | docker build && docker run |
是否依赖 Dockerfile | ✅ 是 |
优点 | 环境一致、可部署 |
缺点 | 每次都要重构建 |
🧠 什么时候该选哪个?
场景 | 推荐方式 |
---|---|
本地开发 + 实时改动 | ✅ 热更新(挂载代码) |
正式打包 + 发布 | ✅ 构建镜像 |
CI/CD 自动部署 | ✅ 构建镜像推送 registry |
临时测试官方服务 | ✅ 拉取镜像 docker run |
✅ 推荐写法示例(Compose)
热更新版 Compose
yaml
services:
app:
image: node:18
volumes:
- ./my-app:/app
- /app/node_modules
working_dir: /app
command: yarn dev
ports:
- "3000:3000"
构建部署版 Compose
yaml
services:
app:
build: .
ports:
- "3000:3000"
📁 数据持久化与挂载路径
🧠 什么是持久化?
在 Docker 中,如果你不做任何挂载,容器里的数据是临时的,一旦容器被删除,数据就全部消失了(比如数据库记录、上传的文件、缓存等)。
为了让数据保存到你本地的硬盘上 ,我们就要使用 Docker 的 volumes
或 bind mount
来 持久化挂载。
🔁 为什么数据库特别需要持久化挂载?
因为数据库运行时会产生大量的数据文件,如果你不挂载出来,一旦重启容器或删除,数据库就像「格式化」了一样,什么都没了 😱
✅ 持久化挂载语法说明:
yaml
volumes:
- 本地路径:容器路径
📦 各大数据库默认挂载路径对照表
数据库 | 容器内挂载路径(必须) | 示例挂载配置 |
---|---|---|
PostgreSQL | /var/lib/postgresql/data |
./data/postgres:/var/lib/postgresql/data |
MySQL / MariaDB | /var/lib/mysql |
./data/mysql:/var/lib/mysql |
MongoDB | /data/db |
./data/mongo:/data/db |
Redis | /data |
./data/redis:/data |
Elasticsearch | /usr/share/elasticsearch/data |
./data/es:/usr/share/elasticsearch/data |
🐳 多数据库服务 Compose 配置(带本地挂载 + 注释)
yaml
version: '3.9'
services:
# -------------------------------
# PostgreSQL 数据库
# -------------------------------
postgres:
image: postgres:14
container_name: postgres_db
restart: always
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: appdb
volumes:
- ./data/postgres:/var/lib/postgresql/data
ports:
- "5432:5432"
networks:
- backend
# -------------------------------
# MySQL 数据库
# -------------------------------
mysql:
image: mysql:8
container_name: mysql_db
restart: always
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: appdb
MYSQL_USER: user
MYSQL_PASSWORD: password
volumes:
- ./data/mysql:/var/lib/mysql
ports:
- "3306:3306"
networks:
- backend
# -------------------------------
# MongoDB 数据库
# -------------------------------
mongo:
image: mongo:5
container_name: mongo_db
restart: always
volumes:
- ./data/mongo:/data/db
ports:
- "27017:27017"
networks:
- backend
# -------------------------------
# 网络配置
# -------------------------------
networks:
backend:
❓ 常见问题解答(FAQ)
📚 FAQ:初次使用 Docker 启动镜像失败,如何通过配置镜像加速解决?
🔍 问题表现:
• docker pull 卡住很久
• 报错 TLS handshake timeout / connection refused
• docker run 无法正常启动容器 ✅ 原因分析:
Docker 默认从国外 Docker Hub 拉取镜像,国内网络不稳定或被墙,导致拉取失败
✅ 解决方案:配置国内镜像源 在 ~/.docker/daemon.json 中添加:
json
{
"builder": {
"gc": {
"defaultKeepStorage": "20GB",
"enabled": true
}
},
"experimental": false,
"registry-mirrors": [
"https://registry.docker-cn.com",
"https://mirror.baidubce.com",
"https://hub-mirror.c.163.com"
]
}
然后重启 Docker Desktop,使配置生效。
✅ 推荐国内镜像源列表
镜像源 | 地址 |
---|---|
Docker 中国官方 | registry.docker-cn.com |
百度云加速 | mirror.baidubce.com |
网易云加速 | hub-mirror.c.163.com |
阿里云加速(登录后获取) | cr.console.aliyun.com/cn-hangzhou... |
📚 FAQ:使用 .env 后 Docker Compose 启动失败的常见原因与解决方案
❓Q1:为什么不用 .env 的时候服务可以正常运行,一用就出错?
原因 | 说明 | 解决方案 |
---|---|---|
✅ 变量未成功加载 | .env 文件未传入或位置不对 | 使用 --env-file .env 显式指定 |
⚠️ 变量名拼写错误 | Compose 中写了 ${WEB_PATH},但 .env 里没定义或拼错 | 对齐变量名,一字不差 |
⚠️ 中文路径、空格未加引号 | .env 中的路径包含中文或空格 | .env 中加引号:WEB_PATH="/Users/project/..." |
⚠️ registry/npm 源访问失败 | 使用 npm/yarn 默认源被墙 | 配置淘宝镜像:yarn config set registry registry.npmmirror.com |
⚠️ DNS 解析失败 | 使用 Compose 创建了隔离网络,无法访问公网 | 添加 dns: 字段(如 8.8.8.8)解决域名解析问题 |
❓Q2:为啥用 .env 后需要多写这么多配置(DNS、registry 等)?
.env 提供的是"变量抽象",但实际运行的路径、网络、镜像仍然需要你手动保证正确。
所以额外配置是为了弥补:
• 网络隔离带来的 DNS 问题
• 源地址无法访问导致的安装失败
• 字符编码或路径解析错误
✅ 这些内容可以一次性写好,并复用于多个服务/项目。
❓Q3:哪些字段建议抽离为 .env 变量?
字段 | 是否推荐使用变量 | 解决方案 |
---|---|---|
container_name | ✅ 推荐 | 多服务命名统一好管理 |
volumes(本地路径) | ✅ 推荐 | 本地路径变化多,建议抽离 |
ports | ✅ 推荐 | 避免端口冲突 |
environment | ✅ 推荐 | 支持多环境切换(dev/prod) |
command | ✅ 推荐 | 如果启动命令复杂可抽离 |
📌 建议写法小结 ✅ .env 示例(记得加引号)
env
WEB_PATH="/Users/project/[项目名称]"
WEB_PORT=8813
WEB_NAME=web_portal_dev
NODE_ENV=development
✅ docker-compose.yml 示例
yaml
volumes:
- ${WEB_PATH}:/app
ports:
- "${WEB_PORT}:${WEB_PORT}"
container_name: ${WEB_NAME}
dns:
- 8.8.8.8
command: sh -c "yarn config set registry https://registry.npmmirror.com && yarn install && yarn dev"