热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Docker(四)镜像及构建镜像(commit&dockerfile方式)

Docker(四)---镜像及构建镜像(commit&dockerfile方式),Go语言社区,Golang程序员人脉社

Docker(四)—镜像及构建镜像(commit&dockerfile方式)


1.镜像的分层结构

在这里插入图片描述

共享宿主机的kernel
base镜像提供的是最小的Linux发行版
同一docker主机支持运行多种Linux发行版采用分层结构的最大好处是:共享资源
可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。

Docker镜像是由文件系统叠加而成。最底端是一个文件引导系统,即bootfs。Docker用户不会与引导文件系统有直接的交互。

Docker镜像的第二层是root文件系统rootfs,通常是一种或多种操作系统,例如ubuntu等。

在Docker中,文件系统永远都是只读的,在每次修改时,都是进行拷贝叠加从而形成最终的文件系统。Docker称这样的文件为镜像。

一个镜像可以迭代在另一个镜像的顶部。位于下方的镜像称之为父镜像,最底层的镜像称之为基础镜像。

最后,当从一个镜像启动容器时,Docker会在最顶层加载一个读写文件系统作为容器。


2.为什么Docker镜像要采用分层结构?

共享资源


比如:有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份

base 镜像;同时内存中也只需加载一份 base镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享,我们将在后面更深入地讨论这个特性。

这时可能就有人会问了:如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc是否也会被修改?答案是不会! 修改会被限制在单个容器内。 这就是我们接下来要说的容器 Copy-on-Write 特性。

新数据会直接存放在最上面的容器层。 修改现有数据会先从镜像层将数据复制到容器层,修改后的数据直接 保存在容器层中,镜像层保持不变。

如果多个层中有命名相同的文件,用户只能看到最上面那层中的文件。



base镜像

base 镜像简单来说就是不依赖其他任何镜像,完全从0开始建起。

其他镜像都是建立在他的之上,可以比喻为大楼的地基

base 镜像不依赖其他镜像,从 scratch 构建;其他镜像可以之为基础进行扩展。

所以,能称作 base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,比如 Ubuntu, Debian, CentOS 等。


3.镜像的写时复制特性

Copy-on-Write可写容器层
容器层以下所有镜像层都是只读的
docker从上往下依次查找文件
容器层保存镜像变化的部分,并不会对镜像本身进行任何修改
一个镜像最多127

在这里插入图片描述

Docker的这种机制我们称之为写时复制。

镜像是用来创建容器的,是容器的只读模板,默认可以从 docker hub 上下载


4.commit构建镜像

docker commit构建新镜像三部曲:


  • 运行容器



  • 修改容器



  • 将容器保存为新的镜像



缺点:


  • 效率低、可重复性弱、容易出错



  • 使用者无法对镜像进行审计,存在安全隐患



docker ps

将容器保存为新的镜像:

docker commit 3be43c7fa968 busybox:v1

查看指定镜像的创建历史:

docker history busybox:latest
docker history busybox:v1

发现v1中使用了原来的busybox的两层,并且在上面新建了一层,叠加在上面

docker ps
docker rm -f 3be43c7fa968 #删除正在运行的容器需要-f参数强制删除
docker run -it --rm busybox:v1

可以看到即使删除了busybox容器,但修改的镜像被构建成了一个新的镜像,这种commit的方式将数据提交到了镜像层里,没有把数据落到宿主机的磁盘上
在这里插入图片描述


5.dockerfile方式


dockerfile常用指令

FROM:指定base镜像,如果本地不存在会从远程仓库下载。
MAINTAINER:设置镜像的作者,比如用户邮箱等。
COPY:把文件从build context复制到镜像
支持两种形式:COPY src dest 和 COPY ["src", "dest"]
src必须指定build context中的文件或目录
ADD:用法与COPY类似,不同的是src可以是归档压缩文件,文件会被自动解压到dest,也可以自动下载URL并拷贝到镜像:
ADD html.tar /var/www
ADD http://ip/html.tar /var/www
ENV:设置环境变量,变量可以被后续的指令使用:
ENV HOSTNAME server1.example.com
EXPOSE:如果容器中运行应用服务,可以把服务端口暴露出去:
EXPOSE 80
VOLUME:申明数据卷,通常指定的是应用的数据挂载点:
VOLUME ["/var/www/html"]
WORKDIR:为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在会自动创建。
RUN:在容器中运行命令并创建新的镜像层,常用于安装软件包:
RUN yum install -y vim
CMD 与 ENTRYPOINT
这两个指令都是用于设置容器启动后执行的命令,但CMD会被docker run后面的命令行覆盖,而ENTRYPOINT不会被忽略,一定会被执行。
docker run后面的参数可以传递给ENTRYPOINT指令当作参数。
Dockerfile中只能指定一个ENTRYPOINT,如果指定了很多,只有最后一个有效。

