news 2026/4/21 22:22:15

Docker 容器技术入门与实践 (四):Docker存储与网络

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Docker 容器技术入门与实践 (四):Docker存储与网络

Docker存储与网络

引言

在前三篇中,我们探讨了Docker的基本概念、安装配置、镜像管理和容器操作。本篇将聚焦于Docker技术栈中至关重要的两个支柱:存储网络。理解Docker如何管理容器内的数据持久化和网络通信,是构建稳定、可扩展容器化应用的基础。我们将结合OpenEuler操作系统,通过理论讲解、代码示例、功能剖析和日常实践案例,深入解析Docker存储与网络的机制、配置方法和最佳实践。

第一部分:Docker存储

容器默认采用隔离的文件系统。当容器停止或删除时,其内部由镜像提供的文件层以及运行时产生的数据(除非显式保存)都会丢失。这种设计有利于保证环境的一致性,但对于需要持久化保存的数据(如数据库文件、应用日志、配置文件)或需要在容器间共享的数据,就需要Docker提供的存储机制来解决。

1. Docker存储驱动与联合文件系统

  • 联合文件系统(UnionFS):Docker镜像和容器文件系统的基石。它允许将多个目录(称为分支或层)透明地叠加挂载到同一个目录下。底层通常是只读的(如基础镜像层),顶层是可读写的(容器层)。对文件的修改发生在顶层(写时复制,CoW),不影响底层。
  • 存储驱动(Storage Driver):Docker使用存储驱动来管理和实现联合文件系统。不同的驱动有不同的实现方式和性能特点。在OpenEuler上,常见的驱动有:
    • overlay2:目前默认推荐且性能较好的驱动,支持多层镜像。
    • devicemapper:在早期CentOS/RHEL系统中常用,但在OpenEuler上overlay2通常是更好的选择。
    • btrfs:如果OpenEuler的根文件系统是Btrfs,可以使用此驱动(需要btrfs工具)。
    • vfs:简单但性能差,主要用于测试。
  • 查看和设置存储驱动:
    • 查看当前驱动:docker info | grep "Storage Driver"
    • 配置驱动:通常在/etc/docker/daemon.json中设置(若文件不存在则创建):
      { "storage-driver": "overlay2" }
      修改后重启Docker服务:sudo systemctl restart docker

2. 数据卷(Volumes)

数据卷是Docker推荐的持久化数据的方式。它们由Docker管理,独立于容器的生命周期,存储在宿主机文件系统(通常是/var/lib/docker/volumes/)的一个特定区域。

  • 核心优势:
    • 持久化:卷中的数据在容器删除后仍然存在。
    • 解耦:数据存储与容器逻辑分离。
    • 共享:可以在多个容器间安全地共享数据卷。
    • 高效:绕过存储驱动(直接读写宿主机文件系统),性能更好。
    • 备份/迁移:卷可以方便地备份、恢复或迁移。
  • 管理命令:
    • 创建卷:
      docker volume create my_volume # 创建名为my_volume的卷
    • 列出卷:
      docker volume ls
    • 查看卷详情:
      docker volume inspect my_volume
    • 删除卷:
      docker volume rm my_volume # 删除指定卷 docker volume prune # 删除所有未被使用的卷
  • 在容器中使用卷:
    • -v--volume标志:
      # 将卷挂载到容器内的/app/data目录 docker run -d --name my_container -v my_volume:/app/data my_image # 创建匿名卷并挂载 (不推荐,不易管理) docker run -d --name my_container -v /app/data my_image
    • --mount标志(语法更清晰,功能更丰富):
      docker run -d --name my_container \ --mount type=volume,source=my_volume,target=/app/data my_image
    • 文件/目录挂载:虽然-v也能挂载宿主机目录(-v /host/path:/container/path),但严格来说这不属于卷管理,而是绑定挂载(Bind Mounts)。卷是Docker管理的,绑定挂载依赖于宿主机的目录结构。
  • 权限问题:容器内进程访问卷目录的权限取决于容器内进程的UID/GID和宿主机目录的权限。如果宿主机目录权限严格(如属主为root),可能导致容器内普通用户进程无法写入。解决方法:
    • 调整宿主机目录权限(需谨慎)。
    • 在Dockerfile中使用USER指令运行特定用户,并确保该用户在宿主机目录有权限。
    • docker run时使用-u指定UID/GID。
    • 使用命名卷时,Docker通常会自动处理权限(但具体行为可能因驱动而异)。

