2026.09.25 · 网络与容器架构 · 约 8 分钟 · 1926 字
更新于 2026-09-27
Docker 容器化基础:镜像分层原理、多阶段构建、Bridge 网络与数据卷 解析 Docker OverlayFS 分层存储与 Namespace/Cgroups 隔离机制,编写多阶段构建 Dockerfile,并配置自定义 Bridge 网络与只读数据卷。
在生产服务器上直接用宿主机包管理器安装各类运行时,时间一长容易遇到依赖库版本冲突与残留配置文件难以清理的问题。通过 Docker 将服务封装为标准镜像,并配合只读数据卷挂载,可以让线上环境保持干净且易于迁移。
本文梳理 OverlayFS 镜像分层结构、多阶段 Dockerfile 编写方法、自定义 Bridge 网络通信,以及 Bind Mount 与 Named Volume 的适用场景。
容器与虚拟机的区别:三项 Linux 内核机制
Docker 容器内部不包含独立的 Linux 内核,容器进程直接运行在宿主机内核之上,其隔离与分层能力来自三项内核机制:
Docker 容器运行架构:利用多阶段构建剥离 Node.js 编译环境,通过 Namespace 与 Cgroups v2 限制资源,并以 :ro 只读方式挂载宿主机静态产物。
Namespace(命名空间 —— 隔离视图) :
PID Namespace:容器内的主进程看到自己的 PID 为 1,无法看到宿主机上的其他进程。
NET Namespace:为容器分配独立的虚拟网卡(eth0)、IP 地址、路由表与端口空间。
MNT Namespace:为容器提供独立的根目录 / 挂载视图。
Cgroups v2(控制组 —— 限制资源配额) :
限制单个容器可使用的最大内存(如 --memory=256m)和 CPU 份额(如 --cpus=0.5)。当某个容器进程出现内存泄漏时,仅触发该容器内部的 OOM 重启,不会耗尽整台宿主机的内存。
OverlayFS(联合挂载文件系统 —— 共享只读镜像层) :
Docker 镜像由多层只读层(LowerDir)叠加而成。如果在同一台机器上运行 5 个基于 nginx:1.27-alpine 的容器,磁盘只保存一份约 18MB 的基础镜像层,每个容器仅在顶层挂载一个独立的可写层(UpperDir)。
安装 Docker Engine 与守护进程日志限制
在 Ubuntu 24.04 / Debian 12 服务器上,建议使用 Docker 官方 APT 软件源安装 Docker Engine 与 docker compose 插件,并在启动前配置日志大小上限:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 # 1. 安装基础证书工具并导入 Docker 官方 GPG 密钥 sudo apt-get update sudo apt-get install -y ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc # 2. 写入 Docker 官方 APT 软件源并安装 Docker Engine 与 Compose 插件 echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] 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 -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # 3. 写入 /etc/docker/daemon.json(限制容器标准输出日志体积,启用 live-restore) sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json >/dev/null <<'EOF' { "log-driver": "json-file", "log-opts": { "max-size": "20m", "max-file": "5" }, "live-restore": true } EOF sudo systemctl enable --now docker sudo systemctl restart docker
配置说明 :
log-opts 限制单个容器的 JSON 标准输出日志最多占用 20MB × 5 = 100MB,防止长时间运行后 /var/lib/docker/containers/ 占满磁盘。
live-restore: true 允许在升级或重启 dockerd 守护进程期间,保持正在运行的容器不中断。
编写多阶段 Dockerfile(Multi-Stage Build)
将 Astro、Next.js 或 VitePress 等静态站点打包为容器镜像时,不需要把几百兆的 node_modules 和源码带入最终运行镜像。
使用多阶段构建(Multi-Stage Build),可以在第一阶段用 node:22-alpine 编译静态网页,第二阶段仅用 nginx:1.27-alpine 托管编译产物:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 # ========================================== # 阶段 1:Builder 静态编译阶段(构建完成后丢弃) # ========================================== FROM node:22-alpine AS builder WORKDIR /app # 先单独拷贝依赖锁文件,利用 Docker 缓存层加速后续构建 COPY package.json package-lock.json ./ RUN npm ci # 拷贝源码与文章并执行生产构建 COPY . . RUN npm run build # ========================================== # 阶段 2:Production 运行阶段(不含 Node.js 与源码) # ========================================== FROM nginx:1.27-alpine AS production # 拷贝自定义 Nginx 站点配置 COPY deploy/nginx/blog.conf /etc/nginx/conf.d/default.conf # 仅从 builder 阶段复制编译生成的 public/ 目录 COPY --from=builder /app/public /usr/share/nginx/html # 声明监听端口与健康检查 EXPOSE 80 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD wget -qO- http://127.0.0.1:80/ >/dev/null || exit 1
这样构建出的运行镜像体积不到 25MB,且镜像内不包含构建工具链与源代码。
Docker 网络模型与数据持久化(Bind Mount vs. Volume)
1. 自定义 Bridge 网络与容器名解析
Docker 默认的 bridge(docker0 网桥)不支持通过容器名称进行 DNS 解析,容器之间只能按内网 IP 通信。创建自定义网桥(User-Defined Bridge)后,Docker 会为该网桥提供内嵌 DNS 解析(127.0.0.11):
1 2 3 4 # 创建名为 web-net 的自定义桥接网络 docker network create web-net # 接入同一自定义网络的容器,在 Nginx 配置中可直接按容器名转发:proxy_pass http://umami:3000;
2. 端口映射与宿主机防火墙的关系
执行 docker run -p 8080:80 ... 时,Docker 会在内核 iptables 的 PREROUTING / DOCKER 链中直接添加转发规则,其匹配位置在宿主机 ufw 防火墙规则之前。因此,即使 ufw 未放行 8080 端口,外网依然可以直接访问 http://<服务器IP>:8080。
对于仅需由宿主机或前置 Nginx 反向代理访问的内部容器,应将监听地址显式绑定到本机回环 127.0.0.1:
1 2 # 仅允许本机回环访问 8080 端口,不向公网网卡暴露 docker run -d --name internal-app -p 127.0.0.1:8080:80 nginx:1.27-alpine
3. Bind Mount 与 Named Volume 的选择
特性维度
绑定挂载(Bind Mount)
命名数据卷(Named Volume)
挂载语法
-v /var/www/blog/current:/usr/share/nginx/html:ro
-v postgres-data:/var/lib/postgresql/data
宿主机路径
指定宿主机上的任意绝对路径
由 Docker 统一存放在 /var/lib/docker/volumes/<name>/_data
适用场景
静态网页产物目录、Nginx 配置文件(nginx.conf)、SSL 证书目录(便于宿主机脚本直接更新)
数据库存储目录(PostgreSQL / MySQL / SQLite)、Redis 数据文件(由容器自动初始化目录属主与权限)
使用 Docker Compose 编排服务栈
当服务器上同时运行静态博客网关与统计等辅助容器时,可用 /opt/blog-stack/compose.yaml 统一管理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 name: blog-production services: blog-web: image: nginx:1.27-alpine container_name: blog-nginx restart: unless-stopped read_only: true ports: - "80:80" - "443:443" tmpfs: - /var/cache/nginx:uid=101,gid=101,mode=0755 - /var/run:uid=101,gid=101,mode=0755 - /tmp:mode=1777 volumes: - /var/www/blog/current:/usr/share/nginx/html:ro - /opt/blog-stack/nginx/conf.d:/etc/nginx/conf.d:ro - /etc/nginx/ssl:/etc/nginx/ssl:ro - /var/log/nginx-blog:/var/log/nginx:rw deploy: resources: limits: cpus: "0.50" memory: 256M networks: - web-net networks: web-net: driver: bridge
日常维护常用的四条命令:
1 2 3 4 5 6 7 8 9 10 11 12 # 1. 后台启动或应用更新后的配置 docker compose -f /opt/blog-stack/compose.yaml up -d --remove-orphans # 2. 查看各容器运行状态、端口映射与实时资源占用 docker compose -f /opt/blog-stack/compose.yaml ps docker stats --no-stream # 3. 在容器内测试 Nginx 配置语法 docker exec -it blog-nginx nginx -t # 4. 清理未使用的悬空镜像与构建缓存 docker system prune -f