首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >实测有效!手把手带你将 Docker Image 体积减少 90%

实测有效!手把手带你将 Docker Image 体积减少 90%

原创
作者头像
写bug的高哈哈
修改2024-11-20 10:15:28
修改2024-11-20 10:15:28
6180
举报

“好事”文章推荐:🌟 Java图像识别之旅:从入门到实践的全面指南

这篇文章详细介绍了 Java 图像识别的原理、工具、代码实现及应用场景,从入门到实践,带你逐步揭开图像识别的神秘面纱,无论是初学者还是有一定经验的开发者,都能从中获得实用的知识和技能。

Docker Image 体积越大,那部署要花的时间就越长;假如每个版本都有好几 GB 也会拖慢服务打包编译的速度;因此笔者开始动手实践,想看看到底能将 Docker Image 的体积缩小多少!

ㄧ、先初始化一个简单的 Node.js 项目

代码语言:shell
复制
# 创建文件夹
mkdir docker-test
cd docker-test

# 初始化应用
npm init

# 安装 express
npm install express --save

初始化后的 package.json 大概会长这样(scripts 的 start 笔者有微调):

代码语言:shell
复制
{
  "name": "docker-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.18.1"
  }
}

接著我们新增一个 index.js 的文件,文件内容如下:

代码语言:shell
复制
const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

为了实测不同情况下打包的影响,我们安装一个存放在「devDependencies」的依赖:

代码语言:shell
复制
npm install eslint -save-dev

二、编写 Dockefile,了解优化前体积有多大

这边我们就先用最简单的方式写 Dockerfile:

代码语言:shell
复制
FROM node
# 工作目录
WORKDIR /usr/src/app
# 拷贝所需文件
COPY package.json index.js ./
# 安装依赖
RUN npm install
# 提供服务的接口
EXPOSE 3000
CMD ["npm", "start"]

接下来输入 docker build -t docker-test . 就可以创建 Docker Image(docker-test 是名称)。

然后输入 docker images ,确认刚刚创建的 Docker Image 是否存在;从下图我们可以看到 优化前的 Image 大小高达 1.01GB

三、使用 Node.js 的 Alpine 版本

Node.js Alpine 版本的 Image 体积会远小于完整的 Node.js Image,现在我们修改一下 Dockerfile:

代码语言:shell
复制
# 使用 Alpine 版本 
FROM node:alpine
WORKDIR /usr/src/app
COPY package.json index.js ./
RUN npm install
EXPOSE 3000
CMD ["npm", "start"]

输入 docker build -t docker-test-alpine . 来创建 Image,完成后输入 docker images 看看 build 出来的 Image 体积是否改变。

从上图我们可以看到,Alpine 的版本让它的体积从 1.01GB 下降到了 189MB,整整少了 812MB!

四、正式环境下,不需要安装 devDependencies 的依赖

通常一个项目会安装一些 devDependencies 的依赖,但这些依赖只需要在开发环境中辅助使用,在正式环境下并没有安装的必要。

我们调整一下 Dockerfile 安装依赖的指令:

代码语言:shell
复制
FROM node:alpine

WORKDIR /usr/src/app

COPY package.json index.js ./

# 只安装 dependencies 的依赖
RUN npm install --production

EXPOSE 3000

CMD ["npm", "start"]

在上图我们可以看到体积又变小了,果然还有优化的空间(少了 12MB)。

五、如果我们只使用最基础的 Alpine,然后 Node.js 自己安装呢?

刚刚我们使用的是 Node.js 的 Alpine 版本,如果更极端一点,只使用最基础的 Alpine,然后自己额外安装 Node.js 会有什么样的结果呢?

代码语言:shell
复制
# 使用最基础的 Alpine
FROM alpine:latest

# 自己安装 Node.js & npm
RUN apk add --no-cache --update nodejs npm

WORKDIR /usr/src/app

COPY package.json index.js ./

RUN npm install --production

EXPOSE 3000

CMD ["npm", "start"]

没想到这个操作把整包 Image 的体积压的更低了(从 177MB 降到 64.7MB)。

六、采用多阶段构建

Docker Image 你可以理解为很多层互相叠加在一起,从Docker 1.10开始,COPY、ADD 和 RUN 语句会向镜像中添加新层;而在 Docker 的世界中可以允许有多个「FROM」,但只会取用最后一个「FROM」所创建的 Image。

Docker的层用于保存镜像的上一版本和当前版本之间的差异。就像Git的提交一样,如果你与其他存储库或镜像共享它们,就会很方便。但额外的层并不是没有代价的,层仍然会占用空间,你拥有的层越多,最终的镜像就越大。

在了解上面的概念后,我们就可以把「安装编译」的步骤放在第一个「FROM」里面执行,然后第二个 FROM 就只是单纯地把第一层的结果搬过去即可,那么 Dockerfile 实现会长这样:

代码语言:shell
复制
FROM alpine:latest AS builder
RUN apk add --no-cache --update nodejs npm
WORKDIR /usr/src/app
COPY package.json index.js ./
# 先完成安裝编译
RUN npm install --production

FROM alpine:latest
RUN apk add --no-cache --update nodejs npm
WORKDIR /usr/src/app
# 把编译好的全部移动过来
COPY --from=builder /usr/src/app .
EXPOSE 3000
CMD ["npm", "start"]

经过这么多的努力后,我们的 Docker Image 也顺利从 1.01GB 下降到 58.9MB, 减少了超过 94% 的体积 ,并且可以明显感受到 build Image 的速度上升不少。

七、使用 Distroless 让正式环境更加安全

尽管上面我们已经使用 Alpine 让 Docker Image 变得这么小,但在文章的最后我想再提供读者另一个选择, 那就是「Distroless」!

先让我们用它来 Build 一个 Docker Image。

代码语言:shell
复制
FROM node AS builder
WORKDIR /usr/src/app
COPY package.json index.js ./
RUN npm install --production
# 改成用 Distroless
FROM gcr.io/distroless/nodejs
WORKDIR /usr/src/app
COPY --from=builder /usr/src/app .
EXPOSE 3000
CMD ["index.js"]

如果单纯从结果来看,它在体积上(162MB)并没有什么优势,但如果你尝试用 Shell 打开它,会发现 Shell 根本不存在!换而言之,它的安全性相对更高,可以考虑使用它来做正式环境的部署。

以上就是笔者优化 Docker Image 体积的步骤啦!如果文中有表达不清晰、错误的部分再烦请告知。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ㄧ、先初始化一个简单的 Node.js 项目
  • 二、编写 Dockefile,了解优化前体积有多大
  • 三、使用 Node.js 的 Alpine 版本
  • 四、正式环境下,不需要安装 devDependencies 的依赖
  • 五、如果我们只使用最基础的 Alpine,然后 Node.js 自己安装呢?
  • 六、采用多阶段构建
  • 七、使用 Distroless 让正式环境更加安全
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档