3. 绑定挂载(Bind Mounts)

绑定挂载直接将宿主机的文件或目录挂载到容器中。它非常灵活,但将容器与宿主机文件系统紧密耦合。

  • 特点:
    • 直接映射:宿主机路径 <-> 容器路径。
    • 性能好:直接访问宿主机文件系统。
    • 依赖宿主机:路径必须在宿主机存在,容器移植性差。
    • 权限敏感:权限问题比卷更突出(直接使用宿主机的权限设置)。
  • 使用方式:
    # 使用 -v docker run -d --name my_container -v /host/data:/container/data my_image # 使用 --mount docker run -d --name my_container \ --mount type=bind,source=/host/data,target=/container/data my_image
  • 应用场景:
    • 开发时挂载源代码目录到容器,实现代码热更新。
    • 挂载宿主机配置文件到容器。
    • 挂载特定设备文件(如/dev/sda1,需额外权限)。
    • 需要直接读写宿主机已知路径的场景。

4. 临时文件系统(tmpfs mounts)

tmpfs挂载将内存中的临时文件系统挂载到容器中。数据完全存储在内存中,速度快,但容器停止后数据即丢失。

  • 特点:
    • 内存存储:读写速度极快。
    • 非持久化:容器停止即消失。
    • 容量限制:可以设置大小限制(--tmpfs-size)。
  • 使用方式:
    # 使用 --tmpfs docker run -d --name my_container --tmpfs /app/tmp my_image # 使用 --mount docker run -d --name my_container \ --mount type=tmpfs,destination=/app/tmp my_image
  • 应用场景:
    • 存放不需要持久化的临时文件或缓存。
    • 对IO速度要求极高的临时数据处理。

5. 存储实践案例

  • 案例1:MySQL数据库持久化
    # 创建专用卷 docker volume create mysql_data # 运行MySQL容器,将数据目录挂载到卷 docker run -d --name mysql_db \ -e MYSQL_ROOT_PASSWORD=mysecret \ -v mysql_data:/var/lib/mysql \ mysql:latest # 即使删除容器,数据仍在mysql_data卷中。重新创建容器挂载同一卷即可恢复数据。
  • 案例2:开发环境代码热加载
    # 假设项目在宿主机的/home/user/project docker run -d --name dev_env \ -v /home/user/project:/app \ -p 8080:8080 \ my_dev_image # 在宿主机修改代码,容器内应用即时生效(需应用支持热加载)。
  • 案例3:多容器共享配置文件
    # 创建一个卷存放公共配置 docker volume create app_config # 将配置文件放入卷 (需要先挂载到一个临时容器或使用docker cp) docker run --rm -v app_config:/config alpine cp /path/to/local/config.conf /config/ # 多个容器挂载同一个配置卷 docker run -d --name service1 --mount source=app_config,target=/etc/app_config my_image1 docker run -d --name service2 --mount source=app_config,target=/etc/app_config my_image2

第二部分:Docker网络

容器需要与外部世界(其他容器、宿主机、互联网)进行通信。Docker提供了强大的网络功能来满足不同的连接需求。

1. Docker网络驱动

Docker通过可插拔的网络驱动实现不同的网络模型。

  • bridge默认网络驱动。创建一个名为docker0的虚拟网桥(在OpenEuler上可使用ip addr show docker0查看)。每个加入该网络的容器会获得一个虚拟网卡(veth pair),一端在容器内,一端连接到网桥。容器通过网桥进行通信,并可通过NAT访问外部网络。这是最常用的模式,适用于单主机上的容器间通信。
  • host容器直接使用宿主机的网络命名空间(Namespace),共享宿主机的网络栈(IP地址、端口等)。性能最好(无NAT开销),但牺牲了网络隔离性(端口冲突风险)。
  • none容器拥有独立的网络命名空间,但不配置任何网络接口(只有loopback)。容器完全隔离,需要用户手动配置网络(通常结合其他工具使用)。
  • overlay用于跨多个Docker宿主机构建容器网络,是Docker Swarm集群模式的基础。它使用VXLAN等技术实现跨主机容器间的二层通信。
  • macvlan为容器分配一个独立的MAC地址,使其在网络中看起来像是一个物理设备。容器可以直接连接到物理网络(需要交换机支持),获得一个与宿主机同网段的IP地址。适用于需要容器获得真实IP地址的场景。
  • ipvlan类似于macvlan,但容器共享宿主机的MAC地址,使用不同的IP地址(L2模式)或路由(L3模式)。在某些网络策略下比macvlan更灵活。

