前面 使用 Docker 部署 Node 应用 一文中完成了镜像的创建和运行,不过生成的镜像还有些粗糙,需要进一步优化。

镜像的优化

通过 docker images 看到简单的一个 node 服务端应用,超过 1G 大小,因此需要优化一下使其更加轻量。

通过如下命令查看镜像文件里都有什么文件以及分别占用的空间大小:

$ docker history --human --format "{{.CreatedBy}}: {{.Size}}" wayou/my-app
CMD ["node" "dist/main"]: 0B
EXPOSE map[3000/tcp:{}]: 0B
COPY . . # buildkit: 2.24MB
RUN /bin/sh -c yarn build # buildkit: 118B
RUN /bin/sh -c yarn install --frozen-lockfil…: 484MB
RUN /bin/sh -c curl -o- -L https://yarnpkg.c…: 7.59MB
COPY package.json yarn.lock ./ # buildkit: 271kB
WORKDIR /usr/src/app: 0B
/bin/sh -c #(nop) CMD ["node"]: 0B
/bin/sh -c #(nop) ENTRYPOINT ["docker-entry…: 0B
/bin/sh -c #(nop) COPY file:238737301d473041…: 116B
/bin/sh -c set -ex && for key in 6A010…: 7.76MB
/bin/sh -c #(nop) ENV YARN_VERSION=1.22.5: 0B
/bin/sh -c ARCH= && dpkgArch="$(dpkg --print…: 100MB
/bin/sh -c #(nop) ENV NODE_VERSION=14.17.0: 0B
/bin/sh -c groupadd --gid 1000 node && use…: 333kB
/bin/sh -c set -ex; apt-get update; apt-ge…: 561MB
/bin/sh -c apt-get update && apt-get install…: 141MB
/bin/sh -c set -ex; if ! command -v gpg > /…: 7.82MB
/bin/sh -c set -eux; apt-get update; apt-g…: 24.1MB
/bin/sh -c #(nop) CMD ["bash"]: 0B
/bin/sh -c #(nop) ADD file:d9e4f6f4fc33703b7…: 101MB
 

使用更小的基础镜像

通过 node 在 Docker 市场的界面可看到,其中包含很多可使用的选择,

  • jessie-*
  • buster-*
  • stretch-*
  • alpine-*

其中 jessie-, buster- and stretch-* 基于 Debian 系统,alpine-* 则是 Alpine Linux。一般使用 alpine 即可。

- FROM node:14
+ FROM node:14-alpine
 

再次查看大小,减少了一半多来到 600+M

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
wayou/my-app latest f8b6ba45c68f 21 seconds ago 603MB
<none> <none> fe1ff8163c15 23 hours ago 1.44GB
<none> <none> 6e0fb94473a1 3 days ago 1.44GB
 

多次编译

详情及原理参见 Use multi-stage builds。简单来说,构建镜像文件包含很多步骤,中间步骤依赖使用的东西其实在最后成品中并不需要。

因此,我们可以将整个构建过程分成多步,得到一些中间结果。而这些中间结果是下一步所需要的,但生成这些中间结果的依赖却是下一步不需要的,就可以舍弃。

优化后的 Dockerfile:

######## step 1 ########
FROM node:14-alpine AS BUILD_IMAGE # Create app directory
WORKDIR /usr/src/app # Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
# this is for npm
# COPY package*.json ./
# but we use yarn
COPY ["package.json", "yarn.lock", "./"] # npm comes with node
# RUN npm install
# if we use yarn, we need firstly install it
# RUN curl -o- -L https://yarnpkg.com/install.sh | bash # equivalent for `npm ci`, see https://stackoverflow.com/a/58525708/1553656
# If you are building your code for production
# RUN npm ci --only=production
RUN yarn install --frozen-lockfile # Bundle app source
COPY . . RUN yarn build ######## step 2 ######## FROM node:14-alpine WORKDIR /usr/src/app COPY --from=BUILD_IMAGE /usr/src/app/dist ./dist
COPY --from=BUILD_IMAGE /usr/src/app/node_modules ./node_modules EXPOSE 3000
CMD [ "node", "dist/main" ]
 

再次生成镜像后查看大小,又减小了一半,来到 300+M,

$  docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
wayou/my-app latest c0ffda4c908a 19 seconds ago 351MB
<none> <none> f8b6ba45c68f 18 minutes ago 603MB
<none> <none> fe1ff8163c15 23 hours ago 1.44GB
 

优化 node 依赖

去掉 devDependency,更新安装的命令:

- RUN yarn install --frozen-lockfile
+ RUN yarn install --frozen-lockfile --production=true
 

但是,如果编译过程需要编译 TypeScript,跑测试,跑 Lint 等,此方法就不适用,因为这些依赖均在 devDependency

凡事无绝对,虽然安装时不能去掉,但可以在用完之后去掉。

所以在 yarn build 之后使用 npm prune 来手动删除这些无用的依赖:

RUN yarn build

+ # remove development dependencies
+ RUN npm prune --production
 

再次查看大小,减小了一半多:

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
wayou/my-app latest 9aba2a428703 5 seconds ago 129MB
<none> <none> c0ffda4c908a 11 minutes ago 351MB
<none> <none> f8b6ba45c68f 29 minutes ago 603MB
<none> <none> fe1ff8163c15 23 hours ago 1.44GB
<none> <none> 6e0fb94473a1 3 days ago 1.44GB
 

node-prune

使用 node-prune 进一步删除依赖中的无用文件,比如 markdown,测试文件,TypeScript 的类型文件等。

更新后的 Dockerfile:

FROM node:14-alpine AS BUILD_IMAGE

# install node-prune (https://github.com/tj/node-prune)
RUN curl -sfL https://install.goreleaser.com/github.com/tj/node-prune.sh | bash -s -- -b /usr/local/bin # Create app directory
WORKDIR /usr/src/app
… RUN yarn build # remove development dependencies
RUN npm prune --production # run node prune
RUN /usr/local/bin/node-prune FROM node:14-alpine WORKDIR /usr/src/app …
 

注意,运行上面的 Dockerfile 后会报如下错误:

 => ERROR [build_image 2/9] RUN curl -sfL https://install.goreleaser.com/github.com/tj/node-prune.sh | bash              0.4s
------
> [build_image 2/9] RUN curl -sfL https://install.goreleaser.com/github.com/tj/node-prune.sh | bash:
#6 0.366 /bin/sh: curl: not found
#6 0.366 /bin/sh: bash: not found
 

那是因为切换到 node:12-alpine 镜像后其中不再包含 curl 命令,需要单独安装下:

FROM node:14-alpine AS BUILD_IMAGE

