一.Docker镜像原理
1.镜像的概念
镜像是一种轻量级的,可执行的独立软件文件系统,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时所需的库、环境变量和配置文件等。
2.两个问题
(1)为什么Docker镜像比原始软件的依赖包要大?
一个Docker镜像不仅仅包括原始的软件依赖包,它包含运行某个软件所需的所有内容,包括代码、运行时所需的库、环境变量和配置文件等,是一个精简的、可运行的文件系统。
(2)为什么Docker镜像比一个虚拟机操作系统要小?
-虚拟机的Guest OS即为虚拟机安装的操作系统,它是一个完整操作系统内核;虚拟机的Hypervisor层可以简单理解为一个硬件虚拟化平台,它在Host OS是以内核态的驱动存在的。而虚拟机的Guest OS层和Hypervisor层在docker中被Docker Engine层所替代,Docker有着比虚拟机更少的抽象层,Docker运行在容器上的程序通过Docker引擎直接使用实际物理机的硬件资源。
-Docker利用的是宿主机的内核,而不需要Guest OS,因此,当新建一个容器时,Docker不需要和虚拟机一样重新加载一个操作系统,避免了引导、加载操作系统内核这个比较费时费资源的过程。
-Docker通过分层结构原理,进一步将镜像细化,复用共同的系统镜像层,减少安装一个新镜像的体积。
3.Docker的镜像分层原理
(1)UnionFS(联合文件系统)
Union文件系统是一种分层,轻量级并且高性能的文件系统技术,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。Union文件系统技术是Docker镜像的基础。
通俗点说,镜像(Image)就是一堆只读层(read-only layer)的统一视角。它通过UnionFS将一个个完整的镜像细分,抽取功能可以相互独立、相互叠加的公共部分,在下载镜像时将所需的不同基础层按需拉取、组合、叠加,且本地已有的分层则不会再下载。由此镜像被分为两个视角:
- 内部视角:一个镜像文件实际上由一层层具有不同特定功能的基础镜像层文件叠加而来,比如: bootfs 是docker镜像的最底层 ,主要是引导加载kernel 等环境,这一层一般是镜像共用的。rootfs 在bootfs之上,是具体用户空间的文件系统,本质就是各种不同的操作系统的精简发行版, 只需要包括最基本的命令,工具,和程序库 ,因此不同的镜像rootfs可能会存在差别。
- 外部视角:在镜像外部来看,多层基础镜像层相互叠加,它们重叠在一起。除了最下面一层,其它层都会有一个调用指针指向下一层。对外呈现一个统一的、完整的文件视角,这样就隐藏了多层的存在,在用户的角度看来,只存在一个文件系统。
(2)容器的可写层
当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。同时,容器层也可以被打包为基础镜像层进一步拓展、叠加。
(3) 分层的好处
最大的好处就是资源共享。比如:有多个镜像都是从相同的base镜像构建而来的,那么宿主机只需在磁盘中保存一份base镜像。同时内存中也只需要加载一份base镜像,就可以为所有容器服务了。而且由于镜像层都是只读的,因此镜像的每一层都可以被共享、拓展,更加灵活高效。
二. Docker高级网络配置
1.Docker网络配置说明
Docker允许外部与容器、容器与容器之间进行访问和通信,因此Docker允许进行网络配置。Docker默认的网络模式是bridge模式,此模式通过搭建虚拟网桥的方式来实现不同容器之间的数据交换,其特点和原理如下:
- 当 Docker 启动时,Docker引擎会自动在本地主机上创建一个
bridge
虚拟网桥, 同时,Docker 随机分配一个本地未占用的私有网段(在 RFC1918 中定义)中的一个IP地址给bridge
网桥接口。 比如典型的172.17.0.1- 每当创建一个 Docker 容器的时候,同时会创建该容器的一对
veth-pair
接口,这对接口一端在容器内,即eth0
;另一端在本地并被默认挂载到bridge
虚拟网桥上,名称以veth
开头。同时,会给该容器自动分配一个与bridge
虚拟网桥同一网段的子地址。(比如172.17.0.x)veth-pair
接口的特点是,当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker 就创建了在主机和所有容器之间一个虚拟共享网络。
2.Docker网络操作
(1)查看docker网络信息
# docker network ls
(2)查看容器网络
# docker inspect [containerId]
(3)容器间通信
# docker exec -it [containerId] bash #进入容器内部
# curl http://172.17.0.3:8080 #发请求访问另一个tomcat容器
(4)查看网络细节信息
# docker network inspect [dockerName | dockerId]
3.Docker通信模式改进
- 默认网桥存在的问题:实际开发中,我们需要同时部署启动多个项目容器运行,每个项目容器都要与它的组件通信,比如一个web项目打包成容器后要与它的mysql容器、redis容器、tomcat容器等通信。如果我们都使用默认的bridge网桥,那么某些组件的通信就会占用/阻塞网桥资源,影响其他项目的运行。
- 解决方法:每个项目单独使用一个自己的网桥,将不同项目系统之间的通信隔离开来,互不干扰资源调度。
(1)创建自定义网桥
# docker create [网桥名称]
# docker create -d bridge [网桥名称] #随机分配下一个网段
(2)删除网桥
# docker network rm [网桥名称 | 网桥Id]
(3) 启动容器挂载指定网桥
# docker run -d -p 8082:8080 --network newBridge --name tomcat01 tomcat
注意:网桥必须存在时,才能用--network指定
(4)容器通信
若在容器启动时就指定了网桥,则在这个网桥所关联的所有容器间通信时,可以直接使用容器名作为域名来映射地址通信。
三.Docker高级数据卷操作
数据卷是一种可供多个容器或容器与宿主机之间共享数据的特殊文件目录,它具有以下特性:
- `数据卷` 可以在容器之间共享和重用
- 对数据卷的修改更新会立马影响到对应容器
- 对数据卷的操作不会影响镜像
数据卷
默认会一直存在,即使容器被删除
1. 自定义数据卷目录
(1)指定数据卷目录,启动绑定容器
# docker run -v 宿主机绝对路径:容器内路径
#特点:
- 宿主机目录内容会直接覆盖容器目录(不论宿主机目录内容是否为空)
- 宿主机目录和容器目录会相互影响和同步
- 删除容器时,宿主机目录会保留一直存在
- 绝对路径数据卷不会出现在volume ls列表中
(2)指定数据卷只读
# docker run -v 宿主机绝对路径:容器内路径:ro
# 特点:
- 只能在宿主机中更新修改数据卷目录内容,容器只读,无法修改对应目录
- 只能宿主机影响容器,容器不可修改共享目录内容
2. 自动创建数据卷
(1)启动时挂载数据卷
# docker run -v [volumeName]:容器内路径
# 特点:
- 若volumeName数据卷不存在,则自动创建一个名为volumeName的空数据卷,并进行挂载绑定,将容器内路径的内容复制到当前数据卷目录内。
- 若volumeName数据卷已存在,则进行挂载绑定,若数据卷为空,则将容器内路径的内容复制到当前数据卷目录内。否则,将当前数据卷目录内容覆盖容器目录。
(2)创建数据卷
# docker volume create [volumeName]
(3)查看数据卷详细信息(包括路径)
# docker volume inspect [volumeName]
(4)查看数据卷列表
# docker volume ls
(5)删除数据卷
# docker volume rm [volumeName]