一、Docker 是什么?
Docker 是一个开源的容器化平台,让你可以把应用及其依赖打包到一个轻量、可移植的容器中,然后发布到任何 Linux / Windows / macOS 机器上。
🐚 容器 vs 虚拟机
| 特性 | 容器 (Container) | 虚拟机 (VM) |
|---|---|---|
| 启动速度 | 毫秒 ~ 秒级 | 分钟级 |
| 资源开销 | 低(共享宿主机内核) | 高(每个 VM 独占 OS) |
| 镜像大小 | MB ~ GB | GB ~ TB |
| 隔离级别 | 进程级隔离 | 硬件级虚拟化 |
| 移植性 | 极高(一次构建,到处运行) | 一般 |
二、安装与验证
🖥️ 各平台安装方式
| 平台 | 推荐方式 |
|---|---|
| Windows | Docker Desktop for Windows(需 WSL2) |
| macOS | Docker Desktop for Mac |
| Linux (Ubuntu) | curl -fsSL https://get.docker.com | bash |
| Linux (CentOS / RHEL) | sudo yum install -y yum-utils && sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo && sudo yum install docker-ce docker-ce-cli containerd.io |
✅ 验证安装
# 查看版本docker --version
docker compose version
# 运行 Hello World
docker run hello-world
sudo usermod -aG docker $USER 然后重新登录。
三、核心概念
Docker 生态有三大核心对象,理解它们等于掌握 Docker 的 80%:
| 概念 | 类比 | 说明 |
|---|---|---|
| 镜像 (Image) | 📀 安装光盘 / 类 | 只读模板,包含运行应用所需的一切(代码、运行时、库、环境变量、配置文件)。 |
| 容器 (Container) | 🏃 运行的进程 / 实例 | 镜像的运行态实例。可以启动、停止、删除。每个容器是隔离的。 |
| 仓库 (Repository / Registry) | 📦 应用商店 | 存放镜像的地方。公共的 Docker Hub,也可以自建私有仓库。 |
从 仓库 拉取 镜像 → 用镜像创建 容器 → 容器运行应用。修改后可以
docker commit 生成新镜像,推回仓库。
四、镜像管理
📥 拉取镜像
# 从 Docker Hub 拉取
docker pull nginx:latest
# pull 子命令,从仓库拉取镜像
# nginx:latest 镜像名:标签(不指定标签默认 :latest)
docker pull ubuntu:22.04
docker pull python:3.12-slim
# 从私有仓库拉取
docker pull registry.example.com/myapp:v1.0
# pull 子命令,从仓库拉取镜像
# registry.example.com/myapp:v1.0 完整镜像地址:仓库地址/镜像名:标签
📋 查看镜像
docker images
docker image ls
# 简洁模式(只显示镜像 ID)
docker images -q
# -q 只显示镜像 ID(静默模式),可配合 xargs 批量操作
# 按名称过滤
docker images | grep nginx
🏷️ 打标签
docker tag nginx:latest my-nginx:v1
docker tag nginx:latest my-nginx:v1.0.0
🗑️ 删除镜像
# 按名称:标签删除
docker rmi my-nginx:v1
# rmi 子命令,删除镜像(remove image)
# my-nginx:v1 镜像名:标签
# 按 ID 删除
docker rmi abc123def456
# rmi 子命令,删除镜像(remove image)
# abc123def456 镜像 ID(docker images 可以看到短 ID 或完整 ID)
# 强制删除(即使有依赖的容器)
docker rmi -f my-nginx:v1
# -f 强制删除
# 删除所有未使用的镜像(悬空镜像)
docker image prune
# prune 清理无标签的悬空镜像(dangling images)
# 删除所有未被容器使用的镜像(慎用)
docker image prune -a
📸 从容器生成新镜像(docker commit)
# 将容器的当前状态保存为新镜像
docker commit my-nginx my-nginx:custom-v1
# commit 子命令,将容器当前状态保存为新镜像
# my-nginx 容器名称或 ID
# my-nginx:custom-v1 新镜像名:标签
# 添加变更说明
docker commit -m "修改了 nginx.conf" my-nginx my-nginx:v2
# -m -m 提交消息(message),描述做了什么修改
# "修改了 nginx.conf" 提交消息内容
# my-nginx 容器名称或 ID
# my-nginx:v2 新镜像名:标签
📤 导入 / 导出镜像
# 导出镜像为 tar 文件
docker save -o nginx.tar nginx:latest
# save 子命令,保存镜像为 tar 归档
# -o nginx.tar -o 指定输出文件名
# nginx:latest 要导出的镜像名:标签
# 从 tar 文件导入镜像
docker load -i nginx.tar
# load 子命令,加载 tar 归档为镜像
# -i nginx.tar -i 从文件导入(input)
🔧 附:镜像加速器配置
在国内拉取 Docker Hub 镜像通常很慢,建议配置镜像加速器(Registry Mirror)。Docker 支持通过 daemon.json 配置多个加速器地址。
📝 配置方法
编辑(或创建)Docker 配置文件 /etc/docker/daemon.json(Linux / macOS)
或 C:\ProgramData\docker\config\daemon.json(Windows 管理员身份):
/etc/docker/daemon.json
{
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://dockerproxy.com",
"https://docker.nju.edu.cn",
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
• 以上列表是 国内常用公共加速器,可用性随时间变化,请自行测试
• 阿里云加速器:需注册阿里云账号后获取
https://<你的ID>.mirror.aliyuncs.com• 推荐:配置 2~3 个即可,Docker 会按优先级依次尝试
# 重启 Docker 使配置生效
# Linux (systemd)
sudo systemctl daemon-reload && sudo systemctl restart docker
# macOS (Docker Desktop → Settings → Docker Engine → 粘贴 → Apply & Restart)
# Windows
# Docker Desktop → Settings → Docker Engine → 粘贴 daemon.json → Apply & Restart
# 验证是否生效
docker info | findstr -i "Registry Mirrors"
# 输出应显示你配置的镜像地址
🔒 私有仓库(Insecure Registry)
如果自建了 HTTP 协议的私有仓库(非 HTTPS),Docker 默认拒绝连接,需要添加到不安全仓库白名单:
/etc/docker/daemon.json
{
"insecure-registries": [
"192.168.1.100:5000",
"registry.internal.example.com:80"
]
}
# 然后
sudo systemctl restart docker
# 测试
docker pull 192.168.1.100:5000/myapp:v1
🔐 HTTPS 自签证书仓库
如果自建了 HTTPS 协议的私有仓库,但使用了自签证书(非公开 CA 签发),
Docker 默认会因证书不受信任而拒绝连接。此时不要把仓库加到 insecure-registries(那样会降级为 HTTP,不安全),
正确做法是让 Docker 信任该证书:
# 将自签 CA 证书放到 Docker 的仓库证书目录
# 目录命名规则:/etc/docker/certs.d/<仓库地址>:<端口>/
sudo mkdir -p /etc/docker/certs.d/registry.example.com:5000
# 将你的 CA 证书(ca.crt)复制到该目录
sudo cp /path/to/your-ca.crt /etc/docker/certs.d/registry.example.com:5000/ca.crt
# 无需重启 Docker,立即生效
# 测试拉取
docker pull registry.example.com:5000/myapp:v1
# Windows 路径(Docker Desktop)
C:\Users\<你的用户名>\.docker\certs.d\registry.example.com:5000\ca.crt
•
insecure-registries → 跳过 HTTPS,明文传输,仅用于 HTTP 仓库•
certs.d/ 目录 → 保留 HTTPS 加密传输,只是额外信任你的自签证书• 推荐:能用证书信任就不要用 insecure_registries
五、容器管理
🚀 创建并运行容器
-p <宿主机端口>:<容器端口>👉 冒号左边 = 宿主机(你电脑)上要使用的端口
👉 冒号右边 = 容器内部服务监听的端口
一句话记住:「左边宿主机端口,右边容器端口」
例如
-p 8080:80 表示:→ 访问你电脑的
http://localhost:8080→ 流量会转发到容器内部的
80 端口(Nginx 默认监听端口)多端口映射:多个
-p 或用逗号分隔 -p 8080:80 -p 443:443 或 -p "8080:80,443:443"
# 基本运行
docker run nginx
# 后台运行(-d, detached)
docker run -d nginx
# 指定名称(--name)
docker run -d --name my-nginx nginx
# 端口映射 -p 宿主机端口:容器端口
docker run -d -p 8080:80 nginx
# -d 后台运行(detached),容器在后台默默跑
# -p 8080:80 端口映射 格式:宿主机端口:容器端口
# nginx 使用的镜像名
# 挂载卷(-v 宿主机目录:容器目录)
docker run -d -p 8080:80 -v /my/data:/usr/share/nginx/html nginx
# -v /my/data:/usr/share/nginx/html -v 挂载卷 格式:宿主机目录:容器目录
# 设置环境变量(-e)
docker run -d -e MYSQL_ROOT_PASSWORD=root123 mysql:8.0
# -e MYSQL_ROOT_PASSWORD=root123 -e 设置环境变量 格式:KEY=VALUE
# 自动删除(--rm,适合测试)
docker run --rm -it ubuntu:22.04 bash
# --rm 退出后自动删除容器
# -i 保持输入流开放
# -t 分配伪终端
# ubuntu:22.04 使用的镜像
# bash 容器内要执行的命令
# 交互式终端(-it)
docker run -it python:3.12-slim python
# -i 交互输入
# -t 伪终端
# python:3.12-slim 使用的镜像
# python 要执行的命令
📊 查看容器
# 查看运行中的容器
docker ps
# 查看所有容器(包括已停止的)
docker ps -a
# -a 显示所有容器(all),默认只显示运行中的
# 查看最新创建的 N 个容器
docker ps -n 5
# -n N 显示最近 N 个创建的容器
# 仅显示容器 ID
docker ps -q
# -q 只显示容器 ID(静默模式),可配合 $(...) 批量操作
⏯️ 启停容器
# 启动已停止的容器
docker start my-nginx
# my-nginx 容器名称或 ID
# 停止容器
docker stop my-nginx
# my-nginx 容器名称或 ID
# 重启容器
docker restart my-nginx
# my-nginx 容器名称或 ID
# 强制停止(发送 SIGKILL)
docker kill my-nginx
# my-nginx 容器名称或 ID
🔍 进入容器
# 在运行中的容器里执行命令
docker exec -it my-nginx bash
# -i 保持输入流开放(可以交互地输入命令)
# -t 分配伪终端(显示 shell 提示符,支持颜色)
# my-nginx 容器名称或 ID
# bash 容器内要执行的命令
# 组合 -it = 交互式终端,进入后可以像 SSH 一样操作容器
# 执行单条命令(不需要 -it)
docker exec my-nginx ls -la /etc/nginx
# 以 root 用户进入
docker exec -u root -it my-nginx bash
# -u 指定用户(默认是容器 entrypoint 的用户)
📋 容器日志
# 查看日志
docker logs my-nginx
# 实时追踪(类似 tail -f)
docker logs -f my-nginx
# -f 实时追踪输出(follow),Ctrl+C 退出
# my-nginx 容器名称或 ID
# 显示时间戳
docker logs -t my-nginx
# -t 为每条日志添加时间戳
# 只显示最后 N 行
docker logs --tail 50 my-nginx
# --tail 50 只显示最近 50 行日志
# my-nginx 容器名称或 ID
🗑️ 删除容器
# 删除已停止的容器
docker rm my-nginx
# 强制删除运行中的容器
docker rm -f my-nginx
# -f 强制删除(即使容器正在运行)
# my-nginx 容器名称或 ID
# 删除所有停止的容器
docker container prune
# prune 清理所有已停止的容器
# 删除所有容器(慎用!)
docker rm -f $(docker ps -aq)
# $(docker ps -aq) shell 命令替换,将子命令输出作为参数
# docker ps -aq 列出所有容器 ID
# 清理所有停止的容器 + 未使用的网络/镜像/构建缓存
docker system prune -a
# prune 系统级清理子命令
# -a 清理所有未使用的资源(不只是悬空镜像)
📦 容器与宿主机文件互拷
# 从宿主机拷贝到容器
docker cp ./app.conf my-nginx:/etc/nginx/conf.d/
# ./app.conf 宿主机源文件路径
# my-nginx: 容器名称("容器名:" 代表往容器内)
# /etc/nginx/conf.d/ 容器内目标路径
# 从容器的拷贝到宿主机
docker cp my-nginx:/var/log/nginx/access.log ./
# my-nginx: 容器名称("容器名:" 代表从容器的)
# /var/log/nginx/access.log 容器内文件路径
# ./ 宿主机目标路径
📊 查看容器资源占用
# 实时资源监控
docker stats
# [容器名] 可指定容器(不指定则显示所有运行中容器)
# 查看容器内进程
docker top my-nginx
# my-nginx 容器名称或 ID
# 查看容器详细信息(JSON)
docker inspect my-nginx
# my-nginx 容器名称或 ID
# 查看端口映射
docker port my-nginx
# my-nginx 容器名称或 ID
🔗 连接到容器主进程
# 连接到容器的主进程(如 nginx、bash)
docker attach my-nginx
# my-nginx 容器名称或 ID
# 退出时不影响容器继续运行
# Ctrl+P 然后 Ctrl+Q(detach 快捷键)
🔄 容器暂停 / 恢复
# 暂停容器内所有进程(SIGSTOP)
docker pause my-nginx
# my-nginx 容器名称或 ID
# 恢复容器内进程
docker unpause my-nginx
# my-nginx 容器名称或 ID
🔍 查看容器文件变更
# 对比容器文件系统与镜像的差异
docker diff my-nginx
# my-nginx 容器名称或 ID
# 输出示例:
# C /etc/nginx/nginx.conf (修改)
# A /usr/share/nginx/html (新增)
# D /etc/nginx/conf.d/default.conf(删除)
📤 导出容器文件系统
# 将容器文件系统导出为 tar 包(不含元数据/层历史)
docker export my-nginx -o my-nginx.tar
# my-nginx 容器名称或 ID
# -o my-nginx.tar -o 输出文件名
# 从 tar 包导入为镜像
docker import my-nginx.tar my-nginx:snapshot-v1
# my-nginx.tar tar 包路径
# my-nginx:snapshot-v1 镜像名称:标签
✏️ 容器改名 / 更新资源限制
# 重命名容器
docker rename old-name new-name
# old-name 容器原名称
# new-name 新名称
# 更新容器资源限制(无需重启)
docker update --memory 512m --cpus 1 my-nginx
# --memory 512m 内存限制(m=兆字节, g=吉字节)
# --cpus 1 CPU 核心数限制
# my-nginx 容器名称或 ID
🔄 容器暂停 / 恢复
# 暂停容器内所有进程(SIGSTOP)
docker pause my-nginx
# 恢复容器内进程
docker unpause my-nginx
🔍 查看容器文件变更
# 对比容器文件系统与镜像的差异
docker diff my-nginx
# 输出示例:
# C /etc/nginx/nginx.conf (修改)
# A /usr/share/nginx/html (新增)
# D /etc/nginx/conf.d/default.conf(删除)
📤 导出容器文件系统
# 将容器文件系统导出为 tar 包(不含元数据/层历史)
docker export my-nginx -o my-nginx.tar
# 从 tar 包导入为镜像
docker import my-nginx.tar my-nginx:snapshot-v1
✏️ 容器改名 / 更新资源限制
# 重命名容器
docker rename old-name new-name
# 更新容器资源限制(无需重启)
docker update --memory 512m --cpus 1 my-nginx
六、网络与存储
🌐 网络模式
| 网络模式 | 说明 | 使用场景 |
|---|---|---|
bridge(默认) | 容器通过虚拟网桥通信,与宿主机隔离 | 单机多容器互联 |
host | 容器直接使用宿主机网络栈(无隔离) | 追求性能的场景 |
none | 容器无网络 | 安全隔离或自定义网络 |
overlay | 跨宿主机容器通信(Swarm 模式) | 集群部署 |
# 创建自定义网络(推荐,可容器名互联)
docker network create my-net
# 容器加入自定义网络
docker run -d --name web --network my-net nginx
# 查看网络
docker network ls
# 查看网络详情
docker network inspect my-net
# 将已有容器连接到网络
docker network connect my-net my-nginx
# 断开网络
docker network disconnect my-net my-nginx
例如:
web 容器可以通过 http://db:3306 访问 db 容器。
💾 数据持久化:Volumes & Bind Mounts
所有
-v / --volume 参数的格式统一为:-v <宿主机路径或卷名>:<容器内路径>👉 冒号左边 = 宿主机(你的电脑)上的目录/卷名
👉 冒号右边 = 容器内部的目录
一句话记住:「左边宿主机,右边容器内」
| 方式 | 说明 | 命令示例 | 左边是什么 | 右边是什么 |
|---|---|---|---|---|
| Volume (卷,推荐) |
由 Docker 管理,存在宿主机特定目录 | -v mydata:/data |
mydata ← 卷名(Docker 自动管理路径) |
/data ← 容器内的目录 |
| Bind Mount (绑定挂载) |
挂载宿主机任意目录到容器 | -v /宿主机/路径:/容器/路径 |
/宿主机/路径 ← 你电脑上的绝对路径 |
/容器/路径 ← 容器内的目录 |
| tmpfs Mount | 数据存在内存中,容器停止即消失 | --tmpfs /tmp |
无(仅容器内路径) | /tmp ← 容器内的内存目录 |
•
-v /data:/app/data ❌ —— 左边 /data 是宿主机根目录下的 data,不是卷名!•
-v mydata:/app/data ✅ —— 左边 mydata 没有前导斜杠,Docker 会把它当作卷名• 区分方法:左边以
/ 开头 → Bind Mount(宿主机路径);无 / 开头 → Volume(卷名)
# 卷 (Volume) —— 左边是卷名,右边是容器内路径
docker volume create mydata
docker run -d -v mydata:/var/lib/mysql mysql:8.0
# ↑ 卷名 ↑ 容器内目录
# 绑定挂载 (Bind Mount) —— 左边是宿主机路径,右边是容器内路径
docker run -d -p 8080:80 -v $(pwd)/html:/usr/share/nginx/html nginx
# ↑ 宿主机当前目录/html ↑ 容器内 Nginx 静态文件目录
# 绑定挂载用绝对路径(Windows 需写完整路径)
docker run -d -v C:\项目\html:/usr/share/nginx/html nginx
七、Dockerfile 编写
Dockerfile 是构建镜像的「配方文件」。下面从一个 Node.js 应用示例入手:
📄 示例 Dockerfile
# 1. 基础镜像
FROM node:20-alpine
# 2. 设置工作目录
WORKDIR /app
# 3. 复制依赖描述文件(利用缓存层)
COPY package.json package-lock.json ./
# 4. 安装依赖
RUN npm ci --only=production
# 5. 复制源码
COPY . .
# 6. 暴露端口
EXPOSE 3000
# 7. 启动命令
CMD ["node", "src/index.js"]
🔑 Dockerfile 常用指令
| 指令 | 说明 | 示例 |
|---|---|---|
FROM | 指定基础镜像(必须第一行) | FROM python:3.12-slim |
WORKDIR | 设置工作目录(自动创建) | WORKDIR /app |
COPY | 复制文件到镜像 | COPY . . |
ADD | 类似 COPY,支持 URL / 自动解压 tar | ADD app.tar.gz /app |
RUN | 构建时执行命令(产生新层) | RUN apt update && apt install -y curl |
ENV | 设置环境变量 | ENV NODE_ENV=production |
EXPOSE | 声明容器监听端口(文档性质) | EXPOSE 8080 |
CMD | 容器启动默认命令(可被覆盖) | CMD ["python", "app.py"] |
ENTRYPOINT | 容器启动入口(不易覆盖) | ENTRYPOINT ["docker-entrypoint.sh"] |
ARG | 构建参数(构建时变量) | ARG VERSION=1.0 |
USER | 切换到非 root 用户运行 | USER node |
HEALTHCHECK | 健康检查 | HEALTHCHECK CMD curl -f http://localhost || exit 1 |
🔨 构建镜像
# 基本构建
docker build -t myapp:v1 .
# -t myapp:v1 -t 指定镜像名称:标签
# . 构建上下文路径(包含 Dockerfile 的目录)
# 指定 Dockerfile 文件名
docker build -f Dockerfile.prod -t myapp:prod .
# -f Dockerfile.prod -f 指定 Dockerfile 文件名(默认是 Dockerfile)
# -t myapp:prod -t 镜像名称:标签
# . 构建上下文
# 传递构建参数
docker build --build-arg VERSION=2.0 -t myapp:v2 .
# --build-arg VERSION=2.0 --build-arg 传递构建时变量(ARG 指令使用)
# -t myapp:v2 -t 镜像名称:标签
# . 构建上下文
# 多阶段构建(减小镜像体积)
docker build -t myapp:latest .
✨ 多阶段构建示例
# 第1阶段 —— 构建
FROM golang:1.22-alpine AS builder
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o app .
# 第2阶段 —— 运行(极小的镜像)
FROM alpine:3.19
WORKDIR /app
COPY --from=builder /build/app .
EXPOSE 8080
CMD ["./app"]
• 尽量使用官方基础镜像(如
alpine 版本更小)• 把「不常变」的层放前面(COPY package.json 在 COPY . 之前),最大化缓存利用
• 使用多阶段构建减小最终镜像体积
• 不要以 root 运行应用(用
USER 指令切换)
八、Docker Compose 详解
📖 什么是 Docker Compose?
Docker Compose 是一个用于定义和运行多容器 Docker 应用的工具。通过一个 compose.yaml(或 docker-compose.yml)文件,你可以用一条命令启动、停止、管理整个应用栈(例如:前端 + 后端 + 数据库 + Redis + 消息队列)。
现在的命令是
docker compose(中间没有横杠),不再是 docker-compose。
📄 compose.yaml 基本结构
version: "3.9" # ⚠️ 目前可省略(Docker 会自动推断)
services: # 定义各个服务(容器)
web:
build: . # 从 Dockerfile 构建
ports:
- "8080:80"
depends_on:
- db
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root123
volumes:
- db_data:/var/lib/mysql
volumes: # 声明命名卷
db_data:
networks: # 声明网络(可选)
mynet:
🔧 Compose 文件核心配置项
| 配置项 | 说明 | 示例 |
|---|---|---|
services.<name>.image | 使用的镜像 | image: nginx:alpine |
services.<name>.build | 构建配置(Dockerfile 路径) | build: ./backend |
services.<name>.ports | 端口映射 格式:宿主机端口:容器端口 | ports: - "3000:3000" |
services.<name>.environment | 环境变量 | environment: NODE_ENV=production |
services.<name>.env_file | 从文件加载环境变量 | env_file: .env |
services.<name>.volumes | 挂载卷 / 绑定挂载 格式:宿主机路径或卷名:容器内路径 | volumes: - ./data:/data |
services.<name>.depends_on | 依赖服务(启动顺序) | depends_on: - db - redis |
services.<name>.command | 覆盖容器 CMD | command: npm run start:prod |
services.<name>.restart | 重启策略 | restart: unless-stopped |
services.<name>.networks | 指定网络 | networks: - frontend |
services.<name>.healthcheck | 健康检查 | healthcheck: test: ["CMD", "curl", "-f", "http://localhost"] |
services.<name>.container_name | 自定义容器名(不推荐 Compose 中指定) | container_name: my-app |
🚢 Compose 常用命令
# 启动所有服务(-d 后台运行)
docker compose up -d
# 构建并启动(--build 强制重新构建)
docker compose up --build -d
# 查看运行中的服务
docker compose ps
# 查看日志(-f 实时追踪)
docker compose logs -f
# 查看某个服务的日志
docker compose logs web
# 停止所有服务
docker compose stop
# 停止并删除所有服务(容器、网络)
docker compose down
# 停止并删除 + 删除卷(⚠️ 数据会丢失)
docker compose down -v
# 在运行中的服务中执行命令
docker compose exec db bash
# 重启某服务
docker compose restart web
# 暂停 / 恢复服务
docker compose pause web
docker compose unpause web
# 查看服务启动顺序和各种状态
docker compose top
# 查看 Compose 项目的配置(合并后的内容)
docker compose config
# 查看容器资源使用
docker compose stats
🔁 Compose 中 .env 文件
Compose 自动读取同目录下的 .env 文件,变量可用于 Compose 文件的 ${VAR} 占位符中:
# .env 文件
DB_PASSWORD=mys3cret
APP_PORT=4000
# compose.yaml 引用 .env 变量
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
web:
build: .
ports:
- "${APP_PORT}:3000"
九、Compose 实战示例
🌐 Web 应用 + PostgreSQL
services:
web:
build: ./app
ports:
- "3000:3000" # ← 左边:宿主机端口 右边:容器端口
environment:
DATABASE_URL: postgres://user:pass@db:5432/mydb
depends_on:
db:
condition: service_healthy
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- pg_data:/var/lib/postgresql/data # ← 左边:卷名 右边:容器内路径
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
interval: 5s
retries: 5
restart: unless-stopped
volumes:
pg_data:
📦 全栈应用(Vite + FastAPI + Redis + MySQL)
services:
frontend:
build: ./frontend
ports:
- "5173:5173" # ← 左边:宿主机端口 右边:容器端口
environment:
VITE_API_URL: http://localhost:8000
depends_on:
- backend
volumes:
- ./frontend:/app # ← 左边:宿主机源码目录 右边:容器内工作目录
- /app/node_modules # ← 仅容器内路径(匿名卷,避免覆盖 node_modules)
backend:
build: ./backend
ports:
- "8000:8000" # ← 左边:宿主机端口 右边:容器端口
environment:
DB_URL: mysql://root:root123@mysql:3306/mydb
REDIS_URL: redis://redis:6379
depends_on:
- mysql
- redis
volumes:
- ./backend:/app # ← 左边:宿主机源码目录 右边:容器内工作目录
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: mydb
volumes:
- mysql_data:/var/lib/mysql # ← 左边:卷名 右边:容器内数据目录
ports:
- "3306:3306" # ← 左边:宿主机端口 右边:容器端口
redis:
image: redis:7-alpine
volumes:
- redis_data:/data # ← 左边:卷名 右边:容器内数据目录
volumes:
mysql_data:
redis_data:
🧰 Nginx 反向代理
services:
nginx:
image: nginx:alpine
ports:
- "80:80" # ← 左边:宿主机端口 右边:容器端口
- "443:443" # ← 左边:宿主机端口 右边:容器端口
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- web1
- web2
restart: unless-stopped
web1:
build: ./app
environment:
- NODE_ENV=production
web2:
build: ./app
environment:
- NODE_ENV=production
十、日常运维技巧
🧹 清理系统
# 清理所有未使用的资源(容器、网络、悬空镜像、构建缓存)
docker system prune
# 更彻底(包括未使用的镜像和卷)
docker system prune -a --volumes
📦 推送镜像到仓库
# 登录到 Docker Hub
docker login
# 打标签(必须带用户名/仓库前缀)
docker tag myapp:v1 username/myapp:v1
# 推送
docker push username/myapp:v1
# 推送到私有仓库
docker tag myapp:v1 registry.example.com/myapp:v1
docker push registry.example.com/myapp:v1
🔒 以非 root 用户运行
# Dockerfile 中
FROM node:20-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
# 也可以在 Compose 中指定
services:
app:
image: myapp
user: "1000:1000"
🧪 开发时热重载
利用 Bind Mount 将源码挂载到容器,结合 nodemon / uvicorn --reload 实现修改即自动重启:
services:
app:
build: .
volumes:
- .:/app # 源码挂载到容器
command: npx nodemon src/index.js
📈 限制资源
# 限制内存和 CPU
docker run -d --memory="512m" --cpus="1.5" nginx
# Compose 中限制
services:
app:
image: myapp
deploy:
resources:
limits:
memory: 512M
cpus: "1.5"
🏷️ 给镜像加多标签 / 推送到多个仓库
docker tag myapp:v1 myapp:latest
docker tag myapp:v1 username/myapp:v1
docker tag myapp:v1 username/myapp:latest
docker push --all-tags username/myapp
• 不要用
latest 标签部署生产 — 用明确版本号• 始终配置
restart: unless-stopped• 设置健康检查
healthcheck• 敏感信息用
Docker Secrets 或 .env + .gitignore,不要硬编码
🔧 附:Docker 代理配置
在公司网络、学校环境或需要科学上网的场景下,Docker 需要配置代理才能正常拉取镜像、构建和运行容器。代理配置分为三个层面:
| 层面 | 作用范围 | 配置位置 |
|---|---|---|
| Docker Daemon 代理 | docker pull / push / build(守护进程发起的请求) | /etc/systemd/system/docker.service.d/ |
| 容器运行时代理 | 容器内部应用访问外网 | 环境变量 HTTP_PROXY |
| 构建时代理 | Dockerfile 中 RUN 命令下载依赖 | --build-arg 或 ARG |
1️⃣ Docker Daemon 代理(拉取镜像时)
适用于 docker pull、docker push、docker build 中容器引擎下载依赖包等场景:
# Linux (systemd) —— 创建配置目录和文件
sudo mkdir -p /etc/systemd/system/docker.service.d
# 创建代理配置文件
sudo tee /etc/systemd/system/docker.service.d/proxy.conf <<'EOF'
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:7890"
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
Environment="NO_PROXY=localhost,127.0.0.1,.local,.example.com,10.0.0.0/8"
EOF
# 重新加载并重启
sudo systemctl daemon-reload
sudo systemctl restart docker
# 验证代理是否生效
sudo systemctl show docker --property Environment
•
HTTP_PROXY 和 HTTPS_PROXY 值请替换成你自己的代理地址(http:// 协议,不是 socks5)•
NO_PROXY 配置不走代理的地址段,避免本地局域网和内部服务走代理导致连接失败• Docker Desktop(macOS / Windows)用户:Settings → Resources → Proxies 中直接填写
2️⃣ 容器运行时代理
容器内的应用程序需要通过代理访问外网时设置:
# docker run 方式
docker run -e HTTP_PROXY=http://host.docker.internal:7890 \
-e HTTPS_PROXY=http://host.docker.internal:7890 \
-e NO_PROXY=localhost,127.0.0.1 \
alpine:latest curl -s https://www.google.com
# Compose 方式
services:
app:
image: alpine
environment:
HTTP_PROXY: http://host.docker.internal:7890
HTTPS_PROXY: http://host.docker.internal:7890
NO_PROXY: localhost,127.0.0.1
• macOS / Windows(Docker Desktop):
host.docker.internal 自动解析为宿主机地址,可直接用• Linux:默认没有
host.docker.internal,需要用 --add-host host.docker.internal:host-gateway 或在 Compose 中添加 extra_hosts• 或者 Linux 下直接填宿主机内网 IP(如
http://192.168.1.100:7890)
# Linux 下 Compose 添加 host.docker.internal
services:
app:
image: alpine
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
HTTP_PROXY: http://host.docker.internal:7890
3️⃣ 构建时代理(Dockerfile build)
当 Dockerfile 中 RUN 命令需要下载依赖包时,通过构建参数传入代理,不影响最终镜像(构建参数不持久化):
# 命令行构建时传入
docker build \
--build-arg HTTP_PROXY=http://host.docker.internal:7890 \
--build-arg HTTPS_PROXY=http://host.docker.internal:7890 \
-t myapp .
# Dockerfile 中声明 ARG(推荐放在基础镜像之后)
FROM node:20-alpine
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY
# RUN 命令会自动读取这些环境变量
RUN npm install
# 如果用国内 npm 源,也可以配置镜像源
RUN npm config set registry https://registry.npmmirror.com
• 不想每次手动输入
--build-arg,可以在 Shell 中提前 export BUILDKIT_PROGRESS=plain• 或者用 Docker Compose 的
args 字段固化构建参数:services:
app:
build:
context: .
args:
HTTP_PROXY: "http://proxy.example.com:7890"
HTTPS_PROXY: "http://proxy.example.com:7890"
4️⃣ 全局配置(Docker Desktop GUI)
macOS / Windows 用户可以直接在 Docker Desktop 界面配置,不涉及命令行编辑:
Docker Desktop →
Settings (⚙️) →
Resources →
Proxies →
Manual proxy configuration →
HTTP: http://127.0.0.1:7890
HTTPS: http://127.0.0.1:7890
No Proxy: localhost,127.0.0.1,.local,.example.com
→ Apply & Restart
十一、命令速查表
🖼️ 镜像命令
| 命令 | 作用 |
|---|---|
docker pull <镜像> | 拉取镜像 |
docker images | 查看镜像列表 |
docker rmi <镜像> | 删除镜像 |
docker tag <镜像> <新标签> | 打标签 |
docker build -t <名> . | 构建镜像 |
docker save -o file.tar <镜像> | 导出镜像为 tar |
docker load -i file.tar | 从 tar 导入镜像 |
docker push <镜像> | 推送镜像到仓库 |
docker image prune | 清理悬空镜像 |
📦 容器命令
| 命令 | 作用 |
|---|---|
docker run [选项] <镜像> | 创建并启动容器 |
docker ps | 查看运行中容器 |
docker ps -a | 查看所有容器 |
docker start <容器> | 启动容器 |
docker stop <容器> | 停止容器 |
docker restart <容器> | 重启容器 |
docker kill <容器> | 强制杀死容器 |
docker rm <容器> | 删除容器(需停止) |
docker rm -f <容器> | 强制删除容器 |
docker exec -it <容器> bash | 进入容器 |
docker logs [-f] <容器> | 查看日志 |
docker cp <src> <容器>:<dst> | 文件拷贝 |
docker stats | 资源监控 |
docker inspect <容器> | 查看容器详情 |
docker container prune | 清理所有停止容器 |
🌐 网络命令
| 命令 | 作用 |
|---|---|
docker network ls | 查看网络列表 |
docker network create <名> | 创建网络 |
docker network rm <名> | 删除网络 |
docker network connect <网络> <容器> | 连接容器到网络 |
docker network disconnect <网络> <容器> | 断开容器网络 |
💾 卷命令
| 命令 | 作用 |
|---|---|
docker volume ls | 查看卷列表 |
docker volume create <名> | 创建卷 |
docker volume rm <名> | 删除卷 |
docker volume prune | 清理未使用卷 |
🚢 Compose 命令
| 命令 | 作用 |
|---|---|
docker compose up -d | 启动所有服务 |
docker compose down | 停止并删除服务 |
docker compose ps | 查看服务状态 |
docker compose logs -f | 查看日志 |
docker compose exec <服务> bash | 进入服务容器 |
docker compose restart <服务> | 重启服务 |
docker compose stop | 停止服务 |
docker compose start | 启动已停止的服务 |
docker compose pull | 拉取所有服务的镜像 |
docker compose build | 构建所有服务的镜像 |
docker compose config | 验证并查看配置 |
docker compose top | 查看各服务进程 |
docker compose stats | 查看资源占用 |
docker compose down -v | 删除服务 + 卷(数据全清) |
🧹 系统级
| 命令 | 作用 |
|---|---|
docker system df | 查看磁盘使用情况 |
docker system prune | 清理未使用的资源 |
docker system prune -a --volumes | 深度清理所有无用资源 |
docker info | 查看 Docker 系统信息 |
docker version | 查看版本 |