demo1:COPY拷贝文件

COPY:把文件从build context复制到镜像
支持两种形式:COPY src dest 和 COPY ["src", "dest"]
src必须指定build context中的文件或目录

step1 创建一个Dockerfile:

mkdir docker
cd docker/
vim Dockerfile
FROM busybox #指定开始的镜像,若镜像不存在,会去拉取该镜像
COPY testfile / #把当前目录下的testfile文件拷贝到容器的根目录下

注意:

1.dockerfile的目录不要再根目录下,因为默认创建时会把当前目录的所有数据发送给docker引擎,如果在根目录下,就会把根下的所有数据发送给docker进行构建,这显然时不合理的

2.COPY参数要求要拷贝的文件必须在当前目录,不能写绝对路径,只能是相对路径。拷贝的目的地可以是目录或文件

echo redhat > testfile

在这里插入图片描述
step2 删除之前的镜像(没有做过之前的实验可忽略此步骤):

docker images
docker rmi busybox:v1
docker rmi busybox:v2
docker images

在这里插入图片描述
step3 构建镜像:

docker build -t demo:v1 .

可以看到在dockerfile里执行一行命令,提交一次。通过dockerfile可以清晰的看到在每一层里干了什么,可以实现安全审计功能;而commit方式构建镜像时是看不到的

docker history demo:v1

在这里插入图片描述


demo2:RUN在容器中运行命令

RUN:在容器中运行命令并创建新的镜像层,常用于安装软件包:
RUN yum install -y vim

step1 修改Dockerfile:

step1 修改Dockerfile:
vim Dockerfile
FROM busybox
COPY testfile /
RUN echo hello nigar !! > file1

说明:文件第一行内容是把镜像运行成一个容器,后面所有操作都是在容器中完成的

step2 构建镜像:

docker build -t demo:v2 .

v2是在v1的基础上又构建了一层,下面的层没有改变,直接共享了。我们可以看到COPY testfile /的动作没有重复再做,而是Using cache,即使用缓存 :
在这里插入图片描述
step3 测试:

docker run -it demo:v2

查看到file1的内容即为hello nigar !!
在这里插入图片描述


demo3:镜像分层的缓存特性

step1 修改Dockerfile:

vim Dockerfile
FROM busybox
COPY testfile /
RUN echo hello nigar !! > file1
RUN echo hello nigar !! > file2

step2 构建镜像:

docker build -t demo:v3 .

Dockerfile没有变更时会使用本地的cache,无需重新做,可以加速构建过程。这就是镜像分层的缓存特性
在这里插入图片描述

step3 测试:

docker run -it demo:v3

在这里插入图片描述


demo4:ADD自动解压文件

ADD:用法与COPY类似,不同的是src可以是归档压缩文件,文件会被自动解压到dest,也可以自动下载URL并拷贝到镜像:
ADD html.tar /var/www
ADD http://ip/html.tar /var/www

step1 放一个nginx的压缩包在/root/docker下

step2 修改Dockerfile:

vim Dockerfile
FROM busybox
ADD nginx-1.16.1.tar.gz /

step3 构建镜像:

docker build -t demo:v4 .

ADD的用法与COPY类似,但不同的是它可以将文件自动解压到dest

step4 测试:

docker run -it demo:v4

在这里插入图片描述


demo5:ENV定义环境变量

ENV:设置环境变量,变量可以被后续的指令使用:
ENV HOSTNAME sevrer1.example.com

step1 修改Dockerfile:

vim Dockerfile
FROM busybox
ENV hostname server1
ADD nginx-1.16.1.tar.gz / #定义环境变量hostname为server1

step2 构建镜像:

docker build -t demo:v5 .

step3 测试:

docker run -it demo:v5

env查看到环境变量信息:
在这里插入图片描述


demo6:VOLUME声明数据卷,在封装应用容器时常用

VOLUME:申明数据卷,通常指定的是应用的数据挂载点:
VOLUME ["/var/www/html"]

step1 修改Dockerfile:

vim Dockerfile
FROM busybox
ENV hostname server1
ADD nginx-1.16.1.tar.gz /
VOLUME ["/data"]

step2 构建镜像:

docker build -t demo:v6 .

在这里插入图片描述
step3 查看镜像的创建历史:

docker history demo:v6

在这里插入图片描述
step4 进入容器,创建文件:

docker run -it demo:v6
按ctrl+p+q退出

在这里插入图片描述
step5 查看demov6的挂载信息:

docker ps #找出对应的容器ID
docker inspect f9770256d7bc