2. Docker网络模型

  • 容器网络命名空间:每个容器在创建时(除非使用--network=host--network=container:<id>)会获得一个独立的网络命名空间,包含自己的网络接口、路由表、防火墙规则等。
  • docker0网桥:bridge模式下,宿主机上的虚拟网桥。它连接着所有属于默认bridge网络的容器。
  • veth pair:虚拟以太网设备对。一端(vethX)在宿主机的命名空间连接到docker0网桥,另一端(eth0)在容器的命名空间内。
  • NAT (SNAT/DNAT):默认情况下,容器通过docker0网桥访问外部网络时,源IP(Container IP)会被SNAT(源地址转换)为宿主机的IP。当外部访问映射到容器的端口时(-p 80:8080),会使用DNAT(目的地址转换)将目标IP和端口转换为容器的IP和端口。

3. 网络管理命令

  • 列出网络:
    docker network ls
  • 查看网络详情:
    docker network inspect bridge # 查看默认bridge网络详情
  • 创建网络:
    docker network create my_network # 创建一个新的bridge网络 docker network create -d macvlan --subnet=192.168.1.0/24 --gateway=192.168.1.1 -o parent=eth0 my_macvlan_net # 创建macvlan网络
  • 删除网络:
    docker network rm my_network # 删除网络(需无容器连接) docker network prune # 删除所有未被使用的网络
  • 将容器连接到网络:
    docker run -d --name container1 --network my_network my_image # 启动时连接 docker network connect my_network existing_container # 连接已运行容器
  • 断开容器与网络的连接:
    docker network disconnect my_network existing_container

4. 端口发布(Port Publishing)

为了让外部网络(宿主机外部)能够访问容器内部的服务,需要将容器内部的端口映射(发布)到宿主机的端口上。

  • -p--publish标志:
    # 将容器80端口映射到宿主机8080端口 (TCP默认) docker run -d -p 8080:80 nginx # 映射UDP端口 docker run -d -p 8080:80/udp my_udp_service # 映射多个端口 docker run -d -p 8080:80 -p 8443:443 nginx # 让Docker自动分配宿主机端口 (查看用docker ps或docker port) docker run -d -p 80 nginx

    查看端口映射:

  • docker port container_name # 查看指定容器的端口映射 docker ps # 查看PORTS列

5. 容器间通信

  • 同一网络内:Docker为同一网络内的容器提供了基于容器名称(或使用--name指定的别名)的DNS解析服务。容器间可以直接通过容器名进行通信,无需知道对方的IP地址。
    docker network create app_net docker run -d --name web --network app_net nginx docker run -it --name client --network app_net alpine / # ping web # 在client容器内ping web容器,成功 / # wget -O- http://web # 访问web容器的nginx
  • 不同网络:默认情况下,不同网络的容器无法直接通信(除非通过宿主机路由或额外配置)。需要将容器连接到同一个网络,或者配置网络路由规则。

6. 网络实践案例

  • 案例1:Web应用栈 (Nginx + PHP-FPM + MySQL)
    # 创建专用网络 docker network create web_app_net # 运行MySQL (使用卷持久化) docker run -d --name mysql --network web_app_net -v mysql_data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=pass mysql # 运行PHP-FPM (挂载应用代码) docker run -d --name php-fpm --network web_app_net -v $(pwd)/app:/var/www/html php:fpm # 运行Nginx (挂载代码和配置,发布端口) docker run -d --name nginx --network web_app_net -v $(pwd)/app:/var/www/html -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf -p 80:80 nginx # 在app目录放入PHP代码。Nginx配置中设置fastcgi_pass php-fpm:9000; 容器间通过名称php-fpm通信。
  • 案例2:使用host网络提升性能
    docker run -d --name high_perf_app --network host my_image # 容器直接使用宿主机网络 # 注意:容器内应用监听端口时,会直接占用宿主机的端口,可能导致冲突。
  • 案例3:macvlan给容器真实IP
    # 假设宿主机eth0在192.168.1.0/24网段,网关192.168.1.1 docker network create -d macvlan --subnet=192.168.1.0/24 --gateway=192.168.1.1 -o parent=eth0 macvlan_net docker run -d --name container_with_ip --network macvlan_net my_image # 容器将获得一个192.168.1.0/24网段的独立IP,可与同网段其他物理设备直接通信。
  • 案例4:Docker Compose定义网络与存储 (简化上述Web栈)
    version: '3.8' services: mysql: image: mysql:latest volumes: - mysql_data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: pass networks: - app_net php-fpm: image: php:fpm volumes: - ./app:/var/www/html networks: - app_net nginx: image: nginx:latest volumes: - ./app:/var/www/html - ./nginx.conf:/etc/nginx/nginx.conf ports: - "80:80" networks: - app_net volumes: mysql_data: networks: app_net: driver: bridge
    运行:docker-compose up -d

