Docker镜像优化:从1.16GB到22.4MB

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Docker是一个供软件开发人员和系统管理员使用容器构建、运行和与分享应用程序的平台。容器是在独立环境中运行的进程,它运行在自己的文件系统上,该文件系统是使用docker镜像构建的。镜像中包含运行应用程序所需的一切(编译后的代码、依赖项、库等等)。镜像使用Dockerfile文件定义。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"术语dockerization或containerization通常用于定义创建Docker容器的过程。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因为容器具备如下优点,所以"},{"type":"text","text":"很受欢迎"},{"type":"text","text":":"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"灵活性:即使是最复杂的应用程序也可以容器化。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"轻量化:容器共享主机内核,使得它们远比虚拟机高效。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"便携性:可以做到本地编译,到处运行。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"松耦合:容器自我封装,一个容器被替换或升级不会打断别的容器。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"安全性:容器对进程进行了严格的限制和隔离,而无需用户进行任何配置。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在这篇文章中,我将重点讨论如何优化Docker镜像以使其轻量化。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"让我们从一个示例开始,在该示例中,我们构建了一个React应用程序并将其容器化。运行npx命令并创建Dockerfile之后,我们得到了如图1所示的文件结构。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"npx create-react-app app --template typescript"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/5a\/5a814d807e239c52887d1de76629e99b.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"图1:文件结构"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果我们构建一个基础的Dockerfile(如下所示),我们最终会得到一个1.16 GB的镜像:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"embedcomp","attrs":{"type":"table","data":{"content":"

FROM node:10

 

WORKDIR \/app

COPY app \/app

RUN npm install -g webserver.local

RUN npm install && npm run build

 

EXPOSE 3000

CMD webserver.local -d .\/build"}}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/0b\/0bc747430757de34de72748a511f05b8.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"图2:镜像的初始大小为1.16GB"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"第一步优化:使用轻量化基础镜像"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在"},{"type":"link","attrs":{"href":"https:\/\/hub.docker.com\/","title":"","type":null},"content":[{"type":"text","text":"Docker Hub"}]},{"type":"text","text":"(公共Docker仓库)中,有一些镜像可供下载,每个镜像都有不同的特征和大小。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通常,相较于基于其他Linux发行版(例如"},{"type":"link","attrs":{"href":"https:\/\/hub.docker.com\/_\/ubuntu","title":"","type":null},"content":[{"type":"text","text":"Ubuntu"}]},{"type":"text","text":")的镜像,基于"},{"type":"link","attrs":{"href":"https:\/\/hub.docker.com\/_\/alpine","title":"","type":null},"content":[{"type":"text","text":"Alpine"}]},{"type":"text","text":"或"},{"type":"link","attrs":{"href":"https:\/\/hub.docker.com\/_\/busybox","title":"","type":null},"content":[{"type":"text","text":"BusyBox"}]},{"type":"text","text":"的镜像非常小。这是因为Alpine镜像和类似的其他镜像都经过了优化,其中仅包含最少的必须的软件包。在下面的图片中,你可以看到Ubuntu、Alpine、Node和基于Alpine的Node镜像之间的大小比较。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/86\/8636fe5ac03b51740ed84bc2d8de4990.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"图3:基础镜像的不同大小"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过修改Dockerfile并使用Alpine作为基础镜像,我们的镜像最终大小为330MB:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"embedcomp","attrs":{"type":"table","data":{"content":"

FROM node:10-alpine

 

WORKDIR \/app

COPY app \/app

RUN npm install -g webserver.local

RUN npm install && npm run build

 

EXPOSE 3000

CMD webserver.local -d .\/build"}}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/b0\/b0c525a22c2b853edc10853e58bc385b.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"图4:经过第一步优化后镜像大小为330MB"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"第二步优化:多阶段构建"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过多阶段构建,我们可以在Dockerfile中使用多个基础镜像,并将编译成品、配置文件等从一个阶段复制到另一个阶段,这样我们就可以丢弃不需要的东西。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在本例中,我们部署React应用程序需要的是编译后的代码,我们不需要源文件,也不需要node_modules目录和package.json文件等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过将Dockerfile修改为如下内容,我们最终得到的镜像大小为91.5MB。请记住,来自第一阶段(第1-4行)的镜像不会被自动删除,Docker将它保存在cache中,如果我们在另一个构建镜像过程中执行了相同的阶段,就可以使镜像构建更快。所以你必须手动删除第一阶段镜像。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"embedcomp","attrs":{"type":"table","data":{"content":"

FROM node:10-alpine AS build

WORKDIR \/app

COPY app \/app

RUN npm install && npm run build

 

 

FROM node:10-alpine

WORKDIR \/app

RUN npm install -g webserver.local

COPY --from=build \/app\/build .\/build

EXPOSE 3000

CMD webserver.local -d .\/build"}}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/de\/defd6ffdfe16ec546d5a5b083c94a322.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"图5:第二步优化后的镜像大小为91.5MB"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"现在我们有了一个Dockerfile,它有两个阶段:在第一个阶段中,我们编译项目,在第二个阶段中,我们在web服务器上部署应用程序。然而,Node容器并不是提供网页(HTML、CSS和JavaScript文件、图片等)服务的最佳选择,最好的选择是使用像Nginx或Apache这样的服务。在本例中,我将使用Nginx。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过将Dockerfile修改为如下内容,我们的镜像最终大小是22.4MB,如果我们运行这个容器,我们可以看到网页"},{"type":"text","text":"可以正常工作,没有任何问题"},{"type":"text","text":"(图7)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"embedcomp","attrs":{"type":"table","data":{"content":"

FROM node:10-alpine AS build

WORKDIR \/app

COPY app \/app

RUN npm install && npm run build

 

 

FROM nginx:stable-alpine

COPY --from=build \/app\/build \/usr\/share\/nginx\/html

EXPOSE 80

CMD [\"nginx\", \"-g\", \"daemon off;\"]"}}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/a5\/a5679d4a483b0592976dff51e625a40b.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"图6:第三步优化后的镜像大小为22.4MB"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/5a\/5aea754a91e0157bf3503daca2a5337a.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"图7:最终容器的运行结果"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"参考"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/docs.docker.com\/get-started\/","title":"","type":null},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"https:\/\/docs.docker.com\/get-started\/"}]}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/docs.docker.com\/develop\/develop-images\/multistage-build\/","title":"","type":null},"content":[{"type":"text","marks":[{"type":"underline"}],"text":"https:\/\/docs.docker.com\/develop\/develop-images\/multistage-build\/"}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"原文链接:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"https:\/\/medium.com\/the-agile-crafter\/docker-image-optimization-from-1-16gb-to-22-4mb-53fdb4c53311"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章