docker引擎在启动熔器时发现定义了卷,会自动生成一个卷。而docker引擎在启动容器时,自动在本地为它创建了这个目录,并且挂载在容器内,可以让容器读取到本地的数据目录
在这里插入图片描述

step6 进入目录,查看到刚刚创建的文件file:

cd /var/lib/docker/volumes/2abf295690bffe9eb6caac67aa365a666d49a8ed1f42c108f7b754ac2af7f260/_data

在这里插入图片描述
step7 释放数据卷:

docker ps
docker rm -f f9 #删除容器(此处使用容器ID的简写,因为只有一个f9开头的ID)
docker volume prune #释放数据卷
docker volume ls #查看有哪些数据卷

在这里插入图片描述


demo7:WORKDIR设置镜像中的当前工作目录

WORKDIR:为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在会自动创建。

step1 修改Dockerfile:

vim Dockerfile
FROM busybox
ENV hostname server1
WORKDIR /nginx
ADD nginx-1.16.1.tar.gz /nginx
VOLUME ["/data"]

step2 构建镜像:

docker build -t demo:v7 .

在这里插入图片描述
step3 测试:

docker run -it --rm demo:v7

我们可以发现,进入容器时就默认在/nginx这个目录下,而将nginx的包解压在了这个目录中。

这个目录之前并不存在,是WORKDIR自动创建的

在这里插入图片描述


demo8:CMD与ENTRYPOINT

这两个指令都是用于设置容器启动后执行的命令,但CMD会被docker run后面的命令行覆盖,而ENTRYPOINT不会被忽略,一定会被执行。
docker run后面的参数可以传递给ENTRYPOINT指令当作参数。
Dockerfile中只能指定一个ENTRYPOINT,如果指定了很多,只有最后一个有效。

CMD:

step1 修改Dockerfile:

vim Dockerfile
FROM busybox
ENV hostname server1
WORKDIR /nginx
ADD nginx-1.16.1.tar.gz /nginx
VOLUME ["/data"]
CMD echo 'hello docker!!!'

step2 构建镜像:

docker build -t demo:v8 .

在这里插入图片描述

step3 测试:

docker run -it --rm demo:v8
docker run -it --rm demo:v8 sh #命令被覆盖

在这里插入图片描述


ENTRYPOINT:

step1 修改Dockerfile:

vim Dockerfile
FROM busybox
ENV hostname server1
WORKDIR /nginx
ADD nginx-1.16.1.tar.gz /nginx
VOLUME ["/data"]
ENTRYPOINT echo 'hello docker!!!'

step2 构建镜像:

docker build -t demo:v9 .

在这里插入图片描述

step3 测试:

docker run -it --rm demo:v9
docker run -it --rm demo:v9 sh #命令没有被覆盖

在这里插入图片描述


demo9:shell和exec格式的区别:


区别1:

exec格式:
step1 修改Dockerfile:

vim Dockerfile
FROM busybox
ENV hostname server1
WORKDIR /nginx
ADD nginx-1.16.1.tar.gz /nginx
VOLUME ["/data"]
ENTRYPOINT ["/bin/echo","hello"]
CMD ["docker!!"]

step2 构建镜像:

docker build -t demo:v10 .

在这里插入图片描述

step3 测试:

docker run -it --rm demo:v10
docker run -it --rm demo:v10 linux #输出的docker变为linux

说明:Exec格式时,ENTRYPOINT可以通过CMD提供额外参数,CMD的额外参数可以在容器启动时动态替换。在shell格式时,ENTRYPOINT会忽略任何CMD或者docker run提供的参数
在这里插入图片描述


区别2:shell格式底层会调用/bin/sh -c来执行命令,可以解析变量,而下面的exec格式不会

shell格式:
step1 修改Dockerfile:

vim Dockerfile
FROM busybox
ENV name redhat
ENTRYPOINT echo "hello,$name"

step2 构建镜像:

docker build -t demo:v11 .

step3 测试:

docker run -it --rm demo:v11

可以看到变量$name的值被输出了
在这里插入图片描述

exec格式:
step1 修改Dockerfile:

vim Dockerfile
FROM busybox
ENV name redhat
ENTRYPOINT ["/bin/echo","hello,$name"]

step2 构建镜像:

docker build -t demo:v12 .

step3 测试:

docker run -it --rm demo:v12

可以看到变量$name没有被解析,而是直接输出了$name
在这里插入图片描述
所以exec格式需要改写:

vim Dockerfile
FROM busybox
ENV name redhat
ENTRYPOINT ["/bin/sh","-c","echo hello,$name"]

再次测试,变量就被解析了
在这里插入图片描述




