Docker中的网络与数据管理
一、Docker网络管理
Docker默认使用bridge(单主机互联)和overlay(可跨主机互联)两种网络驱动来进行容器的网络管理。如果需要,用户还可以自定义网络驱动插件进行Docker容器的网络管理。下面将针对Docker默认的网络管理和自定义网络管理进行详细讲解。
1.Docker默认网络管理
在进行Docker安装时,Docker就会自动创建三种网络。客户端可以通过网络管理指令进行查看$docker network ls
上述指令用于列举Docker中所有的网络,执行后的效果如图1-1所示。
从图1-1可以看出,Docker中默认的三种网络分别为bridge、host和none,其中,名为bridge的网络就是默认的bridge驱动网络,也是容器创建时默认的网络管理方式,配置后可以与宿主机通信从而实现与互联网通信功能,而host和none属于无网络,容器添加到这两个网络时不能与外界网络通信。
下面通过创建一个示例来演示默认的bridge网络管理方式,其执行过程如下。
(1)创建并启动容器。
在终端窗口中执行如下指令,如图1-2所示。
$docker run itd --name=networktest ubuntu
上述指令在后台创建了一个镜像名称为ubuntu的容器,并为启动后的容器命名为networktest。
(2)使用网络查看指令查看网络详情
具体指令如下。
$docker network inspect bridge
上述指令用于检查名称为bridge的网络详情,需要指明网络名称或者网络ID,执行上述指令后,效果如图1-3所示。
从图1-3可以看出,执行上述指令后就会显示出bridge网络的所有详细信息,其中就包括了使用默认的bridge网络管理方式启动的名称为networktest的容器。
选要注意的是,这里介绍的三种网络bridge、host和none都是在非集群环境下 Docker提供的默认网络,而在Docker Swarm集群环境下,除了这三种默认网络外,Docker还提供了docker_gwbridge和ingress两种默认网络。
2.自定义网络介绍
虽然Docker提供的默认网络的使用比较简单,但是为了保证各容器中应用的安全性,在实际开发中更推荐使用自定义的网络进行容器管理。
在Docker中,可以自定义bridge网络、overlay网络,也可以创建network plugin(网络插件)或者远程网络以实现容器网络的完全定制和控制。接下来将分别针对这几种自定义网络进行讲解。
(1)Bridge networks(桥接网络)
为了保证容器的安全性,我们可以使用基于bridge的驱动创建新的bridge网络,这种基于bridge驱动的自定义网络可以较好的实现容器隔离。
(2)Overlay network in swarm mode(swarm集群中的覆盖网络)
在Docker Swarm集群环境下可以创建基于overlay驱动的自定义网络。为了保证安全性,Swarm集群使用自定义的overlay网络只适用于需要服务的集群中的节点,而不会对外部其他服务或者Docker主机开放。
(3)Custom network plugins(定制网络插件)
如果前面几种自定义网络都无法满足要求时,就可以使用Docker提供的插件来自定义网络驱动插件。自定义网络插件会在Docker进程所在主机上作为另一个运行的进程。
3.自定义bridge网络
下面将针对非集群环境下基于bridge驱动的自定义网络进行详细讲解。
(1)创建自定义网络
在Docker主机上可以使用docker network create指令来创建网络,具体操作指令如下。
$ docker network create --driver bridge isolated_nw
执行上述指令可以创建一个基于bridge驱动的名称为isolated_nw的网络。其中–driver(可简写为-d)用于指定网络驱动类型,isolated_nw就是新创建的网络名称。需要说明的是,–driver bridge可以省略,省略时Docker会默认使用基于bridge驱动来创建新的网络。
创建完网络后,可以使用docker network ls指令查看创建的网络是否成功,效果如图1-4所示。
从图1-4可以看出,新创建的isolated_nw网络已经在列表中展示出来,这说明新的bridge网络创建成功。
除docker network ls指令外,还可以使用docker network inspect指令查看新建网络的详细信息。
(2)使用自定义网络启动容器
自定义网络创建成功后,就可以使用该网络启动一个容器,具体操作指令如下。
$ docker run --network=isolated_nw -itd --name=nwtest busybox
执行上述指令后,会创建一个名为nwtest的容器,指令中的–network参数指定了该容器的网络连接为自定义的isolated_nw。
通过docker inspect nwtest指令可以查看启动后的容器网络详情,来检查其网络管理方式,效果如下图所示。
从上图可看出,名为nwtest的容器使用的就是自定义的isolated_nw网络进行容器
网络管理的。
(3)为容器添加网络管理
名为nwtest的容器使用的只有自定义的isolated_nw一种网络管理方式,我们还可以继续为该容器添加其他网络管理方式,具体操作指令如下。
$ docker network connect bridge nwtest
执行上述制指令后,会为容器添加一中默认的bridge网络管理方式。再次使用docker inspect nwtest指令查看该容器网络详情,效果如下图所示。
从上图可看出,执行完为容器添加网络管理的指令后,容器nwtest就拥有了两种网络管理方式,分别为默认的bridge网络和自定义的isolated_nw网络。
(4)断开容器网络连接
容器既可以连接网络,也可以断开网络。这里以断开nwtest容器的自定义网络isolated_nw为例进行演示,断开网络连接的指令如下。
$ docker network disconnect isolated_nw nwtest
断开网络连接的指令与连接网络的指令类似,在使用时也需要指定网络名称和容器名称。
(5)移除自定义网络
当不再需要某个网络时,可以将该网络移除,但在移除网络之前,一定要将所有与该网络连接的容器断开。移除自定义网络的指令如下。
$ docker network rm isolated_nw
执行上述指令后,就可以成功移除名称为isolated_nw的自定义网络。当网络移除成功后,会返回网络名称。为了验证网络是否移除成功,可以使用docker network ls指令列举所有网络进一步确认。
4.容器之间的网络通信
Docker中的不同容器之间需要通过网络来进行通信,那么各个容器之间具体是如何实现通信的呢?接下来,下面将以非集群环境下的容器通信为例,对Docker容器之间的通信进行讲解。
实现Docker容器之间网络通信的具体步骤如下。
(1)创建容器
1)创建两个默认的bridge网络的容器,具体操作指令如下。
$ docker run -itd --name=container1 busybox
$ docker run -itd --name=container2 busybox
执行上述指令后,会创建两个名为container1和container2的容器,同时他们都是使用默认的bridge进行网络管理的。
2)创建一个使用自定义的isolated_nw网络(需要预先创建)的容器,具体指令操作如下。
$ docker run --network=isolated_nw -itd --name=container3 busybox
执行完上述指令后,会创建一个名为container3的容器,使用–network参数指定了该容器的网络管理为自定义的isolated_nw。
3)为container2容器新增一个自定义的isolated_nw网络连接,具体操作指令如下。
$docker network connect isolated_nw container2
执行上述指令后,container2容器同时就拥有了bridge和isolated_nw两种网络管理方式。
执行完上述3个步骤后,container使用的是默认的bridge网络管理,从container3使用的是自定义的isolated_nw网络管路,而container2使用的是默认的bridge网络管理和自定义的isolated_nw网络管理。这3个容器具体的网络管理关系,可以通过下图进行说明。
从上图可看出,container和container2在同一个默认的bridge网络管理下,这两个容器可以相互通信;而container2和container3在同一个自定义的isolated_nw网络管理下,这两个容器也可以相互通信;但是container1和container3属于两个不同的网络环境,所以这两个容器无法进行通信。
(2)容器地址查看
为了演示上图的不同容器之间的网络通信情况,这里需要先查看各个容器的网络地址。
$docker attach container2
然后,使用ifconfig指令查看当前容器被动态分配的IP地址,如下图所示。
从上图中可看出,在container2容器内部有两个网卡eth0和eth1(这就是使用了两种网络管理方式自动产生的),并分别对应的IP地址为172.17.0.4和172.18.0.4。
接下来,分别进入容器container1和container3,并通过ifconfig指令查看对应容器的ip地址,效果如下所示。
从上图可看出,conyainer1的ip地址为:172.17.0.3,conatiner3的ip地址为:172.18.0.3。
(3)容器通信测试
首先,使用docker attach container1指令进入container1容器内部,使用ping指令连接container3来查看是否能够通信,效果如下所示。
从上图可看出,在container1内部不管是使用“ping -w 4 IP”(-w 4限制响应4次),还是“ping -w 4 容器名称”的指令都无法连通container3。这也就验证了两个容器不在同一个网络环境下,无法通信的判断。
接着,使用docker attatch container2指令进入container2容器内部,使用容器IP分别连接container1和container3进行通信测试,效果如下图所示。
从上图可看出,在container2内部使用“ping -w 4 IP”的指令可以同时连通container1和container3,这也与前面的分析结果相同。
最后,再在container2容器内部使用容器名称分别连接container1和container3进行通信测试,效果如下所示。
从上图可以看出,在container2内部使用“ping -w 4容器名称”的指令可以连通container3,而连接container1却显示”bad address ‘container1’“错误。
通过前面的测试,我们可以得出一个结论:不同容器之间通信必须在同一个网络环境下;使用默认bridge网络管理的容器可以使用容器IP进行通信,但无法使用容器名称进行通信;而使用自定义网络管理的容器则可以同时使用IP和容器名称进行通信。
(4) 拓展知识
默认网络下使用–link参数通过容器名称进行通信
前面的示例已经演示说明了使用默认网络管理的容器无法使用容器名称进行通信,而单纯使用IP地址进行通信显然是不可靠的,因为多数情况下IP地址都是动态分配的,当容器重启后其它容器就无法正确连接到该容器了。若想要在默认网络下,使用容器名称进行通信,则需要使用–link参数,该参数是在启动容器时进行容器连接使用的。
在默认网络下,使用–link参数的具体指令如下。
$docker run -itd --name=container4 --link container1:c1 busybox
执行上述指令后会新建并启动一个名为container4的容器,指令中的-itd用于指定后台交互式运行,–name用于指定生成容器的名称,而–link container1:c1则将新建的container4容器连接到了container1容器且为container1容器定义了别名c1。
这种使用–link参数创建的默认网络下的容器可以使用容器名称或别名与指定来连接的容器进行通信了。所以这里容器container4可以使用容器名称container1或者别名c1与container1进行通信,但容器container1仍然不可以使用容器名称与container4进行通信,具体操作如下所示。
二、Docker Swarm集群
1.Docker Swarm概述
Docker Swarm集群的主要特点如下。
(1)方便创建和管理集群
(2)可扩展
(3)可实现期望的状态调节
(4)集群中多主机网络自动拓展管理
(5)提供服务发现能力
(6)可实现负载均衡
(7)安全性强
(8)支持延迟更新和服务回滚
2.Docker Swarm使用
(1)环境搭建
1)准备3台Ubuntu系统主机(即用于搭建集群的3个Docker机器),每台机器上都需要安装Docker并且可以连接网络,同时要求Docker版本必须是1.12及以上,因为老版本不支持Docker Swarm。
2)集群管理节点Docker机器的IP地址必须固定,集群中的所有节点都能够访问该管理节点。
3)集群节点之间必须使用相应的协议并保证其以下端口号可用:
用于集群管理通信的TCP端口2377;
TCP和UDP端口7946,用于节点间的通信;
UDP端口4789,用于覆盖网络流量。
为了进行下面示例的演示,此处按照要求在虚拟机中分别安装了3台使用Ubuntu16.04系统的机器,这三台机器的主机名称分别为manager1(作为管理节点)、worker1(作为工作节点)和worker2(作为工作节点),其IP地址分别如下。
manager1:192.168.10.111
worker1:192.168.10.112
worker2:192.168.10.113
manager1(作为管理节点):
worker1(作为工作节点):
worker2(作为工作节点):
(2)创建Docker Swarm集群
1)在名为manager1的Docker机器上创建Docker Swarm集群,具体操作指令如下。
$docker swarm init --advertise-addr 192.168.10.111
执行上述指令后,Docker就自动在IP为192.168.10.111的机器上(也就是manager1机器上)创建一个Swarm集群,并将该IP地址的机器设置为集群管理节点。需要说明的是,如果只是测试单节点的集群,直接使用docker swarm init指令即可。
执行上述指令后,效果如下所示。
执行创建指令后,如果出现上图中所示的信息,就表示Docker Swarm集群创建成功。从上图中可看出,创建集群后显示了两条指令,这两条指令分别是在添加工作节点和管理节点时是使用的。
2)在管理节点上,使用docker node ls指令查看集群节点信息,效果如下图所示。
从上图可看出,此时只创建了一个集群节点(默认为管理节点),而没有其他工作节点,因此只显示一条节点信息。
(3)向Docker Swarm集群添加工作节点
1)启动另外两台Docker机器worker1和worker2,分别打开终端窗口,执行向集群中加入工作节点的指令,具体操作指令如下。
$ docker swarm join --token SWMTKN-1-0geihx91e570ib9djxz9lndida09uyfnjmbtfs3kjyi95zo4ic-007hhrxohem1yknbzpcyjix0j 192.168.10.111:2377d
需要特别注意的是,上述指令中的–token参数表示向指定集群中加入工作节点的认证信息。读者在进行学习时,一定要使用自己在前面创建Docker Swarm集群时返回的向集群中添加工作节点的指令,而不是直接使用 该文章中的指令。如果已忘记添加到Docker Swarm集群中的指令,可以在集群管理节点上执行“docker swarm join-token worker”指令进行查看。
2)在次在集群管理节点上使用docker node ls指令查看集群节点信息,效果如下图所示。
从上图可看出,集群节点列表显示出了1个管理节点和2个工作节点,这说明Swarm集群搭建成功。
(4)向Docker Swarm集群部署服务
在Docker Swarm集群中部署服务时,既可以使用Docker Hub上自带的镜像来启动服务,也可以使用自己通过Dockerfile来构建的镜像来启动服务那么必须先将镜像推送到Docker Hub中心仓库。
为了方便读者的学习,这里以使用Docker Hub上自带的alpine镜像为例来部署集群服务,具体操作指令如下。
$docker service create --replicas 1 --name helloworld alpine ping docker.com
上述部署服务指令中个参数的具体说明如下。
docker service create指令:用于在Swarm集群中创建一个基于alpine镜像的服务。
–replicas参数:指定了该服务只有一个副本实例。
–name参数:指定创建成功后的服务名称为helloworld。
ping docker.com指令:表示服务启动后执行的命令。
Docker Swarm集群上的服务管理与容器操作指令类似,只不过服务管理指令是以“docker srevice ”开头,而容器管理指令是以“docker container”开头。个别指令除外,如–replicas。
(5)查看Docker Swarm集群中的服务
1)当服务部署完成后,在管理节点上可以通过docker service ls指令查看当前集群中的服务列表信息,具体操作指令如下。
$docker service ls
2)可以使用docker service inspect指令,查看部署的服务具体详情,具体操作指令如下。
$docker service inspect helloworld
3)可以使用docker service ps指令查看指定服务在集群节点上的分配和运行情况,具体操作指令如下。
$docker service ps helloworld
(6)更改Docker Swarm集群服务副本数量
在集群中部署的服务,如果只运行一个副本,就无法体现出集群的优势,并且一旦该机器或副本奔溃,该服务将无法访问,所以通常一个服务会启动多个服务副本。
在管理节点manager1上,更改服务副本数量的指令如下。
$docker service scale helloworld=5
更改完成后,就可以使用docker service ps指令查看这5个服务副本在3个节点上的具体分布和运行情况,效果如下图所示。
从上图可看出,helloworld服务的5个副本实例被随机分配到了manager1、worker1和worker2这三个节点上运行,并且他们的状态都是Running,表示服务正常运行。
执行docker service ps helloworld指令查看服务的运行情况后,我们还可以在有服务副本分配的节点上使用docker ps指令查看任务运行情况。
(7)删除服务
对于不需要的服务,我们可以进行删除,具体操作指令如下。
$docker service rm helloworld
在集群管理节点manager1上执行上述删除服务指令后(需要指定删除服务的名称),该服务就会在集群中彻底删除。
需要说明的是,执行上述指令删除服务后,在集群中有该服务副本运行的节点上,这些服务副本仍需要一定的时间清除,此时我们可以使用docker ps查看具体清除情况。
(8)访问服务
前面部署的服务都没有直接向外界暴露服务端口,外界也无法正常访问服务。接下来我们就通过自定义overlay驱动网络为例来讲解集群下的网络管理与服务访问,具体的实现过程如下。
1)在集群管理节点manager1上,执行docker network ls指令查看网络列表,效果如下图所示。
从上图可以看出,与非集群环境下的Docker网络对比,Docker Swarm集群网络列表中分别增加了一个以bridge和overlay为驱动的网络。在集群中发布服务时,如果没有指定网络,那么默认使用名为ingress网络连接的,而在实际开发中,则会使用自定义的overlay驱动进行服务管理。
2)在集群管理节点manager1上,创建以ovrelay为驱动的自定义网络,具体操作指令如下。
$docker network create --driver overlay my-multi-host-network
上述指令以overlay为驱动创建了一个名为my-multi-host-network的网络。
3)在集群管理节点manager1上,再次部署服务,具体操作指令如下。
$docker service create --network my-multi-host-network --name my-web --publish 8080:80 --replicas 2 nginx
上述部署服务的指令中,–network参数用于指定服务使用自定义的overlay驱动网络my-multi-host-network连接;–name参数用于指定服务启动后的名称;–publish(也可以使用-p)参数用于映射对外服务端口;–replicas参数用于指定该服务的副本数量;nginx表示是基于nginx镜像构建的服务。
4)在管理节点manager1上,使用docker service ps my-web指令查看服务的两个服务副本运行情况,结果如下图所示。
从上图可看出,该服务的两个副本任务被随机分配到了worker1和worker2两台节点机器上,并已正常运行。
需要注意的是,由于是随机分配,实际操作中的显示可能并不与上图中的完全相同,也可能会分配到其他两台节点机器上,如manager1和worker2。
5)外界访问服务
打开浏览器,使用任意一台节点机器的"IP+8080"端口进行服务访问,都可以正常显示,具体效果如下图所示。
从上图中可看出,当在任意节点上访问服务时,都可以正常访问部署的服务。这是由于集群负载均衡器将请求路由到一个活动容器,从而实现容器内部服务的正常访问,这也体现出了Docker Swarm负载均衡这一特点。
三、Docker数据卷管理
1.Volumes数据卷的优势
虽然Docker数据外部挂载机制提供了三种数据管理方式,但在实际使用中,用到更多的是Volumes和Bind mounts这两种数据管理方式。这两种数据管理方式中,Volumes完全由Docker管理,是官方相对推荐的数据管理方式;而Bind mounts则要依赖于主机的目录结构。
与Bind mounts(绑定挂载)相比,Volumes(数据卷)有以下几个优势。
(1)数据卷比绑定挂载更容易备份和迁移。
(2)可以使用Docker CLI指令或Docker API来管理数据卷。
(3)在Linux和Windows容器上都可以使用数据卷。
(4)在对合容器之间可以更安全的共享数据卷。
(5)数据卷驱动器允许在远程主机或云提供商上存储数据卷,并且加密数据卷的内部或添加其它功能。
(6)一个新数据卷的内容可以由一个容器预填充。
2.Volumes数据卷的使用
了解数据卷的优势后,接下来就以数据卷为例来演示Docker如何进行数据卷管理。
(1)创建并管理数据卷
1)创建数据卷
在Docker主机终端,通过docker volume create指令创建一个名为my-vol的数据卷,具体操作指令如下。
$docker volume create my-vol
2)查看数据卷
使用docker volume ls指令查看本地数据卷列表,具体操作指令如下。
$docker volume ls
执行上述指令后,会列举出本地Docker机器上的所有数据卷,效果如下所示。
从上图可看出,新创建的my-vol数据卷上已经显示在本地Docker主机上,这说明数据卷创建成功。
3)核查数据卷
使用docker volume inspect指令查看指定数据卷详情,具体操作指令如下。
$docker volume inspect my-vol
执行上述指令后,会将名为my-vol的数据卷的详细信息展示出来,效果如下图所示。
4)删除数据卷
当不在需要使用数据卷后,可以使用命令docker volume rm指令删除指定名称的数据卷,具体操作指令如下。
$docker volume rm my-vol
执行上述指令后,会将名为my-vol的数据卷删除,当删除成功后会返回该数据卷名称。
(2)启动容器并加载数据卷
前面单独使用docker volume数据卷管理指令演示了数据卷的基本用法,接下来将结合具体的容器,来演示如何在容器创建时配置并管理docker volume数据卷。
1)查看本机容器和数据卷
在Docker主机终端分别使用docker ps -a和docker volume ls指令查看本地Docker机器上存在的容器和数据卷,效果如下图所示。
从上图可看出,目前本地Docker主机上没有任何容器和数据卷。为了避免后续示例演示的干扰,如果机器上已经存在容器和数据卷,最好将已存在的容器和数据卷删除。
2)确认查看本机Docker文件系统中的容器和数据卷首先在Docker主机终端中将普通用户切换到root用户,然后进入“/var/lib/docker”目录,即Docker默认在本机上的文件系统目录,查看信息,效果如下图所示。
从上图可看出,本地Docker机器的文件系统中包含了两个重要的文件目录,分别为containers和volumes,这两个文件目录就是用于存放用户创建的容器和数据卷的。因为前面已经确认Docker机器上没有任何容器和数据卷,所以这两个文件目录是空的。
3)启动容器并挂载数据卷
使用docker run指令创建并启动一个容器,同时挂载一个数据卷,具体操作指令如下。
$docker run -d -it --name devtest --mount source=myvol,target=/app busybox:latest
也可以使用-v参数挂载数据卷,具体操作指令如下。
$docker run -d -it --name devtest2 -v myvol:/app busybox:latest
在上述两种指令中,首先通过docker run指令创建并启动一个容器,并指定创建容器的名称分别为devtest和的devtest2,然后分别通过–mount和-v两种参数来实现数据卷的挂载。这两个容器共享了同一个数据卷myvol,并将该数据卷挂载到了各自容器中的app目录下。
需要注意的是,本文章讲解的是使用Volumes进行数据管理,不管是–mount source=myvol还是-v myvol,前面第一个参数都是设置的数据卷名称。执行完指令后,会自动在Docker文件系统的数据卷目录/var/lib/docker/volumes下创建一个myvol子目录来保存数据。如果是使用Bind mounts(绑定挂载)进行的数据管理,那么第一个参数就是宿主机保存数据的具体地址(如-v /src/muvolume/data:/app)。
4)再次查看本机容器和数据卷列表
在Docker主机终端分别使用docker ps -a和docker volume ls指令查看本地Docker机器上存在的容器和数据卷,效果如下图所示。
从上图可看出,容器创建成功后会自动加载了数据卷。值得一提的是,如果在创建容器时数据卷不存在,则Docker会自动创建。
5)检查容器详情
在Docker主机终端使用docker inspect指令查看容器详情(主要查看数据挂载信息),效果如下图所示。
从上图可看出,容器挂载了Mounts信息,其中包括挂载类型为volume、数据卷名称为myvol、数据在本地Docker机器上的对应存储地址、数据在容器中的对应地址app目录以及容器中的数据是可读者的(RW:true)等。
6)再次确认本机Docker文件系统中的容器和数据卷
首先在Docker主机终端中将普通用户切换到root用户,然后进入“/var/lib/docker”目录,然后分别进入containers容器文件目录和volumes数据卷文件目录查看内容,结果如下图所示。
从上图可看出,新建的两个容器和数据卷已自动生成在本地Docker文件目录中。此时,如果我们将两个容器都删除,则本地Docker文件目录中的容器也会自动消失,但数据卷却可以保留,除非数据卷也被删除。
四、问题集锦
1.问题一
解决办法:通过docker pull指令拉取镜像到本地。
2.问题二
解决方法:
3.问题三
因忘记截图,所以在此简单描述一下我所遇到的问题。容器创建并启动成功后,使用docker attach指令无法进入容器,并且无错误提示,但是使用docker exec指令却可以进入指令。
解决方法:
尝试了网上找的种种方法后还是不能解决,最终功夫不负有心人,我通过查看可以进去的同学的容器的运行情况,发现他们的启动容器运行的命令为“sh”,而我的为“python app.py”,这才知道所用镜像是拉取的,而我的是构建的,拉取镜像并重新创建和启动容器后成功进入到容器。
4.问题四
因忘记截图,所以在此简单描述一下我所遇到的问题。在更改Docker Swarm集群服务副本数量后,使用docker service ps指令查看副本在3个节点上的具体分布和运行情况后,发现只有管理节点的服务状态为Running。
解决方法:
通过认真阅读书本前面的内容,发现每台机器必须要可以连接网络,于是检查了网络情况,果不其然,只有管理节点是可以连接到网络,其余2台主机都无法连接网络,重新添加了网络并部署服务后,发现服务运行正常。
五、文章小结
本文章主要讲解了Docker中网络与数据管理。通过学习本文章,读者可对Docker中的网络、数据管理以及Docker Swarm的基本知识有一定的了解,同时能够掌握Docker中自定义的网络管理和Volumes数据卷管理的具体使用。
</div>
<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-258a4616f7.css" rel="stylesheet">
</div>
- 1
- 2
- 3