# alpine doesn't come with curl
RUN apk update && apk add curl bash && rm -rf /var/cache/apk/* # install node-prune (https://github.com/tj/node-prune)
RUN curl -sfL https://install.goreleaser.com/github.com/tj/node-prune.sh | bash -s -- -b /usr/local/bin # Create app directory
WORKDIR /usr/src/app …
 

这次优化后的大小减少了几 M:

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
wayou/my-app latest 113ca4503190 3 minutes ago 126MB
<none> <none> 9aba2a428703 46 minutes ago 129MB
<none> <none> c0ffda4c908a 57 minutes ago 351MB
<none> <none> f8b6ba45c68f About an hour ago 603MB
<none> <none> fe1ff8163c15 24 hours ago 1.44GB
 

手动删除

根据 Honey, I shrunk the node_modules! ...and improved app’s performance in the process 里的介绍再手动删除一些依赖文件:


# run node prune
RUN /usr/local/bin/node-prune # remove unused dependencies
RUN rm -rf node_modules/rxjs/src/
RUN rm -rf node_modules/rxjs/bundles/
RUN rm -rf node_modules/rxjs/_esm5/
RUN rm -rf node_modules/rxjs/_esm2015/ FROM node:14-alpine
 

查看大小,减小了 3M,聊胜于无:

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
wayou/my-app latest 2c54b4ee27cd 4 seconds ago 123MB
<none> <none> 113ca4503190 9 minutes ago 126MB
<none> <none> 9aba2a428703 52 minutes ago 129MB
<none> <none> c0ffda4c908a About an hour ago 351MB
<none> <none> f8b6ba45c68f About an hour ago 603MB
<none> <none> fe1ff8163c15 24 hours ago 1.44GB
<none> <none> 6e0fb94473a1 3 days ago 1.44GB
 

相关资源

The text was updated successfully, but these errors were encountered:

使用 Docker 部署 Node 应用 - 镜像文件尺寸的优化的更多相关文章

  1. docker制作node程序镜像:

    准备: 需要5个文件 新建一个docker文件夹 1 .ignore git忽略文件用的 2 pakage.json 安装NODE程序的 也可以直接拷贝进 docker文件加 3 node环境 lin ...

  2. docker部署harbor私有镜像库(3)

    一.harbor介绍 在实际生产运维中,往往需要把镜像发布到几十.上百台或更多的节点上.这时单台Docker主机上镜像已无法满足,项目越来越多,镜像就越来越多,都放到一台Docker主机上是不行的,我 ...

  3. 使用 Docker 部署 Node 应用

    容器将应用与环境打包整合,解决了应用外部依赖的痛点,打包后通过窗口可方便地部署到任意环境,用过就知道很香. 创建示例应用 以 NestJS 为例,先创建一个示例应用. $ npm i -g @nest ...

  4. docker部署node.js

    1.dockerfile FROM node:14.16.0 RUN mkdir -p /var/log/lily/ RUN mkdir -p /opt/node # 工作目录 WORKDIR /op ...

  5. Docker部署Registry私有镜像库

    拉取镜像 docker pull registry:2.6.2   生成账号密码文件,这里采用htpasswd方式认证 docker run --rm --entrypoint htpasswd re ...

  6. docker部署nodejs项目应用

    之前笔者弄了一套nestjs项目放在自己服务器上,并用pm2管理进程. 现在要把pm2停止,尝试一下用docker容器,那么首先要安装docker 一.安装docker 由于笔者服务器的系统是cent ...

  7. docker 部署nestjs应用

    搭建nodejs运行环境,使用了node容器运行 1.安装运行node image docker pull node:latest docker run -itd --name mynode node ...

  8. Maven+Docker 部署

    Maven+Docker 部署 安装jdk8镜像 docker pull openjdk:8-jdk-alpine maven插件推送方式 修改/etc/docker/daemon.json文件,加入 ...

  9. Docker部署FastDFS(附示例代码)

    1. FastDFS简介   FastDFS是一个开源的分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下载)等,解决了大容量存储和负载均衡的问题.特别适合以文 ...

随机推荐

  1. 开源囧事4:你们这些卖代码的能不能留自己的QQ号?留我QQ号干嘛?

    缘起于开源项目 从 2017 年开始,陆陆续续写了一些开源项目放到开源网站里,都是一些实战项目,给大家练练手.有基础整合的demo,有 Spring Boot 博客项目,有 Spring Boot 商 ...

  2. windows 7系统封装总结

    win7系统封装总结 需求:对于个人家庭用户,网上下载原版镜像或者下载好别人封装好的系统都无所谓,但是在公司办公的特殊环境下, 有时需要经常装一些特殊的软件,根据实际情况,封装一个适合本公司使用环境的 ...

  3. 【2020BUAA软件工程】个人博客作业

    个人作业博客 项目 内容 北航2020软工 班级博客 作业要求 具体要求 我的课程目标 学习软件工程,掌握团队合作,锻炼自我 作业在哪个方面帮助我实现目标 通读<构建之法>,尝试理解软件工 ...

  4. Java中对象池的本质是什么?(实战分析版)

    简介 对象池顾名思义就是存放对象的池,与我们常听到的线程池.数据库连接池.http连接池等一样,都是典型的池化设计思想. 对象池的优点就是可以集中管理池中对象,减少频繁创建和销毁长期使用的对象,从而提 ...

  5. 说了你可能不信leetcode刷题局部链表反转D92存在bug,你看了就知道了

    一.题目描述 找出数组中重复的数字 > 在一个长度为 n 的数组 nums 里的所有数字都在 0-n-1 的范围内.数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次. ...

  6. CMMI V2.0丨如何通过CMMI真正在企业中的实施规模化敏捷开发

    在过去的几年中,敏捷开发已经从一个利基概念(利基是指针对企业的优势细分出来的市场,这个市场不大,而且没有得到令人满意的服务.产品推进这个市场,有盈利的基础.)转变为全球许多大公司采用的标准实践. 通过 ...

  7. makefile的函数集合

    strip函数:$(strip text) 函数功能:去除字符串空格函数 示例: STR =        a    b c      LOSTR = $(strip $(STR)) #结果是&quo ...

  8. 02、SpringBoot2入门

    1.系统要求 Java 8 & 兼容java14 . Maven 3.3+ idea 2019.1.2 1.1.maven设置 <mirrors> <mirror> & ...

  9. 阅读vue源码-----内置组件篇(keep-alive)

    1.前言: <keep-alive>是vue实现的一个内置组件,也就是说vue源码不仅实现了一套组件化的机制,也实现了一些内置组件. <keep-alive>官网介绍如下:&l ...

  10. Spring 注解动态数据源设计实践

    Spring 动态数据源 动态数据源是什么?解决了什么问题? 在实际的开发中,同一个项目中使用多个数据源是很常见的场景.比如,一个读写分离的项目存在主数据源与读数据源. 所谓动态数据源,就是通过Spr ...