文章目录
- Docker数据管理
- 数据卷(Data Volumes)
- 示例
- 数据卷容器(Data Volume Containers)
- 示例
- 端口映射
- 容器互联
- Docker镜像的创建方法
- 基于现有镜像创建
- 1.首先启动一个镜像,在容器里做修改
- 2.然后将修改后的容器提交为新的镜像,需要使用该容器的 ID 号创建新镜像
- 基于本地模板创建
- 1. 从开源项目(如OPENVZ)下载操作系统模板文件
- 导入为镜像
- 3. 基于Dockerfile创建
- Dockerfile
- 联合文件系统(UnionFS):
- 镜像加载原理
Docker数据管理
在 Docker 中,数据管理是一个重要的方面,尤其是在需要持久化数据或在不同容器之间共享数据时。
Docker 提供了两种主要的数据管理方式:数据卷(Data Volumes)和数据卷容器(Data Volume Containers)。
数据卷(Data Volumes)
数据卷是 Docker 中的一个特殊目录,它可以在容器之间共享和重用,并且独立于容器的生命周期。数据卷位于容器文件系统之外,因此即使删除了容器,数据卷中的数据也不会丢失。
示例
我们首先拉取了一个 CentOS 7 的镜像,然后创建了一个容器 web1
,并使用 -v
选项将宿主机的 /var/www
目录挂载到容器内的 /data1
目录。
docker pull centos:7
docker run -v /var/www:/data1 --name web1 -it centos:7 /bin/bash
在容器内部,我们创建了一个文件 abc.txt
并写入了一些内容。由于 /data1
是一个数据卷,这个文件实际上被写入了宿主机的 /var/www
目录中。
echo "this is web1" > /data1/abc.txt
exit
退出容器后,我们可以在宿主机上验证这一点:
cat /var/www/abc.txt
数据卷容器(Data Volume Containers)
数据卷容器是一种特殊类型的容器,它专门用于提供数据卷给其他容器使用。这种方式允许在不同的容器之间共享数据,无需手动管理数据卷的挂载路径。
示例
我们首先创建了一个名为 web2
的数据卷容器,它有两个数据卷:/data1
和 /data2
。
docker run --name web2 -v /data1 -v /data2 -it centos:7 /bin/bash
在 web2
容器内部,我们向这两个数据卷中分别写入了文件。
echo "this is web2" > /data1/abc.txt
echo "THIS IS WEB2" > /data2/ABC.txt
然后,我们创建了一个新的容器 web3
,并使用 --volumes-from
选项将 web2
容器中的数据卷挂载到 web3
中。这样,web3
就可以访问 web2
中的数据卷了。
docker run -it --volumes-from web2 --name web3 centos:7 /bin/bash
在 web3
容器内部,我们可以验证是否能够访问到 web2
中的数据卷内容。
cat /data1/abc.txt
cat /data2/ABC.txt
总结
- 数据卷:提供了在容器和宿主机之间共享数据的机制,且数据独立于容器的生命周期。
- 数据卷容器:允许在不同的容器之间共享数据,简化了数据管理。
端口映射
端口映射机制允许将容器内的服务暴露给外部网络访问。实质上是将宿主机的端口映射到容器中的指定端口。
- 端口映射解决了外部访问容器内服务的问题。
示例:
-
随机映射端口:
docker run -d --name test1 -P nginx
-P
表示随机选择一个宿主机端口映射到容器的80端口(通常为服务默认端口)。
-
指定映射端口:
docker run -d --name test2 -p 43000:80 nginx
-p 43000:80
表示将宿主机的43000端口映射到容器的80端口。
验证:
使用 docker ps -a
查看容器状态及端口映射情况:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9d3c04f57a68 nginx "/docker-entrypoint.…" 4 seconds ago Up 3 seconds 0.0.0.0:43000->80/tcp test2
b04895f870e5 nginx "/docker-entrypoint.…" 17 seconds ago Up 15 seconds 0.0.0.0:49170->80/tcp test1
- 可通过浏览器访问:
http://宿主机IP:43000
和http://宿主机IP:49170
来验证服务是否正常。
容器互联
默认情况下,Docker容器重启后其内部IP地址可能会发生变化,导致容器间通信不便。
- 容器互联则提供了更为便捷且稳定的容器间通信方式,避免了因IP变化带来的困扰。
解决方案:
使用容器互联功能,通过容器名称在容器间建立稳定的网络通信隧道。
命令示例:
-
创建并运行源容器(命名为
web1
):docker run -itd -P --name web1 centos:7 /bin/bash
-
创建并运行接收容器(命名为
web2
),并通过--link
选项指定与web1
互联:docker run -itd -P --name web2 --link web1:web1 centos:7 /bin/bash
--link web1:web1
表示将web1
容器的名称及其别名都设置为web1
,从而使web2
能够识别并与之通信。
测试互联:
进入web2
容器内部,执行以下命令测试与web1
的连通性:
docker exec -it web2 bash
ping web1
若能成功收到回复,则表明两容器间的互联配置正确。
以下是对Docker镜像创建方法的整理,包括基于现有镜像创建、基于本地模板创建以及基于Dockerfile创建三种方式,并详细解释了联合文件系统(UnionFS)、镜像加载原理以及Dockerfile的相关内容。
Docker镜像的创建方法
创建镜像有三种方法,分别为基于已有镜像创建、基于本地模板创建以及基于Dockerfile创建。
基于现有镜像创建
1.首先启动一个镜像,在容器里做修改
例如使用docker run -it centos:7 /bin/bash
命令启动一个CentOS 7的容器。
docker create -it centos:7 /bin/bash
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
000550eb36da centos:7 "/bin/bash" 3 seconds ago Created gracious_bassi
2.然后将修改后的容器提交为新的镜像,需要使用该容器的 ID 号创建新镜像
docker commit -m "new" -a "centos" 000550eb36da centos:test
##格式:
docker commit -m "new" -a "centos" <CONTAINER_ID> centos:test
##常用选项:
-m 说明信息;
-a 作者信息;
-p 生成过程中停止容器的运行。
docker images
- 注意事项:
- 使用
docker ps -a
可以查看所有容器的状态,包括已停止的容器。 - 提交时,需要提供容器的ID或名称、说明信息、作者信息等。
- 使用
基于本地模板创建
通过导入操作系统模板文件可以生成镜像,模板可以从 OPENVZ 开源项目下载,下载地址为http://openvz.org/Download/template/precreated
1. 从开源项目(如OPENVZ)下载操作系统模板文件
wget http://download.openvz.org/template/precreated/debian-7.0-x86-minimal.tar.gz
导入为镜像
cat debian-7.0-x86-minimal.tar.gz | docker import - debian:test
- 注意事项:
- 需要确保下载的模板文件是完整的,并且与Docker版本兼容。
- 导入时,可以为新镜像指定一个标签(tag)。
3. 基于Dockerfile创建
Dockerfile
- Dockerfile是一个文本文件,包含了构建Docker镜像所需的一系列指令。
- 每条指令都会创建一个新的镜像层,并且可以被缓存和复用。
- Dockerfile的结构大致分为四个部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。
- Dockerfile中的指令可以包括复制文件、安装软件包、设置环境变量等。
详细来说,Docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
Dockerfile是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。有了Dockerfile,当我们需要定制自己额外的需求时,只需在Dockerfile上添加或者修改指令,重新生成 image 即可, 省去了敲命令的麻烦。
除了手动生成Docker镜像之外,可以使用Dockerfile自动生成镜像。Dockerfile是由多条的指令组成的文件,其中每条指令对应 Linux 中的一条命令,Docker 程序将读取Dockerfile 中的指令生成指定镜像。
Dockerfile结构大致分为四个部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。Dockerfile每行支持一条指令,每条指令可携带多个参数,支持使用以“#“号开头的注释。
联合文件系统(UnionFS):
我们下载的时候看到的一层层的就是联合文件系统。
- Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。AUFS、Overlay2 及 Devicemapper 都是一种 UnionFS。
- Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
- 特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
镜像加载原理
- Docker镜像由多层文件系统组成,最底层是bootfs,包含bootloader和kernel。
- 在bootfs之上是rootfs,包含了典型的Linux系统目录和文件。
- 当创建容器时,Docker会在镜像的最上层添加一个空的read-write层,容器内的所有文件修改都会发生在这一层。
详细来讲,
Docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统就是UnionFS。
bootfs主要包含bootloader和kernel,bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统。
在Docker镜像的最底层是bootfs,这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs,在bootfs之上。包含的就是典型Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
我们可以理解成一开始内核里什么都没有,操作一个命令下载debian,这时就会在内核上面加了一层基础镜像;再安装一个emacs,会在基础镜像上叠加一层image;接着再安装一个apache,又会在images上面再叠加一层image。最后它们看起来就像一个文件系统即容器的rootfs。在Docker的体系里把这些rootfs叫做Docker的镜像。但是,此时的每一层rootfs都是read-only的,我们此时还不能对其进行操作。当我们创建一个容器,也就是将Docker镜像进行实例化,系统会在一层或是多层read-only的rootfs之上分配一层空的read-write的rootfs。
- 为什么Docker里的centos大小才200M?:
- Docker中的镜像通常是精简的操作系统,只包含最基本的命令、工具和程序库。
- 不同的Linux发行版可以共用bootfs,因此它们的镜像大小相对较小。
详细来讲,因为对于精简的OS,rootfs可以很小,只需要包含最基本的命令、工具和程序库就可以了,因为底层直接用宿主机的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以共用bootfs。
- Docker镜像结构的分层:
- 镜像由多层构成,每一层都是只读的。
- 容器在镜像的最上面添加了一层可读写层,用于存储容器内的文件修改。
- 如果删除了容器,其最上面的可读写层也会被删除,但镜像层不会受到影响。
- 镜像层是不可变的,即使在某一层中添加了一个文件并在下一层中删除它,该文件仍然会保留在镜像中(但在容器中不可见)。
镜像不是一个单一的文件,而是有多层构成。容器其实是在镜像的最上面加了一层读写层,在运行容器里做的任何文件改动,都会写到这个读写层。如果删除了容器,也就删除了其最上面的读写层,文件改动也就丢失了。Docker使用存储驱动管理镜像每层内容及可读写层的容器层。
(1)Dockerfile 中的每个指令都会创建一个新的镜像层;
(2)镜像层将被缓存和复用;
(3)当Dockerfile 的指令修改了,复制的文件变化了,或者构建镜像时指定的变量不同了,对应的镜像层缓存就会失效;
(4)某一层的镜像缓存失效,它之后的镜像层缓存都会失效;
(5)镜像层是不可变的,如果在某一层中添加一个文件,然后在下一层中删除它,则镜像中依然会包含该文件,只是这个文件在 Docker 容器中不可见了。