推荐阅读
  • 数字图书馆近期展出了一批精选的Linux经典著作,这些书籍虽然部分较为陈旧,但依然具有重要的参考价值。如需转载相关内容,请务必注明来源:小文论坛(http://www.xiaowenbbs.com)。 ... [详细]
  • 本文详细介绍了在 Ubuntu 系统上搭建 Hadoop 集群时遇到的 SSH 密钥认证问题及其解决方案。通过本文,读者可以了解如何在多台虚拟机之间实现无密码 SSH 登录,从而顺利启动 Hadoop 集群。 ... [详细]
  • Python错误重试让多少开发者头疼?高效解决方案出炉
    ### 优化后的摘要在处理 Python 开发中的错误重试问题时,许多开发者常常感到困扰。为了应对这一挑战,`tenacity` 库提供了一种高效的解决方案。首先,通过 `pip install tenacity` 安装该库。使用时,可以通过简单的规则配置重试策略。例如,可以设置多个重试条件,使用 `|`(或)和 `&`(与)操作符组合不同的参数,从而实现灵活的错误重试机制。此外,`tenacity` 还支持自定义等待时间、重试次数和异常处理,为开发者提供了强大的工具来提高代码的健壮性和可靠性。 ... [详细]
  • Android 构建基础流程详解
    Android 构建基础流程详解 ... [详细]
  • 在开发过程中,我最初也依赖于功能全面但操作繁琐的集成开发环境(IDE),如Borland Delphi 和 Microsoft Visual Studio。然而,随着对高效开发的追求,我逐渐转向了更加轻量级和灵活的工具组合。通过 CLIfe,我构建了一个高度定制化的开发环境,不仅提高了代码编写效率,还简化了项目管理流程。这一配置结合了多种强大的命令行工具和插件,使我在日常开发中能够更加得心应手。 ... [详细]
  • PHP 5.5.31 和 PHP 5.6.17 安全更新发布
    PHP 5.5.31 和 PHP 5.6.17 已正式发布,主要包含多个安全修复。强烈建议所有用户尽快升级至最新版本以确保系统安全。 ... [详细]
  • 本文介绍如何使用OpenCV和线性支持向量机(SVM)模型来开发一个简单的人脸识别系统,特别关注在只有一个用户数据集时的处理方法。 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 服务器部署中的安全策略实践与优化
    服务器部署中的安全策略实践与优化 ... [详细]
  • 本文介绍了如何利用Shell脚本高效地部署MHA(MySQL High Availability)高可用集群。通过详细的脚本编写和配置示例,展示了自动化部署过程中的关键步骤和注意事项。该方法不仅简化了集群的部署流程,还提高了系统的稳定性和可用性。 ... [详细]
  • 在Eclipse中提升开发效率,推荐使用Google V8插件以增强Node.js的调试体验。安装方法有两种:一是通过Eclipse Marketplace搜索并安装;二是通过“Help”菜单中的“Install New Software”,在名称栏输入“googleV8”。此插件能够显著改善调试过程中的性能和响应速度,提高开发者的生产力。 ... [详细]
  • Parallels Desktop for Mac 是一款功能强大的虚拟化软件,能够在不重启的情况下实现在同一台电脑上无缝切换和使用 Windows 和 macOS 系统中的各种应用程序。该软件不仅提供了高效稳定的性能,还支持多种高级功能,如拖放文件、共享剪贴板等,极大地提升了用户的生产力和使用体验。 ... [详细]
  • 在Ubuntu系统中安装Android SDK的详细步骤及解决“Failed to fetch URL https://dlssl.google.com/”错误的方法
    在Ubuntu 11.10 x64系统中安装Android SDK的详细步骤,包括配置环境变量和解决“Failed to fetch URL https://dlssl.google.com/”错误的方法。本文详细介绍了如何在该系统上顺利安装并配置Android SDK,确保开发环境的稳定性和高效性。此外,还提供了解决网络连接问题的实用技巧,帮助用户克服常见的安装障碍。 ... [详细]
  • 触发器的稳态数量分析及其应用价值
    本文对数据库中的SQL触发器进行了稳态数量的详细分析,探讨了其在实际应用中的重要价值。通过研究触发器在不同场景下的表现,揭示了其在数据完整性和业务逻辑自动化方面的关键作用。此外,还介绍了如何在Ubuntu 22.04环境下配置和使用触发器,以及在Tomcat和SQLite等平台上的具体实现方法。 ... [详细]
  • 利用ZFS和Gluster实现分布式存储系统的高效迁移与应用
    本文探讨了在Ubuntu 18.04系统中利用ZFS和Gluster文件系统实现分布式存储系统的高效迁移与应用。通过详细的技术分析和实践案例,展示了这两种文件系统在数据迁移、高可用性和性能优化方面的优势,为分布式存储系统的部署和管理提供了宝贵的参考。 ... [详细]
author-avatar
柳辰光
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有