为什么运行服务器的 Docker 容器会向外界公开端口,即使该端口被 iptables 阻止?

kah*_*ara 24 iptables docker

我在 Docker 容器内运行 MySQL 时遇到问题。我的测试映像是从以下 Dockerfile 构建的:

# See: https://index.docker.io/u/brice/mysql/

FROM ubuntu:12.10
MAINTAINER Joni Kahara <joni.kahara@async.fi> 

# Because docker replaces /sbin/init: https://github.com/dotcloud/docker/issues/1024
RUN dpkg-divert --local --rename --add /sbin/initctl
RUN ln -s /bin/true /sbin/initctl

RUN apt-get update
RUN apt-get upgrade -y

RUN apt-get -y install mysql-server

RUN sed -i -e"s/^bind-address\s*=\s*127.0.0.1/bind-address = 0.0.0.0/" /etc/mysql/my.cnf

RUN /usr/bin/mysqld_safe & \
    sleep 10s && \
    mysql -e "GRANT ALL ON *.* to 'root'@'%'; FLUSH PRIVILEGES;"

EXPOSE 3306

VOLUME ["/var/lib/mysql", "/var/log/mysql"]

CMD ["mysqld_safe"]
Run Code Online (Sandbox Code Playgroud)

从上面的文件构建图像后,我运行它:

docker run -p 3306:3306 asyncfi/magento-mysql
Run Code Online (Sandbox Code Playgroud)

之后一切都变好了,我可以从本地机器登录到这个 MySQL 实例。但是,我也可以从任何其他机器登录。

我已经设置了我的防火墙来过滤除进入特定端口(“隐藏的”SSH、HTTP、HTTPS)的流量之外的所有内容,并且这种过滤实际上似乎有效;例如,如果我在端口 1234 上运行 Django 开发服务器,那么我可以从本地机器连接,但不能从外部连接。因此,防火墙似乎在过滤数据包时,它们将被送往作为“普通”进程运行的服务器,但当服务器在容器内运行时则不会。

iptables -L -v --line-numbers 说明如下:

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1     2265  107K ACCEPT     all  --  lo     any     anywhere             anywhere
2     240K  319M ACCEPT     all  --  any    any     anywhere             anywhere             ctstate RELATED,ESTABLISHED
3       14  1040 ACCEPT     tcp  --  any    any     anywhere             anywhere             tcp dpt:<REDACTED>
4       21  1092 ACCEPT     tcp  --  any    any     anywhere             anywhere             tcp dpt:http
5        6   360 ACCEPT     tcp  --  any    any     anywhere             anywhere             tcp dpt:https
6      538 34656 LOG        all  --  any    any     anywhere             anywhere             limit: avg 5/min burst 5 LOG level debug prefix "iptables DROP: "
7      551 35424 DROP       all  --  any    any     anywhere             anywhere

Chain FORWARD (policy ACCEPT 5 packets, 296 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 ACCEPT     all  --  docker0 docker0  anywhere             anywhere
2     6752  396K ACCEPT     all  --  docker0 !docker0  anywhere             anywhere
3     125K  188M ACCEPT     all  --  any    docker0  anywhere             anywhere             ctstate RELATED,ESTABLISHED

Chain OUTPUT (policy ACCEPT 51148 packets, 14M bytes)
num   pkts bytes target     prot opt in     out     source               destination
Run Code Online (Sandbox Code Playgroud)

Docker 版本是:

Client version: 0.7.3
Go version (client): go1.2
Git commit (client): 8502ad4
Server version: 0.7.3
Git commit (server): 8502ad4
Go version (server): go1.2
Last stable version: 0.7.3
Run Code Online (Sandbox Code Playgroud)

为什么MySQL端口对外暴露?

kah*_*ara 29

感谢#docker IRC 频道用户 Michael Crosby 和 Paul Czar,我现在可以回答我自己的问题。问题在于我像这样运行容器:

docker run -p 3306:3306 asyncfi/magento-mysql
Run Code Online (Sandbox Code Playgroud)

这将容器的端口发布到主机的所有接口,这绝对不是我此时要寻找的。要仅绑定到 localhost,必须按如下方式运行容器:

docker run -p 127.0.0.1:3306:3306 asyncfi/magento-mysql
Run Code Online (Sandbox Code Playgroud)

此外EXPOSE,Dockerfile 中的行不是必需的,因为“公开”机制用于链接容器