【docker集群应用】Docker网络与资源控制

文章目录

Docker 网络

Docker 网络实现原理

Docker 使用 Linux 桥接技术,在宿主机上虚拟一个名为 docker0 的 Docker 容器网桥。当 Docker 启动一个容器时,会根据 docker0 网桥的网段分配给容器一个 IP 地址(Container-IP)。由于同一宿主机内的容器都连接到同一个网桥,因此容器之间可以通过各自的 Container-IP 直接通信。

Docker 网桥是虚拟的,不是真实存在的网络设备,因此外部网络无法直接寻址到它,这意味着外部网络无法直接通过 Container-IP 访问容器。如果希望外部网络能够访问容器,可以通过端口映射将容器端口映射到宿主主机,即使用 docker run 命令的 -p-P 参数。

端口映射示例

bash 复制代码
# 随机映射端口(从32768开始)
docker run -d --name test1 -P nginx

# 指定映射端口
docker run -d --name test2 -p 43000:80 nginx

通过 docker ps -a 可以查看容器的端口映射情况,例如:

bash 复制代码
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS                   NAMES
9d3c04f57a68   nginx     "/docker-entrypoint...."   4 seconds ago    Up 3 seconds    0.0.0.0:43000->80/tcp   test2
b04895f870e5   nginx     "/docker-entrypoint...."   17 seconds ago   Up 15 seconds   0.0.0.0:49170->80/tcp   test1

可以通过浏览器访问 http://192.168.80.10:43000http://192.168.80.10:49170 来访问对应的容器。

查看容器的输出和日志信息

使用 docker logs 命令可以查看容器的输出和日志信息:

bash 复制代码
docker logs 容器的ID/名称

Docker 的网络模式

使用 --net--network 选项指定容器的网络模式

  1. Host 模式
    • 相当于 Vmware 中的桥接模式,与宿主机在同一个网络中,但没有独立 IP 地址。
    • 容器与宿主机共享同一个 Network Namespace,使用宿主机的 IP 和端口。
    • 使用 --net=host 指定。
  2. Container 模式
    • 新创建的容器与已存在的容器共享一个 Network Namespace。
    • 共享 IP、端口范围等,但文件系统、进程列表等仍然隔离。
    • 使用 --net=container:NAME_or_ID 指定。
  3. None 模式
    • 容器拥有自己的 Network Namespace,但不进行任何网络配置。
    • 只有 lo 回环网络,没有其他网卡。
    • 无法联网,但保证了容器的安全性。
    • 使用--net=none指定。
  4. Bridge 模式
    • Docker 的默认网络模式。
    • 容器使用独立的 Network Namespace,并连接到 docker0 虚拟网卡。
    • 通过 docker0 网桥和 iptables nat 表配置与宿主机通信。
    • 为每个容器分配 IP,并通过 veth pair 设备与 docker0 网桥连接。
    • 默认设置,可省略或使用 --net=bridge 指定。
  5. 自定义网络
    • 允许用户自定义网络配置,如指定子网、网关等。

    • 可以使用 docker network create 命令创建自定义网络。

    • 示例:

      bash 复制代码
      # 创建自定义网络
      docker network create --subnet=172.18.0.0/16 --opt "com.docker.network.bridge.name"="docker1" mynetwork
      #docker1 为执行 ifconfig -a 命令时,显示的网卡名,如果不使用 --opt 参数指定此名称,那你在使用 ifconfig -a 命令查看网络信息时,看到的是类似 br-110eb56a0b22 这样的名字,这显然不怎么好记。
      #mynetwork 为执行 docker network list 命令时,显示的bridge网络模式名称。
      # 使用指定 IP 运行容器
      docker run -itd --name test4 --net mynetwork --ip 172.18.0.10 centos:7 /bin/bash

查看 Docker 网络列表

使用 docker network lsdocker network list 命令可以查看 Docker 网络列表:

bash 复制代码
docker network ls
# 或
docker network list

示例输出:

bash 复制代码
NETWORK ID     NAME      DRIVER    SCOPE
2b4359d229c6   bridge    bridge    local
0fa580365d39   host      host      local
cc13aa84a223   none      null      local

