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

标签 docker

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

docker run -p 2000-3000:2000-3000 myapp

当我运行这个 docker 命令时,我的开发虚拟机停止运行。

然后查看进程,每个端口都有一个 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

它们都是 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)

每个进程使用一 block 私有(private)内存(/proc/$pid/smaps中的Pss)

$ 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

每个端口也有 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
...

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

最佳答案

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

Nigel Brown 在 The docker-proxy 上写了一篇详细的文章这解释了如何以及为什么。

The docker-proxy, then, is a 'catch all' method for allowing container port forwarding to the Docker host. However, it's generally considered that the docker-proxy is an inelegant solution to the problems highlighted above, and when a large range of container ports are exposed, it consumes considerable memory. An attempt was previously made to remove the dependency for the docker-proxy, but this fell foul of the limitations of the aged kernel in RHEL 6.x and CentOS 6.x, which the Docker project feels duty bound to support. Hence, the docker-proxy remains a major constituent part of the Docker experience in all Docker versions up to the current version 1.5. As I write, version 1.6 is due for imminent release, and there have been moves to remove the automatic requirement for the docker-proxy, which I'll cover in another article.

Docker 现在为 disable the userland proxy with --userland-proxy=false 添加了一个守护程序运行时选项。 .这是在 v1.7 中引入的。

好像有一个few边缘案例 bugsexist禁用用户态代理时。还有IPV6 issues

有一个开放的 GitHub 问题用于禁用 userland proxy by default (Docker 不再支持 RHEL6)。

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

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

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

proxy implementationpackage看起来很干净并且使用内置的 Go 功能,所以这可能只是 Go 的初始垃圾收集限制,允许它增长到 ~ 5MB。

编辑:内存使用量有been improved in Docker 1.12 .每个端口仍然有一个进程,但每个进程现在只使用约 750k 的私有(private)内存空间。

关于docker - 为什么 Docker 运行这么多进程来将端口映射到我的应用程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37770567/

相关文章:

python - 尝试从 dockerized Python 脚本连接时出现 FTP 错误 "500 Illegal PORT command"

docker-compose exec 失败 : executable file not found in $PATH

docker - 与 Portainer : "resource is online but isn' t responding to connection attempts"连接

docker - docker-compose 网络名称的最大长度是多少?

ubuntu - Docker 上的 Cassandra - nodetool 连接问题

node.js - 在 docker nodejs 中没有安装

docker - 我可以将相同的卷挂载到多个 docker 容器吗

docker - 需要docker来构建docker吗?

tomcat - 在启动期间将部署文件传递到 docker 容器中

docker - Docker Swarm创建真实集群:已注册和已删除