web-dev-qa-db-fra.com

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?

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 j'exécute 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 comme un 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?

24
kahara

Grâce à #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 à ce 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 ligne EXPOSE dans Dockerfile n'est pas nécessaire car le mécanisme "expose" est utilisé pour lier les conteneurs .

29
kahara