绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
使用 Docker 构建前端应用
2020-05-09 11:50:20

随着容器化技术的大行其道,Docker 在前端领域中也有着越来越广泛的应用。本文主要介绍了容器化技术给前端工程带来的变化,演示了如何使用 Docker 构建不同种类的前端应用。

什么是 Docker

Docker 初是 dotCloud 公司创始人 Solomon Hykes 在法国期间发起的一个公司内部项目,它是基于 dotCloud 公司多年云服务技术的一次革新,并于 2013 年 3 月以 Apache 2.0 授权协议开源,主要项目代码在 GitHub 上进行维护。Docker 项目后来还加入了 Linux 基金会,并成立推动开放容器联盟(OCI)

Docker 使用 Google 公司的 Go 语言 开发实现,基于 Linux 内核的 cgroupnamespace,以及 AUFS 类的 Union FS 等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它隔离的进程,因此称其为容器。初实现是基于 LXC,从 0.7 版本后开始去除 LXC,转而使用自行开发的 libcontainer,从 1.11 开始,进一步演进使用 runCcontainerd

Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。

前端为什么要用 Docker

这里只讨论使用 Docker 给前端带来的优势,偏运维相关的比如启动速度快,资源利用率高等略过,有兴趣的同学可以上官网看看文档。

  • 提供一致的运行环境。在任何环境下使用 Docker 构建的镜像的运行环境都是确定的,Docker 给应用提供了一个从开发到上线均一致的环境。比如 Node.js 项目在不同版本下性能表现不一致,开发环境用的是 Node.js 6,UAT 环境用了 Node.js 10,那么很可能接口的压测结果不一致。
  • 更轻松的迁移。由于 Docker 确保了运行环境的一致性,使得应用的迁移更加容易。可以很轻易将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行。比如接到任务说下周要加一个分区,或者客户要求部署私有云,可以很放心的说镜像拿走,而不用担心环境问题。
  • 持续交付和部署。代码从开发到终在生产环境上的部署,需要经过很多中间环境,通过定制应用镜像来实现持续集成、持续交付,非常有助于降低构建持续交付流程的复杂程度。在中小型公司可以考虑直接使用 GitLab CI 搭建持续集成环境。
  • 快速部署、回滚。得益于 Docker 使用的分层存储和镜像技术,使得扩展镜像变得非常简单。可以预先把程序需要的依赖,静态资源等在构建过程中添加到镜像,在需要的时候启动该容器实现快速部署、回滚、止血。比如当出现线上事故需要回滚时,传统做法是触发某些自动化工具去拉代码装依赖打包后部署,一旦某个环节出了问题,譬如网络被墙了导致依赖拉不下来,构建失败等等,小事故可能会演变为 P0 事故。

使用 Docker 构建 Web 前端项目

Web 前端项目的部署上线一般会经历 babel 编译,webpack 构建等过程,终将打包后的静态资源放在静态资源服务器上。

步,创建项目。这个过程和使用的框架并没有太多关系,这里就拿 React 来演示,使用 create-react-app 创建项目,进入目录后使用 npm run build 命令构建出部署所需要的静态资源

npx create-react-app my-app
cd my-app
npm run build

第二步,选择合适的静态资源服务器。这里选用 Nginx,这是一款轻量级的 HTTP 服务器,具有很多非常优越的特性:轻量、高性能、并发能力强,用来部署静态页面很便捷

在根目录创建 nginx.conf,按需进行配置

  • 现代前端框架几乎都使用了 HTML5 push/pop history API 来完全控制 Web 应用程序的历史记录,在 Nginx 中需要配置 try_files 指令
  • 前后端分离后,在 Nginx 中需要配置反向代理解决前端跨域问题
  • ...
server {
    listen 80 default_server;
    server_name _;

    location  / {
      root /usr/share/nginx/html;
      index  index.html ;
      try_files $uri $uri/ /index.html;
    }

    # location  ~ /api/  {
    #   proxy_connect_timeout 2s;
    #   proxy_read_timeout 600s;
    #   proxy_send_timeout 600s;
    #   proxy_pass http://gateway:8080;
    #   proxy_set_header        Host    $host:80;
    #   proxy_set_header        X-Real-IP       $remote_addr;
    #   proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    #   client_max_body_size    1000m;
    # }
}

