前言

对于前端日常开发而言,有时也会用到Docker,结合到目前我们在做的 Nebula Studio (nebula的图形界面工具),使用docker主要基于以下考虑:

  • 我们的工具背后有好几个服务组合在一起,诸如不同技术栈的现有服务,纯前端的静态资源。
  • 目前我们还没有云,想让用户对服务组合无感,能直接在本地一键启动应用并使用。
  • 团队本就提供有 nebula镜像版本 实践,给了我们前端一些参考和借鉴。

镜像的构建

  1. 既然要使用Docker来承载我们的应用,就得将项目进行镜像构建,与所有build镜像相似,需要配置一份命名为[Dockerfile ](https://docs.docker.com/engine/reference/builder/)的文件,文件是一些步骤的描述,简单来说就是把项目复制到镜像里,并设置好启动方式:<br /> ![image.png](https://cdn.nlark.com/yuque/0/2020/png/88240/1580050092442-e6c33234-a1a2-4433-acf3-f21c6273993b.png#align=left&display=inline&height=236&name=image.png&originHeight=472&originWidth=852&size=74360&status=done&style=none&width=426)

镜像体积优化

  1. 如果按照上述的配置文件来构建Docker镜像,以我们的项目为例,将会生成一个体积约为1.3GB的镜像,这个看起来有点吓人,因为即使在网速快的用户电脑上光下载镜像也需要等待不少时间,这是不能接受的。在调研了相应的资料后,了解到可以从以下几个方面缩小体积,进行优化:

基础镜像源的选择

  1. 所谓基础镜像源,就是我们在进行构建步骤时,选择的一个基础环境(如上 `node:10` ),通过查看 [Dockerhub](https://hub.docker.com/_/node) 上有关node的基础环境镜像时,我们会发现有n多版本,虽然都是node相关基础镜像,但不同版本,他们除了node版本不同外,在内部集成的环境也有所不一样,例如带有 [alpine](https://yeasy.gitbooks.io/docker_practice/cases/os/alpine.html) 的版本,相当于是一个比较精巧的linux系统镜像,在我们常规系统中所附带的工具,在此版本运行的容器中都会发现不存在,比如bash、curl等,由此来缩小体积。根据项目实际需要,当我把基础镜像换为 [alpine](https://yeasy.gitbooks.io/docker_practice/cases/os/alpine.html) 版本后,再次进行构建,此时镜像体积已大幅度减小,从1.3GB直降为500多MB,体积优化效果明显,所以当你发现自己构建的镜像体积过大时,可以考虑从更换基础镜像源的方式来着手,看看是否使用了过于臃肿的镜像源。

Multi-stage构建镜像

  1. 所谓 [multi-stage](https://docs.docker.com/develop/develop-images/multistage-build/) 即是Docker镜像构建的时候采取的策略,详细可点击链接提供的资料。简言之就是利用Docker构建提供的规则:Dockerfile的操作都会增加一个所谓镜像的“层”,每一层都会增加镜像体积,通过采用多步骤策略,每一步骤包含具有相同意义的一系列操作(例如构建,部署),步骤与步骤之间通过产物镜像引用的方式,由此来缩减最终构建镜像所需要的层数,具体操作比如:
  1. # 设置第一步骤产生的镜像,并命名为builder
  2. FROM node:10-alpine as builder
  3. WORKDIR /nebula-web-console
  4. # 复制当前项目内容至镜像中
  5. ADD . /nebula-web-console
  6. # 进行相应的构建
  7. RUN npm install
  8. RUN npm run build
  9. ....
  10. # 进行第二步骤构建
  11. FROM node:10-alpine
  12. WORKDIR /nebula-web-console
  13. # 复制第一步构建镜像的产物内容至当前镜像,只用到了一层镜像层从而节约了之前构建步骤的镜像层数
  14. COPY --from=builder . /nebula-web-console
  15. CMD ["npm", "run", "docker-start"]

.dockerignore

  1. 类似我们熟悉的 `.gitignore`,就是当我们在进行 `COPY` `ADD` 文件复制操作时,将不必要的文件忽略掉(诸如文档文件、git文件、node_modules以及一些非生成必要文件等),从而减小镜像体积,更详细内容可参考文档连接:[.dockerignore](https://docs.docker.com/engine/reference/builder/#dockerignore-file)。

操作合并

  1. 基于上述提到在 Dockerfile 构建镜像的过程做,每一个操作都会在前一步镜像基础上增加一“层”,可以利用 `&` 来合并多个操作,减少层数,比如:
  1. # 以下两个操作分别代表两层
  2. RUN npm install
  3. RUN npm run build

改为:

  1. # 使用 & 后变了为一层
  2. RUN npm install && npm run build

由此我们减少了层数的增加,即减少了镜像的体积。同时,在构建镜像的过程中,我们也可以通过在达到相同目的的前提下,尽量减少不必要的操作来减少“层数”的添加。

前端常规性体积优化

  • 压缩丑化代码,移除源码

    此操作可以放在构建步骤阶段,这样会进一步缩小镜像的文件体积。

  • node_modules 只下载生产环境需要的代码

    此操作可以放在部署阶段,只下载生产环境所需要的第三方依赖代码: npm install --production

  • 公共资源放在CDN

    如果镜像被期待运行在联网环境,可以考虑将一些体积相比较大的公共文件(图片、第三方库等)放在CDN服务 器上,将部分资源剥离出去,也会进一步缩小体积。

  • 更多

    以上只作为一个线索参考,更多前端常规的优化步骤,都可以迁移至镜像中进行,比较和我们本地开发一样,镜像构建也是一个运行代码的环境嘛。

小结

以上便是我在此次使用Docker镜像来运行我们 Nebula Studio 所用到的一些优化镜像体积的方法,希望能给需要的人一些帮助和参考,可能还有一些认识不准确的地方,欢迎斧正,同样欢迎各位试用,嘻嘻~