Docker 是个划时代的开源项目,它彻底释放了计算虚拟化的威力,极大提高了应用的维护效率,降低了云计算应用开发的成本!使用 Docker,可以让应用的部署、测试和分发都变得前所未有的高效和轻松!
1Q:Docker commit如何用?
A:简单的回答就是,不要用 commit,去写 Dockerfile。
Docker 不是虚拟机。这句话要在学习 Docker 的过程中反复提醒自己。所以不要把虚拟机中的一些概念带过来。Docker 提供了很好的 Dockerfile 的机制来帮助定制镜像,可以直接使用 Shell 命令,非常方便。而且,这样制作的镜像更加透明,也容易维护,在基础镜像升级后,可以简单地重新构建一下,就可以继承基础镜像的安全维护操作。
使用 docker commit 制作的镜像被称为黑箱镜像,换句话说,就是里面进行的是黑箱操作,除本人外无人知晓。即使这个制作镜像的人,过一段时间后也不会完整的记起里面的操作。那么当有些东西需要改变时,或者因基础镜像更新而需要重新制作镜像时,会让一切变得异常困难,就如同重新安装调试配置服务器一样,失去了 Docker 的优势了。
另外,Docker 不是虚拟机,其文件系统是 Union FS,分层式存储,每一次 commit 都会建立一层,上一层的文件并不会因为 rm 而删除,只是在当前层标记为删除而看不到了而已,每次 docker pull 的时候,那些不必要的文件都会如影随形,所得到的镜像也必然臃肿不堪。而且,随着文件层数的增加,不仅仅镜像更臃肿,其运行时性能也必然会受到影响。这一切都违背了 Docker 的最佳实践。
使用 commit 的场合是一些特殊环境,比如入侵后保存现场等等,这个命令不应该成为定制镜像的标准做法。所以,请用 Dockerfile 定制镜像。
2Q:为什么说不要使用 import, export, save, load, commit 来构建镜像?
A:commit 命令在前一个问答已经说过,这是制作黑箱镜像,无法维护,不应该被使用。
import 和 export 的做法,实际上是将一个容器来保存为 tar 文件,然后在导入为镜像。这样制作的镜像同样是黑箱镜像,不应该使用。而且这类导入导出会导致原有分层丢失,合并为一层,而且会丢失很多相关镜像元数据或者配置,比如 CMD 命令就可能丢失,导致镜像无法直接启动。
save 和 load 确实是镜像保存和加载,但是这是在没有 registry 的情况下,手动把镜像考来考去,这是回到了十多年的 U 盘时代。这同样是不推荐的,镜像的发布、更新维护应该使用 registry。无论是自己架设私有 registry 服务,还是使用公有 registry 服务,如 Docker Hub。
3Q:Dockerfile 怎么写?
A:最直接也是最简单的办法是看官方文档。
这篇文章讲述具体 Dockerfile 的命令语法:https://docs.docker.com/engine/reference/builder/
然后,学习一下官方的 Dockerfile 最佳实践:https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/
最后,去 Docker Hub 学习那些官方(Official)镜像 Dockerfile 咋写的。
4Q:Dockerfile 就是 Shell 脚本吧?
A:不是这样的。Dockerfile 不等于 .sh 脚本,Dockerfile 确实是描述如何构建镜像的,其中也提供了 RUN 这样的命令,可以运行 shell 命令。但是和普通 shell 脚本还有很大的不同。
Dockerfile 描述的实际上是镜像的每一层要如何构建,所以每一个RUN是一个独立的一层。所以一定要理解“分层存储”的概念。上一层的东西不会被物理删除,而是会保留给下一层,下一层中可以指定删除这部分内容,但实际上只是这一层做的某个标记,说这个路径的东西删了。但实际上并不会去修改上一层的东西。每一层都是静态的,这也是容器本身的 immutable 特性,要保持自身的静态特性。
所以很多新手会常犯下面这样的错误,把 Dockerfile 当做 shell 脚本来写了:
RUN yum update
RUN yum -y install gcc
RUN yum -y install python
ADD jdk-xxxx.tar.gz /tmp
RUN cd xxxx && install
RUN xxx && configure && make && make install
这是相当错误的。除了无畏的增加了很多层,而且很多运行时不需要的东西,都被装进了镜像里,比如编译环境、更新的软件包等等。结果就是产生非常臃肿、非常多层的镜像,不仅仅增加了构建部署的时间,也很容易出错。
正确的写法应该是把同一个任务的命令放到一个 RUN 下,多条命令应该用 && 连接,并且在最后要打扫干净所使用的环境。比如下面这段摘自官方 redis 镜像 Dockerfile 的部分:
RUN buildDeps='gcc libc6-dev make' \
&& set -x \
&& apt-get update && apt-get install -y $buildDeps --no-install-recommends \
&& rm -rf /var/lib/apt/lists/* \
&& wget -O redis.tar.gz "$REDIS_DOWNLOAD_URL" \
&& echo "$REDIS_DOWNLOAD_SHA1 *redis.tar.gz" | sha1sum -c - \
&& mkdir -p /usr/src/redis \
&& tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
&& rm redis.tar.gz \
&& make -C /usr/src/redis \
&& make -C /usr/src/redis install \
&& rm -r /usr/src/redis \
&& apt-get purge -y --auto-remove $buildDeps
5
Q:那我把所有命令都合并到一个 RUN 就对了吧?
A:不是把所有命令都合为一个 RUN,要合理分层,以加快构建和部署。合理分层就是将具有不同变更频繁程度的层,进行拆分,让稳定的部分在基础,更容易变更的部分在表层,使得资源可以重复利用,以增加构建和部署的速度。以 node.js 的应用示例镜像为例,其中的复制应用和安装依赖的部分,如果都合并一起,会写成这样:
COPY . /usr/src/app
RUN npm install
但是,在 node.js 应用镜像示例中,则是这么写的:
COPY package.json /usr/src/app/
RUN npm install
COPY . /usr/src/app
从层数上看,确实多了一层。但实际上,这三行分开是故意这样做的,其目的就是合理分层,充分利用 Docker 分层存储的概念,以增加构建、部署的效率。在 docker build 的构建过程中,如果某层之前构建过,而且该层未发生改变的情况下,那么 docker 就会直接使用缓存,不会重复构建。因此,合理分层,充分利用缓存,会显著加速构建速度。
第一行的目的是将 package.json 复制到应用目录,而不是整个应用代码目录。这样只有 pakcage.json 发生改变后,才会触发第二行 RUN npm install。而只要 package.json 没有变化,那么应用的代码改变就不会引发 npm install,只会引发第三行的 COPY . /usr/src/app,从而加快构建速度。而如果按照前面所提到的,合并为两层,那么任何代码改变,都会触发 RUN npm install,从而浪费大量的带宽和时间。合理分层除了可以加快构建外,还可以加快部署,要知道,docker pull 的时候,是分层下载的,并且已存在的层就不会重复下载。
比如,这里的 RUN npm install 这一层,往往会几百 MB 甚至上 GB。而在 package.json 未发生变更的情况下,那么只有 COPY . /usr/src/app 这一层会被重新构建,并且也只有这一层会在各个节点 docker pull 的过程中重新下载,往往这一层的代码量只有几十 MB,甚至更小。这对于大规模的并行部署中,所节约的东西向流量是非常显著的。特别是敏捷开发环境中,代码变更的频繁度要比依赖变更的频繁度高很多,每次重复下载依赖,会导致不必要的流量和时间上的浪费。
小伙伴们冲鸭,后台留言区等着你!
关于Docker,今天你学到了什么?还有哪些不懂的?除此还对哪些话题感兴趣?快来留言区打卡啦!留言方式:打开第XX天,答:……
同时欢迎大家搜集更多问题,投稿给我们!风里雨里留言区里等你~
福利
1、扫描添加小编微信,备注“姓名+公司职位”,加入【云计算学习交流群】,和志同道合的朋友们共同打卡学习!
推荐阅读:
IEEE 回应禁止华为系审稿人;WiFi联盟、蓝牙联盟已恢复华为成员资格;中国计算机学会:暂时中止与IEEE通信学会合作……
ARM 发布新一代 CPU 和 GPU,实现 20% 性能提升!
前端开发 20 年变迁史
北漂杭漂的程序员,是如何买到第一套房子?
“爱装X”开源组织:“教科书级”AI知识树究竟长什么样?
500行Python代码打造刷脸考勤系统
权游播完了, 你在骂烂尾, 有人却悄悄解锁了新操作……