Docker-Bridge Network 02 Conteneur et communication externe

Cette section présente la communication entre le conteneur et l'extérieur en mode réseau de pont.

1. Avant-propos 2. Accès du conteneur à l'extérieur 2.1 Accès au réseau externe 2.2 Principe 2.3 Résumé d'une image 2.4 Capture de paquets 3. Accès externe au conteneur 3.1 Créer un conteneur nginx et accès de l'extérieur 3.2 Principe 3.3 Résumé d'une image 3.4 Capture de paquets 3.5 docker-proxy 4 .Résumé

1. Introduction

La section précédente a présenté le processus de communication entre les conteneurs. Le service est déployé dans le conteneur. Nous devons accéder au service de l'extérieur. Alors, comment le conteneur communique-t-il avec l'extérieur?

2. Accès des conteneurs à l'extérieur

Dans cette section, nous utilisons toujours le conteneur bbox1 pour les expériences. Tout d'abord, assurez-vous que la machine virtuelle Host1 peut accéder à Internet. Dans la section "Préparation de l'environnement Docker", j'ai présenté comment la machine virtuelle peut directement envoyer une requête ping à Baidu.
Pour clarifier, le réseau externe ne fait pas nécessairement référence à Internet, et externe et interne sont des concepts relatifs. Tout réseau autre que le réseau de conteneurs peut être appelé un réseau externe, tel que le réseau où se trouve Host1.

2.1 Accès à Internet

[root@docker1 ~]# docker exec -it bbox1 sh
/ # ping www.baidu.com
PING www.baidu.com (180.101.49.11): 56 data bytes
64 bytes from 180.101.49.11: seq=0 ttl=51 time=21.308 ms
64 bytes from 180.101.49.11: seq=1 ttl=51 time=24.613 ms

2.2 Principe

Rappelez la connexion réseau actuelle du conteneur:

Essayons d'analyser que bbox1 a envoyé un paquet ping. Selon la table de routage de bbox1, le paquet a été envoyé à docker0. Comment docker0 et enp0s3 sont-ils connectés?
Linux lui-même a des fonctions de routage et de transfert, donc en fait le système Linux lui-même peut être utilisé comme routeur. Exécutez la commande cat /proc/sys/net/ipv4/ip_forward, vous pouvez voir ip_forward = 1, indiquant que le système a activé le transfert de routage.
Ensuite, après que docker0 a envoyé le paquet de données, il doit être transmis conformément à la table de routage de l'hôte. La route par défaut de l'hôte pointe vers enp0s3, donc enp0s3 a reçu le paquet.
Je comprends personnellement qu'à ce moment, l'IP source du paquet de données sur enp0s3 est bbox1, l'IP de destination est baidu, et il devrait pouvoir atteindre baidu; mais lorsque baidu renvoie le paquet de réponse, il ne sait pas où se trouve cette IP de réseau privé. Aucune route de premier niveau ne peut être trouvée, donc enp0s3 doit exécuter SNAT avant d'envoyer un message ici.
Je ne comprends pas très bien le processus de retour spécifique. Certains étudiants qui comprennent clairement ont du mal à l'expliquer spécifiquement. Merci.
En ce qui concerne SNAT, nous devons mentionner les gros killer-IPtables du noyau Linux.
Exécution dans la machine virtuelle iptables -t nat -vnL, affichez la table nat.

Chain POSTROUTING (policy ACCEPT 21 packets, 1479 bytes)
 pkts bytes target     prot opt in   out      source            destination         
    3   202 MASQUERADE  all  --  *   !docker0  172.17.0.0/16     0.0.0.0/0 

Après que docker0 ait envoyé le message, il sera transmis via le routage du noyau linux et atteindra enp0s3. Avant d'atteindre enp0s3, il passera par la POSTROUTINGchaîne iptables pour SNAT, qui est la règle ci-dessus. L'idée principale est de remplacer l'IP et le MAC source par l'IP et le MAC d'enp0s3 après le routage en effectuant MASQUERADE (masquerade) sur les paquets avec l'IP source de 172.17.0.0/16 et l'IP de destination arbitraire.

2.3 Un résumé de l'image

  1. bbox1 ping Baidu, le message est envoyé à docker0;
  2. docker0 envoie le message, après le routage et le transfert du noyau et le traitement SNAT, l'IP et le MAC source du message sont remplacés par l'IP et le MAC d'enp0s3 pour atteindre enp0s3;
  3. Enp0s3 envoie un message pour visiter Baidu.

2.4 Capture de paquets

L'équipement et les adresses réseau actuels sont les suivants:

Équipement IP MAC
Container bbox1 172.17.0.2 02:42:ac:11:00:02
网桥docker0 172.17.0.1 02:42:a8:64:6c:32
虚拟机网卡enp0s3 192.168.0.11 08:00:27:70:b6:ef

在bbox1内部执行ping www.baidu.com

  • 在docker0上抓包:
[root@docker1 ~]# tcpdump -nei docker0 icmp
listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
12:49:11.669684 02:42:ac:11:00:02 > 02:42:a8:64:6c:32, ethertype IPv4 (0x0800), length 98: 172.17.0.2 > 180.101.49.11: ICMP echo request, id 9728, seq 0, length 64
12:49:11.697374 02:42:a8:64:6c:32 > 02:42:ac:11:00:02, ethertype IPv4 (0x0800), length 98: 180.101.49.11 > 172.17.0.2: ICMP echo reply, id 9728, seq 0, length 64
  • 在enp0s3上抓包:
