Docker & Kubernetes 完全掌握 第5篇: Docker 网络与卷
Docker & Kubernetes Complete Guide Part 5: Docker Network and Volume
前言:容器间通信与数据管理的核心
在使用 Docker 部署应用程序时,最重要的两个主题就是网络和卷。在由多个容器组成的微服务架构中,容器间的通信是必不可少的,而且容器被删除后数据仍需保留的情况也非常常见。
本第5篇将深入介绍 Docker 的网络模型和卷系统,并一起学习可以在实际运营环境中使用的实用示例。
1. Docker 网络概述
1.1 Docker 网络的必要性
容器基本上在隔离的环境中运行。但在实际应用程序中,Web 服务器需要与数据库通信,API 网关需要与多个微服务连接。Docker 网络可以安全高效地管理这种容器间通信。
1.2 网络相关基本命令
# 查看网络列表
docker network ls
# 查看网络详细信息
docker network inspect [网络名]
# 创建网络
docker network create [网络名]
# 删除网络
docker network rm [网络名]
# 批量删除未使用的网络
docker network prune
2. Docker 网络类型
2.1 Bridge 网络(默认)
Bridge 网络是 Docker 的默认网络驱动,允许同一主机内的容器相互通信。安装 Docker 时会自动创建名为 docker0 的桥接网络。
# 使用默认 bridge 网络运行容器
docker run -d --name web1 nginx
# 查看默认 bridge 网络信息
docker network inspect bridge
特点:
- 支持同一主机上容器间的通信
- 主机与容器之间使用 NAT(网络地址转换)
- 通过端口映射(-p 选项)允许外部访问
- 默认 bridge 中无法通过容器名通信(只能通过 IP)
2.2 Host 网络
Host 网络让容器直接使用主机的网络栈。由于没有网络隔离,性能更好但需要注意安全性。
# 使用 host 网络运行容器
docker run -d --network host --name web-host nginx
# 无需端口映射即可直接通过主机的 80 端口访问
特点:
- 使用与主机相同的网络环境
- 无 NAT 开销,网络性能更好
- 无需端口映射(直接使用主机端口)
- 仅在 Linux 上完全支持(macOS、Windows 有限制)
2.3 None 网络
None 网络完全禁用容器的网络。用于完全不需要网络的批处理作业或安全性要求高的环境。
# 使用 none 网络运行容器
docker run -d --network none --name isolated alpine sleep 3600
# 检查网络接口(只有 lo)
docker exec isolated ip addr
特点:
- 无网络接口(只有 loopback)
- 完全阻断外部通信
- 最高级别的网络隔离
2.4 Overlay 网络
Overlay 网络可以实现跨多个 Docker 主机的容器间通信。在 Docker Swarm 或 Kubernetes 等集群环境中是必需的。
# 需要启用 Swarm 模式
docker swarm init
# 创建 overlay 网络
docker network create -d overlay my-overlay-network
# 在 overlay 网络中创建服务
docker service create --name web --network my-overlay-network nginx
特点:
- 支持多主机间容器通信
- 使用 VXLAN 技术的虚拟网络
- Swarm 模式下自动服务发现
- 内置负载均衡功能
3. 自定义网络
3.1 用户自定义 Bridge 网络
使用用户自定义 bridge 网络而非默认 bridge 网络有多种优势。
# 创建用户自定义网络
docker network create my-app-network
# 指定子网和网关
docker network create \
--driver bridge \
--subnet 172.20.0.0/16 \
--gateway 172.20.0.1 \
my-custom-network
# 将容器连接到网络
docker run -d --name db --network my-app-network mysql:8.0
docker run -d --name web --network my-app-network nginx
用户自定义网络的优势:
- 自动 DNS 解析:可以通过容器名进行通信
- 更好的隔离:与其他网络的容器自动隔离
- 动态连接:可以将运行中的容器连接/断开网络
- 可配置:可以自定义子网、网关、IP 范围等
3.2 通过容器名通信
# 创建用户自定义网络
docker network create app-net
# 运行 MySQL 容器
docker run -d \
--name mysql-db \
--network app-net \
-e MYSQL_ROOT_PASSWORD=secret \
mysql:8.0
# Web 应用程序可以通过 mysql-db 这个名称访问
docker run -d \
--name webapp \
--network app-net \
-e DB_HOST=mysql-db \
my-webapp:latest
4. 容器间通信
4.1 同一网络内通信
# 创建网络
docker network create backend
# 将两个容器连接到同一网络
docker run -d --name server1 --network backend alpine sleep 3600
docker run -d --name server2 --network backend alpine sleep 3600
# 从 server1 ping server2 测试
docker exec server1 ping -c 3 server2
4.2 连接到多个网络
一个容器可以连接到多个网络。这对于充当代理或网关的容器很有用。
# 创建两个网络
docker network create frontend
docker network create backend
# 数据库只连接到 backend
docker run -d --name db --network backend mysql:8.0
# Web 服务器连接到 frontend
docker run -d --name web --network frontend nginx
# API 服务器连接到两个网络
docker run -d --name api --network frontend node:18
docker network connect backend api
4.3 网络连接和断开
# 将运行中的容器连接到网络
docker network connect my-network container-name
# 从网络断开容器
docker network disconnect my-network container-name
# 以特定 IP 地址连接
docker network connect --ip 172.20.0.100 my-network container-name
5. DNS 和服务发现
5.1 内置 DNS 服务器
Docker 在用户自定义网络中提供内置 DNS 服务器(127.0.0.11)。通过它可以使用容器名或网络别名查找其他容器。
# 检查 DNS 配置
docker exec webapp cat /etc/resolv.conf
# nameserver 127.0.0.11
# options ndots:0
5.2 网络别名 (Alias)
# 设置网络别名
docker run -d \
--name mysql-primary \
--network app-net \
--network-alias db \
--network-alias database \
mysql:8.0
# 也可以通过 db 或 database 这些名称访问
docker run --rm --network app-net alpine ping -c 2 db
5.3 轮询 DNS
如果有多个具有相同网络别名的容器,Docker DNS 会以轮询方式返回 IP。
# 以相同别名运行多个 Web 服务器
docker run -d --name web1 --network app-net --network-alias webserver nginx
docker run -d --name web2 --network app-net --network-alias webserver nginx
docker run -d --name web3 --network app-net --network-alias webserver nginx
# 请求 webserver 会连接到三个容器之一
docker run --rm --network app-net alpine nslookup webserver
6. 数据持久化的重要性
6.1 容器的易失性
容器本质上是易失的(ephemeral)。当容器被删除时,存储在容器内部的所有数据也会一起消失。在处理数据库、用户上传文件、配置文件等重要数据时,这会成为严重问题。
# 在容器内创建文件
docker run -d --name temp-container alpine sh -c "echo 'important data' > /data.txt && sleep 3600"
docker exec temp-container cat /data.txt # important data
# 删除容器
docker rm -f temp-container
# 新容器中没有数据
docker run --rm alpine cat /data.txt # 错误:文件不存在
6.2 需要数据持久化的情况
- 数据库:MySQL、PostgreSQL、MongoDB 等的数据文件
- 用户上传:图片、文档等用户上传的文件
- 日志文件:应用程序日志、访问日志
- 配置文件:应用程序配置、证书
- 会话数据:缓存、会话存储
7. Docker 卷类型
7.1 Volumes(托管卷)
由 Docker 管理的卷,是最推荐的方式。卷创建在 Docker 的存储区域(/var/lib/docker/volumes/)中。
# 创建卷
docker volume create my-data
# 查看卷列表
docker volume ls
# 卷详细信息
docker volume inspect my-data
# 使用卷运行容器
docker run -d \
--name db \
-v my-data:/var/lib/mysql \
mysql:8.0
# 或使用 --mount 标志(更明确)
docker run -d \
--name db \
--mount source=my-data,target=/var/lib/mysql \
mysql:8.0
Volumes 的优势:
- 可以通过 Docker CLI 轻松管理(备份、迁移)
- 在 Linux 和 Windows 容器上都可以工作
- 可以在多个容器之间安全共享
- 通过卷驱动支持远程存储、加密
- 独立于主机的文件系统结构
7.2 Bind Mounts
将主机的特定路径挂载到容器中。在开发环境中将源代码实时反映到容器中时很有用。
# 将主机目录挂载到容器
docker run -d \
--name web \
-v /host/path:/container/path \
nginx
docker run -d \
--name web \
-v $(pwd)/html:/usr/share/nginx/html \
nginx
# 只读挂载
docker run -d \
--name web \
-v /host/path:/container/path:ro \
nginx
# 使用 --mount 标志(更明确)
docker run -d \
--name web \
--mount type=bind,source=/host/path,target=/container/path \
nginx
Bind Mounts 的特点:
- 需要指定主机的准确路径
- 直接访问主机文件系统
- 适合开发环境中源代码的实时反映
- 如果主机目录不存在会自动创建(需要注意)
7.3 tmpfs Mounts
tmpfs 将数据存储在主机的内存中。用于临时存储敏感信息或需要高性能时使用。
# 使用 tmpfs 挂载
docker run -d \
--name cache \
--tmpfs /app/cache \
my-app:latest
# 使用 --mount 标志
docker run -d \
--name secure-app \
--mount type=tmpfs,destination=/run/secrets,tmpfs-size=64m \
my-app:latest
tmpfs 的特点:
- 只存储在内存中,非常快
- 容器停止时数据自动删除
- 适合临时存储敏感数据(密码、API 密钥)
- 仅在 Linux 上支持
8. 卷创建和管理
8.1 卷创建和查看
# 创建基本卷
docker volume create app-data
# 创建带标签的卷
docker volume create \
--label project=myapp \
--label env=production \
myapp-data
# 查看所有卷
docker volume ls
# 按标签过滤
docker volume ls --filter label=project=myapp
# 查看特定卷详细信息
docker volume inspect app-data
8.2 删除卷
# 删除特定卷(仅当未使用时)
docker volume rm app-data
# 删除所有未使用的卷
docker volume prune
# 带过滤器删除
docker volume prune --filter label=env=development
8.3 卷共享
# 创建卷
docker volume create shared-data
# 多个容器使用同一卷
docker run -d --name writer -v shared-data:/data alpine sh -c "while true; do date >> /data/log.txt; sleep 5; done"
docker run -d --name reader -v shared-data:/data:ro alpine tail -f /data/log.txt
9. 卷驱动
9.1 本地驱动选项
# 创建 NFS 卷
docker volume create \
--driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,rw \
--opt device=:/path/to/share \
nfs-volume
# 以特定文件系统类型创建卷
docker volume create \
--driver local \
--opt type=ext4 \
--opt device=/dev/sdb1 \
ext4-volume
9.2 第三方卷驱动
可以使用各种第三方卷驱动来利用云存储或分布式文件系统。
- Amazon EBS:AWS 的 Elastic Block Store
- Azure File Storage:Microsoft Azure 的文件存储
- GlusterFS:分布式文件系统
- Portworx:企业级容器存储
- REX-Ray:支持多种存储平台
10. 数据备份和恢复
10.1 卷备份
# 使用临时容器备份卷
docker run --rm \
-v my-data:/source:ro \
-v $(pwd):/backup \
alpine tar cvf /backup/my-data-backup.tar -C /source .
# 压缩备份
docker run --rm \
-v my-data:/source:ro \
-v $(pwd):/backup \
alpine tar czvf /backup/my-data-backup.tar.gz -C /source .
10.2 卷恢复
# 创建新卷
docker volume create my-data-restored
# 从备份恢复
docker run --rm \
-v my-data-restored:/target \
-v $(pwd):/backup \
alpine tar xvf /backup/my-data-backup.tar -C /target
10.3 容器间卷复制
# 从源卷复制到目标卷
docker run --rm \
-v source-volume:/source:ro \
-v target-volume:/target \
alpine cp -av /source/. /target/
10.4 数据库备份示例
# MySQL 数据库备份
docker exec mysql-container mysqldump -u root -p'password' --all-databases > backup.sql
# PostgreSQL 数据库备份
docker exec postgres-container pg_dumpall -U postgres > backup.sql
# MongoDB 数据库备份
docker exec mongo-container mongodump --archive --gzip > backup.gz
11. 实战示例:Web 应用程序栈
11.1 利用网络和卷的完整栈
# 创建网络
docker network create webapp-network
# 创建卷
docker volume create mysql-data
docker volume create webapp-uploads
# MySQL 数据库
docker run -d \
--name mysql \
--network webapp-network \
-v mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=rootpass \
-e MYSQL_DATABASE=webapp \
-e MYSQL_USER=appuser \
-e MYSQL_PASSWORD=apppass \
mysql:8.0
# Web 应用程序
docker run -d \
--name webapp \
--network webapp-network \
-v webapp-uploads:/app/uploads \
-e DB_HOST=mysql \
-e DB_USER=appuser \
-e DB_PASSWORD=apppass \
-e DB_NAME=webapp \
-p 3000:3000 \
my-webapp:latest
# Nginx 反向代理
docker run -d \
--name nginx \
--network webapp-network \
-v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \
-p 80:80 \
nginx:alpine
11.2 使用 Docker Compose 管理
# docker-compose.yml
version: '3.8'
services:
mysql:
image: mysql:8.0
networks:
- webapp-network
volumes:
- mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: webapp
MYSQL_USER: appuser
MYSQL_PASSWORD: apppass
webapp:
image: my-webapp:latest
networks:
- webapp-network
volumes:
- webapp-uploads:/app/uploads
environment:
DB_HOST: mysql
DB_USER: appuser
DB_PASSWORD: apppass
DB_NAME: webapp
depends_on:
- mysql
nginx:
image: nginx:alpine
networks:
- webapp-network
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
ports:
- "80:80"
depends_on:
- webapp
networks:
webapp-network:
driver: bridge
volumes:
mysql-data:
webapp-uploads:
12. 网络和卷最佳实践
12.1 网络最佳实践
- 使用用户自定义网络:使用自定义网络而非默认 bridge,利用 DNS 解析和隔离优势
- 只暴露必要的端口:用 -p 选项最小化暴露给外部的端口
- 按服务分离网络:将前端、后端、数据库等分离到不同的网络
- 利用网络别名:使用别名实现灵活的服务发现
12.2 卷最佳实践
- 使用命名卷:使用命名卷而非匿名卷以便于管理
- 开发使用 bind mount,生产使用 volume:根据环境选择合适的挂载方式
- 定期备份:重要数据必须定期备份
- 只读挂载:对于配置文件等不需要更改的数据使用 :ro 选项
- 清理未使用的卷:使用 docker volume prune 定期清理
结论
Docker 网络和卷是基于容器的应用程序的核心组成部分。通过适当的网络配置可以确保容器间安全高效的通信,通过正确的卷策略可以确保数据的持久性和安全性。
本篇学习的内容总结:
- Docker 网络类型(bridge、host、none、overlay)及各自的用途
- 用户自定义网络的优势和基于 DNS 的服务发现
- 卷、bind mount、tmpfs 的区别和适当的使用场景
- 数据备份和恢复策略
下一篇第6篇将介绍 Kubernetes 基础。我们将了解为什么需要 Kubernetes、它的架构是如何构成的、核心对象是什么。