今天的文章要来介绍如何产生 Docker 的映像档了,有了上一篇文章的介绍相信读者对於 Docker 已经有了初步的了解了,应该知道要有映像档是可以用来虚拟化应用程序及其执行环境的档案,但执行环境基本上不用自己写因为 DockerHub 上面都有,所以今天这篇文章主要会介绍如何产生应用程序的映像档。
不晓得大家有没有写过 C++,要产生一个可以执行的 .out
档通常都会写一个 Makefile 最後再下 make
的指令来产生 .out
档,之所以要先讲这个跟 Docker 毫无相关的原因是因为 Docker 要产生映像档的方式跟这个几乎是一样的做法,而要产生映像档时要写的档案就叫做 Dockerfile 也是本篇文章要讲的重要内容。
由於笔者本身是前端出身因此这篇文章会来介绍如何产生前端的应用程序,接下来就正式进入本篇文章的重点吧!
Dockerfile 的写法简单来说分为四个阶段:
所以简单的写法就会像下面这样:
接下来就简单的用白话文来解释一下上面每一行在做的事情:
/app
的资料夹中,但要如何可以让这个 /app
的资料夹中有程序码可以让我执行呢?/app
中,这就是 COPY . /app
的作用。npm install
并且利用 node index.js
来执行这个 index.js
档。其实除了上面的写法外,Dockerfile 还有以下几个比较进阶的写法,分别是:
ARG
中先被定义。CMD
,最後只会执行最後写的那个 CMD
。CMD
来说 ENTRYPOINT
会更优先执行。上面的 CMD
跟 ENTRYPOINT
看起来很像但其实两者是不太一样的,除了优先执行顺序外还有一个很重要的观念是,当今天 Dockerfile 只设定 CMD
而没有设定 ENTRYPOINT
时,Docker 在启动容器时会先使用预设的 ENTRYPOINT
指令,而预设的指令为 /bin/sh -c
,所以假如今天要让容器不用这种方式启动的话,就要记得使用 ENTRYPOINT
这个写法喔!
其实 Dockerfile 还有一个很重要的观念要跟读者说,就是 Dockerfile 在每次要产生一个新的映像档前都会先看 Dockerfile 中有没有哪个是被修改过的,有点像是 Git 在检查档案有没有被修改的道理,如果发现该行的结果其实是不需要修改的话,Docker 就会很聪明的直接利用上一次产生的映像档当成是 cache 来当作是该行的结果。
举例来说:在上面的例子每一次都一定会拉到正确的 node:10-alpine 所以每次在产生映像档前我就不需要重新下载从之前已经下载好的 node:10-alpine 中拿过来用就好,也因为这个特性可以让 Dockerfile 在写法上可是有着效能上的差距,接下来我们就来一起看一下如何改善上面的 Dockerfile 写法吧!
首先我们先来看原本的写法:
上面这份 Dockerfile 最大的问题就在於 COPY . /app
以及 RUN npm i && node index.js
这两行,每次只要我资料夹内有档案变动,我就要重新复制所有的档案到 /app
这个资料夹,乍看之下好像没什麽问题,但熟悉前端的人就会知道这些档案也包括了 package.json
以及 package-lock.json
这两个用来管理 mode_modules
的档案,也就会造成每次我复制档案时都会重新跑底下 npm install
这就会让整个 build 的过程变得相当久。
所以我们可以简单调整一下,先复制 package.json
以及 package-lock.json
这两个档案,然後跑 npm install
,这样只要我没有变动到安装套件就不用花很长的时间再重新安装套件了,最终改善後的写法就像下面这样:
虽然行数变多了,但我们来看一下执行结果:
可以发现只要我没有动到 package.json
也就是没有安装新的套件,我就不会执行 npm i
这个指令,也因此让 Docker 可以更有效率的产生这个映像档,不用每次都重新安装套件。
multi-stage build 可以想像成是一个档案有多个阶段的 build,也就是我要把某一阶段 build 好的档案传给另一阶段让他可以利用,举个例子来说:前端通常都会利用 webpack 进行专案内容打包的工作,但打包完会变成一个又一个的静态档,这时候就必须要利用 multi-stage build 的观念,把第一个 build 也就是经由 webpack 打包好的静态档传给下一个 build 可能是利用 nginx 来 serve 这些静态档。
multi-stage build 的写法也很简单,只要用到 as
这个关键字就好,透过 as
就可以把这个映像档的内容快速地提供给该 Dockerfile 下的其他映像档使用,写法如下:
可以发现这个 as
的关键字最主要的做法就是要把这个 FROM
的阶段当作是一个标签可以让其他阶段在进行操作时可以用 --from=标签
的方式进行使用,所以 multi-stage build 最主要的作用就是帮助一个复杂的 Dockerfile 可以有效的管理各个阶段的 build 并且可以让下一个阶段的 build 能使用上一个阶段的产物。
-t
代表的是 tag 的意思。但有时候可能会出现这个画面:
这是因为这个映像档正在被某个容器使用中,因此想要移除该映像档前必须要先移除该容器。
但有时候可能会出现这个画面:
这是因为这个容器正在使用中,因此想要移除该容器前必须要先把该容器暂停。
今天介绍了如何撰写 Dockerfile 来产生 Docker 映像档,但假如我今天有多个档案每个档案都必须要执行,那我不就要连续下三次 docker build
以及 docker run
的指令,这样也太麻烦,即便我用 shellscript 的方式来统整这些指令还是很不方便,因此在明天的文章笔者要来介绍一个进阶的 Docker 用法叫 Docker Compose,就敬请期待明天的文章吧XD
如果对於文章有什麽问题都欢迎在下面留言给笔者,让我们就明天的文章见吧!
>>: JavaScript入门 Day13_如何使用数字5
既然空间有维度, 阵列也像是空间一样, 他是拥有维度的, 就让我们探索看看吧 二维阵列 就如同象棋棋...
20201228 bind > 9.17.7 , dnsdist > 1.3.0 bin...
昨天和前天我们分别介绍了UITableView和XIB,今天我们就来利用这两个工具来实做一个能显示餐...
环境建置 安装python 至python官网下载并开启python安装档 https://www....
起源 於 2015 年 3 月 Facebook 开放了 React Native 的原始码,让使...