为什么Docker运行这么多进程来将端口映射到我的应用程序?

Mat*_*att 10 docker

我有一个在容器中运行的应用程序,需要将一系列端口映射到它.

docker run -p 2000-3000:2000-3000 myapp
Run Code Online (Sandbox Code Playgroud)

当我运行这个docker命令时,我的开发vm会停止运行.

然后查看进程,docker-proxy每个端口都有一个运行

$ ps -ef 
...
root     19796  7835  0 03:31 ?        00:00:00 docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 4000 -container-ip 172.17.0.4 -container-port 3000
root     19804  7835  0 03:31 ?        00:00:00 docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 3999 -container-ip 172.17.0.4 -container-port 2999
root     19812  7835  0 03:31 ?        00:00:00 docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 3998 -container-ip 172.17.0.4 -container-port 2998
...

$ ps -ef | grep -c docker-proxy
1003
Run Code Online (Sandbox Code Playgroud)

他们都是docker守护进程的孩子

root@default-docker:~# pstree -p
init(1)-+-VBoxService(1251)
        |-acpid(1277)
        |-crond(1235)
        |-docker(7835)-+-docker-containe(7841)-+-docker-containe(8031)---gitlab-ci-multi(8048)
        |              |                       |-docker-containe(9678)---mysqld(9693)
        |              |                       `-docker-containe(20577)---registry(20591)
        |              |-exe(19796)
        |              |-exe(19804)
        |              |-exe(19812)
Run Code Online (Sandbox Code Playgroud)

每个进程使用一块私有内存(Pssin /proc/$pid/smaps)

$ for pid in $(pgrep exe); do printf "pid:%5s mem:%5s\n" $pid $(awk '/^Pss:/{t=t+$2}END{print t}' /proc/$pid/smaps); done
...
pid:28534 mem: 4011
pid:28543 mem: 3817
pid:28552 mem: 4001
Run Code Online (Sandbox Code Playgroud)

每个端口都有适用的DNAT规则,这就是我希望在具有专用网络的Linux主机上完成此操作的方法.

root@default-docker:~# iptables -t nat -vnL DOCKER
Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination         
...
    0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:4000 to:172.17.0.4:3000
    0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:3999 to:172.17.0.4:2999
    0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:3998 to:172.17.0.4:2998
...
Run Code Online (Sandbox Code Playgroud)

为什么Docker每端口启动一个进程?
为什么每个进程需要4-6MB的内存?
为什么Docker完全使用用户空间进程?

Mat*_*att 6

为什么Docker完全使用用户空间进程?

Nigel Brown写了一篇关于docker-proxy的详细文章,解释了如何以及为什么.

docker-proxy,然后,是一个"捕获所有"用于允许容器端口转发到主机多克尔方法.然而,通常认为对于docker-proxy上面强调的问题是一种不优雅的解决方案,并且当暴露大量容器端口时,它消耗相当大的内存.之前曾尝试删除对该依赖项的依赖docker-proxy,但这与RHEL 6.x和CentOS 6.x中老化内核的限制相违背,Docker项目认为这些内容必须支持.因此,在docker-proxy当前版本1.5之前, 仍然是所有Docker版本中Docker体验的主要组成部分.在我写的时候,版本1.6即将发布,并且已经采取行动删除了自动要求docker-proxy,我将在另一篇文章中介绍.

Docker现在包含一个守护程序运行时选项,用于禁用userland代理--userland-proxy=false.这是在v1.7中引入的.

似乎有一个少数边缘情况的错误存在禁用用户级代理时.还有IPV6问题

有一个打开的GitHub问题,默认情况下禁用userland代理(Docker不再支持RHEL6).

为什么Docker每端口启动一个进程?

除了以这种方式实现之外,似乎没有其他理由.单个进程应该能够处理容器的所有端口映射

为什么每个进程需要4-6MB的内存?

代理实现包装看起来干净和内置转到功能使用所以这可能只是转到最初的垃圾收集范围,允许它增长到5MB〜.

编辑:Docker 1.12中的内存使用情况有所改善.每个端口仍然有一个进程,但每个进程现在只使用~750k的私有内存空间.