什么是Docker
Docker是一个开源的虚拟化平台,可以让开发人员将应用程序和依赖项打包在轻量级容器中,然后可以轻松地在任何环境中运行。这样,开发人员可以将容器作为独立的可移植单元在不同的环境中部署和运行应用程序,而不用担心环境的差异会对应用程序的行为产生影响。例如,您可以使用Docker在开发环境中测试应用程序,然后将容器部署到生产环境中运行。总之,Docker可以让开发人员更轻松地创建、部署和运行应用程序。
- 灵活性:即使是最复杂的应用程序也可以容器化。
- 轻量化:容器共享主机内核,使得它们远比虚拟机高效。
- 便携性:可以做到本地编译,到处运行。松耦合:容器自我封装,一个容器被替换或升级不会打断别的容器。
- 安全性:容器对进程进行了严格的限制和隔离,而无需用户进行任何配置。
在这篇文章中,我将重点讨论如何优化 Docker 镜像以使其轻量化。
优化过程
让我们从一个示例开始,在该示例中,我们构建了一个 React 应用程序并将其容器化。运行 npx 命令并创建 Dockerfile 之后,我们得到了如图 1 所示的文件结构。
npx create-react-app app --template typescript
如果我们构建一个基础的 Dockerfile(如下所示),我们最终会得到一个 1.16 GB 的镜像:
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
第一步优化:使用轻量化基础镜像
在 Docker Hub(公共 Docker 仓库)中,有一些镜像可供下载,每个镜像都有不同的特征和大小。
通常,相较于基于其他 Linux 发行版(例如 Ubuntu)的镜像,基于 Alpine 或 BusyBox 的镜像非常小。这是因为 Alpine 镜像和类似的其他镜像都经过了优化,其中仅包含最少的必须的软件包。
在下面的图片中,你可以看到 Ubuntu、Alpine、Node 和基于 Alpine 的 Node 镜像之间的大小比较。
通过修改 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
第二步优化:多阶段构建
通过多阶段构建,我们可以在 Dockerfile 中使用多个基础镜像,并将编译成品、配置文件等从一个阶段复制到另一个阶段,这样我们就可以丢弃不需要的东西。
我们部署 React 应用程序需要的是编译后的代码,我们不需要源文件,也不需要 node_modules 目录和 package.json 文件等。
通过将 Dockerfile 修改为如下内容,我们最终得到的镜像大小为 91.5MB。请记住,来自第一阶段(第 1-4 行)的镜像不会被自动删除,Docker 将它保存在 cache 中,如果我们在另一个构建镜像过程中执行了相同的阶段,就可以使镜像构建更快。所以你必须手动删除第一阶段镜像。
FROM node:10-alpine AS build
WORKDIR /app
COPY app /app
RUN npm install && npm run build
FROM node:10-alpineWORKDIR /app
RUN npm install -g webserver.local
COPY --from=build /app/build ./build
EXPOSE 3000
CMD webserver.local -d ./build
现在我们有了一个 Dockerfile,它有两个阶段:在第一个阶段中,我们编译项目,在第二个阶段中,我们在 web 服务器上部署应用程序。
然而,Node 容器并不是提供网页(HTML、CSS 和 JavaScript 文件、图片等)服务的最佳选择,最好的选择是使用像 Nginx 或 Apache 这样的服务。在本例中,我将使用 Nginx。
通过将 Dockerfile 修改为如下内容,我们的镜像最终大小是 22.4MB,如果我们运行这个容器,我们可以看到网页可以正常工作,没有任何问题。
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;"]
最终容器的运行结果
总结:
您可以使用多种方法来优化Docker镜像大小。这里列举几种常用的方法:
- 使用基础镜像:选择一个较小的基础镜像来作为您的应用程序的镜像。这样,您的镜像就不会包含多余的文件和依赖项。
- 使用多个镜像:将您的应用程序拆分成多个镜像,每个镜像只包含一个特定的功能。这样,您就可以在运行时动态加载镜像,而不需要在每个镜像中都包含所有功能。
- 压缩镜像:使用压缩工具对镜像进行压缩,可以节省镜像的空间。
- 清理无用文件:在构建镜像时,确保只包含必需的文件和依赖项。在构建过程中,可以使用命令来清理缓存和无用的文件。
- 使用 alpine 版本的镜像:alpine 版本的镜像比普通版本的镜像要小得多,因为它们只包含基本的 Linux 系统功能。因此,您可以使用 alpine 版本的镜像来构建您的应用程序。
- 删除不必要的依赖项:在构建镜像时,确保只安装必需的依赖