美文网首页
实测有效!手把手带你将 Docker Image 体积减少 90

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

作者: 写bug写bug | 来源:发表于2024-01-31 11:50 被阅读0次

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

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

    # 创建文件夹
    mkdir docker-test
    cd docker-test

    # 初始化应用
    npm init

    # 安装 express
    npm install express --save

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

    {
      "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 的文件,文件内容如下:

    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}`)
    })

    为了实测不同情况下打包的影响,我们使用 npm 安装ESlint 工具,并将其保存为开发依赖项:

    npm install eslint -save-dev

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

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

    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:

    # 使用 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 的依赖

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

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

    FROM node:alpine

    WORKDIR /usr/src/app

    COPY package.json index.js ./

    # 只安装正式环境的依赖
    RUN npm install --production

    EXPOSE 3000

    CMD ["npm", "start"]

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

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

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

    # 使用最基础的 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 实现会长这样:

    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。

    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 体积的步骤啦!如果文中有表达不清晰、错误的部分再烦请告知。

    相关文章

      网友评论

          本文标题:实测有效!手把手带你将 Docker Image 体积减少 90

          本文链接:https://www.haomeiwen.com/subject/slzoodtx.html