总结

  • Host:容器使用宿主机的 IP 和端口。
  • Container:容器与另一个指定容器共享 IP 和端口范围。
  • None:关闭容器的网络功能。
  • Bridge :默认模式,为每个容器分配 IP 并连接到 docker0 虚拟网桥。
  • 自定义网络:允许用户自定义网络配置。

Docker 容器网络命名空间示例

创建并运行容器
bash 复制代码
docker run -itd --name test1 centos:7 /bin/bash  # 创建名为 test1 的容器
查看容器列表
bash 复制代码
docker ps -a

输出示例:

CONTAINER ID   IMAGE      COMMAND       CREATED      STATUS       PORTS     NAMES
3ed82355f811   centos:7   "/bin/bash"   5 days ago   Up 6 hours             test1
查看容器进程号
bash 复制代码
docker inspect -f '{{.State.Pid}}' 3ed82355f811  # 查看 test1 容器的进程号

输出示例:

25945
查看容器的命名空间编号
bash 复制代码
ls -l /proc/25945/ns  # 查看 test1 容器的进程、网络、文件系统等命名空间编号

输出示例:

lrwxrwxrwx 1 root root 0 1月   7 11:29 ipc -> ipc:[4026532572]
lrwxrwxrwx 1 root root 0 1月   7 11:29 mnt -> mnt:[4026532569]
lrwxrwxrwx 1 root root 0 1月   7 11:27 net -> net:[4026532575]
lrwxrwxrwx 1 root root 0 1月   7 11:29 pid -> pid:[4026532573]
lrwxrwxrwx 1 root root 0 1月   7 12:22 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 1月   7 11:29 uts -> uts:[4026532570]
创建并运行共享网络命名空间的容器
bash 复制代码
docker run -itd --name test2 --net=container:3ed82355f811 centos:7 /bin/bash  # 创建名为 test2 的容器,并与 test1 共享网络命名空间
查看容器列表
bash 复制代码
docker ps -a

输出示例:

CONTAINER ID   IMAGE      COMMAND       CREATED          STATUS          PORTS     NAMES
ff96bc43dd27   centos:7   "/bin/bash"   48 seconds ago   Up 46 seconds             test2
3ed82355f811   centos:7   "/bin/bash"   58 minutes ago   Up 58 minutes             test1
查看容器进程号
bash 复制代码
docker inspect -f '{{.State.Pid}}' ff96bc43dd27  # 查看 test2 容器的进程号

输出示例:

27123
查看容器的命名空间编号
bash 复制代码
ls -l /proc/27123/ns  # 查看 test2 容器的进程、网络、文件系统等命名空间编号

输出示例:

lrwxrwxrwx 1 root root 0 1月   7 12:27 ipc -> ipc:[4026532692]
lrwxrmxrwx 1 root root 0 1月   7 12:27 mnt -> mnt:[4026532690]
lrwxrwxrwx 1 root root 0 1月   7 12:27 net -> net:[4026532575]
lrwxrwxrwx 1 root root 0 1月   7 12:27 pid -> pid:[4026532693]
lrwxrwxrwx 1 root root 0 1月   7 12:27 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 1月   7 12:27 uts -> uts:[4026532691]

Docker 资源控制

Docker 通过 Cgroups(Control Groups)机制来控制和限制容器使用的资源,包括 CPU、内存和磁盘 IO。以下是对这些资源控制的详细解释和示例。

1. CPU 资源控制

1.1 设置 CPU 使用率上限

  • CFS(Completely Fair Scheduler):Linux 使用CFS来调度各个进程对CPU的使用,CFS默认的调度周期是100ms。
  • --cpu-period:设置CPU调度周期(微秒),有效范围是1ms到1s(1000到1000000)。
  • --cpu-quota :设置每个周期内容器能使用的CPU时间(微秒),值必须大于等于1000。
    示例:
