Kubernetes 入门实战课
罗剑锋
Kong 高级工程师,Nginx/OpenResty 开源项目贡献者
19527 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 41 讲
Kubernetes 入门实战课
15
15
1.0x
00:00/00:00
登录|注册

04|创建容器镜像:如何编写正确、高效的Dockerfile

你好,我是 Chrono。
上一次的课程里我们一起学习了容器化的应用,也就是被打包成镜像的应用程序,然后再用各种 Docker 命令来运行、管理它们。
那么这又会带来一个疑问:这些镜像是怎么创建出来的?我们能不能够制作属于自己的镜像呢?
所以今天,我就来讲解镜像的内部机制,还有高效、正确地编写 Dockerfile 制作容器镜像的方法。

镜像的内部机制是什么

现在你应该知道,镜像就是一个打包文件,里面包含了应用程序还有它运行所依赖的环境,例如文件系统、环境变量、配置参数等等。
环境变量、配置参数这些东西还是比较简单的,随便用一个 manifest 清单就可以管理,真正麻烦的是文件系统。为了保证容器运行环境的一致性,镜像必须把应用程序所在操作系统的根目录,也就是 rootfs,都包含进来。
虽然这些文件里不包含系统内核(因为容器共享了宿主机的内核),但如果每个镜像都重复做这样的打包操作,仍然会导致大量的冗余。可以想象,如果有一千个镜像,都基于 Ubuntu 系统打包,那么这些镜像里就会重复一千次 Ubuntu 根目录,对磁盘存储、网络传输都是很大的浪费。
很自然的,我们就会想到,应该把重复的部分抽取出来,只存放一份 Ubuntu 根目录文件,然后让这一千个镜像以某种方式共享这部分数据。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Dockerfile是创建容器镜像的关键,记录了构建指令,如选择基础镜像、拷贝文件、运行脚本等。每个指令生成一个Layer,按顺序执行这些指令,最终创建出一个新的镜像。镜像内部由多个Layer组成,通过Union FS技术合并在一起,实现共享和节约资源。Dockerfile的基本结构和使用方法得到了清晰的解释,读者可以通过实例了解如何使用Dockerfile创建镜像。文章通过生动的比喻和实例演示,使读者能够快速了解Docker镜像的内部机制和Dockerfile的作用,为读者提供了正确、高效地编写Dockerfile制作容器镜像的方法。 文章还介绍了Dockerfile的常用指令和最佳实践,包括选择基础镜像、拷贝文件、运行Shell命令、声明服务端口号等。此外,还详细讲解了docker build的用法,包括构建上下文、.dockerignore文件的使用以及镜像标签的添加。最后,文章提供了Dockerfile示例和课下作业,引导读者进一步学习高级技巧。 总之,本文通过清晰的解释和实例演示,帮助读者快速了解Docker镜像的内部结构和Dockerfile的编写方法,为读者提供了丰富的学习资源和思考题。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Kubernetes 入门实战课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(39)

  • 最新
  • 精选
  • includestdio.h
    关于指令生成层的问题需要再补充哈:只有 RUN, COPY, ADD 会生成新的镜像层,其它指令只会产生临时层,不影响构建大小,官网的镜像构建最佳实践里面有提及 https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ Only the instructions RUN, COPY, ADD create layers. Other instructions create temporary intermediate images, and do not increase the size of the build.

    作者回复: many thanks。

    2022-06-29
    2
    68
  • 陈卧虫
    1. 创建和修改文件:通过在写时复制实现;删除文件:通过白障实现,也就是通过一个文件记录已经被删除的文件。 2. 镜像分层的好处:可以重复使用未被改动的layer,每次修改打包镜像,只需重新构建被改动的部分

    作者回复: great

    2022-06-29
    17
  • 风飘,吾独思
    1.容器最上一层是读写层,镜像所有的层是只读层。容器启动后,Docker daemon会在容器的镜像上添加一个读写层。 2.容器分层可以共享资源,节约空间,相同的内容只需要加载一份份到内存。

    作者回复: great

    2022-06-29
    12
  • hiDaLao
    请问下docker pull时输出的layer的值为什么和docker inspect里面layer信息的sha256的值不一样呢?

    作者回复: docker pull的layer是压缩数据的sha256,docker inspect是解压后数据的sha256。

    2022-07-19
    11
  • ENTRYPOINT 和 CMD 的本质区别是什么的? 什么时候用 ENTRYPOINT 什么时候用 CMD?

    作者回复: 看小贴士应该就能够理解它们两个的区别了,ENTRYPOINT是执行的命令, CMD是参数。 感觉这应该是docker当初的设计小失误,其实用哪个没有什么太严格的区分。

    2022-06-29
    2
    9
  • CK
    还是没太理解构建上下文的意思,是指docker build的时候指定路径?比如文中示例docker build -f Dockerfile.busybox . 是一个.表示,我执行文末的课下作业时,显示COPY failed: file not found in build context or excluded by .dockerignore: stat default.conf: file does not exist,是不是docker build时的路径没指定好呢

    作者回复: “上下文”这个词确实很难理解,最好直接用英文context,就是要打包进镜像的文件所在的目录。 如果copy时在这个目录里找不到文件,当然就会报错了。

    2022-06-30
    8
  • Geek_666217
    构建包如果出错了,注意注释和内容不要再同一行,会将注释视为参数

    作者回复: 是的,Dockerfile的注释比较特殊,必须的单独一行,不能在行尾。

    2022-09-29归属地:北京
    6
  • Geek_f20da9
    老师有时间帮忙看一下,不知道写的对不对。 dockerfile常用参数: 1.ARG:镜像层的环境变量 2.FROM:拉取基础镜像 3.COPY:拷贝文件 4.ADD:拷贝文件、URL、压缩文件等 5.EVN:镜像层和容器层参数 6.EXPOSE:暴露容器内部端口给外部使用 7.RUN:执行shell指令 8.CMD:构建完成时执行的指令 思考题: 1.docker采用UNION FS文件系统,将文件系统分为上层和下层。即上层为容器层,下层为镜像层。如果下层有修改,运行容器时,上层会同步修改。如果上层有数据修改(即容器层数据修改),不会影响到下层(即镜像层)。 2.好处:共享已存在的layer,如果有新的数据加入,只会增量在最上层新增layer层。减少了网络传输等一些成本。

    作者回复: 写的很好。

    2022-09-17归属地:北京
    2
    5
  • 每天晒白牙
    chatgpt的回答 1.容器运行时需要写入数据,但是Docker镜像的分层技术是只读的,这会导致冲突。为了解决这个问题,Docker采用了一种称为“容器层”的技术,用于在镜像的基础上创建一个可写的文件系统层,用于存储容器中的数据和修改。 具体来说,当创建一个新的Docker容器时,Docker会在镜像的基础上创建一个可写的文件系统层,称为“容器层”,用于存储容器中的数据和修改。容器层会覆盖镜像中相应的文件系统层,从而实现容器的个性化定制和隔离。 容器层是可写的,因此容器运行时可以向其中写入数据和修改文件。这些修改都是存储在容器层中的,而不会影响到镜像中的文件系统层。这样可以保证镜像的不变性和可重复性,从而方便镜像的管理和使用。 需要注意的是,容器层是临时的,当容器被删除时,容器层也会被删除。因此,容器层中存储的数据和修改都是临时的,不会对镜像产生影响。如果需要将容器中的数据持久化保存,可以使用Docker的数据卷或者绑定挂载等技术 2.镜像的分层结构带来了以下好处: 减小镜像的大小:镜像的分层结构可以将镜像拆分成多个只读的文件系统层,这些层可以共用相同的Layer,从而减小镜像的大小,提高镜像的构建和传输效率。 提高镜像的可重复性:镜像的分层结构可以保证镜像的不变性和可重复性,因为每个文件系统层都是只读的,不会被修改。这样可以方便镜像的管理和使用。 方便镜像的定制和扩展:镜像的分层结构可以方便镜像的定制和扩展,因为可以在镜像的基础上创建一个可写的容器层,用于存储容器中的数据和修改。这样可以实现容器的个性化定制和隔离。 提高镜像的安全性:镜像的分层结构可以提高镜像的安全性,因为每个文件系统层都是只读的,不会被修改。这样可以避免恶意软件或攻击者修改镜像中的文件,从而提高镜像的安全性。 方便镜像的共享和复用:镜像的分层结构可以方便镜像的共享和复用,因为可以将多个镜像共用相同的Layer,从而减小镜像的大小,提高镜像的构建和传输效率。这样可以方便镜像的共享和复用,提高镜像的可用性和可维护性。

    作者回复: awesome,不过chatGPT使用也要适度,当心它一本正经地胡说八道。

    2023-05-17归属地:北京
    4
  • 虢國技醬
    "Dockerfile 里,第一个指令必须是 FROM,用来选择基础镜像" 一直有个疑问,写Dockerfile都必须有个基础镜像,那么依赖的这些基础镜像 的最原始镜像是怎么制作的? 这里研究了一下文档,同步给大家: https://docs.docker.com/build/building/base-images/#create-a-simple-parent-image-using-scratch 两个方式: 1、Create a full image using tar 2、Create a simple parent image using scratch 特别是 scratch 这个: You can use Docker’s reserved, minimal image, scratch, as a starting point for building containers. Using the scratch “image” signals to the build process that you want the next command in the Dockerfile to be the first filesystem layer in your image. While scratch appears in Docker’s repository on the hub, you can’t pull it, run it, or tag any image with the name scratch. Instead, you can refer to it in your Dockerfile.

    作者回复: great

    2023-03-10归属地:广东
    4
收起评论
显示
设置
留言
39
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部