Docker(二)—— Docker核心功能全解析:网络、资源控制、数据卷与镜像构建实战

文章目录

  • 前言
  • 一、Docker网络管理
    • [1.1 Docker网络实现原理](#1.1 Docker网络实现原理)
    • [1.2 Docker端口映射](#1.2 Docker端口映射)
      • [1.2.1 随机端口映射](#1.2.1 随机端口映射)
      • [1.2.2 指定端口映射](#1.2.2 指定端口映射)
      • [1.2.3 Docker端口映射总结](#1.2.3 Docker端口映射总结)
    • [1.3 Docker的网络模式](#1.3 Docker的网络模式)
      • [1.3.1 host模式(与宿主机共享网络栈)](#1.3.1 host模式(与宿主机共享网络栈))
      • [1.3.2 Container模式(与其他容器共享网络栈)](#1.3.2 Container模式(与其他容器共享网络栈))
      • [1.3.3 无网络模式(none)](#1.3.3 无网络模式(none))
      • [1.3.4 桥接模式(bridge)](#1.3.4 桥接模式(bridge))
      • [1.3.5 自定义模式](#1.3.5 自定义模式)
      • [1.3.6 Docker网络模式总结](#1.3.6 Docker网络模式总结)
  • 二、Docker资源控制(Docker优化)
    • [2.1 CPU资源控制](#2.1 CPU资源控制)
      • [2.1.1 设置CPU使用率上限(--cpu-period / --cpu-quota)](#2.1.1 设置CPU使用率上限(--cpu-period / --cpu-quota))
      • [2.1.2 设置CPU占用比(权重 --- --cpu-shares)](#2.1.2 设置CPU占用比(权重 — --cpu-shares))
      • [2.1.3 绑定指定CPU(--cpuset-cpus)](#2.1.3 绑定指定CPU(--cpuset-cpus))
      • [2.1.4 CPU压力测试与验证示例](#2.1.4 CPU压力测试与验证示例)
      • [2.1.5 CPU资源控制注意事项](#2.1.5 CPU资源控制注意事项)
    • [2.2 内存使用限制](#2.2 内存使用限制)
      • [2.2.1 --memory与--memory-swap规则](#2.2.1 --memory与--memory-swap规则)
      • [2.2.2 内存限制示例命令](#2.2.2 内存限制示例命令)
      • [2.2.3 内存限制验证与OOM行为](#2.2.3 内存限制验证与OOM行为)
      • [2.2.4 内存限制建议与注意](#2.2.4 内存限制建议与注意)
    • [2.3 磁盘IO(blkio/io)控制](#2.3 磁盘IO(blkio/io)控制)
      • [2.3.1 常用Docker磁盘IO限制参数](#2.3.1 常用Docker磁盘IO限制参数)
      • [2.3.2 磁盘IO限制验证(dd测试)](#2.3.2 磁盘IO限制验证(dd测试))
      • [2.3.3 磁盘IO控制注意事项](#2.3.3 磁盘IO控制注意事项)
    • [2.4 清理Docker占用的磁盘空间](#2.4 清理Docker占用的磁盘空间)
    • [2.5 Docker资源控制常见命令速查](#2.5 Docker资源控制常见命令速查)
    • [2.6 Docker资源控制常见陷阱与建议](#2.6 Docker资源控制常见陷阱与建议)
  • [三、Docker数据卷容器(Data Volumes Containers)](#三、Docker数据卷容器(Data Volumes Containers))
    • [3.1 数据卷](#3.1 数据卷)
      • [3.1.1 创建与挂载数据卷](#3.1.1 创建与挂载数据卷)
      • [3.1.2 在数据卷中写入数据](#3.1.2 在数据卷中写入数据)
      • [3.1.3 查看宿主机同步的数据](#3.1.3 查看宿主机同步的数据)
    • [3.2 数据卷容器](#3.2 数据卷容器)
      • [3.2.1 创建数据卷容器](#3.2.1 创建数据卷容器)
      • [3.2.2 在数据卷容器中写入数据](#3.2.2 在数据卷容器中写入数据)
      • [3.2.3 使用--volumes-from共享数据卷](#3.2.3 使用--volumes-from共享数据卷)
      • [3.2.4 在新容器中验证共享数据](#3.2.4 在新容器中验证共享数据)
    • [3.3 数据卷与数据卷容器总结](#3.3 数据卷与数据卷容器总结)
  • 四、Docker容器互联(使用CentOS镜像)
    • [4.1 创建并运行源容器web1](#4.1 创建并运行源容器web1)
    • [4.2 创建并运行接收容器web2(--link互联)](#4.2 创建并运行接收容器web2(--link互联))
    • [4.3 在接收容器web2中测试连接](#4.3 在接收容器web2中测试连接)
    • [4.4 Docker容器互联总结](#4.4 Docker容器互联总结)
  • 五、Docker镜像的创建
    • [5.1 基于现有镜像创建](#5.1 基于现有镜像创建)
      • [5.1.1 启动容器并进行修改](#5.1.1 启动容器并进行修改)
      • [5.1.2 提交容器为新镜像](#5.1.2 提交容器为新镜像)
    • [5.2 基于本地模板创建](#5.2 基于本地模板创建)
      • [5.2.1 下载操作系统模板](#5.2.1 下载操作系统模板)
      • [5.2.2 导入模板为Docker镜像](#5.2.2 导入模板为Docker镜像)
    • [5.3 基于Dockerfile创建(重点)](#5.3 基于Dockerfile创建(重点))
      • [5.3.1 Docker镜像的分层结构与UnionFS](#5.3.1 Docker镜像的分层结构与UnionFS)
      • [5.3.2 Dockerfile操作常用指令详解(重点)](#5.3.2 Dockerfile操作常用指令详解(重点))
      • [5.3.3 Dockerfile实战示例(构建Apache镜像)](#5.3.3 Dockerfile实战示例(构建Apache镜像))
      • [5.3.4 基于Dockerfile构建镜像](#5.3.4 基于Dockerfile构建镜像)
      • [5.3.5 Docker镜像分层与缓存机制解析](#5.3.5 Docker镜像分层与缓存机制解析)
    • [5.4 Docker镜像创建方式总结](#5.4 Docker镜像创建方式总结)
  • [Docker 命令无法补全解决方案](#Docker 命令无法补全解决方案)
  • 总结

前言

在容器化技术飞速发展的今天,Docker作为最主流的容器引擎,已经成为开发、测试和运维岗位的必备技能。但很多同学在使用Docker时,往往只停留在"拉取镜像、启动容器"的基础操作,对Docker的网络通信、资源限制、数据持久化以及镜像定制等核心功能理解不深,导致在实际项目中遇到各种"卡壳"问题。

本文将从实战角度出发,系统梳理Docker的六大核心模块:网络管理资源控制数据卷容器端口映射容器互联镜像创建,每个模块都包含原理讲解、命令示例和注意事项,帮你打通Docker使用的"任督二脉"。无论你是刚接触Docker的新手,还是需要巩固基础的开发者/运维工程师,这篇文章都能为你提供实用的指导。

一、Docker网络管理

Docker容器的网络通信是容器化应用部署的核心环节------容器之间如何通信?容器如何被外部网络访问?不同场景下该选择哪种网络模式?这些问题都需要通过Docker的网络管理机制来解决。

1.1 Docker网络实现原理

Docker的网络通信依赖于Linux桥接技术 ,其核心是宿主机上虚拟的docker0网桥。具体实现逻辑如下:

  1. 虚拟网桥(docker0) :Docker启动时会在宿主机创建一个名为docker0的虚拟网桥,它相当于一个"虚拟交换机",负责连接宿主机上的所有Docker容器。
  2. Container-IP分配 :启动容器时,Docker会从docker0的网段(默认通常是172.17.0.0/16)中分配一个唯一的IP地址(即Container-IP)给容器,并将docker0设置为容器的默认网关。
  3. 容器间通信 :同一宿主机内的所有容器都接入docker0网桥,因此容器之间可以通过各自的Container-IP直接通信(无需经过宿主机的物理网卡)。
  4. 外部网络访问限制docker0是宿主机虚拟的网络设备,并非真实的物理网卡,外部网络无法直接通过Container-IP访问容器。若需外部访问,需通过端口映射将容器端口映射到宿主机端口,再通过"宿主机IP:宿主机端口"访问容器。

1.2 Docker端口映射

容器内部的端口默认无法被外部网络访问(因docker0是虚拟网桥),需通过端口映射 将容器端口映射到宿主机端口,实现外部访问。Docker支持两种端口映射方式:随机映射(-P)和指定映射(-p)

1.2.1 随机端口映射

使用-P(大写)参数,Docker会自动从32768开始分配一个未使用的宿主机端口,映射到容器暴露的端口(如Nginx的80端口)。适用于无需固定端口的场景(如测试环境)。

实战示例

bash 复制代码
# 启动Nginx容器,随机映射端口
docker run -d --name test1 -P nginx

# 查看端口映射结果(重点看PORTS列)
docker ps -a
# 输出示例:
# CONTAINER ID   IMAGE  COMMAND       CREATED          PORTS                   NAMES
#6fd7a69e7883   nginx          "/docker-entrypoint...."   15 seconds ago   Up 14 seconds               0.0.0.0:49158->80/tcp, :::49158->80/tcp   test1

# 外部访问(替换为宿主机IP)
http://192.168.80.10:49158

# 查看容器日志(排查访问问题)
docker logs test1  # 或使用容器ID

1.2.2 指定端口映射

使用-p(小写)参数,手动指定"宿主机端口:容器端口",适用于需要固定访问端口的场景(如生产环境的Web服务)。

实战示例

bash 复制代码
# 启动Nginx容器,指定宿主机43000端口→容器80端口
docker run -d --name test2 -p 43000:80 nginx

# 查看端口映射结果
docker ps -a
# 输出示例:
# CONTAINER ID   IMAGE  COMMAND       CREATED          PORTS                   NAMES
# b3369e74b2a8   nginx     "/docker-entrypoint...."   25 seconds ago   Up 23 seconds   0.0.0.0:43000->80/tcp, :::43000->80/tcp   test2

# 外部访问(固定端口43000)
http://192.168.80.10:43000

# 查看容器日志(排查访问问题)
docker logs test2  # 或使用容器ID

1.2.3 Docker端口映射总结

映射方式 参数 特点 适用场景
随机映射 -P 自动分配宿主机端口(32768+) 测试环境、无需固定端口
指定映射 -p 宿主机端口:容器端口 手动指定端口,固定访问地址 生产环境、需要固定端口的服务

注意:宿主机端口需未被占用,若端口冲突,容器启动会失败,需更换宿主机端口。

1.3 Docker的网络模式

使用docker run创建容器时,可通过--net--network参数指定容器的网络模式,不同模式对应不同的网络隔离与通信能力。Docker支持5种核心网络模式,以下逐一解析。

1.3.1 host模式(与宿主机共享网络栈)

  • 原理 :类似VMware的"桥接模式",容器不创建独立的Network Namespace(网络命名空间),而是与宿主机共享同一个网络栈。因此,容器不会虚拟自己的网卡、配置独立IP,而是直接使用宿主机的IP和端口

  • 特点:网络性能最优(无额外网络转发开销),但容器会占用宿主机的端口,存在端口冲突风险。

  • 适用场景:需要高性能网络的应用(如数据库)

  • 实战命令

    bash 复制代码
    # 启动Nginx容器,使用host模式
    docker run -d --name nginx-host --network host nginx
    # 访问容器:直接通过宿主机IP(无需端口映射,容器用宿主机80端口)
    # http://宿主机IP:80


1.3.2 Container模式(与其他容器共享网络栈)

  • 原理 :新创建的容器不与宿主机共享网络,而是与已存在的某个容器 共享同一个Network Namespace。两个容器共享IP、端口范围,但文件系统、进程列表等其他资源仍保持隔离;可通过lo回环网卡直接通信。

  • 适用场景:需要两个容器紧密协作(如"应用容器+日志收集容器"),且希望避免端口映射的场景。

  • 实战案例

    bash 复制代码
    # 1. 先创建基础容器test1-container(CentOS 7)
    docker run -itd --name test1-container centos:7 /bin/bash
    
    # 2. 查看test1-container的进程号(用于后续验证网络命名空间)
    docker inspect -f '{{.State.Pid}}' test1-container  # 输出示例:1753
    
    # 3. 查看test1-container的网络命名空间(记录net对应的编号,如4026532575)
    ls -l /proc/1753/ns
    # 输出示例:
    # lrwxrwxrwx 1 root root 0 1月   7 11:27 net -> net:[4026532504]
    bash 复制代码
    # 4. 创建test2-container,指定与test1-container共享网络
    docker run -itd --name test2-container --net=container:test1-container centos:7 /bin/bash
    
    # 5. 验证网络命名空间共享(test2-container的net编号与test1-container一致)
    docker inspect -f '{{.State.Pid}}' test2-container  # 输出示例:1844
    ls -l /proc/1844/ns
    # 输出示例:
    # lrwxrwxrwx 1 root root 0 1月   7 12:27 net -> net:[4026532504]

1.3.3 无网络模式(none)

  • 原理 :容器拥有独立的Network Namespace,但Docker不为其配置任何网络(无网卡、无IP、无路由),仅保留lo回环网卡(用于容器内部进程通信)。

  • 特点:完全封闭的网络环境,无法联网,安全性极高。

  • 适用场景:不需要网络通信的离线任务(如本地数据处理、加密计算)。

  • 实战命令

    bash 复制代码
    docker run -itd --name test-none --network none centos:7 /bin/bash
    # 进入容器查看网络(仅lo网卡)
    docker exec -it test-none ip addr

1.3.4 桥接模式(bridge)

  • 原理 :Docker的默认网络模式(不指定--net时默认使用),类似VMware的"NAT模式"。容器拥有独立的Network Namespace,并通过docker0网桥与宿主机通信,具体流程,如下:
    1. Docker启动时创建docker0虚拟网桥;
    2. 为每个容器分配Container-IP,并设置docker0的IP地址为容器的默认网关。
    3. 在主机上创建一对veth pair(虚拟网卡对)(连接两个不同的网络命名空间):一端作为容器内的eth0网卡,另一端放在主机中, 以 * 这样类似的名字命名,并将这个网络设备加入到 docker0 网桥;
    4. 通过iptablesnat表配置端口转发,实现容器与外部网络的通信。
  • 补充说明virbr0docker0的区别------virbr0是Linux虚拟化技术(如KVM、VirtualBox)创建的虚拟网桥,用于虚拟机通信;docker0仅用于Docker容器。
  • 总结:bridge网络模式中,容器运行在同一宿主机内的虚拟网桥上,可以通过容器互相通信,与宿主机网络隔离。

1.3.5 自定义模式

Docker允许用户创建自定义网络,支持三种驱动:

  • bridge:类似默认bridge模式,但增加了DNS解析(容器可通过名称通信)、网络隔离等功能。单机网络模式,适合在一台宿主机、内容器互联;
  • overlay:用于跨主机容器通信(Docker Swarm集群场景);
  • macvlan:容器像一台物理机一样直接获取宿主机的所在的网络的IP(容器像物理机一样直接连接局域网)

实战:创建自定义bridge网络并指定IP

默认bridge模式不支持手动指定Container-IP,需通过自定义网络实现:

bash 复制代码
# 1. 创建自定义bridge网络(子网172.18.0.0/16,网卡名docker1)
docker network create --subnet=172.18.0.0/16 --opt "com.docker.network.bridge.name"="docker1" mynetwork
# 参数说明:
# --subnet:指定网络子网;
# --opt "com.docker.network.bridge.name":指定宿主机上的网卡名(默认是br-xxx格式,不易记);
# mynetwork:自定义网络名称。

# 2. 启动容器时指定自定义网络和IP
docker run -itd --name test4 --net mynetwork --ip 172.18.0.10 centos:7 /bin/bash

# 3. 验证IP(进入容器查看)
docker exec -it test4 ip addr  # 应显示172.18.0.10
docker inspect test4


bash 复制代码
# 管理 Linux 桥接网络
brctl show
# 管理 Docker 容器网络
docker network ls

1.3.6 Docker网络模式总结

网络模式 核心特点 适用场景
host 共享宿主机网络栈,无端口映射 对网络性能要求高,无端口冲突风险的场景
Container 共享其他容器网络,隔离其他资源 容器间紧密协作(如应用+日志收集)
none 无网络配置,仅lo网卡 离线任务、高安全性需求
bridge 默认模式,独立网络栈+docker0网桥 单主机容器通信,常规场景
自定义 支持DNS、跨主机、MAC模拟 集群部署、复杂网络隔离

额外附加

  1. Overlay:这是Docker Swarm模式的网络,主要用于在多个主机上创建一个分布式网络。容器间即便在不同的主机也能完成通信,相当于在跨主机的容器之间创建了一个覆盖网络。
  2. Macvlan:Macvlan模式可以让容器直接连接到主机的物理网络,每个Macvlan接口都有一个唯一的MAC地址,此模式使得容器看起来就像是网络上的物理设备。

二、Docker资源控制(Docker优化)

为避免单个容器占用过多宿主机资源(如CPU、内存),Docker基于Linux的cgroups(Control Groups)机制实现资源限制。

cgroups是Linux内核提供的资源管理工具,支持限制、统计、优先级分配等功能。

cgroups 的 4 大功能(简要)

  • 资源限制:限制任务使用的总资源量。
  • 优先级分配:如通过 cpu 时间片和 IO 带宽分配优先级。
  • 资源统计:统计 cpu 时长、内存用量等。
  • 任务控制:对 cgroup 中的进程执行挂起/恢复等操作。

2.1 CPU资源控制

2.1.1 设置CPU使用率上限(--cpu-period / --cpu-quota)

  • 原理:Linux使用CFS(完全公平调度器)调度CPU,通过两个参数控制容器CPU使用率:

    • --cpu-period:调度周期(单位:微秒,默认100000,即100ms);
    • --cpu-quota:容器在一个周期内可使用的CPU时间(单位:微秒,默认-1,即无限制);
    • 计算公式:可用CPU核心数 = cpu-quota / cpu-period(如50000/100000=0.5,即50%的单核CPU)。
  • 实战示例

    bash 复制代码
    # 方式1:使用--cpu-quota(限制为50%单核CPU)
    docker run -itd --name test6 --cpu-quota 50000 centos:7 /bin/bash
    
    # 方式2:使用--cpus(更直观,Docker 1.13+支持)
    docker run -itd --name cputest --cpus="0.5" centos:7 /bin/bash
    # 说明:--cpus="0.5" 等价于 --cpu-period=100000 --cpu-quota=50000
    
    # 进行压测并在宿主机查看cpu使用率
    docker stats
  • 注意:若宿主机有4个逻辑核,0.5个CPU相当于整机CPU能力的12.5%(0.5/4=0.125)。

  • 最小值/范围--cpu-period 有效范围通常 1000 ~ 1000000(单位 us)。--cpu-quota 必须 >= 1000(1 ms)或者 -1(不限制)。

2.1.2 设置CPU占用比(权重 --- --cpu-shares)

  • 原理--cpu-shares指定CPU使用的相对权重 (默认1024),仅在CPU资源紧张(容器争用CPU)时生效,并非硬限制。例如:

    • 容器A(--cpu-shares 512)与容器B(--cpu-shares 1024)争用CPU时,分配比约为1:2。
  • 实战示例

    bash 复制代码
    # 创建两个不同权重的容器
    docker run -itd --name c1 --cpu-shares 512 centos:7
    docker run -itd --name c2 --cpu-shares 1024 centos:7
    bash 复制代码
    # 验证:在容器内运行压力测试工具stress
    # 1. 进入容器安装stress(先在容器内设置阿里源)
    docker cp CentOS-Base.repo c1:/etc/yum.repos.d/
    docker exec -it c1 bash
    yum install -y epel-release && yum install -y stress
    
    # 2. 每个容器启动4个CPU压力进程
    stress -c 4  # 在c1和c2中分别执行
    
    # 3. 宿主机查看CPU分配(倾向于1:2)
    docker stats

2.1.3 绑定指定CPU(--cpuset-cpus)

  • 原理:将容器进程绑定到宿主机的指定CPU核心(硬亲和性),避免进程在不同核心间切换,提升性能稳定性。

  • 实战示例

    bash 复制代码
    # 将容器绑定到宿主机第1、3个核心(核心编号从0开始)
    docker run -itd --name test7 --cpuset-cpus "1,3" centos:7 /bin/bash
    
    # 验证:宿主机查看核心利用率
    top  # 按键盘1键,查看CPU1和CPU3的使用率
    # 或进入容器运行 taskset -p <pid>

2.1.4 CPU压力测试与验证示例

通过自定义脚本模拟CPU高负载,验证资源限制效果:

  • 在容器内创建一个繁忙循环脚本:

    bash 复制代码
    # /cpu.sh
    #!/bin/bash
    i=0
    while true; do let i++; done
  • 在容器内运行 ./cpu.sh,在宿主机观察 topdocker stats

    bash 复制代码
    docker exec -it <container> bash
    ./cpu.sh
  • 分别进入容器,进行压力测试

    bash 复制代码
    yum install -y epel-release
    yum install -y stress
    stress -c 4				#产生四个进程,每个进程都反复不停的计算随机数的平方根
  • 修改 cgroups 手工测试(示例):

    bash 复制代码
    # 找到容器对应的 cgroup 路径(容器ID替换)
    cd /sys/fs/cgroup/cpu/docker/<container-id>/
    cat cpu.cfs_period_us
    cat cpu.cfs_quota_us
    echo 50000 > cpu.cfs_quota_us   # 设置配额(临时生效)

2.1.5 CPU资源控制注意事项

  1. --cpu-shares权重,非硬限制(CPU空闲时,容器可使用超过权重的资源);
  2. --cpu-quota/--cpus硬限制,容器无法突破设定的CPU上限(quota = -1 表示无限制);
  3. --cpuset-cpus适合对性能稳定性要求高的场景(避免与其他进程抢核)(如数据库容器)。
  4. 在多核宿主机上理解 quota/period 的含义(单位是 "相对于 1 个 CPU 的份额")。

2.2 内存使用限制

内存限制通过-m/--memory--memory-swap参数实现,避免容器耗尽宿主机内存。

2.2.1 --memory与--memory-swap规则

  • --memory:限制容器可使用的物理内存 (如-m 512m表示512MB);
  • --memory-swap:限制容器可使用的物理内存+交换分区(swap) 总量,需与--memory配合使用;
  • 核心规则:
    1. 示例-m 300m --memory-swap=1g:物理内存300MB,swap可用700MB(1G-300M);
    2. 不设置--memory-swap:默认swap为--memory的2倍(如-m 512m,swap默认1024MB);
    3. --memory-swap=-1:swap无限制(使用宿主机所有可用swap);
    4. --memory-swap=--memory:容器不可使用swap(物理内存用尽触发OOM)。

2.2.2 内存限制示例命令

bash 复制代码
# 1. 限制物理内存512MB(swap默认1024MB)
docker run -itd --name memtest -m 512m centos:7 /bin/bash

# 2. 限制物理内存300MB,swap总量1GB(swap可用700MB)
docker run -itd --name memtest2 -m 300m --memory-swap=1g centos:7 /bin/bash

2.2.3 内存限制验证与OOM行为

  • 验证内存限制

    bash 复制代码
    # 1. 宿主机查看容器内存限制(替换为容器ID)
    cd /sys/fs/cgroup/memory/docker/<容器ID>/
    cat memory.limit_in_bytes  # 输出内存限制(单位:字节,512MB=536870912字节)
    cat memory.usage_in_bytes  # 输出当前内存使用量
    
    # 2. 容器内模拟内存高负载(使用stress)
    docker exec -it memtest bash
    stress --vm 1 --vm-bytes 600m  # 尝试使用600MB内存(超过512MB限制)


  • OOM行为 :若容器内存超过限制且无swap可用,内核会触发OOM Killer杀死容器,可通过docker logs查看日志或者 dmesg 来确认 OOM 事件。

2.2.4 内存限制建议与注意

  1. 生产环境必须为容器设置内存限制,避免单个容器把宿主机内存耗尽;
  2. 内存敏感型应用(如Redis、MySQL)建议禁用swap(--memory-swap=--memory),避免swap导致性能下降;
  3. 配合容器健康检查和重启策略(如--restart=on-failure),应对OOM后的容器恢复。
  4. 在 cgroup v2 环境下内存控制文件名/行为可能与 v1 略有不同(检查 /sys/fs/cgroup 结构)。

2.3 磁盘IO(blkio/io)控制

Docker基于cgroupsblkio控制器(cgroup v1)或io控制器(cgroup v2)限制容器的磁盘读写速率和IOPS(每秒输入输出次数)。

2.3.1 常用Docker磁盘IO限制参数

参数 作用 示例
--device-read-bps 限制设备读速率(单位:B/s、KB/s、MB/s) --device-read-bps /dev/sda:1M
--device-write-bps 限制设备写速率 --device-write-bps /dev/sda:1M
--device-read-iops 限制设备读IOPS(次数) --device-read-iops /dev/sda:100
--device-write-iops 限制设备写IOPS(次数) --device-write-iops /dev/sda:100

实战示例 :限制容器对/dev/sda(宿主机磁盘)的写速率为1MB/s

bash 复制代码
docker run -it --name iotest --device-write-bps /dev/sda:1MB centos:7 /bin/bash

2.3.2 磁盘IO限制验证(dd测试)

通过dd命令(跳过文件系统缓存)测试写速率:

bash 复制代码
# 容器内执行dd命令(写入10个1MB的块)跳过文件系统缓存
dd if=/dev/zero of=test.out bs=1M count=10 oflag=direct

# 输出示例(写速约1MB/s,符合限制):
# 10485760 bytes (10 MB) copied, 10.0028 s, 1.0 MB/s

2.3.3 磁盘IO控制注意事项

  1. 限制需指定具体块设备路径 (如/dev/sda),路径错误会导致限制失效;
  2. 云环境或虚拟化环境中,底层存储(如AWS EBS、阿里云云盘)可能有自身IO限制,容器层限制需结合底层限制配置;
  3. cgroup v2环境中,IO限制参数不同(如使用--device-io-max),需参考对应Docker版本文档。

2.4 清理Docker占用的磁盘空间

Docker运行一段时间后,会积累停止的容器、未使用的镜像、网络和构建缓存,可通过以下命令清理:

bash 复制代码
# 清理所有未使用的资源(停止的容器、未使用的镜像、网络、缓存)
docker system prune -a
# 注意:此命令会删除所有未活跃的资源,执行前确认无需保留!

2.5 Docker资源控制常见命令速查

bash 复制代码
# CPU相关
docker run -itd --name c1 --cpu-shares 512 centos:7  # 权重512
docker run -itd --name c2 --cpu-quota 50000 centos:7  # 50%单核
docker run -itd --name c3 --cpuset-cpus "1,3" centos:7  # 绑定核心1、3
docker run -itd --name c4 --cpus="0.5" centos:7  # 直观指定0.5核

# 内存相关
docker run -itd --name memtest -m 512m centos:7  # 512MB物理内存
docker run -itd --name memtest2 -m 300m --memory-swap=1g centos:7  # 300M+700M swap

# 磁盘IO相关
docker run -it --name iotest --device-write-bps /dev/sda:1MB centos:7  # 写速1MB/s

# 监控与验证
docker stats  # 实时监控容器资源使用
docker exec -it <容器ID> bash  # 进入容器操作
cat /sys/fs/cgroup/cpu/docker/<容器ID>/cpu.cfs_quota_us  # 查看CPU配额
cat /sys/fs/cgroup/memory/docker/<容器ID>/memory.limit_in_bytes  # 查看内存限制

# 清理资源
docker system prune -a  # 清理未使用资源

2.6 Docker资源控制常见陷阱与建议

  1. 权重vs限额--cpu-shares是相对权重(争用时生效),--cpu-quota/--cpus是硬限额(强制限制);
  2. cgroup版本差异:CentOS 7默认用cgroup v1,CentOS 8+或新内核可能用cgroup v2,控制器名称和参数不同(如blkio→io);
  3. IO 限制依赖底层设备:在云/虚拟机上测试时,注意底层虚拟磁盘的行为。
  4. 生产环境监控:建议搭配Prometheus+Grafana+cAdvisor监控容器资源,及时发现资源瓶颈;
  5. 权限控制 :修改/sys/fs/cgroup目录下的配置需root权限,优先使用docker run参数配置,避免直接修改系统文件。

三、Docker数据卷容器(Data Volumes Containers)

容器的文件系统是临时的------容器删除后,内部数据会丢失。Docker的数据卷(Data Volumes)机制解决了这一问题,实现数据持久化;而数据卷容器则进一步简化了多容器间的数据共享。

3.1 数据卷

数据卷是容器内的特殊目录,可与宿主机目录或其他容器共享,具备以下特性:

  • 数据持久化:容器删除后,数据卷中的数据不会丢失;
  • 双向同步:宿主机与容器对数据卷的修改实时同步;
  • 跨容器共享:多个容器可挂载同一个数据卷。

3.1.1 创建与挂载数据卷

通过docker run-v--mount参数挂载数据卷,格式:-v 宿主机目录:容器内目录

bash 复制代码
# 挂载宿主机/var/www目录到容器内/data1目录
docker run -v /opt/www:/data1 --name web1 -it centos:7 /bin/bash
# 参数说明:
# /var/www:宿主机目录(不存在会自动创建);
# /data1:容器内目录(不存在会自动创建);
# web1:容器名称。
  • -v /var/www:/data1: 将宿主机上的 /var/www 目录挂载到容器中的 /data1 目录。这样容器内 /data1 的修改会同步到宿主机上的 /var/www
  • --name web1: 给容器指定一个名称 web1
  • -it centos:7 /bin/bash: 使用 centos:7 镜像启动容器并进入交互式 shell。

3.1.2 在数据卷中写入数据

进入容器后,在数据卷目录(/data1)中创建文件,数据会同步到宿主机:

bash 复制代码
# 容器内执行(写入数据到/data1/abc.txt)
echo "this is web1" > /data1/abc.txt
exit

此时,容器中的 /data1/abc.txt 文件与宿主机中的 /var/www/abc.txt 文件是同步的。即使容器退出,宿主机上的数据依然存在。

3.1.3 查看宿主机同步的数据

退出容器后,查看宿主机/var/www目录,数据已同步:

bash 复制代码
# 宿主机执行
cat /opt/www/abc.txt  # 输出:this is web1

3.2 数据卷容器

数据卷容器是专门用于提供数据卷的容器 ,不运行应用程序,仅作为"数据载体",供其他容器通过--volumes-from挂载其数据卷。适用于多容器共享数据的场景(如微服务中的配置共享、日志存储)。

3.2.1 创建数据卷容器

bash 复制代码
# 创建数据卷容器web2,挂载两个数据卷/data1和/data2
docker run --name web2 -v /data1 -v /data2 -it centos:7 /bin/bash
# 说明:-v /data1 未指定宿主机目录,Docker会在宿主机/var/lib/docker/volumes/下创建匿名卷
  • --name web2: 给容器命名为 web2
  • -v /data1 -v /data2: 在容器内部挂载了两个数据卷 /data1/data2。这些数据卷不依赖于宿主机,而是仅仅存在于容器内。

3.2.2 在数据卷容器中写入数据

进入web2容器,在数据卷中写入测试数据:

bash 复制代码
# 进入web2容器
docker exec -it web2 bash

# 在/data1和/data2中写入数据
echo "this is web2" > /data1/abc.txt
echo "THIS IS WEB2" > /data2/ABC.txt

3.2.3 使用--volumes-from共享数据卷

创建新容器web3,通过--volumes-from挂载web2的数据卷:

bash 复制代码
# 创建web3,共享web2的所有数据卷
docker run -it --volumes-from web2 --name web3 centos:7 /bin/bash
# 说明:--volumes-from web2 表示继承web2的所有数据卷配置
  • --volumes-from web2: 这表示将容器 web2 中的所有数据卷挂载到新容器 web3 中。

3.2.4 在新容器中验证共享数据

进入web3容器,查看/data1/data2目录,可看到web2中写入的数据:

bash 复制代码
# 进入web3容器
docker exec -it web3 bash

# 查看数据
cat /data1/abc.txt  # 输出:this is web2
cat /data2/ABC.txt  # 输出:THIS IS WEB2

3.3 数据卷与数据卷容器总结

  1. 数据卷 (Data Volumes) :解决"容器数据持久化"问题,通过-v挂载宿主机目录;
  2. 数据卷容器(Data Volumes Containers) :解决"多容器数据共享"问题,通过--volumes-from继承数据卷,无需每个容器都挂载宿主机目录;
  3. 注意 :数据卷容器删除后,其数据卷(匿名卷)不会被删除,需手动清理(docker volume rm <卷ID>)。

四、Docker容器互联(使用CentOS镜像)

容器互联是指通过网络让两个或多个容器直接通信,Docker早期通过--link选项实现,适用于简单的单主机容器通信场景(复杂场景建议使用自定义网络)。

4.1 创建并运行源容器web1

首先创建"源容器"web1,作为通信的发起方:

bash 复制代码
# 启动web1容器(后台运行,随机端口映射)
docker run -itd -P --name web1 centos:7 /bin/bash
# 参数说明:
# -itd:交互式+后台运行;
# -P:随机映射端口;
# --name web1:指定容器名称(互联需依赖名称)。

4.2 创建并运行接收容器web2(--link互联)

创建"接收容器"web2,通过--link选项连接web1,格式:--link 源容器名称:源容器别名

bash 复制代码
# 启动web2,通过--link连接web1(别名为web1)
docker run -itd -P --name web2 --link web1:web1 centos:7 /bin/bash
# 说明:--link web1:web1 表示将web1容器暴露给web2,web2中可通过"web1"这个别名访问web1。

4.3 在接收容器web2中测试连接

进入web2容器,通过ping命令测试与web1的通信(无需知道web1Container-IP):

bash 复制代码
# 1. 进入web2容器
docker exec -it web2 bash

# 2. 测试与web1的连通性(使用别名web1)
ping web1
# 输出示例(ping通表示互联成功):
# PING web1 (172.17.0.2) 56(84) bytes of data.
# 64 bytes from web1 (172.17.0.2): icmp_seq=1 ttl=64 time=0.068 ms

4.4 Docker容器互联总结

  1. 核心原理--link会在接收容器的/etc/hosts文件中添加源容器的别名与Container-IP的映射,因此接收容器可通过别名通信;
  2. 局限性--link仅支持单主机容器互联,且不支持动态更新(源容器IP变化后,接收容器的/etc/hosts不会自动更新);
  3. 替代方案 :复杂场景(如跨主机、动态容器)建议使用Docker自定义网络(如overlay),支持DNS自动解析和动态IP更新。

五、Docker镜像的创建

Docker镜像是容器的"模板",包含容器运行所需的程序、库、配置等。创建Docker镜像主要有三种方式:基于现有容器创建基于本地模板创建基于Dockerfile创建(最常用、最灵活)。

5.1 基于现有镜像创建

该方式是"先修改容器,再将修改后的容器提交为新镜像",适用于快速定制简单镜像。

5.1.1 启动容器并进行修改

bash 复制代码
# 1. 启动一个CentOS 7容器(交互式)
docker create -it --name mycentos centos:7 /bin/bash  # 创建容器
docker start <容器ID>  # 启动容器
docker exec -it <容器ID> bash  # 进入容器

# 2. 修改容器内部的环境(例如安装软件包、修改配置文件等),然后退出容器
# 安装OpenJDK 8
yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel
# 验证java版本
java-version
yum clean all

5.1.2 提交容器为新镜像

使用docker commit命令将修改后的容器提交为新镜像,格式:docker commit -m "提交说明" -a "作者" 容器ID 新镜像名:标签

bash 复制代码
# 提交容器(容器ID替换为实际ID)
docker commit -m "openjdk8" -a "simon" 1450d38ffda5 openjdk:8

# 查看新镜像
docker images
# 输出示例:
# REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
# openjdk      8         4ee649b7cf2b   5 seconds ago   469MB

5.2 基于本地模板创建

通过导入现成的操作系统模板(如OpenVZ模板)创建镜像,适用于快速获取特定系统环境的场景。

5.2.1 下载操作系统模板

从OpenVZ官网下载模板(以Debian 7为例):

bash 复制代码
# 使用wget下载模板
wget http://download.openvz.org/template/precreated/debian-7.0-x86-minimal.tar.gz
# 或使用curl下载
curl -L http://download.openvz.org/template/precreated/debian-7.0-x86-minimal.tar.gz -o debian-7.tar.gz

5.2.2 导入模板为Docker镜像

使用docker import命令导入模板:

bash 复制代码
# 将模板文件导入为镜像(镜像名debian:test)
cat debian-7.0-x86-minimal.tar.gz | docker import - debian:test

# 查看镜像
docker images
# 输出示例:
# REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
# debian       test      5120c6b1c973   4 seconds ago   215MB

5.3 基于Dockerfile创建(重点)

Dockerfile是一个包含一系列指令 的文本文件,每条指令对应镜像的一层,通过docker build命令自动构建镜像。这种方式支持自动化、可重复构建,是生产环境中创建镜像的首选方式。

5.3.1 Docker镜像的分层结构与UnionFS

Docker镜像基于UnionFS(联合文件系统) 构建,具有以下特点:

  • 分层存储:每一条Dockerfile指令生成一层镜像,层与层之间相互独立;
  • 只读特性:所有镜像层都是只读的,容器启动时会在镜像层之上添加一层"可读写层"(容器层);
  • 缓存机制:Docker会缓存已构建的镜像层,若指令或文件未变化,直接复用缓存,加速构建。

为什么Docker中的CentOS镜像只有200MB左右?

传统CentOS系统镜像约4GB,而Docker镜像仅保留rootfs(根文件系统,包含/bin/etc等核心目录),共享宿主机的bootfs(引导文件系统,包含内核),因此体积大幅缩小。

5.3.2 Dockerfile操作常用指令详解(重点)

Dockerfile指令按功能可分为基础镜像指令镜像操作指令容器启动指令等,以下是常用指令:

  1. FROM

    指定新镜像基于的基础镜像,Dockerfile 的第一条指令必须为 FROM

    dockerfile 复制代码
    FROM centos:7
  2. MAINTAINER

    指定镜像的维护者信息:

    dockerfile 复制代码
    MAINTAINER "Simon Cai <simoncwh@example.com>" 
  3. RUN

    执行命令并将结果提交到镜像中。常用来安装软件包、修改配置等。

    dockerfile 复制代码
    RUN yum install -y httpd
  4. ENTRYPOINT

    设置容器启动时默认执行的命令(不可被覆盖,优先级高于CMD):

    dockerfile 复制代码
    ENTRYPOINT ["httpd", "-D", "FOREGROUND"]
  5. CMD

    容器启动时执行的默认命令。CMD 指令会被 docker run 命令后指定的命令覆盖。

    dockerfile 复制代码
    CMD ["httpd", "-D", "FOREGROUND"]
  6. EXPOSE

    声明容器内的端口(仅文档说明,不实际映射):

    dockerfile 复制代码
    EXPOSE 80
  7. ENV

    设置环境变量(容器内可使用):

    dockerfile 复制代码
    ENV MY_VAR=my_value
  8. ADD

    将文件或目录从宿主机复制到镜像中,支持从 URL 下载文件,并能自动解压归档文件:

    dockerfile 复制代码
    ADD myfile.tar.gz /app
  9. COPY

    将本地文件或目录复制到镜像中(仅本地文件,无解压):

    dockerfile 复制代码
    COPY . /app
  10. VOLUME

    声明容器内的挂载点(创建匿名卷):

    dockerfile 复制代码
    VOLUME ["/data"]
  11. USER

    设置容器内运行命令时的用户:

    dockerfile 复制代码
    USER root
  12. WORKDIR

    设置后续指令的工作目录(类似cd):

    dockerfile 复制代码
    WORKDIR /app
  13. ONBUILD

    设置当该镜像作为基础镜像时,后续 Dockerfile 执行的命令:

    dockerfile 复制代码
    ONBUILD RUN echo "Building from base image"
  14. HEALTHCHECK

    设置容器的健康检查:

    dockerfile 复制代码
    HEALTHCHECK CMD curl --fail http://localhost:8080 || exit 1

关键指令区别

  • RUN vs CMD vs ENTRYPOINT
    • RUN:构建镜像时执行(如安装软件);
    • CMD:容器启动时执行,可被docker run后的命令覆盖(如docker run xxx bash会覆盖CMD);
    • ENTRYPOINT:容器启动时执行,不可被覆盖,若需传参需用docker run --entrypoint
  • ADD vs COPY
    • ADD支持URL下载和自动解压(如.tar.gz),功能更丰富;
    • COPY仅复制本地文件,功能简单,推荐优先使用(避免意外解压)。

5.3.3 Dockerfile实战示例(构建Apache镜像)

以构建一个基于CentOS 7的Apache(httpd)镜像为例,完整流程如下:

  1. 创建工作目录
bash 复制代码
mkdir -p /opt/apache && cd /opt/apache
  1. 编写Dockerfile
bash 复制代码
vim Dockerfile
#基于的基础镜像
FROM centos:7
#维护镜像的用户信息
MAINTAINER this is apache image <cwh>
#镜像操作指令安装apache软件,需提前准备国内源文件
ADD CentOS-Base.repo /etc/yum.repos.d/
RUN yum clean all
#RUN yum -y update
RUN yum -y install httpd
#开启 80 端口
EXPOSE 80
#复制网站首页文件
ADD index.html /var/www/html/index.html


//方法一:
#将执行脚本复制到镜像中
ADD run.sh /opt/run.sh
#启动容器时执行脚本
CMD sh /opt/run.sh

//方法二:
ENTRYPOINT [ "/usr/sbin/apachectl" ]
CMD ["-D", "FOREGROUND"]

//方法三
# 启动 httpd 服务
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
bash 复制代码
准备执行脚本(方式一)
vim run.sh
#!/bin/bash
rm -rf /run/httpd/*							#清理httpd的缓存
/usr/sbin/apachectl -D FOREGROUND			#指定为前台运行
#因为Docker容器仅在它的1号进程(PID为1)运行时,会保持运行。如果1号进程退出了,Docker容器也就退出了。

# 准备网站页面
echo "this is test web" > index.html

5.3.4 基于Dockerfile构建镜像

使用docker build命令构建镜像,格式:docker build -t 镜像名:标签 构建上下文路径.表示当前目录为构建上下文)。

bash 复制代码
# 构建镜像(镜像名httpd:centos,标签centos)注意末尾的.
docker build -t httpd:centos ./

# 查看构建的镜像
docker images
# 输出示例:
# REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
# httpd        centos    9e154b3b93e6   8 seconds ago    493MB
bash 复制代码
# 新镜像运行容器
docker run -d -p 1216:80 httpd:centos

# 测试
http://192.168.10.14:1216/


5.3.5 Docker镜像分层与缓存机制解析

  • 分层机制 :Dockerfile中的每条指令对应一层镜像,例如:
    1. FROM centos:7 → 基础层;
    2. RUN yum install -y httpd → 安装层;
    3. COPY index.html /var/www/html/ → 复制层。
  • 缓存机制
    • 若Dockerfile指令未变化,且依赖的文件(如index.html)未修改,Docker会复用缓存层;
    • 若某一层指令或文件变化,该层及之后的所有层都会重新构建(缓存失效)。
  • 镜像层是不可变的
    • 删除容器时只会删除其上面的读写层,底层的镜像层不会丢失。
  • 优化建议
    1. 频繁变化的指令(如COPY)放在Dockerfile末尾,减少重新构建的层数;
    2. 合并RUN指令(用&&连接),减少镜像层数(如合并yum installyum clean);
    3. 使用.dockerignore文件排除不需要的文件(如node_modules、日志文件),减小构建上下文体积。

5.4 Docker镜像创建方式总结

  • 基于现有镜像创建:通过修改容器并提交为新的镜像。
  • 基于本地模板创建:从模板文件导入创建镜像。
  • 基于 Dockerfile 创建:通过编写 Dockerfile 来定制镜像,支持自动化构建。

Docker 命令无法补全解决方案

  1. 首先安装 bash-completion 包:
bash 复制代码
yum install -y bash-completion
  1. 重新加载 bash 配置使补全生效:
bash 复制代码
source /etc/profile.d/bash_completion.sh
  1. 之后测试 Docker 命令补全是否正常工作:
bash 复制代码
docker run --cpu-  # 按Tab键应该会显示补全选项

总结

本文系统梳理了Docker的六大核心功能:网络管理、资源控制、数据卷容器、端口映射、容器互联和镜像创建,每个模块都从"原理+实战"角度出发,提供了可直接复用的命令和配置示例。

Docker的核心价值在于"隔离"与"标准化"------通过网络隔离实现容器间通信控制,通过资源限制避免宿主机资源耗尽,通过数据卷实现数据持久化,通过Dockerfile实现镜像的标准化构建。这些功能看似独立,实则相辅相成,共同构成了Docker容器化应用的基础。

建议大家在学习过程中"边学边练":每掌握一个知识点,就动手执行命令验证效果(如创建自定义网络、设置CPU限制、编写Dockerfile),只有通过实战才能真正理解Docker的底层逻辑。后续我还会分享Docker Compose、Docker Swarm等容器编排工具的使用,欢迎持续关注!

相关推荐
曲幽3 小时前
别再用网页翻译看源码了!你的私人翻译神器LibreTranslate,部署避坑指南来了
python·docker·web·pot·translate·libretranslate·arogstranslate
XIAOHEZIcode1 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
用户0328472220702 天前
如何搭建本地yum源(上)
运维
武子康2 天前
调查研究-183 Apple container:Mac 上用轻量 VM 跑 Linux 容器,Swift 会改写本地容器体验吗?
docker·容器·apple
大树885 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠5 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质5 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
Inhand陈工5 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
Alsn865 天前
等待学习-学习目录:Docker 容器安全攻防
学习·安全·docker
网络研究院5 天前
2026年网络安全
网络·安全·法律·法规·趋势·发展