Pourquoi un conteneur Docker exécutant un serveur expose-t-il le port au monde extérieur alors que ce port est bloqué par iptables?

24

J'ai un problème avec MySQL fonctionnant à l'intérieur d'un conteneur Docker. Mon image de test est construite à partir du Dockerfile suivant:

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

FROM ubuntu:12.10
MAINTAINER Joni Kahara <[email protected]> 

# 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"]

Après avoir construit une image à partir du fichier ci-dessus, je l'exécute avec:

docker run -p 3306:3306 asyncfi/magento-mysql

Après quoi tout est gonflé et je peux me connecter à cette instance de MySQL depuis la machine locale. Cependant, je peux également me connecter depuis n'importe quelle autre machine.

J'ai configuré mon pare-feu pour filtrer tout sauf le trafic entrant dans des ports spécifiques (SSH "caché", HTTP, HTTPS), et ce filtrage semble en fait fonctionner; par exemple, si je lance un serveur de développement Django sur le port 1234, je peux me connecter depuis la machine locale, mais pas depuis l'extérieur. Le pare-feu semble donc filtrer les paquets lorsqu'ils sont destinés à un serveur qui s'exécute en tant que processus "ordinaire", mais pas lorsque le serveur s'exécute à l'intérieur d'un conteneur.

iptables -L -v --line-numbers dit ce qui suit:

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

La version Docker est:

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

Pourquoi le port MySQL est-il exposé au monde extérieur?

kahara
la source

Réponses:

28

Grâce aux utilisateurs de la chaîne #docker IRC Michael Crosby et Paul Czar, je suis maintenant en mesure de répondre à ma propre question. Le problème réside dans le fait que j'ai exécuté le conteneur comme ceci:

docker run -p 3306:3306 asyncfi/magento-mysql

Cela publie le port du conteneur vers toutes les interfaces de la machine hôte, ce qui n'est certainement pas ce que je cherchais pour le moment. Pour se lier uniquement à localhost, il était nécessaire d'exécuter le conteneur comme suit:

docker run -p 127.0.0.1:3306:3306 asyncfi/magento-mysql

De plus, la EXPOSEligne dans Dockerfile n'est pas nécessaire car le mécanisme "expose" est utilisé pour lier les conteneurs .

kahara
la source