Docker容器生产实践1——永远设置容器内存限制

2、一个进程是否使用了swap空间以及使用了多少swap空间,可以用/proc/$pid/ap中所有内存区域的swap值进行累加可以计算出

在默认情况下,docker容器并不会对容器内部进程使用的内存大小进行任何限制。对于PaaS系统而言,或者对于直接使用docker的用户而言,这非常危险。如果哪个业务容器,出现了内存泄漏;那么它可能会危害到整个主机系统,导致业务app容器所在的主机出现oom。本文将介绍着眼于docker对内存资源的使用,解释背后的原理。同时也给出k8s上如何配置内存限制的方法。

从docker容器中拷贝到宿主机上_docker导出文件到宿主机从docker容器中拷贝到宿主机上_docker导出文件到宿主机


从docker容器中拷贝到宿主机上_docker导出文件到宿主机


docker做的工作实际上是由runc完成的,docker 创建的hostconfig.json文件(也就是oci接口文件)中,有如下字段描述-m,--memory-reservation等内存资源限制参数:

通过下面参数可以为容器设置一个内存使用量硬大小,当超出这个大小时刻,linux系统会根据配置设置决定是否进入oom-killer状态。

docker runbash>cat /proc/24360/cgroup|grep memory --name zxy-docker -m 1g -it busybox bash

单位为:b,k,m和g

如果设置了-m参数,通常情况下如果容器使用内存量超过了设置的硬水线,那么linux的oom-killer触发,它将根据oom-score对容器内部进程进行oom kill。但是不影响宿主机上其他进程。

这个参数设置一定需要在容器run或者create过程中使用了-m参数才可以设置。设置了-m参数,如果容器使用内存超限了,那么oom-kill将触发。如果设置了--oom-kill-disable, 那么容器不会oom,但是此时容器内部申请内存的进程将hang,直到他们可以申请到内存(容器内其他进程释放了内存) 。

不要在没有使用-m的时候设置--oom-kill-disable 因为这会影响到宿主机的oom-killer

docker 设置容器的-m是通过设置memory cgoup的memory.limit_in_bytes实现的。在没有设置-m的时候这个值为-1,表示容器使用的内存不受限制。

`bash>docker run --name zxy-memoimit -it -m 1g docker-build:12.06 bash

bash>docker inspect zxy-memoimit|grep -i pid

“Pid”:24360

9:memory:/docker/xxxxx

bash>cd /sys/fs/cgroups/memory/docker/xxxx

bash> cat memory.limit_in_bytes

1073741824`

--oom-kill-disable参数实际设置的就是这是了同级目录之下的memory.oom_control,设置此参数就相当于做了如下动作

bash> echo 1 >memory.oom_control

对linux memory cgroup感兴趣的朋友可以参考:

一文

在上一节中,我们介绍了-m硬限制容器使用的内存资源。一旦设置了这个-m参数,那么容器内进程使用量超过这个数值,就会或者hang住。docker还提供了一种soft limit就是--memory-reservation,单位和-m一致。当设置了这个参数以后, 如果宿主机系统内存不足,有新的内存请求时刻,那么linux会尝试从设置了此参数的容器里回收内存,回收的办法就是swap了。那么如果此容器还在继续使用内存,那么此容器会遇到很大的性能下降 。

通常实践是设置--memory-reservevation 的值小于-m的值。

和-m参数一致,此参数docker也是借助于memory cgroup的memory.soft_limit_in_bytes 实现。

memory MemoryReservation MemorySwap MemorySwappiness

下文节选自

limits:

cpu: 100m

memory: 100Mi

`其中limits节限制memory设置的就是docker 容器的-m,而且k8s仅仅使用了-m参数其他参数都没有使用。

Docker网络

例如:

Docker网络

从a容器ping b容器

使用docker0网桥,docker0的默认网段是172.17.0.0,地址为172.17.0.1,通过bridge模式启动的容器,进入容器日内部并使用ip route show指令可以看到其使用的就是docker0的地址。

在宿主机上通过brctl show docker0可以看到docker0桥接的网卡与启动的容器的v一致。

容器之间的通讯:

1、数据包从a容器对应的v流到docker0

3、b容器的v收到广播并回复d2、docker0广播arp寻找b容器对应的地址ocker0自己就是目标

4、a容器与b容器建立连接并实现通信

容器与外网通讯

1、v数据流到docker0网桥

2、docker0网桥流量流向0

3、0流量流向对应的目标

只要是0可以访问到的,容器就可以访问到

直接使用宿主机的网络,无法指定出入的流量以及暴露的端口,默认暴露出去的地址是0.0.0.0:xxxx,可以直接访问(TODO())。

通过docker指令创建自定义的网桥,由于默认的bridge模式无法为container指定ip,所以需要通过自定义网桥的方式来实现,且自定义网桥可以限制容器之间的相互访问,跨网桥无法互相访问。

使用指定网桥的时候只要通过network指定网桥名称即可,且使用自定义的网桥可以指定容器的IP。并且由于是固定IP,就可以通过iptable来做各种的规则。

这个模式就是指定一个已有的容器,共享该容器的IP和端口。除了网络方面两个容器共享,其他的如文件系统,进程等还是隔离开的。

这个模式下,dokcer不为容器进行任何网络配置。需要我们自己为容器添加网卡,配置IP。

Docker是通过iptable的方式实现流量的控制的

通过添加iptable规则实现

该指令添加了一条nat规则,把所有来自 172.17.0.0/16 网段且即将流出本主机的数据包的源 IP 地址都修改为 10.0.0.100(建议通过添加自定义网桥的方式来做)。

直接通过-p的方式暴露一个端口出去,默认使用的是0.0.0.0,所有网卡均可访问,也可以在参数中指定特定的网卡,例如:-p 192.168.1.1:80:80来指定只能通过该网卡来访问。

查看nat表

iptables -L -n -t nat --line-numbers

查看路由规则

route -n