使用Docker高效部署前端应用

容器的每一个阶段都应该是短暂的

通过 Dockerfile 构建的镜像所启动的容器应该尽可能短暂 (ephemeral)。短暂意味着可以很快地启动并且终止

使用 .dockerignore 排除构建无关文件

.dockerignore 语法与 .gitignore 语法一致。使用它排除构建无关的文件及目录,如 node_modules

使用multistage构建

多阶段构建可以有效减小镜像体积,特别是对于需编译语言而言,一个应用的构建过程往往如下

  1. 安装编译工具
  2. 安装第三方库依赖
  3. 编译构建应用

在前两步会有大量的镜像体积冗余,使用多阶段构建可以避免这一问题,参考前端应用的dockerfile示例。

FROM node:8.16.2-alpine AS build
WORKDIR /
COPY package.json yarn.lock ./
RUN yarn install
COPY / /
RUN yarn build
### stage: app ###
FROM nginx:1.15-alpine AS app
LABEL maintainer=" An<an@email.com>"
LABEL app=Website
COPY nginx/ /etc/nginx/
COPY build/ /usr/share/nginx/html
EXPOSE 80

避免安装不必要的包

减小体积,减少构建时间。如前端应用使用 npm install --production 只装生产环境所依赖的包。

减小容器耦合

如一个web应用将会包含三个部分,web 服务,数据库与缓存。把他们解耦到多个容器中,方便横向扩展。如果你需要网络通信,则可以将他们至于一个网络下。

减少镜像层数

  • 只有 RUN, COPY, ADD 会创建层数, 其它指令不会增加镜像的体积
  • 尽可能使用多阶段构建

使用以下方法安装依赖

# 使用以下方法安装依赖
RUN yum install -y node python go
# 错误的方法安装依赖,这将增加镜像层数
RUN yum install -y node 
RUN yum install -y python 
RUN yum install -y go

充分利用构建的缓存

在镜像的构建过程中 docker 会遍历 Dockerfile 文件中的所有指令,顺序执行。对于每一条指令,docker 都会在缓存中查找是否已存在可重用的镜像,否则会创建一个新的镜像

跳过缓存

我们可以使用 docker build --no-cache 跳过缓存

  • ADD 和 COPY 将会计算文件的 checksum 是否改变来决定是否利用缓存
  • RUN 仅仅查看命令字符串是否命中缓存,如 RUN apt-get -y update 可能会有问题

如一个 node 应用,可以先拷贝 package.json 进行依赖安装,然后再添加整个目录,可以做到充分利用缓存的目的。

FROM node:8.16.2-alpine AS build
WORKDIR /
COPY package.json yarn.lock ./
#此处可以充分利用缓存
RUN yarn install --production
COPY / /
RUN yarn build

开发在遇到的问题(解决办法汇总)

目前的镜像存在两个问题,导致每次部署时间过长,不利于产品的快速交付,没有快速交付,也就没有敏捷开发 (Agile)

  • 构建镜像时间过长
  • 构建镜像大小过大,多时甚至 1G+

解决办法:

从devdependencies下手

对于每次部署,如果能够减少无用包的下载,便能够节省很多镜像构建时间。eslint,mocha,chai等代码风格测试模块可以放到devDependencies中。在生产环境中使用npm install --production装包。

我们注意到,相对于项目的源文件来讲,package.json是相对稳定的。如果没有新的安装包需要下载,则再次构建镜像时,无需重新装包。则可以在 npm install 上节省一半的时间。

利用镜像缓存

对于 ADD 来讲,如果需要添加的文件内容的 checksum 没有发生变化,则可以利用缓存。把 package.json 与源文件分隔开写入镜像是一个很好的选择。目前,如果没有新的安装包更新的话,可以节省一半时间

多阶段构建

得益于缓存,现在镜像构建时间已经快了不少。但是,此时镜像的体积依旧过于庞大,这也将会导致部署时间的加长。原因如下

考虑下每次 CI/CD 部署的流程

  1. 在构建服务器构建镜像
  2. 把镜像推至镜像仓库服务器
  3. 在生产服务器拉取镜像,启动容器

显而易见,镜像体积过大会造成传输效率低下,增加每次部署的延时

即使,构建服务器与生产服务器在同一节点下,没有延时的问题。减少镜像体积也能够节省磁盘空间(使用较早期的镜像)

使用文件存储服务

分析一下 50M+ 的镜像体积,nginx:10-alpine 的镜像是16M,剩下的40M是静态资源。

如果把静态资源给上传到文件存储服务,即OSS,并使用 CDN 对 OSS 进行加速。则没有必要打入镜像了,此时镜像大小会控制在 20M 以下

关于静态资源,可以分类成两部分

  • /static,此类文件在项目中直接引用根路径,打包时复制进 /public 下,需要被打入镜像
  • /build,此类文件需要 require/import 引用,会被 webpack 打包并加 hash 值,并通过 publicPath 修改资源地址。可以把此类文件上传至 oss,并加上永久缓存,不需要打入镜像

最佳实践

FROM node:10-alpine as builder
ENV PROJECT_ENV production
ENV NODE_ENV production
# http-server 不变动也可以利用缓存
WORKDIR /code
ADD package.json /code
RUN npm install --production
ADD . /code
# npm run uploadOss 是把静态资源上传至 oss 上的脚本文件
RNN npm run build && npm run uploadOss
# 选择更小体积的基础镜像
FROM nginx:10-alpine
COPY --from=builder code/public/index.html
code/public/favicon.ico /usr/share/nginx/html/
COPY --from=builder code/public/static /usr/share/nginx/html/static
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值