4

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

 3 years ago
source link: http://dockone.io/article/1721158
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
0*cwFmgUG9LI9s97lX.png

图源  www.docker.com

Docker是软件开发者和系统管理员用容器构建、运行和共享应用程序的平台。一个 容器 是一个运行在隔离环境中、拥有自己的文件系统上的进程;这个文件系统是使用 docker镜像 构建的。镜像文件包括运行应用程序所需的一切(编译后的代码、依赖关系、库等)。镜像可以使用一个名为 Dockerfile 的文件来定义

术语 Docker化(dockerization) 或者 容器化(containerization) 通常用于定义创建Docker容器的过程。

容器之所以流行,是因为它们具有以下一些特点,

  • 灵活 :即使是最复杂的应用也可以被容器化。
  • 轻量级 :容器共享主机内核,使其比虚拟机更高效。
  • 可移植 :可在本地编译并在任何地方运行。可在本地编译并在任何地方运行。
  • 松耦合 :容器各自是独立封装的,允许一个容器被替换或升级而不影响、中断其他容器。
  • 安全 :容器采用积极的限制和隔离策略,不需要用户进行任何配置。

在本篇文章中,我将专注于优化Docker镜像以实现轻量级。

让我们从一个例子开始:在这个例子中,我们构建了一个React应用程序,我们想要将其docker化。运行 npx 命令并创建Dockerfile后,我们的文件结构就像 图1 一样。

npx create-react-app app --template typescript
0*CwWLe_mX6YXnVlW5.png

图1: 文件结构

如果我们构建一个基础的Dockerfile,我们会得到一个如下所示的1.16GB的Docker镜像:

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
0*M2WiAKbrcoIwDO8W.png

图2: 镜像的初始大小为1.16GB

初次优化**: 使用轻量级的基础镜像**

Docker Hub (公共Docker仓库)中,有多个镜像可供下载,每个镜像都有不同的特点和大小。

通常情况下,基于 AlpineBusyBox 的镜像与基于 Ubuntu 等其他Linux发行版的镜像相比,体积极小。这是因为Alpine和其他的映像已经被优化,包含了最少的但必要的软件包。在下图中,你可以看到Ubuntu、Alpine、Node和基于Alpine的Node基础镜像大小的对比。

0*NyJgka2ebrfG6nzJ.png

图3: 不同大小的基础镜像

通过修改Dockerfile,使用Alpine作为基础镜像,最后我们的镜像大小是330MB:

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
0*qwtP4fm0dUL7VnN-.png

图4: 镜像优化后大小是330MB

第二次优化**: 使用多阶段构建**

通过多阶段构建,我们可以在Dockerfile中使用多个基础镜像,并将工件、配置文件等从一个阶段复制到另一个阶段,这样我们就可以丢弃不需要的东西。

在这个例子中,我们部署React应用需要的是编译后的代码,我们不需要源文件,也不需要 node_modules 目录,也不需要 package.json 等。

通过将Dockerfile改成下面这样,我们的镜像最终大小为91.5 MB。值得注意的是,上一阶段的镜像(第1-4行)不会自动删除,Docker会将其保存在缓存中,以便我们在另一个构建中使用相同阶段时运行速度更快,所以必须手动删除。

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
0*HKFCdIosZROgm8Vx.png

图5: 在第二次优化以后镜像的大小是91.5MB

现在,我们有一个Docker文件,其中定义有两个阶段:在第一个阶段,我们编译项目。在第二个阶段,我们将应用程序部署在Web服务器上。然而,Node容器并不是服务静态资源(HTML、CSS和JavaScript文件、图片等)的最佳选择,最佳的选择是使用像 NginxApache 这样的服务器。在这种情况下,我选择使用Nginx。

通过将Docker文件改成下面这样,我们的镜像最终大小为22.4 MB。如果我们运行这个容器,我们可以看到这个应用能够正常工作( 图7 )。

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;"]
0*HkJiAQcGsFz0UXXy.png

图6: 在第三次优化以后镜像大小为22.4MB

0*IX32KFTFcYcEuY5N.png

图7: 执行容器的最终结果

参考


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK