Docker网络通信原理

Docker为什么可以映射端口出来原理是什么?

Docker容器只能和宿主机进行通信,如果docker容器的服务需要暴露出来,需要宿主机端口映射出来。

参考文档

##
https://www.jianshu.com/p/87e558d21b70

原理图

Docker网络通信原理_第1张图片

 暴露端口

同一个网络中的容器之间虽然可以互相 ping 通,但是并不意味着可以任意访问容器中的任何服务。Docker 为容器增加了一套安全机制,只有容器自身允许的端口,才能被其他容器所访问。如下所示,我们可以通过 docker container ls 命令可以看到容器暴露给其他容器访问的端口是 80,那么我们只能容器的 80 端口进行访问,而不能对没有开放的 22 端口进行访问。

$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
5a8dece3841d        nginx               "/docker-entrypoint.…"   3 minutes ago       Up 3 minutes        80/tcp              web

$ telnet 172.18.0.2 80
Trying 172.18.0.2...
Connected to 172.18.0.2.
Escape character is '^]'.

$ telnet 172.18.0.2 20
Trying 172.18.0.2...
telnet: Unable to connect to remote host: Connection refused

我们可以在镜像创建的时候定义要暴露的端口,也可以在容器创建时定义要暴露的端口,使用 --expose。如下所示,就额外暴露了 20、22 这两个端口。

$ docker container run -d --name web --expose 22 --expose 20 nginx

$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
4749dac32711        nginx               "/docker-entrypoint.…"   12 seconds ago      Up 10 seconds       20/tcp, 22/tcp, 80/tcp   web

容器的端口暴露类似于打开了容器的防火墙,具体能不能通过这个端口访问容器中的服务,还得看容器中有无应用监听并处理来自这个端口的请求

端口映射

上面提到的桥接网络中的容器只能与位于相同网络中的容器进行通信,假如一个容器想对外提供服务的话,需要进行端口映射。端口映射将容器的某个端口映射到 Docker 主机端口上。那么任何发送到该端口的流量,都会被转发到容器中。如图所示,容器内部开放端口为 80,该端口被映射到了 Docker 主机的 10.0.0.15 的 5000 端口上。最终访问 10.0.0.15:5000 的所有流量都会被转发到容器的 80 端口

Docker网络通信原理_第2张图片

如下图所示,假设我们运行了一个新的 web 服务容器,并且将容器 80 端口映射到 Dokcer 主机的 5000 端口。

$ docker container run -d --name web --network localnet -p 5000:80 nginx

端口映射的原理 

## 启动容器
docker run -d --network=bridge -p 9097:80 --restart=always nginx

这行命令指定容器网络采用桥接模式,同时指定将host机的9097端口映射到容器的80端口,每个容器都有自己的内网ip地址,可以理解为加入以下iptables命令。

iptables -t nat -I PREROUTING -p tcp --dport 9097 -j DNAT --to $容器ip:80

事实上docker也是这样做的,只是给他docker自身创建了一个DOCKER链,在匹配到目的地址非本地地址时,会跳转到DOCKER链执行,在DOCKER链当中执行DNAT操作,上述命令就改成了,最终目的是一样的

iptables -t nat -I DOCKER ! -i docker0 -p tcp --dport 9097 -j DNAT --to 172.17.0.2:80

查看iptables规则

## 查看 iptables 中有一条 Chain DOCKER 的链
iptables -t nat -vnL

## 显示 Chain DOCKER 的 line-number
sudo iptables -t nat -vnL DOCKER --line-number

相关命令

# 列出运行在本地 docker 主机上的全部网络
docker network ls

# 提供 Docker 网络的详细配置信息
docker network inspect 

# 创建新的单机桥接网络,名为 localnet,其中 -d 不指定的话,默认是 bridge 驱动。并且主机内核中也会创建一个新的网桥。
docker network create -d bridge localnet

# 删除 Docker 主机上指定的网络
docker network rm

# 删除主机上全部未使用的网络
docker network prune

# 运行一个新的容器,并且让这个容器加入 Docker 的 localnet 这个网络中
docker container run -d --name demo1 --network localnet alpine sleep 3600

# 运行一个新的容器,并且让这个容器暴露 22、20 两个端口
docker container run -d --name web --expose 22 --expose 20 nginx

# 运行一个新的容器,并且将这个容器的 80 端口映射到主机的 5000 端口
docker container run -d --name web --network localnet -p 5000:80 nginx

# 查看系统中的网桥
brctl show

你可能感兴趣的:(#,Docker,docker,容器,java)