Docker 完整教程(3,4) | 网络与挂载

本教程侧重于命令实践和理解,提供可在本地环境测试的实例,每章结束都有总结要点。

目录

前边介绍了 Docker 基础概念和安装 以及 Docker 常用命令实践。本篇介绍 docker 容器的两个重要概念,网络机制和容器挂载。

  1. [Docker 网络机制详解](#Docker 网络机制详解)
  2. [Docker 数据卷和挂载](#Docker 数据卷和挂载)

第3章:Docker 网络机制详解

3.1 Docker 网络基础

Docker 网络是容器间通信和容器与外部世界通信的基础。理解网络机制对于构建复杂的容器化应用至关重要。

每个 Docker 容器都有自己的网络命名空间,包括:独立的网络接口,路由表,iptables 规则和端口空间。

查看网络信息

bash 复制代码
# 列出所有网络
docker network ls

# 查看网络详细信息
docker network inspect bridge

# 查看容器网络配置
docker inspect container_name | grep -A 20 "NetworkSettings"

3.2 Docker 网络驱动类型

运行 docker network ls 查看网络,比如

bash 复制代码
❯ docker network ls

NETWORK ID     NAME            DRIVER    SCOPE
fef63891b2a7   bridge          bridge    local
150f1dc61078   nginx_default   bridge    local
ce0e3369b5e1   host            host      local
050afab805f4   none            null      local

可以看到存在三种类型:bridge, host, none。

1. Bridge 网络(默认)

Bridge 是 Docker 的默认网络驱动,适用于单主机上的容器通信。

  • 作用:为容器提供独立的网络命名空间,同时允许容器间通信
  • 特点:容器获得私有 IP(通常是 172.17.x.x),通过 NAT 访问外网
  • 使用场景:大部分单机容器应用的默认选择

常用命令:

bash 复制代码
# 查看默认 bridge 网络
docker network inspect bridge

# 运行容器使用默认网络
docker run -d --name app1 nginx
docker run -d --name app2 nginx

# 查看容器 IP
docker inspect app1 | grep IPAddress
docker inspect app2 | grep IPAddress

# 容器间通信测试
docker exec app1 ping $(docker inspect app2 | grep IPAddress | head -1 | cut -d'"' -f4)

2. Host 网络

Host 网络模式下,容器直接使用主机的网络栈。

  • 特点:容器直接使用主机的网络栈,没有网络隔离
  • 性能:网络性能最好,没有 NAT 转换开销
  • 风险:安全性较低,容器可以直接访问主机网络
bash 复制代码
# 使用 host 网络运行容器
docker run -d --network host --name host-app nginx

# 查看网络配置(与主机相同)
docker exec host-app ip addr show

# 直接通过主机 IP 访问
curl http://localhost:80

3. None 网络

None 网络模式下,容器没有网络接口。

bash 复制代码
# 运行无网络容器
docker run -d --network none --name no-network alpine sleep 3600

# 查看网络接口(只有 loopback)
docker exec no-network ip addr show

4. 自定义 Bridge 网络

自定义网络提供更好的隔离性和容器间的名称解析。

bash 复制代码
# 创建自定义网络
docker network create --driver bridge my-network

# 查看网络详情
docker network inspect my-network

# 在自定义网络中运行容器
docker run -d --network my-network --name web nginx
docker run -d --network my-network --name db mysql:8.0 -e MYSQL_ROOT_PASSWORD=password

# 容器间可以通过名称通信
docker exec web ping db
docker exec db ping web

5. 自定义 Bridge 网络的 IP 段

Docker 默认使用 172.17.0.0/16 网段,如果服务器的 172.xx 网段被占用,为避免冲突,可以通过 /etc/docker/daemon.json 修改全局默认配置,举个例子:

bash 复制代码
# 编辑 /etc/docker/daemon.json
{
  "bip": "100.10.100.1/24",
  "default-address-pools":
  [
    {"base":"100.10.0.0/16","size":24}
  ]
}

配置说明:

  • bip:设置默认 bridge 网络的 IP 段
  • default-address-pools:设置自定义网络的默认 IP 池
bash 复制代码
# 重启 Docker 服务使配置生效
sudo systemctl restart docker

当然,也可以为单个容器创建指定 IP 段网络,比如

bash 复制代码
```bash
# 创建开发环境网络
docker network create \
  --subnet=10.10.0.0/24 \
  --gateway=10.10.0.1 \
  dev-network

3.3 端口映射

基本端口映射

通过 -p <host_port>:<container_port> 可以将容器端口映射到主机端口。

bash 复制代码
# 映射单个端口
docker run -d -p 8080:80 nginx

# 映射多个端口
docker run -d -p 8080:80 -p 8443:443 nginx

# 映射到指定 IP
docker run -d -p 127.0.0.1:8080:80 nginx

# 映射随机端口
docker run -d -P nginx

# 查看端口映射
docker port container_name

高级端口配置

bash 复制代码
# UDP 端口映射
docker run -d -p 53:53/udp nginx

# 端口范围映射
docker run -d -p 8000-8010:8000-8010 nginx

# 查看所有端口映射
docker ps --format "table {{.Names}}\t{{.Ports}}"

3.4 实践练习

练习1:Web 应用 + 数据库通信

bash 复制代码
# 创建自定义网络
docker network create webapp-network

# 启动数据库容器
docker run -d \
  --name database \
  --network webapp-network \
  -e MYSQL_ROOT_PASSWORD=rootpass \
  -e MYSQL_DATABASE=webapp \
  mysql:8.0

# 等待数据库启动
sleep 30

# 启动 Web 应用容器
docker run -d \
  --name webapp \
  --network webapp-network \
  -p 8080:80 \
  nginx

# 测试容器间连通性
docker exec webapp ping database

# 在 Web 容器中安装网络工具并测试数据库连接
docker exec webapp apt-get update
docker exec webapp apt-get install -y telnet
docker exec webapp telnet database 3306

# 清理
docker stop webapp database
docker rm webapp database
docker network rm webapp-network

练习2:负载均衡配置

bash 复制代码
# 创建负载均衡网络
docker network create lb-network

# 启动多个后端服务
docker run -d --name backend1 --network lb-network nginx
docker run -d --name backend2 --network lb-network nginx
docker run -d --name backend3 --network lb-network nginx

# 创建 nginx 配置文件
mkdir -p /tmp/docker-tutorial/nginx-lb
cat > /tmp/docker-tutorial/nginx-lb/nginx.conf << 'EOF'
events {
    worker_connections 1024;
}

http {
    upstream backend {
        server backend1:80;
        server backend2:80;
        server backend3:80;
    }

    server {
        listen 80;
        location / {
            proxy_pass http://backend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}
EOF

# 启动负载均衡器
docker run -d \
  --name load-balancer \
  --network lb-network \
  -p 8080:80 \
  -v /tmp/docker-tutorial/nginx-lb/nginx.conf:/etc/nginx/nginx.conf \
  nginx

# 测试负载均衡
for i in {1..6}; do
  curl -s http://localhost:8080 | grep -o "backend[0-9]" || echo "Request $i"
done

# 清理
docker stop load-balancer backend1 backend2 backend3
docker rm load-balancer backend1 backend2 backend3
docker network rm lb-network

3.5 网络故障排查

常用网络调试命令

bash 复制代码
# 在容器中安装网络工具
docker exec -it container_name bash
apt-get update && apt-get install -y iputils-ping telnet curl netcat

# 测试网络连通性
ping target_host
telnet target_host port
curl http://target_host:port
nc -zv target_host port

# 查看网络接口
ip addr show
ip route show

# 查看端口监听
netstat -tulpn
ss -tulpn

常见网络问题

bash 复制代码
# 1. 容器无法访问外网
docker run --rm busybox ping google.com

# 2. 容器间无法通信
docker exec container1 ping container2

# 3. 端口映射不生效
docker port container_name
netstat -tulpn | grep port_number

# 4. DNS 解析问题
docker exec container_name nslookup google.com
docker exec container_name cat /etc/resolv.conf

3.6 高级网络配置

网络别名

网络别名最大的用途是实现简单的负载均衡。多个容器可以使用同一个别名,Docker 会自动进行 DNS 轮询。

bash 复制代码
# 创建网络
docker network create test-network

# 为容器设置网络别名
docker run -d --name web1 --network web-cluster --network-alias webapp nginx
docker run -d --name web2 --network web-cluster --network-alias webapp nginx
docker run -d --name web3 --network web-cluster --network-alias webapp nginx

# 测试别名解析
docker run --rm --network web-cluster busybox nslookup webapp
# 会看到多个 IP 地址,每次访问会轮询到不同的容器

多网络连接

bash 复制代码
# 创建多个网络
docker network create frontend
docker network create backend

# 启动数据库(仅在后端网络)
docker run -d --name db --network backend mysql:8.0 -e MYSQL_ROOT_PASSWORD=pass

# 启动应用服务器(连接两个网络)
docker run -d --name app nginx
docker network connect frontend app
docker network connect backend app

# 启动前端(仅在前端网络)
docker run -d --name web --network frontend nginx

# 验证网络连接
docker exec app ping db      # 应该成功
docker exec web ping app     # 应该成功
docker exec web ping db      # 应该失败

网络策略和安全

bash 复制代码
# 创建隔离网络
docker network create --internal secure-network

# 在隔离网络中的容器无法访问外网
docker run -d --name isolated --network secure-network nginx
docker exec isolated ping google.com  # 应该失败

# 使用自定义 IPAM
docker network create \
  --driver bridge \
  --subnet=192.168.100.0/24 \
  --ip-range=192.168.100.128/25 \
  --gateway=192.168.100.1 \
  custom-subnet

# 指定容器 IP
docker run -d --name fixed-ip --network custom-subnet --ip 192.168.100.130 nginx

本章总结

在本章中,我们全面学习了 Docker 网络机制:

  1. 网络基础:理解了 Docker 网络的基本概念和命名空间隔离
  2. 网络驱动:掌握了 Bridge、Host、None 和自定义网络的使用
  3. 端口映射:学会了各种端口映射配置和高级用法
  4. 实践应用:通过 Web 应用、微服务、负载均衡等场景加深理解
  5. 故障排查:了解了网络问题的诊断和解决方法
  6. 高级配置:掌握了网络别名、多网络连接、安全策略等高级特性

关键概念总结

  • 网络隔离:每个容器都有独立的网络命名空间
  • 服务发现:自定义网络中容器可以通过名称互相访问
  • 端口映射:将容器端口暴露到主机上
  • 网络安全:通过网络隔离实现安全边界

最佳实践要点

  • 为不同的应用创建独立的自定义网络
  • 避免使用默认 bridge 网络进行生产部署
  • 合理规划端口映射,避免端口冲突
  • 使用网络别名实现服务发现
  • 实施网络隔离提高安全性

常见应用场景

  • 前后端分离应用的网络隔离
  • 负载均衡和服务发现
  • 多环境部署的网络规划
  • 容器集群的网络管理

下一章我们将学习 Docker 数据卷和挂载,了解如何持久化容器数据。


第4章:Docker 数据卷和挂载

4.1 数据持久化的重要性

容器是无状态的,当容器删除时,容器内的数据也会丢失。为了实现数据持久化,Docker 提供了多种数据存储方案。

数据丢失问题演示

bash 复制代码
# 创建一个容器并写入数据
docker run -it --name temp-container ubuntu:20.04 bash

# 在容器内创建文件
echo "Important data" > /tmp/important.txt
cat /tmp/important.txt
exit

# 删除容器
docker rm temp-container

# 重新创建同名容器,数据已丢失
docker run -it --name temp-container ubuntu:20.04 bash
cat /tmp/important.txt  # 文件不存在
exit
docker rm temp-container

4.2 Docker 存储类型

Docker 提供三种主要的数据存储方式:

1. Volumes(数据卷)

数据卷是 Docker 管理的存储区域,存储在主机文件系统中,但完全由 Docker 管理。

bash 复制代码
# 创建数据卷
docker volume create my-volume

# 查看所有数据卷
docker volume ls

# 查看数据卷详细信息
docker volume inspect my-volume

# 使用数据卷运行容器
docker run -d --name web-server -v my-volume:/usr/share/nginx/html nginx

# 在另一个容器中访问同一数据卷
docker run -it --rm -v my-volume:/data ubuntu:20.04 bash

# 在容器内创建文件
echo "<h1>Hello from Volume!</h1>" > /data/index.html
exit

# 测试 Web 服务器
curl http://localhost:80  # 如果映射了端口

# 清理
docker stop web-server
docker rm web-server
docker volume rm my-volume

2. Bind Mounts(绑定挂载)

绑定挂载将主机文件系统的目录或文件直接挂载到容器中。

bash 复制代码
# 创建主机目录
mkdir -p /tmp/docker-tutorial/html
echo "<h1>Hello from Bind Mount!</h1>" > /tmp/docker-tutorial/html/index.html

# 使用绑定挂载运行容器
docker run -d \
  --name bind-web \
  -p 8080:80 \
  -v /tmp/docker-tutorial/html:/usr/share/nginx/html \
  nginx

# 测试访问
curl http://localhost:8080

# 在主机上修改文件
echo "<h1>Updated from Host!</h1>" > /tmp/docker-tutorial/html/index.html

# 再次测试,内容已更新
curl http://localhost:8080

# 清理
docker stop bind-web
docker rm bind-web

3. tmpfs Mounts(临时文件系统挂载)

tmpfs 挂载将数据存储在主机内存中,容器停止时数据会丢失。

bash 复制代码
# 使用 tmpfs 挂载
docker run -d \
  --name tmpfs-test \
  --tmpfs /tmp:rw,noexec,nosuid,size=100m \
  nginx

# 查看挂载信息
docker exec tmpfs-test mount | grep tmpfs

# 在 tmpfs 中写入数据
docker exec tmpfs-test bash -c "echo 'Temporary data' > /tmp/temp.txt"
docker exec tmpfs-test cat /tmp/temp.txt

# 重启容器,数据丢失
docker restart tmpfs-test
docker exec tmpfs-test cat /tmp/temp.txt  # 文件不存在

# 清理
docker stop tmpfs-test
docker rm tmpfs-test

4.3 数据卷管理

数据卷操作

bash 复制代码
# 创建数据卷
docker volume create app-data
docker volume create db-data
docker volume create logs

# 列出所有数据卷
docker volume ls

# 查看数据卷详细信息
docker volume inspect app-data

# 删除数据卷
docker volume rm logs

# 删除所有未使用的数据卷
docker volume prune

# 查看数据卷使用情况
docker system df

数据卷备份和恢复

这里 --rm 表示创建后删除停止的容器,常用语一次性任务。

bash 复制代码
# 创建测试数据
docker volume create backup-demo
docker run --rm -v backup-demo:/data ubuntu:20.04 bash -c "
  echo 'Important data 1' > /data/file1.txt
  echo 'Important data 2' > /data/file2.txt
  mkdir /data/subdir
  echo 'Subdirectory data' > /data/subdir/file3.txt
"

# 备份数据卷
docker run --rm \
  -v backup-demo:/source \
  -v $(pwd):/backup \
  ubuntu:20.04 \
  tar czf /backup/backup-demo.tar.gz -C /source .

# 验证备份文件
ls -la backup-demo.tar.gz

# 创建新数据卷用于恢复
docker volume create restore-demo

# 恢复数据
docker run --rm \
  -v restore-demo:/target \
  -v $(pwd):/backup \
  ubuntu:20.04 \
  tar xzf /backup/backup-demo.tar.gz -C /target

# 验证恢复的数据
docker run --rm -v restore-demo:/data ubuntu:20.04 find /data -type f -exec cat {} \;

# 清理
docker volume rm backup-demo restore-demo
rm backup-demo.tar.gz

4.4 实践练习

练习1:数据库数据持久化

bash 复制代码
# 创建数据库数据卷
docker volume create mysql-data

# 启动 MySQL 容器
docker run -d \
  --name mysql-persistent \
  -e MYSQL_ROOT_PASSWORD=mypassword \
  -e MYSQL_DATABASE=testdb \
  -v mysql-data:/var/lib/mysql \
  -p 3306:3306 \
  mysql:8.0

# 等待数据库启动
sleep 30

# 连接数据库并创建数据
docker exec -it mysql-persistent mysql -uroot -pmypassword -e "
  USE testdb;
  CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50));
  INSERT INTO users (name) VALUES ('Alice'), ('Bob'), ('Charlie');
  SELECT * FROM users;
"

# 停止并删除容器
docker stop mysql-persistent
docker rm mysql-persistent

# 使用相同数据卷重新启动容器
docker run -d \
  --name mysql-restored \
  -e MYSQL_ROOT_PASSWORD=mypassword \
  -v mysql-data:/var/lib/mysql \
  -p 3306:3306 \
  mysql:8.0

# 等待启动
sleep 30

# 验证数据仍然存在
docker exec -it mysql-restored mysql -uroot -pmypassword -e "
  USE testdb;
  SELECT * FROM users;
"

# 清理
docker stop mysql-restored
docker rm mysql-restored
docker volume rm mysql-data

练习2:多容器数据共享

bash 复制代码
# 创建共享数据卷
docker volume create shared-data

# 启动数据生产者容器
docker run -d \
  --name producer \
  -v shared-data:/data \
  ubuntu:20.04 \
  bash -c "
    while true; do
      echo \"\$(date): Producer data\" >> /data/producer.log
      sleep 5
    done
  "

# 启动数据消费者容器
docker run -d \
  --name consumer \
  -v shared-data:/data \
  ubuntu:20.04 \
  bash -c "
    while true; do
      if [ -f /data/producer.log ]; then
        echo \"Consumer read: \$(tail -1 /data/producer.log)\"
      fi
      sleep 3
    done
  "

# 启动数据处理器容器
docker run -d \
  --name processor \
  -v shared-data:/data \
  ubuntu:20.04 \
  bash -c "
    while true; do
      if [ -f /data/producer.log ]; then
        wc -l /data/producer.log > /data/stats.txt
        echo \"Processed at \$(date)\" >> /data/stats.txt
      fi
      sleep 10
    done
  "

# 查看各容器日志
echo "Producer logs:"
docker logs producer --tail 5

echo "Consumer logs:"
docker logs consumer --tail 5

echo "Processor logs:"
docker logs processor --tail 5

# 查看共享数据
docker run --rm -v shared-data:/data ubuntu:20.04 ls -la /data
docker run --rm -v shared-data:/data ubuntu:20.04 cat /data/stats.txt

# 清理
docker stop producer consumer processor
docker rm producer consumer processor
docker volume rm shared-data

4.5 高级挂载选项

只读挂载

bash 复制代码
# 只读绑定挂载
mkdir -p /tmp/docker-tutorial/readonly-data
echo "Read-only data" > /tmp/docker-tutorial/readonly-data/config.txt

docker run -it --rm \
  -v /tmp/docker-tutorial/readonly-data:/data:ro \
  ubuntu:20.04 bash

# 在容器内尝试写入(应该失败)
# echo "new data" > /data/config.txt  # Permission denied
# cat /data/config.txt  # 可以读取
# exit

挂载单个文件

bash 复制代码
# 创建配置文件
echo "database_host=localhost" > /tmp/docker-tutorial/app.conf

# 挂载单个文件
docker run -it --rm \
  -v /tmp/docker-tutorial/app.conf:/app/config/app.conf:ro \
  ubuntu:20.04 bash

# 在容器内查看文件
# cat /app/config/app.conf
# exit

挂载选项

bash 复制代码
# 使用特定的挂载选项
docker run -d \
  --name mount-options-test \
  --mount type=bind,source=/tmp/docker-tutorial,target=/data,readonly \
  nginx

# 查看挂载信息
docker inspect mount-options-test | grep -A 10 "Mounts"

# 清理
docker stop mount-options-test
docker rm mount-options-test

4.6 性能和最佳实践

性能考虑

bash 复制代码
# 比较不同存储类型的性能
# 1. 数据卷性能测试
docker volume create perf-volume
docker run --rm \
  -v perf-volume:/data \
  ubuntu:20.04 \
  bash -c "time dd if=/dev/zero of=/data/test bs=1M count=100"

# 2. 绑定挂载性能测试
mkdir -p /tmp/docker-tutorial/perf-bind
docker run --rm \
  -v /tmp/docker-tutorial/perf-bind:/data \
  ubuntu:20.04 \
  bash -c "time dd if=/dev/zero of=/data/test bs=1M count=100"

# 3. tmpfs 性能测试
docker run --rm \
  --tmpfs /data:rw,size=200m \
  ubuntu:20.04 \
  bash -c "time dd if=/dev/zero of=/data/test bs=1M count=100"

# 清理
docker volume rm perf-volume
rm -rf /tmp/docker-tutorial/perf-bind

三种方式比较:

存储类型 性能特点 适用场景
tmpfs 最快 临时文件、缓存、高频读写的临时数据
数据卷 (Volume) 较快 生产环境的首选
绑定挂载 (Bind Mount) 最慢 开发调试、直接访问宿主机文件

最佳实践

bash 复制代码
# 1. 使用命名数据卷而不是匿名数据卷
docker volume create app-logs
docker run -d -v app-logs:/var/log/app nginx

# 2. 为不同类型的数据使用不同的数据卷
docker volume create app-data      # 应用数据
docker volume create app-config    # 配置文件
docker volume create app-logs      # 日志文件

# 3. 定期备份重要数据卷
docker run --rm \
  -v app-data:/source:ro \
  -v $(pwd):/backup \
  ubuntu:20.04 \
  tar czf /backup/app-data-$(date +%Y%m%d).tar.gz -C /source .

# 4. 监控数据卷使用情况
docker system df -v

# 清理
docker volume rm app-logs app-data app-config

本章总结

在本章中,我们深入学习了 Docker 数据卷和挂载机制:

  1. 数据持久化重要性:理解了容器数据丢失问题和持久化的必要性
  2. 存储类型:掌握了 Volumes、Bind Mounts、tmpfs Mounts 三种存储方式
  3. 数据卷管理:学会了数据卷的创建、查看、备份、恢复等操作
  4. 实践应用:通过数据库持久化、开发环境同步、多容器数据共享等场景加深理解
  5. 高级选项:了解了只读挂载、单文件挂载、挂载选项等高级用法
  6. 性能优化:掌握了不同存储类型的性能特点和最佳实践

关键概念总结

  • 数据卷:Docker 管理的持久化存储,推荐用于生产环境
  • 绑定挂载:直接挂载主机目录,适合开发环境
  • tmpfs 挂载:内存存储,适合临时数据
  • 数据共享:多个容器可以共享同一个数据卷

存储选择指南

  • 生产数据:使用 Volumes
  • 开发调试:使用 Bind Mounts
  • 临时缓存:使用 tmpfs Mounts
  • 配置文件:使用只读 Bind Mounts
  • 日志文件:使用 Volumes 或 Bind Mounts

下一章我们将学习 Dockerfile 编写和镜像构建,了解如何创建自定义镜像。

相关推荐
倔强的石头1062 小时前
【Linux指南】gdb进阶技巧:断点高级玩法与变量跟踪实战
linux·运维
是垚不是土3 小时前
Prometheus接入“飞书“实现自动化告警
运维·安全·自动化·github·飞书·prometheus
不语n4 小时前
Windows+Docker+AI开发板打造智能终端助手
python·docker·树莓派·香橙派·dify·ollama·ai开发板
天航星4 小时前
Docker 安装 Jenkins
java·运维·jenkins
waves浪游5 小时前
Linux基本指令(中)
linux·运维·python
荣光波比6 小时前
Docker(三)—— Docker Compose 编排与 Harbor 私有仓库实战指南
运维·docker·容器·云计算
落日漫游6 小时前
DockerCE与cri-docker核心区别解析
运维·docker·kubernetes
YongCheng_Liang6 小时前
Linux 基础命令的 7 大核心模块
linux·运维·服务器
Light606 小时前
领码方案|微服务与SOA的世纪对话(3):方法论新生——DDD、服务网格与AI Ops的融合之道
运维·人工智能·微服务·ddd·soa·服务网格·ai ops