docker 限制
Docker是一个开源的应用容器引擎,允许开发者打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。容器是完全使用沙盒机制,相互之间不会有任何接口。在进行资源管理和限制方面,Docker提供了多种机制来限制容器的资源使用,包括CPU、内存、磁盘I/O以及网络带宽。下面是一些基本的资源限制方法:
--cpus
参数来限制容器可以使用的CPU资源。例如,docker run --cpus=".5" nginx
命令会限制nginx容器最多只能使用50%的CPU资源。docker run -d --cpus="0.5" --name test_cpu ubuntu /bin/sh -c "while true; do :; done"
97ad37f98476ceeaad63fcdea723fef082cf9521afcd3c7b572f93d05aeed1b2
docker stats 97ad37f98476ceeaad63fcdea723fef082cf9521afcd3c7b572f93d05aeed1b2
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
97ad37f98476 test_cpu 51.06% 356KiB / 31.34GiB 0.00% 866B / 0B 0B / 0B 1
--cpuset-cpus
参数可以指定容器可以使用的CPU核心。例如,docker run --cpuset-cpus="0-2,4" nginx
命令会限制nginx容器只能使用CPU的第1、2、3和第5个核心。docker run -d --cpuset-cpus="0-2,4" --cpus="0.5" --name test_cpu ubuntu /bin/sh -c "while true; do :; done"
docker inspect --format '{{.HostConfig.CpusetCpus}}' test_cpu
0-2,4
ps -eo %cpu,%mem,pid,cmd --sort=-%cpu |grep while
99.9 0.0 24905 /bin/sh -c while true; do :; done
0.0 0.0 30116 grep while
taskset -pc 24905
pid 24905's current affinity list: 0-2,4
--memory
或-m
参数可以限制容器使用的最大内存量。例如,docker run -m 256m nginx
命令会限制nginx容器最多只能使用256MB的内存。docker run --rm -d -m 400m --name test_cpu debian_with_stress /bin/sh -c " stress --vm 1 --vm-bytes 100M --vm-hang 0"
c6d45bcaaba0fb4178a541afdbbc7ab37ce70a7b968b66da4eb4b1b03f2b883e
docker stats c6d45bcaaba0fb4178a541afdbbc7ab37ce70a7b968b66da4eb4b1b03f2b883e
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
c6d45bcaaba0 test_cpu 0.00% 100.8MiB / 400MiB 25.21% 1.09kB / 0B 0B / 0B 3
--memory-swap
参数可以限制容器使用的内存加上交换区的总量。例如,docker run --memory="256m" --memory-swap="1g" nginx
命令会限制nginx容器使用的内存加上交换区的总量不超过1GB。docker run --rm -d --memory="500m" --memory-swap="1g" --name test_cpu debian_with_stress /bin/sh -c " stress --vm 1 --vm-bytes 400M --vm-hang 0"
正常
time dd if=/dev/zero of=/tmp/testfile bs=1M count=100 oflag=direct
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.149226 s, 703 MB/s
real 0m0.152s
user 0m0.001s
sys 0m0.037s
--device-read-bps
和--device-write-bps
参数来限制容器对特定设备的读写速率。例如,docker run --device-write-bps /dev/sda:1mb nginx
命令会限制nginx容器对/dev/sda设备的写速率不超过1MB/s。docker run --rm -it --device-write-bps /dev/vdb:1mb ubuntu /bin/bash
root@6f08d52efcac:/# time dd if=/dev/zero of=/tmp/testfile bs=1M count=100 oflag=direct
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 100.008 s, 1.0 MB/s
real 1m40.011s
user 0m0.043s
sys 0m0.000s
--device-read-iops
和--device-write-iops
参数可以限制容器对特定设备的读写操作次数。例如,docker run --device-write-iops /dev/sda:1000 nginx
命令会限制nginx容器对/dev/sda设备的写操作不超过每秒1000次。root@79698c20e560:/# time dd if=/dev/zero of=/mnt/testfile bs=4k count=10000 oflag=direct
10000+0 records in
10000+0 records out
40960000 bytes (41 MB, 39 MiB) copied, 0.687875 s, 59.5 MB/s
real 0m0.690s
user 0m0.018s
sys 0m0.167s
docker run --rm -it --device-read-iops /dev/vdb:500 --device-write-iops /dev/vdb:500 ubuntu /bin/bash
root@ea535a7335eb:/# time dd if=/dev/zero of=/mnt/testfile bs=4k count=10000 oflag=direct
10000+0 records in
10000+0 records out
40960000 bytes (41 MB, 39 MiB) copied, 19.9105 s, 2.1 MB/s
real 0m19.913s
user 0m0.001s
sys 0m0.470s
time dd if=/mnt/testfile of=/dev/null bs=4k iflag=direct
10000+0 records in
10000+0 records out
40960000 bytes (41 MB, 39 MiB) copied, 19.9077 s, 2.1 MB/s
real 0m19.910s
user 0m0.001s
sys 0m0.292s
Docker原生并不直接支持网络带宽的限制。但是,可以通过第三方工具如tc
(traffic control)来实现对容器网络带宽的限制。此外,Docker的网络插件机制允许使用不同的网络驱动来提供额外的网络功能,包括网络带宽限制。
Docker提供了灵活的资源限制选项,帮助用户更好地管理和分配容器资源。通过合理设置这些参数,可以确保容器应用的高效运行,同时避免单个容器占用过多资源而影响系统的稳定性。需要注意的是,合理的资源限制策略应该基于对应用性能需求的理解和测试。
如果你已经准备好尝试使用iptables
直接在宿主机上操作以添加端口映射到Docker容器,下面是一个基于Debian镜像的示例。请注意,这个过程涉及到底层的网络配置,如果操作不当可能会影响到宿主机和其他容器的网络连接。请确保你已经备份了重要数据,并且最好在一个测试环境中进行以下操作。
首先,创建并启动一个基于Debian镜像的Docker容器,我们假设你已经映射了一些初始端口,比如22和80。
docker run -d --name my-debian-container -p 22:22 -p 80:80 debian
Docker容器的网络命名空间并不直接暴露,但我们可以通过查找容器的进程ID(PID)来间接获取。首先,找到容器的PID:
docker inspect --format '{{ .State.Pid }}' my-debian-container
然后,你可以通过查看/proc/<PID>/ns/net
来确认网络命名空间,但这通常不是必需的,因为我们将直接在宿主机上操作iptables
。
现在,我们将使用iptables
在宿主机上为Docker容器添加新的端口映射规则。假设我们要添加8080端口的映射:
# 先找到Docker使用的网桥接口,通常是docker0
docker_network_interface=$(ip -o -4 addr show scope global | awk '{print $2}' | grep docker0)
# 添加iptables规则
iptables -t nat -A DOCKER -p tcp --dport 8080 -j DNAT --to-destination $(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my-debian-container):8080
iptables -t filter -A DOCKER -d $(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my-debian-container)/32 ! -i $docker_network_interface -o $docker_network_interface -p tcp -m tcp --dport 8080 -j ACCEPT
8083->8082
# 添加DNAT规则,将宿主机的8083端口流量转发到容器的8082端口
sudo iptables -t nat -A DOCKER -p tcp --dport 8083 -j DNAT --to-destination $(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my-debian-container):8082
# 添加允许规则,允许流向容器8082端口的流量
docker_network_interface=$(ip -o -4 addr show scope global | awk '{print $2}' | grep docker0)
sudo iptables -t filter -A DOCKER -d $(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my-debian-container)/32 ! -i $docker_network_interface -o $docker_network_interface -p tcp -m tcp --dport 8082 -j ACCEPT
这里,我们添加了两条iptables
规则:
iptables -t nat -L -n -v
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
32 1712 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
1 60 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
24 1521 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
0 0 MASQUERADE tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:80
0 0 MASQUERADE tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:22
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:172.17.0.2:80
0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:2200 to:172.17.0.2:22
22 1144 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:8080
iptables -t nat -L DOCKER -n -v | grep 'tcp dpt:' | awk '{print $11}'|awk -F ':' '{print $2}'
80
2200
8080
ss -tnlp | awk '{print $4}' | awk -F ':' '{print $2}' | grep -vE '^\s*$'
6010
6011
6012
6013
80
22
2200
docker0
网桥,你需要相应地调整命令中的网桥接口名称。请谨慎操作,并确保你理解每条命令的含义和潜在影响。
因篇幅问题不能全部显示,请点此查看更多更全内容