第三步,定制镜像。在项目的根目录创建 Dockerfile 文件来定制我们的镜像

  1. 使用 FROM 指令指定基础镜像,官方已经给我们准备好了 Nginx 的镜像
  2. 使用 LABEL 指令为构建的镜像设置作者信息
  3. 使用 ADD 指令将 build 文件夹下的所有文件拷贝至 Nginx 的根目录
  4. 使用 ADD 指令添加上一步准备好的 Nginx 配置文件
  5. 使用 EXPOSE 指令声明运行时容器提供的服务端口,暴露 80 端口

第四步,构建镜像。使用 docker build 命令进行镜像构建

$ docker build -t himstone/test .
Sending build context to Docker daemon 118.1 MB
Step 1/5 : FROM nginx:latest
 ---> 3c5a05123222
Step 2/5 : LABEL maintainer "himstone.yang@gmail.com"
 ---> Using cache
 ---> fe13a72edfa9
Step 3/5 : ADD ./build/ /usr/share/nginx/html/
 ---> Using cache
 ---> 7725efecebbe
Step 4/5 : ADD nginx.conf /etc/nginx/
 ---> Using cache
 ---> 402dd5589c05
Step 5/5 : EXPOSE 80
 ---> Using cache
 ---> ba0ce6d40a8f
Successfully built ba0ce6d40a8f

第五步,测试并上传镜像。

使用 docker run 命令启动容器并将本地的 8080 端口 映射到容器的 80 端口

$ docker run -d -p 8080:80 himstone/test 
72162395ba4241201e1b3ca08ed38f4da768051d14b3962bc2a1d77261c4df24

打开浏览器,访问 localhost:8080。出现如下页面表示工作正常,测试通过。

使用 docker push 上传镜像。这里只是演示,直接上传到了 Docker Hub 上,推荐使用 Harbor 搭建私有镜像仓库

$ docker login -u himstone -p yourPassword
Login Succeeded
$ docker push himstone/test
The push refers to a repository [docker.io/himstone/test]
e4d08e577219: Pushed
69c46c39d897: Pushed
08422f31c8c5: Pushed
4d3d2ca78cd4: Pushed
9c46f426bcb7: Pushed
latest: digest: sha256:3136cad04911e71d40afb0f481f56c6ac286ac8afe50b5578efe8e617a0f4e32 size: 1365

使用 Docker 构建 Node.js 前端项目

前端应用中还包括使用 Node.js 开发的后端服务,常用于承担一些Api 中间层、BFF层的角色,甚至是完整的核心服务。

步,创建项目。可选的框架有很多,比如 express,koa 等,在这里拿阿里开源的 Egg.js 做演示,使用 egg-init 初始化项目,再将 package.json 里 scripts-start 里的 --daemon 去掉,在 Docker 内建议前台运行

egg-init egg-example --type=simple
cd egg-example
npm i

第二步,定制镜像。在项目的根目录创建 Dockerfile 文件来定制我们的镜像

  1. 使用 FROM 指令指定基础镜像,这里使用官方提供的 node:8
  2. 使用 LABEL 指令为构建的镜像设置作者信息
  3. 使用 COPY 指令将根目录下的所有文件拷贝至镜像内
  4. 使用 RUN 指令执行 npm install 安装依赖
  5. 使用 EXPOSE 指令声明运行时容器提供的服务端口,暴露 7001 端口
  6. 使用 CMD 指令设置容器启动命令为 npm start

第三步,构建镜像。使用 docker build 命令进行镜像构建

$ docker build -t himstone/test-egg .
Sending build context to Docker daemon 123.5 MB
Step 1/6 : FROM node:8
 ---> c5e9a81034a9
Step 2/6 : LABEL maintainer "himstone.yang@gmail.com"
 ---> Using cache
 ---> f68494fbcd6e
Step 3/6 : COPY . .
 ---> 685e9ad05928