[root@docker1 ~]# tcpdump -nei enp0s3 icmp
listening on enp0s3, link-type EN10MB (Ethernet), capture size 262144 bytes
12:49:11.669700 08:00:27:70:b6:ef > 48:0e:ec:3b:b3:41, ethertype IPv4 (0x0800), length 98: 192.168.0.11 > 180.101.49.11: ICMP echo request, id 9728, seq 0, length 64
12:49:11.697340 48:0e:ec:3b:b3:41 > 08:00:27:70:b6:ef, ethertype IPv4 (0x0800), length 98: 180.101.49.11 > 192.168.0.11: ICMP echo reply, id 9728, seq 0, length 64

从enp0s3的报文可以看出,源IP和MAC已经是enp0s3的了。

3.外部访问容器

3.1 创建nginx容器并从外部访问

创建一个nginx容器,执行docker run -it -d --name=nginx01 -p 8081:80 nginx该命令将容器的80端口映射到主机的8081端口。
从本虚拟机上curl 127.0.0.1:8081,能返回nginx欢迎信息。从另一台虚拟机上curl 192.168.0.11:8081,也能返回nginx欢迎信息。说明外部网络能访问nginx容器。

3.2 原理

使用了IPtables的DNAT功能。
执行iptables -t nat -vnL查看IPtables规则,可以发现目的端口8081被替换为172.17.0.4:80。

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
    0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8081 to:172.17.0.4:80

3.3 一张图总结

  1. 在Host2里面curl 192.168.0.11:8081,报文到达Host1的enp0s3;
  2. Host1的enp0s3发出报文后,经由内核的转发及DNAT处理,将目的IP替换成nginx01的IP和端口;
  3. docker0收到报文后,根据目的mac找到对应端口,送出报文到nginx01。

3.4 抓包

使用tcpdump,在Host1的网卡及docker0上抓包验证。

  • Host1的enp0s3
[root@docker1 ~]# tcpdump -nei enp0s3 tcp port 8081
listening on enp0s3, link-type EN10MB (Ethernet), capture size 262144 bytes
13:25:14.725366 08:00:27:d4:6f:d1 > 08:00:27:70:b6:ef, ethertype IPv4 (0x0800), length 74: 192.168.0.12.48392 > 192.168.0.11.tproxy: Flags [S], seq 1433025043, win 29200, options [mss 1460,sackOK,TS val 4294829465 ecr 0,nop,wscale 7], length 0
13:25:14.725559 08:00:27:70:b6:ef > 08:00:27:d4:6f:d1, ethertype IPv4 (0x0800), length 74: 192.168.0.11.tproxy > 192.168.0.12.48392: Flags [S.], seq 404119170, ack 1433025044, win 28960, options [mss 1460,sackOK,TS val 59419808 ecr 4294829465,nop,wscale 7], length 0
  • Host1的docker0
[root@docker1 ~]# tcpdump -nei docker0 tcp
listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
13:26:07.014766 02:42:a8:64:6c:32 > 02:42:ac:11:00:04, ethertype IPv4 (0x0800), length 74: 192.168.0.12.48396 > 172.17.0.4.http: Flags [S], seq 1839700092, win 29200, options [mss 1460,sackOK,TS val 4294881751 ecr 0,nop,wscale 7], length 0
13:26:07.015357 02:42:ac:11:00:04 > 02:42:a8:64:6c:32, ethertype IPv4 (0x0800), length 74: 172.17.0.4.http > 192.168.0.12.48396: Flags [S.], seq 3312305882, ack 1839700093, win 28960, options [mss 1460,sackOK,TS val 59472098 ecr 4294881751,nop,wscale 7], length 0

可以看出,docker0上收到的报文,目的IP及MAC已经是nginx01的了。

3.5 docker-proxy

注意:对于外部访问容器,除了iptables DNAT处理外,还有一种方式docker-proxy。网上很多文章写得并不全面,只说了docker-proxy。其实通过上面的分析,只通过DNAT就可以完成外部访问容器了,那docker-proxy什么时候起作用呢?

[root@docker1 ~]# ps -ef|grep proxy
root      4073   927  0 13:07 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 8081 -container-ip 172.17.0.4 -container-port 80
root      4143  1521  0 13:32 pts/0    00:00:00 grep --color=auto proxy

查看进程可以发现,我们的host上也开启了docker-proxy,将host的0.0.0.0:8081转发到容器172.17.0.4:80。
关于docker-proxy和DNAT何时起作用,有一篇文章分析的很好,分享给大家《docker-proxy存在合理性分析》。

4.小结

  • 容器访问外部,由iptables SNAT实现
  • 外部访问容器,由iptables DNAT实现,另外在一些场景下,通过docker-proxy进行转发

下一节,我们介绍bridge network的自定义网络。 点击此处回到docker系列文章目录

 

原创文章,如果转载,请声明出处!

-----------------------------------------------------------------------------------------------

本人微信公众号同步更新云计算、容器、网络、编程等文章,欢迎参观!

 

 

Je suppose que tu aimes

Origine www.cnblogs.com/sunqingliang/p/12731601.html
conseillé
Classement