bash 复制代码
docker run -itd --name test6 --cpu-quota 50000 centos:7 /bin/bash
bash 复制代码
docker ps -a
CONTAINER ID   IMAGE      COMMAND       CREATED      STATUS       PORTS     NAMES
3ed82355f811   centos:7   "/bin/bash"   5 days ago   Up 6 hours             test5
bash 复制代码
cd /sys/fs/cgroup/cpu/docker/3ed82355f81151c4568aaa6e7bc60ba6984201c119125360924bf7dfd6eaa42b/
cat cpu.cfs_quota_us 
-1
bsh 复制代码
cat cpu.cfs_period_us 
100000

这将使容器 test6 在每个CFS周期中最多使用50%的CPU时间。
相关参数
cpu.cfs_period_us:cpu分配的周期(微秒,所以文件名中用 us 表示),默认为100000。
cpu.cfs_quota_us:表示该cgroups限制占用的时间(微秒),默认为-1,表示不限制。 如果设为50000,表示占用50000/100000=50%的CPU。

进行CPU压力测试
bash 复制代码
docker exec -it 3ed82355f811 /bin/bash

vim /cpu.sh
#!/bin/bash
i=0
while true
do
let i++
done

chmod +x /cpu.sh
./cpu.sh

top	#可以看到这个脚本占了很多的cpu资源

设置50%的比例分配CPU使用时间上限

bash 复制代码
docker run -itd --name test6 --cpu-quota 50000 centos:7 /bin/bash#可以重新创建一个容器并设置限额

cd /sys/fs/cgroup/cpu/docker/3ed82355f81151c4568aaa6e7bc60ba6984201c119125360924bf7dfd6eaa42b/
echo 50000 > cpu.cfs_quota_us
docker exec -it 3ed82355f811 /bin/bash
./cpu.sh
bash 复制代码
top	#可以看到cpu占用率接近50%,cgroups对cpu的控制起了效果

在多核情况下,如果允许容器进程完全占用两个 CPU, 则可以将 cpu-period 设置为 100000( 即 0.1 秒), cpu-quota设置为 200000(0.2 秒)。

1.2 设置 CPU 资源占用比

  • --cpu-shares :指定CPU份额,默认值为1024,值为1024的倍数。当多个容器竞争CPU资源时,份额高的容器获得CPU时间片的几率更高。
    示例:
bash 复制代码
#创建两个容器为 c1 和 c2,若只有这两个容器,设置容器的权重,使得c1和c2的CPU资源占比为1/3和2/3。
docker run -itd --name c1 --cpu-shares 1024 centos:7
docker run -itd --name c2 --cpu-shares 2048 centos:7

这将使容器 c2 在CPU资源竞争中获得比容器 c1 多一倍的机会。

bash 复制代码
#分别进入容器,进行压力测试
yum install -y epel-release
yum install -y stress
stress -c 4				#产生四个进程,每个进程都反复不停的计算随机数的平方根
bash 复制代码
#查看容器运行状态(动态更新)
docker stats
CONTAINER ID   NAME             CPU %     MEM USAGE / LIMIT     MEM %     NET I/O          BLOCK I/O         PIDS
c3ee18e65852   c2               66.50%    5.5MiB / 976.3MiB     0.56%     20.4MB / 265kB   115MB / 14.2MB    4
bb02d3b345d8   c1               32.68%    2.625MiB / 976.3MiB   0.27%     20.4MB / 325kB   191MB / 12.7MB    4
  • 可以看到在 CPU 进行时间片分配的时候,容器 c2 比容器 c1 多一倍的机会获得 CPU 的时间片。
  • 但分配的结果取决于当时主机和其他容器的运行状态, 实际上也无法保证容器 c1 一定能获得 CPU 时间片。比如容器 c1 的进程一直是空闲的,那么容器 c2 是可以获取比容器 c1 更多的 CPU 时间片的。极端情况下,例如主机上只运行了一个容器,即使它的 CPU 份额只有 50,它也可以独占整个主机的 CPU 资源。
  • Cgroups 只在容器分配的资源紧缺时,即在需要对容器使用的资源进行限制时,才会生效。因此,无法单纯根据某个容器的 CPU 份额来确定有多少 CPU 资源分配给它,资源分配结果取决于同时运行的其他容器的 CPU 分配和容器中进程运行情况。

