思考了一下,重新开始还是以docker 来开篇,之后的后续也是主要以分布式的内容为主,疫情过去之后大厂裁员严重,基本上目前所有公司面试的要求都到了使用分布式体系,而docker 容器也是分布式部署最常用的,后续也会讲到docker 自身的编排还有k8s 等编排方式的区别还有使用。
docker 概述
每次开始一个新的技术内容,基本都会有这段概述内容,这段内容是描述这个技术本身的一些基本和官方概念,主要作用就是为了让初学者能有一个认识和基本的简单了解,如果不需要可以直接跳到使用阶段,但是不建议初学者跳过。
在使用docker 前我们需要知道什么是docker,docker 本身就是一种容器化技术,它的目标是实现轻量级的操作系统虚拟化解决方案,Docker 的基础是Linux 容器(LXC)等技术。
这里有一个新的名词“LXC” 技术,LXC 为Linux Container 的简写,它与传统虚拟化技术相比,它的优势在于:
- 与宿主机使用同一个内核,性能损耗小;
- 不需要指令级模拟;
- 不需要即时(Just-in-time)编译;
- 容器可以在CPU核心的本地运行指令,不需要任何专门的解释机制;
- 避免了准虚拟化和系统调用替换中的复杂性;
- 轻量级隔离,在隔离的同时还提供共享机制,以实现容器与宿主机的资源共享
docker 并不是LXC 替代品,docker 底层使用了LXC 来实现,LXC 将linux 进程沙盒化,使得进程之间相互隔离,并且能够可控限制各进程的资源分配,在LXC 的基础之上,docker 提供了一系列更强大的功能。
docker 的优势
docker 的优势是很明显的,容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多,docker 对系统资源的利用率也很高,一台主机上可以同时运行数千个 docker 容器。
这些也是由docker 的特性决定的。
- 轻量级:因为底层使用的是lxc 技术,是和宿主机共享主机内核的,所以这就是体现出docker 的轻量级;
- 灵活:docker 的运行是根据本身的镜像来的,而构建镜像是非常方便的,即使是最复杂的应用也可以集装箱化;
- 可堆叠:docker 的镜像是垂直堆叠构建的,docker 本身也就是垂直和即时堆叠服务;
- 便携式:docker 的运行时对镜像的直接操作,命令启动,在本地构建,部署到云,并在任何地方运行都可以;
- 可互换:镜像本身也是可以随时构建替换的,可以即时部署更新和升级;
- 可扩展:可以增加并自动分发容器副本。
docker 的缺陷
相比较于传统虚拟机,docker 的有点相比较是很明显的,同时docker 的缺点也是。
- 隔离性:容器之间共享同一个操作系统内核以及其他组件,所以在受到攻击之类的情况发生时,更容易通过底层操作系统影响到其他容器
- 性能:当同一虚机或者服务器下面的容器需要更高并发量支撑的时候,也就是并发问题成为应用瓶颈的时候,容器会将这个问题放大,所以,并不是所有的应用场景都是适用于容器技术的
- 存储方案:docker容器提供的解决方案是利用volume接口形成数据的映射和转移,以实现数据持久化的目的,但是这样同样也会造成一部分资源的浪费和更多交互的发生,不管是映射到宿主机上还是到网络磁盘,都是退而求其次的解决方案
对比传统虚拟机
docker 的架构
docker 目前版本分为CE 和EE,一般来讲我们使用的都是CE,因为CE 不收费,EE 是提供给企业级的收费服务,它们之前的区别不是大,EE 能实现的功能CE 基本都能实现,主要是EE 会提供给企业技术服务项目,并可运行来自Docker Store的、经过认证的容器和插件。
相对于来说CE 更适合我们开发人员和运维团队构建容器APP。
我们再说回docker 的架构方面,docker 总体架构为c/s 架构,模块之间松耦合,包含了Client, Daemon, Registry, Graph, Driver, Libcontainer 以及Docker Container。
Docker的组件
- Docker Client:是用户界面,它支持用户与Docker Daemon之间通信
- Docker Daemon:Docker最核心的后台进程,运行于主机上,处理服务请求
- Docker registry:是中央registry,支持拥有公有与私有访问权限的Docker容器镜像的备份
- Docker Containers:负责应用程序的运行,包括操作系统、用户添加的文件以及元数据
- Docker Images:是一个只读模板,用来运行Docker容器
- DockerFile:是文件指令集,用来说明如何自动创建Docker镜像
这些组件在我们使用docker 的过程中,都能明显感受到,首先是Client,这个命令输入的基础;registry 用于拉去远程镜像;DockerFile 构建本地镜像;Images 镜像的只读模板,运行docker 容器的基础;Containers 处理部署程序的各种操作命令,操作系统、用户添加的文件以及元数据;Daemon 容器的核心,处理服务请求。
docker 的基本概念-镜像
这里还有三个基本的概念,上面也有提到,其中一个就是镜像。
镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等),镜像不包含任何动态数据,其内容在构建之后也不会被改变。
镜像可以分为两个部分来说,分层存储和Union FS(联合文件系统)
前者的意思是:镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。
后者表示的联合文件系统描述的是:linux的存储技术,也是Docker镜像的存储方式。它是分层的文件系统,将不同目录拉到同一个虚拟目录下,也就是将镜像中的只读文件看成是同一个目录,相当于只有一个文件系统。
镜像构建时,会一层层构建,前一层是后一层的基础,每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。
docker 的基本概念-容器
镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体,容器可以被创建、启动、停止、删除、暂停等。
容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间,因此容器可以拥有自己的root文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。
前面讲过镜像使用的是分层存储,容器也是如此,每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为容器存储层。
容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡,因此,任何保存于容器存储层的信息都会随容器删除而丢失。
docker 的基本概念-仓库
镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。
一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。
通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本,我们可以通过<仓库名>:<标签>的格式来指定具体是这个软件哪个版本的镜像,如果不给出标签,将以latest作为默认标签。
仓库名经常以三段式路径形式出现,比如,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名,但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。
小结
上述基本就是docker 的一些常用的概念,主要是内容还是docker 的架构模型,还有它的三个基本概念,镜像、容器、仓库。
服务器上,docker的安装
这里我使用的是阿里云的服务器来安装docker,如果选择是远程的服务器其实都是大差不差(腾讯云、七牛云、百度云之类的),本地安装我也没试过,毕竟阿里的一月白嫖还是很香的,所以我直接就上阿里的了,这里就不介绍怎么白嫖阿里服务器的选择了,一句话直接拉满。
服务器选择好了之后,还要考虑服务器的系统镜像,我这里使用的是最新的Ubuntu,也可以选择阿里自己优化的Linux,如果是选择的阿里自己优化的Linux 的话,可以直接到阿里的文档中一步一步跟着走即可,文档地址 这个文档里面还是比较全面的,可以用于学习参考。
如果选择跟我一样的Ubuntu 的话,可以跟我下面的命令一步一步走:
查看是否已经安装docker:
如果有安装的话,移除旧版本:
更新软件列表:
允许apt命令可以使用HTTP访问Docker repository:
添加docker 官方GPG key:
添加镜像源(我这里是阿里的):
更新源:
安装docker-ce软件:
重启docker:
测试 - 拉去测试镜像并运行:
测试 - 查看docker 版本:
测试 - 查看docker 的所有本地镜像:
命令补全配置:
这样基本上在服务器上就已经安装好了docker 容器,下一步就是对于docker 的使用了,还有一些对于docker 的基本命令可以在我的另一篇文章:Docker-常用命令总结 中查看,这个文章我会长期补充。
docker 的使用,mysql 和nacos 的镜像拉取和启动
开始使用之前,先总结一下docker 使用学习流程中的几个重点,镜像的拉去 -> 镜像启动 -> 文件和日志的挂载 -> 网络配置管理 -> 私有镜像库的创建 -> 制作镜像 -> docker 的常用单点编排。
首先去拉取镜像,拉取镜像的的前提是要知道镜像对应的版本,这里可以先用docker 提供的dockerHub 网站 来查询对应镜像的版本,比如mysql。
直接去搜索,不用登陆,这里说下docker 的远程库是不用登陆就能拉取的,但是不登陆的话,是不能将自己的镜像推送到docker 提供的库里面的。搜到了直接点进去。
这里提供了两个东西,一个帮助文档里面可以找到mysql 相关的配置内容,可以用于修改mysql 的配置项,还有一个tage 这里面放的就是所有的版本信息,还有相关的pull 的命令,比如:docker pull mysql:5.7.41,这里也不加尾缀的版本,这样拉的就是latest 版本,不建议用这个。
还有一种拉取的方法,直接用run 命令,因为run 命令虽然是启动的命令,但是docker 会在启动前会校验,本地是否存在对应的镜像,如果不存在,则先去远程镜像仓库拉去对应的镜像,然后再启动,具体命令格式后续会提到。
配置阿里云的镜像加速
拉取镜像的时候,我们会发现镜像的拉取速度非常的慢,这里我使用了阿里提供的免费的docker 镜像加速,直接访问阿里云镜像加速地址 ,然后找到镜像加速器,这里有详细的对应命令,直接对着操作就行了,但是注意配置好了之后,一定要重启docker 才能生效。
mysql 的拉取和启动命令
mysql 的镜像拉取:
解析:可以先去docker 镜像官网 查询MySQL 的所有镜像版本,同时还有一些使用方法,找到具体的版本可以直接复制对应的命令。
- pull:去拉取远程镜像。
- mysql:5.7.38:指定mysql 的镜像,如果没有:5.7.38 执行版本的话,就直接拉去mysql 镜像仓库的最新版本。
mysql 的启动运行:
解析:
- run:启动的开始,如果本地存在mysql 的镜像则直接启动,反之则去远程拉取镜像后启动。
- -d:代表后台启动,如果不加的话,就是前端启动,前端启动就意味着不能结束当前。
- -p:将docker 的端口映射到服务器的端口,进行端口暴露,前者是宿主机的,后者docker的。(如果是阿里云服务器的话,要注意添加安全组)
- -v:用于日志绑定映射,还有配置挂载,上面的内容中有两段,第一段是:将自己创建的宿主机上的mysql.conf文件,挂载到docker 容器中的mysql.conf.d 地址上,第二段是:docker 容器中的MySQL 日志文件,映射到宿主机的日志地址。映射和挂载方式就是,宿主机的地址:容器地址
- -e:用于指定MySQL 的本身一些属性执行,比如:MYSQL_ROOT_PASSWORD 可以指定登录密码。
- –name:用于指定镜像启动容器的名字。
- mysql:5.7.38:最后的是启动的镜像版本,不设置则启动MySQL 最新的镜像。
这里还是比较简单的,至于日志和文件挂载我们下面再详说。
nacos 的拉取和启动
nacos 的镜像拉取:
解析:跟上面的mysql 拉取是一样的,只是在docker 文档查询的时候,换成nacos 就行了。
nacos 的启动运行:
解析:跟上面的mysql 启动是一样的,就只有一定的区别
- -e:还是用于加载nacos 本身的一些配置环境变量,如上面的MODE,指定启动模式,standalone 代表的是单例模式。还有NACOS_APPLICATION_PORT 指定端口,如果不指定的话,默认是8848,这里是指定了8849。
日志和文件的挂载
拉取和启动相对来说比较简单,我们只要做到了解,至于命令都是练出来的。我们现在说日志和文件的挂载,docker 提供出来两种方式给我们使用,我们一个个说。
开始前,先说一会docker 镜像的结构,docker 镜像由多个只读层叠加而成,启动容器时,docker会加载只读镜像层并在镜像栈顶部加一个读写层。如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件版本仍然存在,只是已经被读写层中该文件的副本所隐藏,此即**“写时复制(COW)”机制**。
再者说docker 本身的数据存储是不能持久化的,数据是随着容器的启动而读写,容器的删除而清除。只有添加了”卷“,也就是一个或多个目录,这样就可以将数据从宿主机挂载到容器中,这样就不再需要重复上面的拿去的过程了,直接通过宿主机上的文件就能完成读写。
另为一种方法就是:挂载,区别于添加存储卷的配置放在构建镜像时,挂载是在启动容器时的配置,挂载也不在是对于docker 服务管理区域中添加文件目录,同时不再由docker 管理,这种方式是在宿主机上创建目录,然后通过映射挂载将宿主机上的任意文件或文件夹挂载到容器上。
这两种方式的本质还是一样的,就是将自己的文件或者目录挂载到容器上,让容器不再拿取底层镜像的文件进行读写,但是又有区别前者是在docker 的服务管理区创建的,由docker 管理,不存在宿主机的系统镜像不同,权限问题导致文件读写失败。后者是在宿主机中创建的,这里就应该各种系统的权限问题,导致配置繁琐,但是docker 容器重复启动时,访问的文件是同一个。
存储卷优化写入速度
从上面也知道了,docker 容器的读写都是在启动时构建的读写层上面,也就是说每一次的读或者写,都需要将需要读写的文件,复制到读写层,然后读写完成之后再放回对应的镜像层,下次的文件读写再重复这个操作。
为了避免这种情况,构建镜像的时候,Dockerfile 配置文件中应该加入一个存储卷配置。一般情况下,docker 管理宿主机文件系统的一部分,默认位于 /var/lib/docker/volumes 目录中,之后添加的文件夹也是在这个目录下。(最常用的方式)
增加存储卷:
解析:
- FROM:添加基础运行环境,openjdk:8-jdk-alpine
- VOLUME:增加存储卷的命令,这里是增加两个存储全,tmp 和logs
构建镜像:
解析:
- build:开始构建镜像
- -t:镜像的名字及标签,一般命名规则是 仓库名/镜像名:版本号
- . :一定注意,这后面还跟着个 ”.“ ,表示当前目录,这实际上是在指定上下文的目录是当前目录,docker build 命令会将该目录下的内容打包交给 Docker 引擎以帮助构建镜像
运行容器:
查看存储卷:
查看容器信息:
解析:这里可以看到存储的具体目录,比如我下面这个,我们能发现这里存储卷其实是匿名卷,我们也只能通过这里的具体目录找到对应的文件地址。
输出文件内容:
解析:进入文件后,我们可以直接用 ls 命令查看匿名卷下面的所有文件,然后输出具体文件内容。
清理挂载的匿名卷:
清理所有匿名卷:
小结
这里其实还需要注意一点,当容器删除时,匿名卷是不会跟着删除的,这就是实现了数据持久化,但是同时再次启动容器的话,还再次生成一个新的匿名卷,这里就需要手动去命令删除了。
bind挂载共享存储
Bind mounts 模式和Volumes 非常相似,开头的时候也说了,Bind mounts 模式的不同点在于是将宿主机上的任意文件或文件夹挂载到容器,而Volumes 本质上是将Docker服务管理的一块区域(默认是/var/lib/docker/volumes下的文件夹)挂载到容器上。
对于存储卷上面其实也可以看出,重复启动容器会生成多一个匿名卷,每一次访问的都不是同一个文件,这个时候比如mysql 的数据持久化就不能使用这种方法了,所以需要bind 挂载。
先用命令创建一个文件目录,然后我们用上面mysql 的运行命令来分析,上面也说过bind 挂载是在运行镜像时的配置,而不是构建镜像时的配置。
mysql 的运行命令:
解析:这里只看-v 命令
- -v:第一个是将宿主机上的"/tmp/etc/mysql" 目录下的文件,挂载到docker 容器的"/etc/mysql/mysql.conf.d/" 的目录下,用于将宿主机上面的mysql 配置文件替换到docker 容器上的配置项,比如大小忽略
- -v:第二个是将宿主机上的"/tmp/data/mysql" 目录,挂载到docker 容器的"var/lib/mysql" 的目录下,用于数据的持久化存储。
查看容器的状态命令还是和上面一样的,就不重复说了,我们运行之后可以发现,容器删除之后再次启动的话,还是读取同一个文件目录,不会去创建匿名卷,这样我们就能做到共享存储,就算开启了多个mysql 容器,但是存储的路劲是一个的话,也就是挂载的目录是同一个的话,那么数据就会是同一个。
小结
bind mount 和volume 其实都是利用宿主机的文件系统,不同之处在于volume 是docker 自身管理的目录中的子目录,所以不存在权限引发的挂载的问题,并且目录路径是docker 自身管理的,所以也不需要在不同的服务器上指定不同的路径,你不需要关心路径。
bind mount 方式的优点也很明显,除了不同操作系统之间的配置问题,还有权限问题,它能做到volume 方法不能做到的数据共享。
网络优化
上面我们的各种启动容器的命令中其实也看到,对于端口的管理问题,docker 还是比较多的,集群启动时,各个服务的端口也都需要同一个管理,我们下面就说一下docker 的网络配置问题。
还有一个问题,常见的微服务中我们也有能体会到,比如nacos 绝大多数情况下,我们是不可能暴露在公网上面的,但是同时我其余的服务又要访问到nacos,这里就要对docker 的网络进行配置了。
开始之前还是要说一下docker 的网络原理。
docker 使用Linux 桥接,在宿主机虚拟一个docker 容器网桥(docker0),docker 启动一个容器时会根据docker 网桥的网段分配给容器一个IP地址,称为Container-IP,同时docker 网桥是每个容器的默认网关,因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP 直接通信。
docker 网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法通过直接Container-IP 访问到容器,如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主主机(端口映射),即docker run 创建容器时候通过 -p 或 -P 参数来启用,访问容器的时候就通过[宿主机IP]:[容器端口]访问容器。
这上面两段话说的通俗一点就是:宿主机本身存在一个网卡,docker 会自动生成一个docker0 的网桥,当微服务容器或中间件容器启动的时候,会在docker0 上进行注册,然后由docker0 分配一个虚拟的IP,这个时候外部微服务,是无法访问到我们当前宿主机上的服务的。
这个时候就需要端口映射,也就是上面的-p 命令,将宿主机上的端口映射到容器上,比如nacos 启动时,是8849端口,那么我也需要映射到容器的8849端口上,但是容器的IP 并不是宿主机上的IP,如果不进行端口映射就不会将nacos 的服务暴露在公网上。如果再启动一个nacos 服务,不是不需要修改端口的,因为docker0 网桥分配的IP 对于两个nacos 服务是不一样的,但是如果两个服务同时端口映射的话,就不能映射到同一个端口上。
除了小写的-p 之外,还有大写的-P,这个不适用推荐,因为这个是随机映射的宿主机端口。
docker 的五种网络模式
上面也说了宿主机网卡和容器服务之间是有一个docker0 的网桥,那么也可以不用这个网桥,而且使用我们自己配置的网桥。下面我们逐个分析上面列表的网络模式。
首先说host 模式,这个一般不推荐使用,因为这个模式就是不经过docker0,而是直接和宿主机共用网卡,这就会导致问题,如果服务过多、集群过多,就会出现端口管理过于复杂,还有就是有些服务一般是不会暴露在公网上面的,比如:当做注册中心和配置中心的nacos。
配置命令:
解析:使用–-network=host 或者-net=host 都可以,这里是去除了-p 的命令。
container 模式,这个使用的一般也不多,这个主要共享容器的IP,比如:先启动一个nacos,这个时候docker0 会分配一个IP 给到当前容器,然后再启动一个nacos,这个时候如果选择这种模式,那么docker0 就不会再分配IP 给新启动的容器,而是共用指定容器的IP,那么可想而知,这个时候的端口就不能再是8849了,这个也会增加端口管理的问题。
配置命令:
none 模式,这种模式下没有网卡、IP、路由等信息,需要我们自己为Docker容器添加网卡、配置IP等。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。比如:自动任务之类的。
配置命令:
overlay 模式,这个是集群时使用的网络模式,这里的目前是多台宿主机的网络关联,跨主机进行通信。在这个overlay 网络模式里面,有一个类似于服务网关的地址,然后把这个包转发到物理服务器这个地址,最终通过路由和交换,到达另一个服务器的ip地址。
这个后面配置集群的时候再说。
最后一种就是默认的网桥模式,docker0 网桥配置,bridge 模式,这种模式上面也描述过了,本身所有的服务都会注册到网桥上,然后由网桥进行分配IP,这个时候是不会对外暴露的,只有端口进行映射绑定之后,外部服务才能访问容器服务。
创建网络
当我们不希望使用docker0 网桥的时候,也可以创建自己的网桥,因为如果我们的微服务不需要暴露的话,微服务访问是通过getway 进行转发,那么我们只需要暴露getway 就行,其余的微服务不需要想再经过宿主机的网卡,这个时候我们就可以使用自己的网络。
比如:微服务A 要查询mysql 服务中的数据,那么是进过访问宿主机的网卡,然后再调到mysql 的服务中。这样的调用会比较浪费时间,我们使用自己创建的网桥可以避免进过宿主机的网卡,直接在服务之期间通信。
首先我们先看 查看网络列表命令:
创建一个桥接网络命令:
解析:learn-docker-network 是网络名称可以替换
将mysql 启动并接入网络,注意我们这边不需要将mysql 的服务暴露,所以我们不需要将mysql 的端口进行绑定
mysql 启动命令:
解析:还是使用–network 命令,它的等于的值就是我们上面创建的网络名称。
nacose 启动命令:
解析:连接网络的方式还是跟上面一样的。
查看网络详情命令:
解析:learn-docker-network 是自己创建的网桥名称,可以替换。这里就能查看到当前网桥连接了几个服务,同时分配的IP 都是多少。
最后我们在修改服务的配置,docker 网络访问,可以通过IP或者通过服务名称都是可以的,这里我们通过服务名称访问,如果我们使用了maven 打包的方式,我们只需要将pom 文件修改就可以,编译后pom 文件中的内容会自动填充到yml 中。
后续的重新构建镜像,然后重启服务就不一 一演示了,可以自己试试就行。
小结
docker 的网络配置方式,大部分情况下可以使用自己创建的网桥,也可以使用默认的docker0 网桥,其余的网络方式不推荐使用,后续有与集群部署的时候,我们在讨论另外的网络配置方式。
总结
本篇致讲了docker 的基本使用、文件挂载的两种方式,以及最后的创建自己的网络和docker 的默认网络。后续再讲docker 的镜像仓库,还有如何构建镜像,docker-compose 容器编排,以及swarm 集群编排。
后续我还会以hexo 博客项目来构建一次docker 的镜像,然后进行文件挂载(算是本地hexo 的数据迁移),然后启动测试,将镜像上传到镜像仓库,来实践一下docker 的使用,有兴趣的可以看下。
XhLcp-1680847604882)]
最后我们在修改服务的配置,docker 网络访问,可以通过IP或者通过服务名称都是可以的,这里我们通过服务名称访问,如果我们使用了maven 打包的方式,我们只需要将pom 文件修改就可以,编译后pom 文件中的内容会自动填充到yml 中。
后续的重新构建镜像,然后重启服务就不一 一演示了,可以自己试试就行。
小结
docker 的网络配置方式,大部分情况下可以使用自己创建的网桥,也可以使用默认的docker0 网桥,其余的网络方式不推荐使用,后续有与集群部署的时候,我们在讨论另外的网络配置方式。
总结
本篇致讲了docker 的基本使用、文件挂载的两种方式,以及最后的创建自己的网络和docker 的默认网络。后续再讲docker 的镜像仓库,还有如何构建镜像,docker-compose 容器编排,以及swarm 集群编排。