容器的自定义网络
1. 创建相关实验资源。
- 在体验实验室,单击创建资源。
- (可选)在实验室⻚⾯左侧导航栏中,单击云产品资源列表,可查看本次实验资源相关信息(例如IP地址、⽤户信息等)。 说明:资源创建过程需要1~3分钟。
2. 使用自定义网络
在上一个实验中我们讲解了Docker中默认网络模式下的网卡,连通性和端口映射。实际上在Docker中,一共包含了五种网络模式。分别是None,Bridge,Host,Container和自定义模型。其中None模式为无网络容器,在默认情况下Docker中的容器使用的是Bridge网络模型。Host和Container是两种共享网络模型。在本实验中我们来重点讲解Bridge模型。
Bridge网络模式的网络架构,是一种类似家用路由器的NAT网络架构。在这种架构中内网和外网使用不同的网络地址,容器中的网卡和宿主机中的Docker网卡(默认为Docker0)使用私有的内网地址,同时宿主机Docker网卡作为容器中的网卡的默认网关。而宿主机的物理网卡作为外网使用外网地址。
当容器需要访问外网时,Docker通过网络地址转换(NAT)将内网对外的访问请求转发到宿主机的物理网卡实现外网访问。当外网需要访问容器中的服务时,Docker使用目标网络地址转换(DNAT),实现容器的端口映射功能。
- 自定义Bridge网络
在上面的说明中,为大家简单介绍了Docker的Bridge网络模型。在默认情况下新创建的容器会使用Bridge网络模型,同时使用docker 0网卡作为默认网关。在使用bridge模型时,除了使用默认的docker0网卡之外。我们还可以使用docker network创建新的宿主机容器网络。
在创建新的容器网络时我们使用docker network create命令,并且可以使用--gateway参数指定网卡的地址,以及使用--subnet内网地址的网络地址段。
docker network create --gateway 192.168.0.1 --subnet 192.168.0.0/24 network1
- 查看Bridge网络
docker network除了可以创建自定义网络之外,还可以使用docker network ls查看已有的Docker网络。对于单个网络也可以使用docker inspect命令查看详细配置。
另外当自定义bridge网络创建之后,通过宿主机的ifconfig命令可以发现在宿主机中生成了一块新的网卡,网卡的名称前缀为br-。
docker network ls docker inspect network1
ifconfig -s ifconfig br-[网络ID]
说明:此处为network1的网络ID
- 加入自定义Bridge网络
自定义网络创建完毕后,就可以在docker run运行容器的时候,使用--network参数指定容器使用某一个网络,同时我们还可以使用--ip参数指定容器的IP地址。
docker run -itd --name busybox1 --network network1 --ip 192.168.0.101 busybox docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' busybox1
3. 多网络的连通性
在上一个小节中,我们介绍了通过docker network自定义Bridge网络。接下来我们来看一下不同网络之间的容器的连通性问题。
- 不同Bridge网络的连通性
我们尝试在默认的docker0网络中再创建一个容器busybox2,然后通过docker exec命令在busybox2中执行ping命令,来测试该容器和上一个步骤中创建的busybox1之间的连通性。会发现不同网络之间的容器无法互联互通。
docker run -itd --name busybox2 busybox docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' busybox2 docker exec busybox2 ping 192.168.0.101 -w 1
- 容器连接多网络
如果我们需要让处在不同docker网络之间的容器互联互通,从宿主机网络上配置,一般我们可以采用手动配置路由的方式。
除此之外我们还可以从容器上进行配置来解决这个问题。而解决的方式就是通过docker network connect命令为容器创建一个新的网络连接。接下来我们来演示将已经运行容器busybox2,连接到network1网络上。
docker network connect --ip 192.168.0.102 network1 busybox2
- 验证多网络连接
网络联通之后,我们再次测试ping命令。会发现busybox2容器已经可以ping通busybox1容器的网络地址。通过ip add命令。我们发现当使用docker network connect命令创建连接之后,在容器中会生成一块与之对应的新的网卡。
docker exec busybox2 ping 192.168.0.101 -w 1 docker exec busybox2 ip addr
4. 容器中的域名解析
在我们实际使用Docker时,一般来说并不建议将所有的服务的部署在一个容器中,而是尽量让一个容器中只包含一个服务。然后将多个容器加入同一个网络时,如果一个容器中的服务希望访问另一个容器中的服务,就需要知道另一个容器的网络地址才能进行调用。
但是在应用开发阶段,开发者往往并不知道应用所依赖的服务会被部署到具体哪个网络地址。在这种情况下,我们通常会使用域名来解决这个问题,也就是使用一个字符串作为域名表述一个服务的网络地址。然后再容器之上配置DNS域名解析服务,将域名字符串转换成具体IP地址。
- 默认网络容器链接
在docker0默认网络中,我们可以使用--link参数链接一个已经启动的容器。当一个容器使用--link链接到另一个容器之后,在该容器在创建时会在容器中配置本地静态DNS域名文件,将被链接容器的容器名解析成被链接容器的IP地址。
docker run -itd --name domain1 --network network1 busybox docker exec domain1 ping busybox1 -c1 docker exec domain1 ping domain1 -c1
- 自定义网络中得DNS
而在自定义网络中,docker会为自动为网络中得容器添加一个内置得动态DNS服务。在同一网络中容器之间,可以直接使用容器名进行访问。
docker run -itd --name domain3 --network network1 busybox docker run -itd --name domain4 --network network1 busybox docker exec domain3 ping domain3 -c1 docker exec domain3 ping domain4 -c1
- 网络别名
除了使用容器名称之外,我们还可在使用docker run创建容器得时候使用--network-alias参数设置网络别名作为域名。--network-alias参数和-p参数一样,可以并列设置多个,同时设置多个域名
docker run -itd --name domain2 --network-alias web --network-alias db --network network1 busybox docker exec domain1 ping domain2 -c1 docker exec domain1 ping web -c1 docker exec domain1 ping db -c1
5. 容器实现Nginx代理
在上面得步骤中我们讲解了容器中得自定义网络。接下来我们来看一个简单得Nginx代理。来理解自定义网络。在这个例子中,我们创建三个容器,一个通过Python启动http服务,一个启动apahce服务,然后在一个Nginx服务中配置代理,让他转发其他两个服务,并且对外通过端口映射提供服务。
- 容器准备
首先为了避免干扰,我们先删除全部容器。接下来我们创建两个容器,一个是名为python1得python容器,创建之后在80端口启动内置http服务。另一个名为httpd1得httpd容器,也就是apahce服务,默认在80端口启动服务。
在容器创建成功后,我们使用curl进行测试。这里我们使用组合命令,先获取容器得IP,然后作为参数传递给curl
docker rm -f $(docker ps -aq) docker run -d --name python1 python python3 -m http.server 80 docker run -d --name httpd1 httpd curl $(docker inspect python1 -f {{.NetworkSettings.IPAddress}}) curl $(docker inspect httpd1 -f {{.NetworkSettings.IPAddress}})
- 编写Nginx配置文件
接下来我们来配置Nginx容器作为代理服务器。首先我们宿主机中生成Nginx得配置文件proxy.conf。在配置文件中,我们设置两个配置信息,分别是对8001端口的访问转发到python1的80端口,以及对8002端口的访问转发到httpd1的80端口。我们使用vi命令生成proxy.conf并编辑为如下内容。注意使用vi编辑器时:
- 需要先按i键进入编辑模式。
- 编辑完成之后按esc退出编辑模式。
- 然后按大写的ZZ保存并退出vim。
vi proxy.conf
server { listen 8001; server_name 0.0.0.0; location / { proxy_pass http://python1; } } server { listen 8002; server_name 0.0.0.0; location / { proxy_pass http://httpd1; } }
- 编写Dockerfile
Nginx配置文件生成完毕之后,接下来我们来编辑Dockerfile。在Dockerfile中,我们将配置文件复制到/etc/nginx/conf.d/proxy.conf目录中。我们使用vi命令生成proxy.conf并编辑为如下内容
vi pDockerfile
FROM nginx:latest ADD proxy.conf /etc/nginx/conf.d/proxy.conf
- 启动代理服务
Dockerfile编辑完成后,我们继续生成容器镜像proxy。镜像生成成功后,我们通过该镜像创建容器proxy1。在创建容器的时候,我们使用--link参数添加python1和httpd1域名,同时将proxy容器的80,8001,8002端口映射到宿主的8000,8001,8002。
docker build -t proxy . docker run -d --name proxy1 -p 8000:80 -p 8001:8001 -p 8002:8002 \ --link python1 --link httpd1 proxy
- 验证Nginx代理服务
代理服务启动之后,我们使用curl命令进行验证。分别访问127.0.01的8000,8001,8002三个端口,我们会发现通过容器proxy在宿主机上的端口映射,我们实现了对三个容器的统一访问入口。
curl 127.0.0.1:8000 curl 127.0.0.1:8001 curl 127.0.0.1:8002
实验链接:https://developer.aliyun.com/adc/scenario/6efdb318571a4d5ab2f33c24df21ad31