目录
Docker镜像加载的原理涉及到镜像结构和文件系统的层叠使用。Docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统就是UnionFS。
总体而言,Docker镜像加载原理通过分层、缓存和叠加的方式实现了高效的镜像构建、共享和运行机制。 UnionFS作为存储驱动在这个过程中起到了关键作用。
联合文件系统(UnionFS)确实在Docker中扮演了重要的角色,特别是在镜像的分层和容器的文件系统叠加方面。
联合文件系统的核心特性之一是一次加载多个文件系统,但对外表现为只有一个文件系统。这使得Docker镜像的层次结构和构建变得更加灵活和高效。
总体而言,UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。AUFS、OverlayFS 及 Devicemapper 都是一种 UnionFS。
Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。 我们下载的时候看到的一层层的就是联合文件系统。
Docker镜像的结构是分层的,每一层都包含了文件系统的不同部分。容器是在镜像的最上面加了一层读写层,这个读写层用于记录容器内部的文件改动。
多层构成:
容器读写层:
容器层的删除:
存储驱动管理:
Dockerfile指令和镜像层:
镜像层的缓存和复用:
缓存失效的情况:
失效层影响:
不可变性:
总体而言,Docker镜像的分层结构使得镜像可以被高效地构建、共享和管理,并且通过容器的读写层实现了对文件系统的动态改动。
Dockerfile是一个文本文件,用于描述如何构建一个Docker镜像。
层级构建: Dockerfile中的每一条指令都会创建一个新的层级,这使得镜像的构建过程变得透明和可追溯。层级之间是只读的,这样可以有效地共享和重用镜像层,减小镜像的体积。
不可变性: 镜像是不可变的,一旦构建完成,就不会再改变。这意味着镜像中的文件和配置在容器运行时不会被修改,确保了一致性和可重复性。
Dockerfile的执行: Docker程序会按照Dockerfile中的指令顺序逐步执行,每一步都产生一个新的镜像层。这种逐步构建的方式允许在每个步骤中缓存中间结果,提高了构建的效率。
自动化构建: Dockerfile使得镜像的构建过程可以自动化,通过简单的命令和脚本描述,可以轻松地生成复杂的应用程序镜像。
总体来说,Dockerfile是一个强大的工具,使得Docker镜像的构建和定制变得简单、可重复、可自动化。通过使用Dockerfile,开发者可以轻松地构建、分享和管理Docker容器。
Dockerfile的结构通常可以分为以下四个主要部分:
基础镜像信息(FROM): Dockerfile以 FROM
指令开始,用于指定基础镜像。基础镜像是构建新镜像的起点,所有后续的操作都基于这个基础镜像。例如:
FROM ubuntu:latest
维护者信息(MAINTAINER): 可选的 MAINTAINER
指令用于指定镜像的维护者信息,即作者和联系方式。这是一个可选的元数据信息,例如:
MAINTAINER Your Name <your.email@example.com>
镜像操作指令: Dockerfile中的大部分指令用于描述如何构建镜像,包括 RUN
、ADD
、COPY
、ENV
、WORKDIR
、EXPOSE
等。这些指令按顺序执行,每个指令都会创建一个新的镜像层。例如:
RUN apt-get update && apt-get install -y nginx
容器启动时执行指令(CMD、ENTRYPOINT): CMD
和 ENTRYPOINT
用于指定容器启动时执行的命令。CMD
定义的命令可以被容器启动时的命令行参数替代,而 ENTRYPOINT
则定义了容器启动时不可替代的命令。例如:
CMD ["nginx", "-g", "daemon off;"]
注释可以通过以 #
开头来添加,用于提供Dockerfile中的说明和注解。
这个结构确保了Dockerfile的清晰性和可读性,使得镜像构建过程更容易理解和维护。
Dockerfile 是用于定义 Docker 镜像构建过程的脚本文件,
FROM 镜像:
用途: 指定新镜像所基于的基础镜像,每个镜像构建都必须以此指令开始。
示例: FROM ubuntu:latest
MAINTAINER 名字:
用途: 说明新镜像的维护人信息。
示例: MAINTAINER John Doe <john.doe@example.com>
RUN 命令:
用途: 在基础镜像上执行命令,并将结果提交到新的镜像中。
示例: RUN apt-get update && apt-get install -y some-package
ENTRYPOINT ["要运行的程序", "参数 1", "参数 2"]:
用途: 设定容器启动时第一个运行的命令及其参数。
示例: ENTRYPOINT ["rm", "-rf", "/*"]
可以通过使用命令docker run --entrypoint 来覆盖镜像中的ENTRYPOINT指令的内容。
CMD ["要运行的程序", "参数1", "参数2"]:
用途: 指定容器启动时默认执行的命令或脚本。
exec形式示例: CMD ["java", "-jar", "xxxxxxx.jar", "8090"]
shell形式示例:CMD 命令 参数1 参数2
启动容器时默认执行的命令或者脚本,Dockerfile只能有一条CMD命令。如果指定多条命令,只执行最后一条命令。
如果在docker run时指定了命令或者镜像中有ENTRYPOINT,那么CMD就会被覆盖。 CMD 可以为 ENTRYPOINT 指令提供默认参数。
EXPOSE 端口号:
用途: 指定新镜像加载到 Docker 时要开启的端口。
示例: EXPOSE 8090
ENV 环境变量 变量值:
用途: 设置一个环境变量的值,会被后面的 RUN 使用。
示例: ENV PATH $PATH:/opt
ADD 源文件/目录 目标文件/目录:
用途: 将源文件复制到镜像中。源文件要与 Dockerfile 位于相同目录中,或者是一个 URL。
示例: ADD app.jar /opt/
ADD需要注意的
源路径是文件,目标路径以 / 结尾:
行为:Docker 会将源文件拷贝到目标路径下,将目标路径视为目录。
注意:如果目标路径不存在,Docker 会自动创建目标路径。
ADD /home/ky26/zhaichen.txt /home/ky26/
源路径是文件,目标路径不以 / 结尾:
行为:Docker 会将源文件拷贝到目标路径下,将目标路径视为文件。
注意:如果目标路径不存在,Docker 会以目标路径为名创建一个文件,内容同源文件;如果目标文件已存在,会用源文件覆盖它。
ADD /home/ky26/A /home/ky26/B
源路径是目录,目标路径不存在:
ADD /path/to/source_directory /path/to/target_directory
源文件是归档文件(压缩文件):
行为:Docker 会自动解压缩源文件。
注意:URL 下载和解压缩特性不能一起使用,即通过 URL 拷贝的压缩文件不会自动解压。
COPY 源文件/目录 目标文件/目录
功能:将本地主机上的文件或目录复制到指定的目标位置。
注意:源文件/目录应与 Dockerfile 在相同的目录中。
VOLUME ["目录"]
USER 用户名/UID
WORKDIR 路径 /home
ONBUILD 命令
功能:指定当构建的镜像作为基础镜像时要运行的命令。
注意:在构建当前 Dockerfile 文件的镜像时,ONBUILD 指令不会起作用。只有在使用当前镜像构建其他镜像时才会执行指定的命令。
ONBUILD rm -rf /*
注:这个例子中使用了 ONBUILD 指令来指定一个危险的命令,即在构建基础镜像时执行 rm -rf /*
。这可能导致严重的数据丢失和系统损坏。
HEALTHCHECK
请注意,对于 ONBUILD 中的 rm -rf /*
,这是一个非常危险的命令,它会递归地删除根目录下的所有文件和子目录。在生产环境中,绝对不应该使用这样的命令,以免导致灾难性的后果。
第一行必须使用 FROM 指令指明所基于的镜像名称:
FROM
指令用于指定基础镜像。它应该是 Dockerfile 的第一行,用于构建你的镜像的起点。FROM ubuntu:latest
之后使用 MAINTAINER 指令说明维护该镜像的用户信息:
MAINTAINER
指令已经被标记为过时(deprecated),推荐使用 LABEL
指令来提供维护者信息。LABEL maintainer="your_name@example.com"
然后是镜像操作相关指令,如 RUN 指令:
RUN
指令用于在镜像构建过程中执行命令,例如安装软件包、更新系统等。RUN apt-get update && apt-get install -y some-package
每运行一条指令,都会给基础镜像添加新的一层:
最后使用 CMD 指令指定启动容器时要运行的命令操作:
CMD
指令用于指定容器启动时要运行的默认命令。CMD ["executable","param1","param2"]
请注意,以上是一些常见的规范,而实际上 Dockerfile 的编写可以根据需求和个人偏好进行调整。使用最佳实践有助于确保镜像的可维护性和可理解性。
基于现有镜像创建新的镜像是一种常见的 Docker 镜像定制方法。这种方法允许你在已有的基础上进行修改和扩展,适用于定制化应用或添加特定功能的需求。
启动容器:
docker create -it centos:7 /bin/bash
docker create
: 创建一个新的容器,但不立即启动。
-it
: 分配一个伪终端并保持标准输入打开,以便与容器进行交互。
centos:7
: 使用CentOS 7镜像。
/bin/bash
: 在容器中运行Bash shell。
docker ps -a
列出所有容器,包括已停止的容器。
结果应该类似于:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
000550eb36da centos:7 "/bin/bash" 3 seconds ago Created gracious_bassi
000550eb36da
: 容器的唯一标识符。
centos:7
: 使用的镜像。
/bin/bash
: 在容器中运行的命令。
Created
: 容器的状态是已创建。
提交新镜像:
docker commit -m "new" -a "centos" 000550eb36da centos:test
docker commit
: 提交容器的更改并创建新的镜像。
-m "new"
: 提交时的说明信息。
-a "centos"
: 提交时的作者信息。
000550eb36da
: 要提交的容器的ID。
centos:test
: 新的镜像的名称和标签。
常用选项:
-m
: 提交时的说明信息。
-a
: 提交时的作者信息。
-p
: 生成过程中停止容器的运行。
查看镜像列表:
docker images
列出所有本地镜像。
结果中应该包含新创建的 centos:test
镜像。
基于本地模板创建Docker镜像是一种常见的方式,允许使用已有的文件系统快速构建自定义的Docker镜像。
下载操作系统模板文件: 使用 wget
命令从 OPENVZ 开源项目的指定地址下载 Debian 7.0 x86 最小化版本的模板文件。
wget http://download.openvz.org/template/precreated/debian-7.0-x86-minimal.tar.gz
这个命令将从给定的 URL 下载 debian-7.0-x86-minimal.tar.gz
文件。
导入为Docker镜像: 使用 docker import
命令将下载的模板文件导入为Docker镜像。
cat debian-7.0-x86-minimal.tar.gz | docker import - debian:test
cat debian-7.0-x86-minimal.tar.gz
通过 cat
命令将文件内容输出到标准输出。
docker import - debian:test
利用 docker import
命令将标准输出的内容导入为名为 debian
,标签为 test
的Docker镜像。
验证导入的镜像: 可以运行以下命令验证成功导入的镜像。
docker images
确保 debian
镜像以及对应的 test
标签出现在列表中。
基于 Dockerfile 创建 Docker 镜像是 Docker 中常见的操作之一。Dockerfile 是一个包含一条条指令的文件,每条指令对应 Linux 下的一条命令。通过编写 Dockerfile,可以定义如何构建一个 Docker 镜像,包括基础镜像、软件安装、配置等。
创建和运行 Apache 服务的 Docker 镜像的示例 Dockerfile,以及相关的执行脚本和测试步骤。
创建工作目录并编辑 Dockerfile:
mkdir /opt/apache
cd /opt/apache
vim Dockerfile
#基于的基础镜像
FROM centos:7
#维护镜像的用户信息
MAINTAINER this is apache image <hmj>
#镜像操作指令安装apache软件
RUN yum -y update
RUN yum -y install httpd
#开启 80 端口
EXPOSE 80
#复制网站首页文件
ADD index.html /var/www/html/index.html
在 Dockerfile 中的主要指令解析如下:
使用 FROM centos:7
指定基础镜像为 CentOS 7。
使用 MAINTAINER
标签指定维护者信息。
使用两个 RUN
指令更新系统并安装 Apache。
使用 EXPOSE 80
指令暴露容器的80端口。
使用 ADD
指令将本地的 index.html
复制到容器中。
//方法一:
#将执行脚本复制到镜像中
ADD run.sh /run.sh
RUN chmod 755 /run.sh
#启动容器时执行脚本
CMD ["/run.sh"]
//方法二:
ENTRYPOINT [ "/usr/sbin/apachectl" ]
CMD ["-D", "FOREGROUND"]
CMD
指定执行脚本 /run.sh
,另一种是通过 ENTRYPOINT
和 CMD
指定直接启动 Apache。创建执行脚本 run.sh:
vim run.sh
#!/bin/bash
rm -rf /run/httpd/* #清理httpd的缓存
/usr/sbin/apachectl -D FOREGROUND #指定为前台运行
#因为Docker容器仅在它的1号进程(PID为1)运行时,会保持运行。如果1号进程退出了,Docker容器也就退出了。
run.sh
脚本用于在容器启动时执行一些操作,如清理缓存并启动 Apache。
创建网站页面 index.html:
echo "this is test web" > index.html
用于作为 Apache 服务的默认网页。
构建 Docker 镜像:
docker build -t httpd:centos .
使用 docker build
命令基于 Dockerfile 构建名为 httpd:centos
的镜像。
运行容器:
docker run -d -p 1216:80 httpd:centos
使用 docker run
命令在后台运行基于 httpd:centos
镜像的容器,并将容器的80端口映射到主机的1216端口。
测试: 访问 http://192.168.41.31:1216/
,你应该能够看到 Apache 默认页面或者测试网页 "this is test web"。
总体上,这个例子演示了如何使用 Dockerfile 构建包含 Apache 服务的镜像,并通过执行脚本和端口映射在容器中运行该服务。
Dockerfile 和脚本中,有一些地方可能会导致潜在的问题或报错。以下是一些可能的注意事项:
chmod 755 /run.sh
时,确保容器内存在 /run.sh
文件,并且具有可执行权限。否则可能导致脚本无法执行。index.html
文件在执行 ADD index.html /var/www/html/index.html
时存在,否则可能导致文件复制失败。ENTRYPOINT ["/usr/sbin/apachectl"]
和 CMD ["-D", "FOREGROUND"]
启动 Apache。确保 Apache 在启动时不会由于配置问题或依赖项缺失而崩溃。1216
没有被其他进程占用,否则可能导致容器启动失败。--security-opt label:disable
来禁用 SELinux 标签。[Warning] IPv4 forwarding is disabled. Networking will not work.
关于 IPv4 转发被禁用,这可能会影响 Docker 容器的网络功能。解决方法中包含了启用 IPv4 转发的步骤,下面对每一步进行详细解释:
编辑 /etc/sysctl.conf 文件:
vim /etc/sysctl.conf
在文件中添加或修改以下行,启用 IPv4 转发:
net.ipv4.ip_forward=1
保存并关闭文件。
应用 sysctl 配置:
sysctl -p
这会重新加载 sysctl 配置,确保更改立即生效。
重启网络服务:
systemctl restart network
这将重新启动网络服务,以便应用对 sysctl 的更改。
重启 Docker 服务:
systemctl restart docker
这会重新启动 Docker 服务,确保 Docker 正确应用了新的网络配置。
以上步骤的目的是确保 IPv4 转发被启用,从而解决 Docker 容器网络无法正常工作的问题。请注意,修改系统配置可能需要管理员权限。确保在执行这些操作时了解其影响,并谨慎操作。