OpenEuler系统注意事项

  • 防火墙:OpenEuler默认使用firewalld。Docker在安装时通常会添加dockerzone并开放必要的规则。如果遇到网络问题(如端口映射后无法访问),检查firewalld状态和规则:
    sudo systemctl status firewalld sudo firewall-cmd --list-all --zone=docker # 查看docker zone规则 sudo firewall-cmd --add-port=80/tcp --permanent --zone=public # 如果需要额外开放端口到public zone sudo firewall-cmd --reload
  • SELinux:OpenEuler可能启用SELinux。如果使用绑定挂载出现权限问题(即使文件权限正确),可能是SELinux安全上下文导致。可以尝试:
    • 临时禁用SELinux(生产环境不推荐):setenforce 0
    • 添加正确的SELinux标签(使用chconsemanage fcontext)。
    • docker run时使用--security-opt label=disable(禁用SELinux保护,有安全风险)。
    • 使用卷代替绑定挂载(卷通常不受此问题影响)。
  • 网络性能:对于高性能网络需求(如HPC、金融交易),考虑使用host网络、macvlan/ipvlan或高级网络驱动(如SR-IOV),并优化OpenEuler内核参数(如调整net.core.somaxconn,net.ipv4.tcp_tw_reuse等)。测试工具可使用iperf3

总结

Docker的存储和网络机制为容器化应用提供了灵活、可靠的数据管理和通信能力。在OpenEuler系统上:

  • 存储:优先使用数据卷进行持久化存储管理。理解overlay2驱动原理。掌握volumebind mounttmpfs的适用场景和权限管理。结合docker volume命令和Compose文件进行管理。
  • 网络:掌握bridgehostnonemacvlan等核心网络模式及其工作原理。熟练使用docker network命令创建和管理网络。理解容器间通过容器名称同一网络内通信的便利性。熟练使用端口发布(-p)。在OpenEuler上注意firewalldSELinux对网络和存储访问的影响。

通过本篇的学习和实践,您应该能够为容器应用配置合适的持久化存储方案,并构建满足不同需求的容器网络拓扑,为在OpenEuler上部署和管理复杂的容器化服务打下坚实基础。在后续篇章中,我们将探讨Docker Compose、Docker Swarm/Kubernetes集群管理等更高级的主题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/21 22:20:27

计算机图形学(Computer Graphics)核心算法与应用实践笔记

1. 计算机图形学入门&#xff1a;从像素到虚拟世界 第一次接触计算机图形学时&#xff0c;我被屏幕上那些跳动的像素深深吸引。想象一下&#xff0c;你正在玩的3D游戏里随风摇曳的树叶、电影中逼真的特效场景&#xff0c;甚至手机拍照时自动添加的可爱贴纸——这些都离不开图形…

作者头像 李华
网站建设 2026/4/21 22:19:23

汽车以太网主从模式:为何静态配置是车载网络的生命线?

1. 汽车以太网主从模式的本质差异 第一次接触汽车以太网时&#xff0c;我和很多工程师一样&#xff0c;下意识认为它和普通工业以太网没什么区别。直到在实车测试中遇到链路建立延迟导致整车启动超时的问题&#xff0c;才真正理解主从模式静态配置的价值所在。传统工业以太网的…

作者头像 李华
网站建设 2026/4/21 22:17:17

大模型推理优化关键技术及应用实践研究报告解读

中国信通院发布的《大模型推理优化关键技术及应用实践研究报告》指出&#xff0c;大模型推理优化需关注效果、性能和成本三方面&#xff0c;并需协同平衡。报告分析了当前推理优化面临的挑战&#xff0c;提出了模型层、引擎层和系统层三层优化体系&#xff0c;并梳理了产业实践…

作者头像 李华