1.3 设置容器绑定指定的 CPU

  • --cpuset-cpus :允许容器在指定的CPU上运行。
    示例:
bash 复制代码
docker run -itd --name test7 --cpuset-cpus 1,3 centos:7 /bin/bash

这将使容器 test7 只能在CPU 1和CPU 3上运行。

#进入容器,进行压力测试
yum install -y epel-release
yum install stress -y
stress -c 4

然后退出容器,执行 top 命令再按 1 查看CPU使用情况。

2. 内存使用限制

  • -m 或 --memory:限制容器可以使用的最大内存。

示例

bash 复制代码
docker run -itd --name test8 -m 512m centos:7 /bin/bash
docker stats
  • --memory-swap :正常情况下,--memory-swap 的值包含容器可用内存和可用 swap。
    如果 --memory-swap 设置为 0 或者 不设置,则容器可以使用的 swap 大小为 -m 值的两倍。
    如果 --memory-swap 的值和 -m 值相同,则容器不能使用 swap。
    如果 --memory-swap 值为 -1,它表示容器程序使用的内存受限,而可以使用的 swap 空间使用不受限制(宿主机有多少 swap 容器就可以使用多少)。
    强调一下,--memory-swap 是必须要与 --memory 一起使用的。

示例 :容器 test8 最大使用512M内存,容器 test8_swap 可以使用300M内存和700M swap。

bash 复制代码
docker run -itd --name test8 -m 512m centos:7 /bin/bash
docker run -itd --name test8_swap -m 300m --memory-swap=1g centos:7 /bin/bash

所以 -m 300m --memory-swap=1g 的含义为:容器可以使用 300M 的物理内存,并且可以使用 700M(1G - 300)的 swap。

3. 磁盘 IO 配额控制

  • --device-read-bps:限制某个设备上的读速度(bps),单位可以是kb、mb或gb。
  • --device-write-bps(在Docker 25版本之后已无效):限制某个设备上的写速度(bps)。
  • --device-read-iops:限制读某个设备的IOPS(每秒读次数)。
  • --device-write-iops :限制写入某个设备的IOPS(每秒写次数)。
    示例:
bash 复制代码
docker run -itd --name test9 --device-read-bps /dev/sda:1M centos:7 /bin/bash
docker run -it --name test10 --device-write-iops /dev/sda:1000 centos:7 /bin/bash

这将使容器 test9 对设备 /dev/sda 的读速度限制为1MB/s,容器 test10 对设备 /dev/sda 的写IOPS限制为1000次/秒。

通过dd来验证写速度

bash 复制代码
dd if=/dev/zero of=test.out bs=1M count=10 oflag=direct#添加oflag参数以规避掉文件系统cache
10+0 records in
10+0 records out
10485760 bytes (10 MB) copied, 10.0025 s, 1.0 MB/s

清理 Docker 占用的磁盘空间

使用 docker system prune -a 命令可以清理关闭的容器、无用的数据卷和网络,释放磁盘空间。

bash 复制代码
docker system prune -a
相关推荐
勤奋的凯尔森同学1 小时前
webmin配置终端显示样式,模仿UbuntuDesktop终端
linux·运维·服务器·ubuntu·webmin
月光水岸New2 小时前
Ubuntu 中建的mysql数据库使用Navicat for MySQL连接不上
数据库·mysql·ubuntu
狄加山6752 小时前
数据库基础1
数据库
我爱松子鱼2 小时前
mysql之规则优化器RBO
数据库·mysql
chengooooooo2 小时前
苍穹外卖day8 地址上传 用户下单 订单支付
java·服务器·数据库
Rverdoser3 小时前
【SQL】多表查询案例
数据库·sql
Galeoto3 小时前
how to export a table in sqlite, and import into another
数据库·sqlite
人间打气筒(Ada)4 小时前
MySQL主从架构
服务器·数据库·mysql
Bright16684 小时前
centos9安装k8s集群
云原生·容器·kubernetes
leegong231114 小时前
学习PostgreSQL专家认证
数据库·学习·postgresql