Removing intermediate container 3c0e94e7453e
Step 4/6 : RUN npm install
 ---> Running in 94c5e4d37c64
npm WARN co-mocha@1.2.2 requires a peer of mocha@>=1.18 <6 but none is installed. You must install peer dependencies yourself.

up to date in 6.249s
 ---> 8768307d6ae9
Removing intermediate container 94c5e4d37c64
Step 5/6 : EXPOSE 3000
 ---> Running in b554fc4777ab
 ---> 55d1a6cff311
Removing intermediate container b554fc4777ab
Step 6/6 : CMD npm start
 ---> Running in 31378b658364
 ---> c7fdb400b841
Removing intermediate container 31378b658364
Successfully built c7fdb400b841

第四步,测试并上传镜像

使用 docker run 命令启动容器并将本地的 8080 端口映射到容器的 7001 端口

$ docker run -d -p 8080:7001 himstone/test-egg 
72162395ba4241201e1b3ca08ed38f4da768051d14b3962bc2a1d77261c4df24

打开浏览器,访问 localhost:8080。出现如下的页面表示工作正常,测试通过。


使用 docker push 上传镜像。

$ docker push himstone/test-egg
The push refers to a repository [docker.io/himstone/test-egg]
2c4ef22a1c6b: Pushed
7e45aa7e5ac9: Pushed
d9fdc5af195e: Mounted from himstone/test-ssr
245ce6af2e7b: Mounted from himstone/test-ssr
373fc5310302: Mounted from himstone/test-ssr
25494c62cf78: Mounted from himstone/test-ssr
d714f65bc280: Mounted from himstone/test-ssr
fd6060e25706: Mounted from himstone/test-ssr
d7ed640784f1: Mounted from himstone/test-ssr
1618a71a1198: Mounted from himstone/test-ssr
latest: digest: sha256:ce0a10b07ab2f91904d60f2b35754995c177e7dd8e3d0397e84e2453d79a3384 size: 2426

使用 Docker 构建 SSR 服务端渲染的前端项目

上文有介绍如何使用 Docker 构建普通的Web项目,即使用前端渲染,在遭遇 SEO、首屏性能等问题时,往往会考虑使用服务端渲染技术,两者在构建上的差异主要体现在后者不需要静态资源服务器,直接由 Node.js 直出 HTML。因为和构建 Node.js 前端项目的过程中有许多相似处,这里只做简要介绍,完整的 demo 代码可参考文末的链接。

步,创建项目。这里就拿 Next.js 来演示,参考 官方文档 创建项目

第二步,定制镜像。在项目的根目录创建 Dockerfile 文件来定制我们的镜像

  1. 使用 COPY 指令将根目录下的所有文件拷贝至镜像内
  2. 使用 RUN 指令执行 npm install 安装依赖
  3. 使用 RUN 指令执行 npm run build 打包静态资源
  4. 使用 EXPOSE 指令声明运行时容器提供的服务端口,暴露 3000 端口
  5. 使用 CMD 指令设置容器启动命令为 npm start

第三步,构建镜像。使用 docker build 命令进行镜像构建

第四步,测试并上传镜像。

出现如下的页面表示工作正常。


小结

通过上述的三个例子,演示了如何使用 Docker 构建不同类型的前端应用。Docker 为前端应用提供了一致的运行环境,带来了快速部署、回滚等特性。除此之外,还需要考虑容器化应用的部署,容器的编排、调度等问题,可以使用 Kubernetes 等容器管理平台。

当然 Docker 还可以应用到持续集成中,GitLab CI 为 runner 提供了许多执行器,其中就包括了 Docker Executor。如下图所示,Docker Executor 对比其他拥有许多优势,比如每次构建提供一致的运行环境,零配置支持并发构建,适配复杂的构建环境等。


所有的 demo 源代码已上传至 Github,需要的可以参考

himStone/build-frontend-app-with-dockergithub.com图标

分享好友

分享这个小栈给你的朋友们,一起进步吧。

Docker 专区
创建时间:2020-05-08 10:53:18
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

技术专家

查看更多
  • 小雨滴
    专家
戳我,来吐槽~