镜像制作及原因
镜像制作是因为某种需求,官方的镜像无法满足需求,需要我们通过一定手段来自定
义镜像来满足要求。
制作镜像往往因为以下原因
1.
编写的代码如何打包到镜像中直接跟随镜像发布
2.
第三方制作的内容安全性未知,如含有安全漏洞
3.
特定的需求或者功能无法满足,如需要给数据库添加审计功能
4.
公司内部要求基于公司内部的系统制作镜像,如公司内部要求使用自己的操作系
统作为基础镜像
Docker 镜像制作方式
制作容器镜像,主要有两种方法:
•
制作快照方式获得镜像(偶尔制作的镜像):在基础镜像上(比如 Ubuntu
),先登
录容器中,然后安装镜像需要的所有软件,最后整体制作快照。
•
Dockerfile 方式构建镜像(经常更新的镜像):将软件安装的流程写成
Dockerfile
,
使用
docker build
构建成容器镜像。
![](https://i-blog.csdnimg.cn/direct/2117c788bc314e9db7fb562fe9b3daa8.png)
快照方式制作镜像
制作命令
docker commit
•
功能
从容器创建一个新的镜像。
•
参数
○
-a :
提交的镜像作者;
○
-c :
使用
Dockerfile
指令来创建镜像;可以修改启动指令
○
-m :
提交时的说明文字;
○
-p :
在
commit
时,将容器暂停。
•
样例
![](https://i-blog.csdnimg.cn/direct/69f1546bb203422d8259fa722ff2787b.png)
Dockerfile 格式
该指令不区分大小写。然而,约定是它们是大写的,以便更容易地将它们与参数区分
开来。 Docker 按顺序运行指令
Dockerfile Docker 将以
开头
的行视为
#
注释,行中其他任何地方的标记
#
都被视为参数。这允许像 这样的语句:
![](https://i-blog.csdnimg.cn/direct/896b5bd2dd1143f4ac5328ec91e15d92.png)
为什么需要 Dockerfile
•
可以按照需求自定义镜像
○
和
docker commit
一样能够自定义镜像,官方的镜像可以说很少能直接满足
我们应用的,都需要我们自己打包自己的代码进去然后做成对应的应用镜像对外
使用。
•
很方便的自动化构建,重复执行
○
通过
dockerfile
可以自动化的完成镜像构建,而不是像
docker commit
一样,
手动一个命令一个命令执行,而且可以重复执行,
docker commit
的话很容易忘
记执行了哪个命令,哪个命令没有执行。
•
维护修改方便,不再是黑箱操作
○
使用
docker commit
意味着所有对镜像的操作都是黑箱操作,生成的镜像也
被称为黑箱镜像
,dockerfile
很容易二次开发。
•
更加标准化,体积可以做的更小
○
docker
容器启动后,系统运行会生成很多运行时的文件,如果使用
commit
会
导致这些文件也存储到镜像里面,而且
commit
的时候安装了很多的依赖文件,
没有有效的清理机制的话会导致镜像非常的臃肿。使用
Dockerfile
则会更加标准
化,而且提供多级构建,将编译和构建分开,不会有运行时的多余文件,更加的
标准化。
Dockerfile 指令
指令清单
![](https://i-blog.csdnimg.cn/direct/7cc93dd9b89f4a95965fb229bdee8cda.png)
![](https://i-blog.csdnimg.cn/direct/7b4e3c7a3b1c409793ac8299bd4a057c.png)
FROM
•
功能
○
FROM
指令用于
为镜像文件构建过程指定基础镜像
,后续的指令运行于此基
础镜像所提供的运行环境;
注意事项
○
FROM
指令必须是
Dockerfile
中
非注释行或者
ARG
之后的第一个指令
;
○
实践中,基准镜像可以是任何可用镜像文件,默认情况下,
docker build
会在
docker
主机上查找指定的镜像文件
,在其不存在时,则
会自动从
Docker
的公共
库
pull
镜像下来。如果找不到指定的镜像文件,
docker build
会返回一个错误信
息;
○
FROM
可以在一个
Dockerfile
中出现多次,如果有需求在一个
Dockerfile
中
创建多个镜像
,
或将一个构建阶段作为另一个的依赖。
○
如果
FROM
语句没有指定镜像标签,则
默认使用
latest
标签
。
![](https://i-blog.csdnimg.cn/direct/deb6f0d3840e4d2f99317a7cdf44988e.png)
•
参数
○
<platform>:
构建的
cpu
架构,如
linux/amd64
,
linux/arm64
,
windows/amd64
○
<image>
:指定作为
base image
的名称;
○
<tag>
:
base image
的标签,省略时默认
latest
;
○
<digest>
:是镜像的哈希码;
○
AS <name>:
指定构建步骤的名称,配合
COPY --from=<name>
可以完成多
级构建
![](https://i-blog.csdnimg.cn/direct/88b4c793c1c145be82d99c2883874424.png)
LABEL
•
功能
○
为镜像添加元数据,元数据是
kv
对形式
•
语法
Shell
LABEL <key>=<value> <key>=<value> <key>=<value> ...
![](https://i-blog.csdnimg.cn/direct/b8b1bafe96f44f5e846827b1743d18af.png)
COPY
•
功能
○
用于从
docker
主机复制新文件或者目录至创建的新镜像指定路径中 。
•
语法
![](https://i-blog.csdnimg.cn/direct/0cad8b6dfbea40d9b010b347a604e19c.png)
•
参数
○
<src>
:要复制的源文件或目录,
支持使用通配符
;
○
<dest>
:目标路径,即正在创建的
image
的文件系统路径;
建议
<dest>
使用
绝对路径
,否则,
COPY
指定以
WORKDIR
为当前路径
在路径中有空白字符时,通常使用第
2
种格式;
○
--chown
:修改用户和组
○
--from <name>
可选项
:
▪
可以从之前构建的步骤中拷贝内容,结合 FROM .. AS <name>
往往用作
多级构建,后续我们有实战课专门完成多级构建
•
注意事项
○
<src>
必须是
build
上下文中的路径,
不能是其父目录中的文件
;
○
如果
<src>
是目录
,则其
内部文件或子目录会被递归复制
,但
<src>
目录自身
不会被复制
;
○
如果指定了多个
<src>
,或在
<src>
中使用了通配符,则
<dest>
必须是一个目
录,且
必须以
/
结尾
;
○
如果
<dest>
事先不存在,它将
会被自动创建
,这包括父目录路径。
![](https://i-blog.csdnimg.cn/direct/ef0b3a6f266d4ce1bb3bf8c32d8b9072.png)
ENV
•
功能
○
用于为镜像定义所需的
环境变量
,并可被
Dockerfile
文件中
位于其后的
其它指
令
(
如
ENV
、
ADD
、
COPY
等
)
所调用
○
调用格式为
$variable_name
或
${variable_name}
•
语法
![](https://i-blog.csdnimg.cn/direct/c7c450eb56804642842a1b7d378f6353.png)
![](https://i-blog.csdnimg.cn/direct/7afc4d8368c4424ead9699cb693c6249.png)
WORKDIR
•
功能
○
为
Dockerfile
中所有的
RUN
、
CMD
、
ENTRYPOINT
、
COPY
和
ADD
指定
设
定工作目录
•
语法
![](https://i-blog.csdnimg.cn/direct/509b1e821c994e09ba75405bfdae8505.png)
注意事项
○
默认的工作目录是
/
○
如果提供了相对路径,它将相对于前一条
WORKDIR
指令的路径。
○
WORKDIR
指令可以解析先前使用设置的环境变量
ENV
ADD
•
功能
○
ADD
指令类似于
COPY
指令,
ADD
支持使用
TAR
文件和
URL
路径
,
会自动
完成解压和下载
•
语法
![](https://i-blog.csdnimg.cn/direct/d55cd298b9ae43f0820fc2727d1e6a3a.png)
•
参数
○
<src>
:要复制的源文件或目录,
支持使用通配符
;
○
<dest>
:目标路径,即正在创建的
image
的文件系统路径;
建议
<dest>
使用
绝对路径
,否则,
ADD
指定以
WORKDIR
为其实路径;在路径中有空白字符时,
通常使用第
2
种格式;
○
--chown
:修改用户和组
![](https://i-blog.csdnimg.cn/direct/62979b6fbff44295891035439424a1d2.png)
RUN
•
功能
○
用于指定
docker build
过程中运行的程序,其可以是任何命令
•
语法
![](https://i-blog.csdnimg.cn/direct/2d89a7068cc14253aa310adbb584a272.png)
•
参数
○
第一种格式中,
<command>
通常是一个
shell
命令
, 且
以
“/bin/sh -c”
来运
行
它
,Windows
默认为
cmd /S /C
。如果一个脚本
test.sh
不能自己执行,必须要
/bin/sh -c test.sh
的方式来执行,那么,如果使用
RUN
的
shell
形式
,最后
得到的命令相当于:
Bash
/bin/sh -c
"/bin/sh -c 'test.sh'"
○
第二种语法格式中的参数是一个
JSON
格式的数组
,其中
<executable>
为要
运行的命令,后面的
<paramN>
为传递给命令的选项或参数;然而,此种格式指
定的命令
不会以
“/bin/sh -c”
来发起
,因此
常见的
shell
操作
如变量替换以及通配
符
(?,*
等
)
替换
将不会进行
;不过,如果要运行的命令依赖于此
shell
特性的话,可
以将其替换为类似下面的格式。
RUN ["/bin/bash", "-c", "<executable>",
"<param1>"]
Shell
ENV WEB_SERVER_PACKAGE nginx-1.21.1.tar.gz
RUN cd ./src && tar -xf ${WEB_SERVER_PACKAGE}
![](https://i-blog.csdnimg.cn/direct/c7cdcc5d21ae404380bdb27d6af32cfa.png)
CMD
•
功能
○
类似于
RUN
指令
,
CMD
指令也可用于运行任何命令或应用程序,不过,二
者的运行时间点不同
○
RUN
指令运行于映像文件
构建
过程
中,而
CMD
指令运行于基于
Dockerfile
构建出的新映像文件
启动
一个容器时
○
CMD
指令的首要
目的在于为启动的容器指定默认要运行的程序
,且其运行结
束后,容器也将终止;不过,
CMD
指定的命令其可以被
docker run
的命令行选
项所覆盖
○
在
Dockerfile
中可以存在
多个
CMD
指令,但仅最后一个会生效
![](https://i-blog.csdnimg.cn/direct/0550c66a4ef846648993ca753d622555.png)
•
注意事项
○
第二种则用于为
ENTRYPOINT
指令提供默认参数
○
json
数组中,要使用
双引号
,单引号会出错
![](https://i-blog.csdnimg.cn/direct/8d1cd862940348e7975a739294c67227.png)
![](https://i-blog.csdnimg.cn/direct/177848546bd84221aaf8d7847b227f63.png)
EXPOSE
•
功能
○
用于为容器
声明
打开指定要监听的端口
以实现与外部通信
○
该
EXPOSE
指令实际上并不发布端口。它充当构建图像的人和运行容器的人之
间的一种文档,关于要发布哪些端口。要在运行容器时实际发布端口,使用
-p
参
数发布和映射一个或多个端口,或者使用
-P
flag
发布所有暴露的端口并将它们映
射宿主机端口。
•
语法
Shell
EXPOSE <port> [<port>/<protocol>...]
•
参数
○
<protocol>
:
tcp/udp
协议
○
<port>
:端口
•
样例
Shell
EXPOSE 80/tcp
ENTRYPOINT
•
功能
○
用于指定容器的启动入口
•
语法
![](https://i-blog.csdnimg.cn/direct/bde6207bafd547c08d1084d10d650d9e.png)
•
参数
○
json
数组中,要使用
双引号
,单引号会出错
•
样例
Shell
ENTRYPOINT ["nginx","-g","daemon off;"]
ARG
•
功能
○
ARG
指令类似
ENV
,定义了一个变量;区别于
ENV
:用户可以在构建时
docker build --build-arg <varname> = <value>
进行对变量的修改;
ENV
不可以;
○
如果用户指定了未在
Dockerfile
中定义的构建参数,那么构建输出警告。
•
语法
![](https://i-blog.csdnimg.cn/direct/c2aa74b9c3894c2395b048fd12894a14.png)
•
注意事项
○
Dockerfile
可以包含一个或多个
ARG
指令
○
ARG
支持指定默认值
○
使用范围:定义之后才能使用,定义之前为空,如下面的案例,执行命令
docker build --build-arg username=what_user .
第二行计算结果为
some_user
,不是我们指定的
build-arg
中的参数值
what_user
○
ENV
和
ARG
同时存在,
ENV
会覆盖
ARG
![](https://i-blog.csdnimg.cn/direct/85d0878d141b4a37b385c7ec14c4532d.png)
![](https://i-blog.csdnimg.cn/direct/86d4753aa57740fba399b2125b8e65c0.png)
VOLUME
•
功能
○
用于在
image
中创建一个挂载点目录
○
通过
VOLUME
指令创建的挂载点,无法指定主机上对应的目录,是自动生成
的。
•
语法
![](https://i-blog.csdnimg.cn/direct/3c677be151804f30bb18f5cc3dfb1859.png)
•
参数
○
mountpoint:
挂载点目录
○
注意事项
▪
如果挂载点目录路径下此前有文件存在,docker run
命令会在卷挂载完
成后将此前的所有文件复制到新挂载的卷中
▪
其实 VOLUME
指令只是起到了声明了容器中的目录作为匿名卷,但是并
没有将匿名卷绑定到宿主机指定目录的功能。
▪
volume 只是指定了一个目录,用以在用户忘记启动时指定
-v
参数也可以
保证容器的正常运行。比如
mysql
,你不能说用户启动时没有指定
-v
,然后
删了容器,就把
mysql
的数据文件都删了,那样生产上是会出大事故的,所
以
mysql
的
dockerfile
里面就需要配置
volume
,这样即使用户没有指定
-v
,
容器被删后也不会导致数据文件都不在了。还是可以恢复的。
▪
volume 与
-v
指令一样,容器被删除以后映射在主机上的文件不会被删除。
▪
如果-v
和
volume
指定了同一个位置,会以
-v
设定的目录为准,其实
volume
指令的设定的目的就是为了避免用户忘记指定
-v
的时候导致的数据丢
失,那么如果用户指定了
-v
,自然而然就不需要
volume
指定的位置了。
•
样例
Shell
VOLUME ["/data1","/data2"]
SHELL
•
功能
○
SHELL
指令允许覆盖用于
shell
命令形式的默认
shell
。
○
Linux
上的默认
shell
是
["/bin/sh"
,
"-c"]
,在
Windows
上是
["cmd"
,
"/S"
,
"/C"]
○
SHELL
指令必须以
JSON
格式写入
Dockerfile
。
•
语法
Shell
SHELL ["executable", "parameters"]
•
参数
○
executable
:
shell
可执行文件的位置
○
parameters
:
shell
执行的参数
○
注意事项
▪
SHELL 指令可以多次出现。
▪
每个 SHELL
指令都会覆盖所有先前的
SHELL
指令,并影响所有后续指
令。
▪
该 SHELL
指令在
Windows
上特别有用,因为
windows
行有两种不同的
shell
:
cmd
和
powershell
USER
•
功能
○
用于指定运行
image
时的或运行
Dockerfile
中任何
RUN
、
CMD
或
ENTRYPOINT
指令定的程序时的用户名或
UID
○
默认情况下,
container
的运行身份为
root
用户
•
语法
Shell
USER <user>[:<group>]
USER <UID>[:<GID>]
•
参数
○
user:
用户
○
group
:用户组
○
uid:
用户
id
○
gid:
组
id
○
注意事项
▪
<UID>可以为任意数字,但实践中其必须为
/etc/passwd
中某用户的有效
UID,
否则将运行失败
HEALTHCHECK
•
功能
○
HEALTHCHECK
指令告诉
Docker
如何测试容器以检查它是否仍在工作。
○
即使服务器进程仍在运行,这也可以检测出陷入无限循环且无法处理新连接
的
Web
服务器等情况。
•
语法
Shell
HEALTHCHECK [OPTIONS] CMD command (check container health by
running a command inside the container)
HEALTHCHECK NONE (disable any healthcheck inherited from the base
image)
•
参数
○
OPTIONS
选项有:
▪
--interval=DURATION (default: 30s):每隔多长时间探测一次,默认
30
秒
▪
-- timeout= DURATION (default: 30s):服务响应超时时长,默认
30
秒
▪
--start-period= DURATION (default: 0s):服务启动多久后开始探测,默
认
0
秒
▪
--retries=N (default: 3):认为检测失败几次为宕机,默认
3
次
○
返回值
▪
0:容器成功是健康的,随时可以使用
▪
1:不健康的容器无法正常工作
▪
2:保留不使用此退出代码
![](https://i-blog.csdnimg.cn/direct/b8ac0f95117244e1857b65f84284105d.png)
ONBUILD
•
功能
○
用于在
Dockerfile
中
定义一个触发器
○
以该
Dockerfile
中的作为基础镜像由
FROM
指令在
build
过程中被执行
时,
将
会
“
触发
”
创建其
base image
的
Dockerfile
文件中的
ONBUILD
指令
定义的触
发器
•
语法
Shell
ONBUILD <INSTRUCTION>
•
参数:
○
INSTRUCTION
:
dockerfile
的一条指令
•
样例
Shell
ONBUILD ADD . /app/src
![](https://i-blog.csdnimg.cn/direct/f0afe0bee25640038349825cc93e614f.png)
STOPSIGNAL
•
功能
○
STOPSIGNAL
指令设置将发送到容器的系统调用信号。
○
此信号可以是与内核的系统调用表中的位置匹配的有效无符号数,例如
9
,
或者
SIGNAME
格式的信号名,例如
SIGKILL
。
•
语法
Shell
STOPSIGNAL signal
•
参数
○
STOPSIGNAL
指令设置将发送到容器出口的系统调用信号。 此信号可以是与
内核的系统调用表中的位置匹配的有效无符号数,例如
9
,或者
SIGNAME
格式
的信号名,例如
SIGKILL
。
制作命令
docker build
•
功能
docker build
命令用于使用
Dockerfile
创建镜像。
•
语法
Shell
docker build [OPTIONS] PATH | URL |
•
关键参数
○
--build-arg=[] :
设置镜像创建时的变量;
○
-f :
指定要使用的
Dockerfile
路径;
○
--label=[] :
设置镜像使用的元数据;
○
--no-cache :
创建镜像的过程不使用缓存;
○
--pull :
尝试去更新镜像的新版本;
○
--quiet, -q :
安静模式,成功后只输出镜像
ID
;
○
--tag, -t:
镜像的名字及标签,通常
name:tag
或者
name
格式;可以在一次构
建中为一个镜像设置多个标签。
○
--network:
默认
default
。在构建期间设置
RUN
指令的网络模式
•
样例
Shell
docker build -t mynginx:v1 .
Dockerfile 编写优秀实践
1.
善用
.dockerignore
文件
使用它可以标记在执行
docker build
时忽略的路径和文件,
避免
发送
不必要的数据
内
容,从而
加快
整个镜像
创建
过程。
2.
镜像的多阶段构建
通过多步骤创建,可以将编译和运行等过程分开,保证最终生成的镜像只包括运行应
用所需要的最小化环境。当然,用户也可以通过分别构造编译镜像和运行镜像来达到
类似的结果,但这种方式需要维护多个
Dockerfile
。
3.
合理使用缓存
如合理使用
cache
,减少内容目录下的文件,
内容不变的指令尽量放在前面
,这样可
以尽量复用;
4.
基础镜像尽量使用官方镜像,并选择体积较小镜像
容器的核心是应用,大的平台微服务可能几十上百个。选择过大的父镜像(如
Ubuntu
系统镜像)会造成最终生成应用镜像的臃肿,
推荐选用瘦身过的应用镜像(如
node:slim
),或者较为小巧的系统镜像(如
alpine
、
busybox
或
debian
)
;
5.
减少镜像层数
如果希望所生成镜像的层数尽量少,则要
尽量合并
RUN
、
ADD
和
COPY
指令
。通常
情况下,多个
RUN
指令可以合并为一条
RUN
指令;如
apt get update&&apt install
尽
量写到一行
6.
精简镜像用途
尽量让每个镜像的用途都比较
集中单
一,避免构造大而复杂、多功能的镜像;
7.
减少外部源的干扰
如果确实要从外部引入数据,需要指定持久的地址,并带版本信息等,让他人可以复
用而不出错。
8.
减少不必要的包安装
只安装需要的包,不要安装无用的包,减少镜像体积。
镜像制作常见问题
1. ADD 与 COPY 的区别
ADD
:不仅能够将构建命令所在的主机本地的文件或目录,而且能够将远程
URL
所对应的文件或目录,作为资源复制到镜像文件系统。所以,可以认为
ADD
是增强版
的
COPY
,支持将远程
URL
的资源加入到镜像的文件系统。
COPY
:
COPY
指令能够将构建命令所在的主机本地的文件或目录,复制到镜像
文件系统。
有的时候就是只需要拷贝压缩包,那么我们就要用
COPY
指令了
2. CMD 与 EntryPoint 的区别
ENTRYPOINT
容器启动后执行的命令
,
让容器执行表现的像一个可执行程序一
样
,
与
CMD
的 区 别 是 不 可 以 被
docker run
覆 盖
,
会 把
docker run
后 面 的
参 数 当 作 传 递 给
ENTRYPOINT
指令的参数。
Dockerfile
中只能指定一个
ENTRYPOINT,
如果指定了很多
,
只 有 最 后 一 个 有
效 。
docker run
命 令 的
-entrypoint
参 数 可 以 把 指 定 的 参 数 继 续 传 递 给
ENTRYPOINT
组合使用
ENTRYPOINT
和
CMD, ENTRYPOINT
指定默认的运行命令
, CMD
指定默认的运行参数
3. 多个 From 指令如何使用
多个
FROM
指令并不是为了生成多根的层关系,最后生成的镜像,仍以最后一条
FROM
为准,之前的
FROM
会被抛弃,那么之前的
FROM
又有什么意义呢?
每一条
FROM
指令都是一个构建阶段,多条
FROM
就是多阶段构建,虽然最后
生成的镜像只能是最后一个阶段的结果,但是,能够将前置阶段中的文件拷贝到
后边的阶段中,这就是多阶段构建的最大意义。
最大的使用场景是将编译环境和运行环境分离
.
4. 快照和 dockerfile 制作镜像有什么区别?
等同于为什么要使用
Dockerfile
。
5. 什么是空悬镜像(dangling )
仓库名、标签均为
<none>
的镜像被称为虚悬镜像,一般来说,虚悬镜像已经失去了存
在的价值,是可以随意删除的。
造成虚悬镜像的原因:
原因一:
原本有镜像名和标签的镜像,发布了新版本后,重新
docker pull ***
时,旧的镜像名
被转移到了新下载的镜像身上,而旧的镜像上的这个名称则被取消;
原因二:
docker build
同样可以导致这种现象。比如用
dockerfile1
构建了个镜像
tnone1:v1,
又
用另外一个
Dockerfile2
构建了一个镜像
tnone1:v1
,这样之前的那个镜像就会变成空
悬镜像。
6. 中间层镜像是什么?
为了加速镜像构建、重复利用资源,
Docker
会利用
中间层镜像
。所以在使用一段时间
后,可能会看到一些依赖的中间层镜像。默认的
docker image ls
列表中只会显示
顶层镜像,如果希望显示包括中间层镜像在内的所有镜像的话,需要加
-a
参数。
这样会看到很多无标签的镜像,与之前的虚悬镜像不同,这些无标签的镜像很多都是
中间层镜像,是其它镜像所依赖的镜像。这些无标签镜像不应该删除,否则会导致上
层镜像因为依赖丢失而出错。实际上,这些镜像也没必要删除,因为之前说过,相同
的层只会存一遍,而这些镜像是别的镜像的依赖,因此并不会因为它们被列出来而多
存了一份,无论如何你也会需要它们。只要删除那些依赖它们的镜像后,这些依赖的
中间层镜像也会被连带删除。
Docker 镜像原理
docker
是操作系统层的虚拟化,所以
docker
镜像的本质是在模拟操作系统。我们先看
下操作系统是什么。
操作系统基础
操作系统由:进程调度子系统、进程通信子系统、内存管理子系统、设备管理子系统、
文件管理子系统
、网络通信子系统、作业控制子系统组成。
Linux
的
文件管理子系统
由
bootfs
和
rootfs
组成。
(1). bootfs
:要包含
bootloader
和
kernel, bootloader
主要是引导加载
kernel, Linux
刚
启动时会加载
bootfs
文件系统,在
Docker
镜像的最底层是引导文件系统
bootfs
。这
一层与我们典型的
Linux/Unix
系统是一样的,包含
boot
加载器和内核。当
boot
加载
完成之后整个内核就都在内存中了,此时内存的使用权已由
bootfs
转交给内核,此时
系统也会卸载
bootfs
。
(2). rootfs
: 在
bootfs
之上。包含的就是典型
Linux
系统中的
/dev, /proc, /bin, /etc
等
标准目录和文件。
rootfs
就是各种不同的操作系统发行版,比如
Ubuntu
,
Centos
等等。
Union FS(联合文件系统)
联合文件系统(
Union File System
),
2004
年由纽约州立大学开发,它可以把多个
目录内容联合挂载到同一个目录下,而目录的物理位置是分开的。
UnionFS
可以把只
读和可读写文件系统合并在一起,具有写时复制功能,允许只读文件系统的修改可以
保存到可写文件系统当中。
UnionFS
(联合文件系统)是一种分层、轻量级并且高性能的文件系统,它支持对
文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚
拟文件系统下。
UnionFS
是一种为
Linux
,
FreeBSD
和
NetBSD
操作系统设计的把其
他文件系统联合到一个联合挂载点的文件系统服务。它使用
branch
把不同文件系统的
文件和目录
“
透明地
”
覆盖,形成一个单一一致的文件系统。这些
branches
或者是
read-only
或者是
read-write
的,所以当对这个虚拟后的联合文件系统进行写操作的时
候,系统是真正写到了一个新的文件中。看起来这个虚拟后的联合文件系统是可以对
任何文件进行操作的,但是其实它并没有改变原来的文件,这是因为
unionfs
用到了一
个重要的资管管理技术叫写时复制。
写时复制(
copy-on-write
,下文简称
CoW
),也叫隐式共享,是一种对可修改资
源实现高效复制的资源管理技术。它的思想是,如果一个资源是重复的,但没有任何
修改,这时候并不需要立即创建一个新的资源;这个资源可以被新旧实例共享。创建
新资源发生在第一次写操作,也就是对资源进行修改的时候。通过这种资源共享的方
式,可以显著地减少未修改资源复制带来的消耗,
但是也会在进行资源修改的时候增
加小部分的开销。
再看 Docker 镜像是什么
image
里面是一层层文件系统
Union FS
。联合文件系统,可以将几层目录挂载到
一起,形成一个虚拟文件系统。虚拟文件系统的目录结构就像普通
linux
的目录结构一
样,
docker
通过这些文件再加上宿主机的内核提供了一个
linux
的虚拟环境。
每一层文件系统我们叫做一层
layer
,联合文件系统可以对每一层文件系统设置三
种权限,只读(
readonly
)、读写(
readwrite
)和写出(
whiteout-able
),但是
docker
镜像中每一层文件系统都是只读的。
构建镜像的时候,从一个最基本的操作系统开始,每个构建的操作都相当于做一层
的修改,增加了一层文件系统。一层层往上叠加,上层的修改会覆盖底层该位置的可
见性,这也很容易理解,就像上层把底层遮住了一样。当你使用的时候,你只会看到
一个完全的整体,你不知道里面有几层,也不清楚每一层所做的修改是什么。
可以看到镜像分层结构有以下特性
(1)镜像共享宿主机的
kernel
(2)
base
镜像是
linux
的最小发行版
(3)同一个
docker
主机支持不同的
Linux
发行版
(4)采用分层结构,可以上层引用下层,最大化的共享资源
(5)容器层位于可写层,采用
cow
技术进行修改,该层仅仅保持变化的部分,并不
修改镜像下面的部分
(6)容器层以下都是只读层
(7)
docker
从上到下找文件
镜像实现原理
Docker
分层存储实现原理
1. 分层存储实现方式
docker
镜像技术的基础是联合文件系统
(UnionFS),其文件系统是分层的Linux
中各发行版实现的
UnionFS
各不相同,所以
docker
在不同
linux 发行版中使用的也不同。通过 docker info 命令可以查看当前系统所使用哪种 UnionFS,常见的几种
发行版使用如下:
![](https://i-blog.csdnimg.cn/direct/e336d72fa3ac438e8c494d7bd4b772b0.png)
overlay2
是
overlay
的升级版,官方推荐,更加稳定,而新版的
docker
默认也是这个
驱动,
linux
的内核
4.0
以上或者或使用
3.10.0-514
或更高版本内核的
RHEL
或
CentOS
。
2. Union FS 的原理
docker
镜像由
多个只读层叠加面成
,启动容器时,
docker
会
加载只读镜像层并在
镜像栈顶部加一个读写层;
如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下
面的只读层复制到读写层,该文件版本仍然存在,只是已经被读写层中该文件的副本
所隐藏,此即
“
写时复制
(COW)”
机制
![](https://i-blog.csdnimg.cn/direct/362685cb447f4a989ada557f06c76488.png)
如果一个文件在最底层是可见的,如果在
layer1
上标记为删除,最高的层是用户看到
的
Layer2
的层,在
layer0
上的文件,在
layer2
上可以删除,但是只是标记删除,用
户是不可见的,总之在到达最顶层之前,把它标记来删除,对于最上层的用户是不可
见的,当标记一删除,只有用户在最上层建一个同名一样的文件,才是可见的。
3. overlay2 实现
1. 架构
OverlayFS
将单个
Linux
主机上的两个目录合并成一个目录。这些目录被称为层,统
一过程被称为联合挂载
OverlayFS
底层目录称为
lowerdir
, 高层目录称为
upperdir
,
合并统一视图称为
merged
![](https://i-blog.csdnimg.cn/direct/bbe99b5336f940c4beb84cdd712c6275.png)
图中可以看到三个层结构,即
lowerdir
、
upperdir
、
merged
层
2. 分层
•
lowerdir 层
其中
lowerdir
是只读的镜像层
(image layer)
,其中就包含
bootfs/rootfs
层,
bootfs(boot file system)
主要包含
bootloader
和
kernel
,
bootloader
主要是引导加载
kernel
,当
boot
成功
kernel
被加载到内存中,
bootfs
就被
umount
了,
rootfs(root file
system)
包含的就是典型
Linux
系统中的
/dev
、
/proc
、
/bin
、
/etc
等标准目录。
lowerdir
是可以分很多层的,除了
bootfs/rootfs
层以外,还可以通过
Dockerfile
建立很
多
image
层
•
upperdir 层
upper
是容器的读写层
,
采用了
CoW
(
写时复制
)
机制
,
只有对文件进行修改才会将文件拷
贝到
upper
层
,
之后所有的修改操作都会对
upper
层的副本进行修改。
upperdir
层是
lowerdir
的上一层,只有这一层可读可写的,其实就是
Container
层,在启动一个容器
的时候会在最后的
image
层的上一层自动创建,所有对容器数据的更改都会发生在这
一层。
•
workdir 层
它的作用是充当一个中间层的作用
,
每当对
upper
层里面的副本进行修改时
,
会先当到
workdir
,
然后再从
workdir
移动
upper
层
•
merged 层
是一个统一图层
,
从
mergedir
可以看到
lower
,
upper
,
workdir
中所有数据的整合
,
整
个容器展现出来的就是
mergedir
层
.merged
层就是联合挂载层,也就是给用户暴露
的统一视觉,将
image
层和
container
层结合,就如最上边的图中描述一致,同一文
件,在此层会展示离它最近的层级里的文件内容,或者可以理解为,只要
container
层
中有此文件,便展示
container
层中的文件内容,若
container 层中没有,则展示
image
层中的。
3. 如何完成读写
1
、读:
如果文件在
upperdir(
容器
)
层,直接读取文件;
如果文件不在
upperdir(
容器
)
层,则从镜像层
(lowerdir)
读取;
2
、写:
首次写入:如果
upperdir
中不存在,
overlay
和
overlay2
执行
copy_up
操作,把文件
从
lowdir
拷贝到
upperdir
中,由于
overlayfs
是文件级别的
(
即使只有很少的一点修改,
也会产生
copy_up
的动作
)
,后续对同一文件的再次写入操作将对已经复制到容器层的
文件副本进行修改,这也就是常常说的写时复制
(
copy-on-write
)
。
删除文件或目录:当文件被删除时,在容器层
(upperdir)
创建
whiteout
文件,镜像层
(lowerdir)
的文件是不会被删除的,因为它们是只读的,但
whiteout
文件会阻止它们显
示,当目录被删除时,在容器层
(upperdir)
一个不透明的目录,这个和上边的
whiteout
的原理一样,组织用户继续访问,
image
层不会发生改变
3
、注意事项
copy_up
操作只发生在文件首次写入,以后都是只修改副本。
容器层的文件删除只是一个
“
障眼法
”
,是靠
whiteout
文件将其遮挡
,image
层并没有删
除,这也就是为什么使用
docker commit
提交保存的镜像会越来越大,无论在容器层
怎么删除数据,
image
层都不会改变。
docker 镜像加载原理
boots(boot file system
)主要包含
bootloader
和
Kernel, bootloader
主要是引导加
kernel,Linux
刚启动时会加
bootfs
文件系统,在
Docker
镜像的最底层是
bootfs
。这一
层与我们典型的
Linux/Unix
系统是一样的,包含
boot
加載器和内核。当
boot
加载完
成之后整个内核就都在内存中了,此时内存的使用权已由
bootfs
转交给内核,此时系
统也会卸载
bootfs。
rootfs
(
root file system),
在
bootfs
之上。包含的就是典型
Linux
系统中的
/dev,/proc,/bin,/etc
等标准目录和文件。
rootfs
就是各种不同的操作系统发行版,比如
Ubuntu,Centos
等等。
典型的
Linux
在启动后,首先将
rootfs
置为
readonly,
进行一系列检查
,
然后将其切换
为
“readwrite”
供用户使用。在
docker
中,起初也是将
rootfs
以
readonly
方式加载并
检查,然而接下来利用
union mount
的将一个
readwrite
文件系统挂载在
readonly
的
rootfs
之上,并且允许再次将下层的
file system
设定为
readonly
并且向上叠加
,
这样
一组
readonly
和一个
writeable
的结构构成一个
container
的运行目录
,
每一个被称作
一个 Layer下面的这张图片非常好的展示了组装的过程,每一个镜像层都是建立在另一个镜像层
之上的,同时所有的镜像层都是只读的,只有每个容器最顶层的容器层才可以被用户
直接读写,所有的容器都建立在一些底层服务(
Kernel
)上,包括命名空间、控制组、
rootfs 等等,这种容器的组装方式提供了非常大的灵活性,只读的镜像层通过共享也能够减少磁盘的占用。
![](https://i-blog.csdnimg.cn/direct/7b7d171b764b422ebe47fbec95da9437.png)
Docker 卷原理
Docker
卷机制
Docker
又是如何做到把一个宿主机上的目录或者文件,挂载到容器里面去呢?
当容器进程被创建之后,尽管开启了
Mount Namespace
,但是在它执行
chroot
(
chroot
就是可以改变某进程的根目录,使这个程序不能访问目录之外的其他目录,
这个跟我们在一个容器中是很相似的)之前,容器进程一直可以看到宿主机上的整个
文件系统。 而宿主机上的文件系统,也自然包括了我们要使用的容器镜像。这个镜像的各个层,
保存在
/var/lib/docker/overlay2/{layer id}/diff
目录下,在容器进程启动后,它们会被联
合挂载在
/var/lib/docker/{layerid}/merged/
目录中,这样容器所需的
rootfs
就准备好了。
所以,我们只需要在
rootfs
准备好之后,在执行
chroot
之前,把
Volume
指定的宿主
机目录(比如
/home
目录),挂载到指定的容器目录(比如
/test
目录)在宿主机上对
应的目录(即
/var/lib/docker/aufs/mnt/[
可读写层
ID]/test
)上,这个
Volume
的挂载工
作就完成了。 由于执行这个挂载操作时,“
容器进程
”
已经创建了,也就意味着此时
Mount
Namespace
已经开启了。所以,这个挂载事件只在这个容器里可见。你在宿主机上,
是看不见容器内部的这个挂载点的。这就保证了容器的隔离性不会被
Volume
打破。
Docker 网络原理
Linux
常见网络虚拟化
什么是虚拟网卡
虚拟网卡(又称虚拟网络适配器),即用软件模拟网络环境,模拟网络适配器。简单来
说就是软件模拟的网卡。
虚拟网卡:tun/tap
•
简介
tap/tun
虚拟了一套网络接口,这套接口和物理的接口无任何区别,可以配置
IP
,
可以路由流量,不同的是,它的流量只在主机内流通。
tun
和
tap
是两个相对独立的虚拟网络设备,其中
tap
模拟了以太网设备,操作二
层数据包(以太帧),
tun
则模拟了网络层设备,操作三层数据包(
IP
报文)。
使用
tun/tap
设备的目的是实现把来自协议栈的数据包先交由某个打开了
/dev/net/tun
字符设备的用户进程处理后,再把数据包重新发回到链路中。你可以通俗
地将它理解为这块虚拟化网卡驱动一端连接着网络协议栈,另一端连接着用户态程序,
而普通的网卡驱动则是一端连接着网络协议栈,另一端连接着物理网卡。
最典型的
VPN
应用程序为例,程序发送给
tun
设备的数据包
![](https://i-blog.csdnimg.cn/direct/5a6fa13fe41e4de98cfeddb4ba1ae52b.png)
应用程序通过
tun
设备对外发送数据包后,
tun
设备,便会把数据包通过字符设备
发送给
VPN
程序,
VPN
收到数据包,会修改后再重新封装成新报文,譬如数据包原
本是发送给
A
地址的,
VPN
把整个包进行加密,然后作为报文体,封装到另一个发送
给
B
地址的新数据包当中。然后通过协议栈发送到物理网卡发送出去。
使用
tun/tap
设备传输数据需要经过两次协议栈,不可避免地会有一定的性能损耗
,
所以引入了新的网卡实现方式
veth.
虚拟网卡:veth
•
简介
在
Linux Kernel 2.6
版本,
Linux
开始支持网络名空间隔离的同时,也提供了专门的虚
拟以太网(
Virtual Ethernet
,习惯简写做
veth
)让两个隔离的网络名称空间之间可以
互相通信。
直接把
veth
比喻成是虚拟网卡其实并不十分准确,如果要和物理设备类比,它应该相
当于由交叉网线连接的一对物理网卡。形象化的理解如下:
veth
实际上不是一个设备,而
是一对设备
,因而也常被称作
veth pair
。要使用
veth
,
必须在两个独立的网络名称空间中进行才有意义,因为
veth pair
是一端连着协议栈,
另一端彼此相连的,在
veth
设备的
其中一端输入数据,这些数据就会从设备的另外一
端原样不变地流出
.
![](https://i-blog.csdnimg.cn/direct/7bc165ca58454dab8c60e4917cf4f9c2.png)
veth
通信不需要反复多次经过网络协议栈,这让
veth
比起
tap/tun
具有更好的性能。
veth
实现了点对点的虚拟连接,可以通过
veth
连接两个
namespace
,如果我们需要
将
3
个或者多个
namespace
接入同一个二层网络时,就不能只使用
veth
了
。
在物理
网络中,如果需要连接多个主机,我们会使用网桥,或者又称为交换机。
Linux
也提供
了网桥的虚拟实现
虚拟交换机
•
简介
使用
veth pair
将两个隔离的
netns
连接在了一起
,
在现实世界里等同于用一根网线把两
台电脑连接在了一起,但是在现实世界里往往很少会有人这样使用。因为一台设备不
仅仅只需要和另一台设备通信,它需要和很多很多的网络设备进行通信,如果还使用
这样的方式,需要十分复杂的网络接线,并且现实世界中的普通网络设备也没有那么
多网络接口。
那么,想要让某一台设备和很多网络设备都可以通信需要如何去做呢?在我们的日常
生活中,除了手机和电脑,最常见的网络设备就是路由器了,我们的手机连上
WI-FI
,
电脑插到路由器上,等待从路由器的
DHCP
服务器上获取到
IP
,他们就可以相互通信
了,这便是路由器的二层交换功能在工作。
Linux Bridge
最主要的功能就是二层交换,
是对现实世界二层交换机的模拟
.
Linux Bridge
,由
brctl
命令创建和管理。
Linux Bridge
创建以后,真实的物理设备
(如
eth0
)抑或是虚拟的设备(
veth
或者
tap
)都能与
Linux Bridge
配合工作。
![](https://i-blog.csdnimg.cn/direct/e4f5cef2ba064b14b0532940a6a4de8b.png)
虚拟组网 VxLan
物理网络的拓扑结构是相对固定的。云原生时代的分布式系统的逻辑拓扑结构变动频
率,譬如服务的扩缩、断路、限流,等等,都可能要求网络跟随做出相应的变化。
正因如此,软件定义网络(
Software Defined Network
,
SDN
)的需求在云计算和分布
式时代变得前所未有地迫切,
SDN
的核心思路是在物理的网络之上再构造一层虚拟化
的网络。
SDN
里位于下层的物理网络被称为
Underlay
,它着重解决网络的连通性与可管理性,
位于上层的逻辑网络被称为
Overlay
,它着重为应用提供与软件需求相符的传输服务和
网络拓扑。
vlan
交换机是一个
L2
设备,插在同一个交换机的网络设备组成了一个
L2
网络,
L2
网络之
间通过
MAC
地址通信,同时这个
L2
网络也是一个广播域。
同属于一个广播域的两个设备想要通信,一设备须得向网络中的所有设备发送请求信
息,只有对应
MAC
地址的设备才是真正的接收方,但实际上却是数据帧传遍整个网络,
所有设备都会收到,且直接丢弃。
如此一来,将造成一系列不好的后果:网络整体带宽被占用、潜在的信息安全风险、
占用
CPU
资源
……
因此,
VLAN
应运而生!
Vlan(Virtual Local Area Network)
即虚拟局域网,是一个将物理局域网在逻辑上划分成
多个广播域技术。通过在交换机上配置
Vlan
,可以实现在同一
Vlan
用户可以进行二层
互访,在不同
Vlan
间的用户被二层隔离,这样既能够隔离广播域,又可以提升网络安
全性
VLAN
究竟能够解决什么问题?
1
、限制广播域。广播域被限制在一个局域网内,节省了带宽,提高了网络处理能力。
2
、增强局域网的安全性。不同局域网内的报文在传输时是相互隔离的,即一个
VLAN
内的用户不能和其它
VLAN
内的用户直接通信,如果不同
VLAN
要进行通信,则需要
通过路由器或三层交换机等三层设备。
3
、灵活构建虚拟工作组。用局域网可以划分不同的用户到不同的工作组,同一工作组
的用户也不必局限于某一固定的物理范围,网络构建和维护更方便灵活。
不过
VLAN
也并非没有缺点。
1
、随着虚拟化技术的发展,一台物理服务器往往承载了多台虚拟机,公有云或其它大
型虚拟化云数据中心动辄需容纳上万甚至更多租户,
VLAN
技术最多支持
4000
多个
VLAN
,逐渐无法满足需求。
2、公有云提供商的业务要求将实体网络租借给多个不同的用户,这些用户对于网络的
要求有所不同,而不同用户租借的网络有很大的可能会出现
IP
地址、
MAC
地址的重
叠。传统的
VLAN
并没有涉及这个问题,因此需要一种新的技术来保证在多个租户网
络中存在地址重叠的情况下依旧能有效通信的技术。
3
、虚拟化技术使得单台主机可以虚拟化出多台虚拟机同时运行,而每台虚拟机都会有
其唯一的
MAC
地址。这样,为了保证集群中所有虚机可以正常通信,交换机必须保存
每台虚机的
MAC
地址,这样就导致了交换机中的
MAC
表异常庞大,从而影响交换机
的转发性能。
vxlan
VXLAN
是另一种网络虚拟化技术,有点类似于
VLAN
,但功能更强大。
在传统的
VLAN
网络中,共享同一底层
L2
网段的
VLAN
不能超过
4096
个。只有
12
比特用于对
Ethernet Frame
格式中的
VLAN ID
字段进行编码。
VXLAN
协议定义了
8
个字节的
VXLAN Header
,引入了类似
VLAN ID
的网络标识,
称为
VNI
(
VXLAN Network ID
),由
24
比特组成,这样总共是
1600
多万个,从而满
足了大规模不同租户之间的标识、隔离需求。
VXLAN
是基于
L3
网络构建的虚拟
L2
网络,是一种
Overlay
网络。
VXLAN
不关心底
层物理网络拓扑,它将
Ethernet Frame
封装在
UDP
包中,只要它能承载
UDP
数据包,
就可以在远端网段之间提供以太网
L2
连接。
每个
VXLAN
节点上的出站
L2 Ethernet Frame
都会被捕获,然后封装成
UDP
数据包,
并通过
L3
网络发送到目标
VXLAN
节点。当
L2 Ethernet Frame
到达
VXLAN
节点时,
就从
UDP
数据包中提取(解封装),并注入目标设备的网络接口。这种技术称为隧道。
因此,
VXLAN
节点会创建一个虚拟
L2
网段,从而创建一个
L2
广播域。
![](https://i-blog.csdnimg.cn/direct/3ecc757ff083463c95866f13659c1da8.png)
![](https://i-blog.csdnimg.cn/direct/565c6b9b0d6f442c94ec17b5dca88e38.png)
MacVLan
MACVLAN
允许对同一个网卡设置多个
IP
地址,还允许对同一张网卡上设置多个
MAC
地址,这也是
MACVLAN
名字的由来。原本
MAC
地址是网卡接口的
“
身份证
”
,
应该是严格的一对一关系,而
MACVLAN
打破这层关系,方法是在物理设备之上、网
络栈之下生成多个虚拟的
Device
,每个
Device
都有一个
MAC
地址,新增
Device
的
操作本质上相当于在系统内核中注册了一个收发特定数据包的回调函数,每个回调函
数都能对一个
MAC
地址的数据包进行响应,当物理设备收到数据包时,会先根据
MAC
地址进行一次判断,确定交给哪个
Device
来处理。
![](https://i-blog.csdnimg.cn/direct/a051133d7b19420992390cb971629a11.png)
许多网卡在硬件层面对支持的
MAC
地址数量存在限制。超过该限制会导致性能的下降。
所以
macvlan
虽然近乎完美还是没有实际推广完成。
docker 网络分类
docker
常见的网络的分类如下,其中
bridge
网络、
host
网络、
container
网络、
none
网络、
overlay
网络、
macvlan
网络、
ipvlan
网络。其中
overlay
网络往往配合
swarm
和
k8s
来使用。
1. bridge 网络
bridge
驱动会在
Docker
管理的主机上创建一个
Linux
网桥。默认情况下,网桥上
的容器可以相互通信。也可以通过
bridge
驱动程序配置,实现对外部容器的访问。桥
接网络如下
![](https://i-blog.csdnimg.cn/direct/8ab5bc03cd704acf81c59ff418149d6a.png)
2. host 网络
如果启动容器的时候使用
host
模式,那么这个容器将不会获得一个独立的
Network Namespace
,而是和宿主机共用一个
Network Namespace
。容器将不会虚
拟出自己的网卡,配置自己的
IP
等,而是使用宿主机的
IP
和端口。但是,容器的其
他方面,如文件系统、进程列表等还是和宿主机隔离的。
host
网络结构如下:
![](https://i-blog.csdnimg.cn/direct/af9559ae00644f9094b5df3904a5d76e.png)
3. container 网络
这个模式指定新创建的容器和引进存在的一个容器共享一个
network namespace
,
而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的
ip
,而是和一
个指定的容器共享
ip
,端口等,两个容器除了网络方面,其他的如文件系统、进程列
表等还是隔离的。两个容器的进程可以通过
lo
网卡设备通信。容器网络原理如下:
![](https://i-blog.csdnimg.cn/direct/3413f51e19cb40e49b03bdda81c5bff6.png)
4. none 网络
Docker
容器拥有自己的
Network Namespace
,但是,并不为
Docker
容器进行任
何网络配置。也就是说,这个
Docker
容器没有网卡、
IP
、路由等信息。需要我们自己
为
Docker
容器添加网卡、配置
IP
等。
5. overlay 网络
Overlay
驱动创建一个支持多主机网络的覆盖网络。
在不改变现有网络基础设施的前提下,通过某种约定通信协议,把二层报文封装
在
IP
报文之上的新的数据格式。
Overlay 网络实际上是目前最主流的容器跨节点数据传输和路由方案,底层原理
VXLAN.
Overlay
网络将多个
Docker
守护进程连接在一起,允许不同机器上相互通讯,同
时支持对消息进行加密,实现跨主机的
docker
容器之间的通信,
Overlay
网络将多个
Docker
守护进程连接在一起,使
swarm
服务能够相互通信。这种策略消除了在这些
容器之间进行操作系统级路由的需要。下图是个典型的
overlay
网络
![](https://i-blog.csdnimg.cn/direct/26d65e520c2b4ac8811094e7a7c0e75a.png)
6. macvlan 网络
为每个容器的虚拟网络接口分配一个
MAC
地址,使其看起来是直接连接到物理网络
的物理网络接口。在这种情况下,您需要在
Docker
主机上指定一个物理接口以用
于
.macvlan
以及 子网和网关
macvlan
。您甚至可以
macvlan
使用不同的物理网络接
口隔离您的网络。注意要把对应的网卡开启混杂模式命令为
ifconfig
网卡名称
(
如
eth0)
promisc
macvlan
典型的拓扑如下:
7. ipvlan 网络
ipvlan
和
overlay
都可以实现不同主机上的容器之间的通讯,但是
ipvlan
是所有容器都
在一个网段,相当于在一个
vlan
里面,然后可以通过不同的子接口对应不同网段,实
现不同容器之间的通讯。而
overlay
可以实现不同网段之间的通讯。
ipvlan
的
l2
网络
示例如下:
![](https://i-blog.csdnimg.cn/direct/c5c1705e9b2d40a4b4b3e3715b6c0d7e.png)
深入理解 docker Bridge 网络
网络介绍
Docker Bridge
网络采用内置的
bridge
驱动,
bridge
驱动底层采用的是
Linux
内核中
Linux bridge
技术。就网络而言,
bridge
网络是在网络段之间转发流量的链路层设备,
而网桥可以是在主机内核中运行的硬件设备或软件设备;就
Docker
而言,桥接网络使
用软件网桥
docker0
,它允许连接到同一网桥网络的容器进行通信,同时提供与未连
接到该网桥网络容器的隔离。
Docker Container
的
bridge
桥接模式可以参考下图:
![](https://i-blog.csdnimg.cn/direct/97651b6b711c452588ce515484e240a8.png)
•
创建步骤
Bridge
桥接模式的实现步骤主要如下:
1.
Docker Daemon
利用
veth pair
技术,在宿主机上创建两个虚拟网络接口设备,假
设为
veth0
和
veth1
。而
veth pair
技术的特性可以保证无论哪一个
veth
接收到网络报
文,都会将报文传输给另一方。
2.
Docker Daemon
将
veth0
附加到
Docker Daemon
创建的
docker0
网桥上。保证
宿主机的网络报文可以发往
veth0
;
3.
Docker Daemon
将
veth1
添加到
Docker Container
所属的
namespace
下,并被
改名为
eth0
。如此一来,保证宿主机的网络报文若发往
veth0
,则立即会被
eth0
接收,
实现宿主机到
Docker Container
网络的联通性;同时,也保证
Docker Container 单独使用
eth0
,实现容器网络环境的隔离性。
至此本文结束,感谢观看!