前端一提及刀耕火种,那确定紧随着前端工程化这一话题。随着 react
/vue
/angular
,es6+
,webpack
,babel
,typescript
以及 node
的发展,前端已经在逐渐替代过去 script
引 cdn
开发的方式了,掀起了工程化这一大浪潮。得益于工程化的发展与开源社区的良好生态,前端应用的可用性与效率获得了很大提升。css
前端之前是刀耕火种,那前端应用部署在之前也是刀耕火种。那前端应用部署的发展得益于什么,随前端工程化带来的副产品?html
这只是一部分,而更重要的缘由是 devops
的崛起。前端
为了更清晰地理解前端部署的发展史,了解部署时运维和前端(或者更普遍地说,业务开发人员)的职责划分,当每次前端部署发生改变时,能够思考两个问题vue
response header
由谁来配?得益于工程化发展,能够对打包后获得带有 hash 值的文件能够作永久缓存/api
的代理配置由谁来配?在开发环境前端能够开个小服务,启用 webpack-dev-server
配置跨域,那生产环境呢这两个问题都是前端面试时的高频问题,但话语权是否掌握在前端手里node
时间来到 React
刚刚发展起来的这一年,这时已经使用 React
开发应用,使用 webpack
来打包。可是前端部署,还是刀耕火种react
若是本篇文章可以对你有所帮助,能够帮我在 shfshanyue/op-note 上点个 starwebpack
若是你是新人的话,目前在阿里云买机器会有优惠,能够点击 连接 购买。你能够跟着个人笔记 服务器运维指南 来开始维护服务器并搭建应用。nginx
一台跳板机git
一台生产环境服务器程序员
一份部署脚本
前端调着他的 webpack
,开心地给运维发了部署邮件并附了一份部署脚本,想着第一次不用套后端的模板,第一次前端能够独立部署。想着本身基础盘进一步扩大,前端不由开心地笑了
运维照着着前端发过来的部署邮件,一遍又一遍地拉着代码,改着配置,写着 try_files
, 配着 proxy_pass
。
这时候,前端静态文件由 nginx
托管,nginx
配置文件大体长这个样子
server { listen 80; server_name shanyue.tech; location / { # 避免非root路径404 try_files $uri $uri/ /index.html; } # 解决跨域 location /api { proxy_pass http://api.shanyue.tech; } # 为带 hash 值的文件配置永久缓存 location ~* \.(?:css|js)$ { try_files $uri =404; expires 1y; add_header Cache-Control "public"; } location ~ ^.+\..+$ { try_files $uri =404; } }
不过...常常有时候跑不起来
运维抱怨着前端的部署脚本没有标好 node
版本,前端嚷嚷着测试环境没问题
这个时候运维须要费不少心力放在部署上,甚至测试环境的部署上,前端也要费不少心力放在运维如何部署上。这个时候因为怕影响线上环境,上线每每选择在深夜,前端和运维身心俱疲
不过向来如此
鲁迅说,向来如此,那便对么。
这个时候,不管跨域的配置仍是缓存的配置,都是运维来管理,运维不懂前端。但配置方式倒是前端在提供,而前端并不熟悉 nginx
docker
的引进,很大程度地解决了部署脚本跑不了这个大BUG。dockerfile
即部署脚本,部署脚本即 dockerfile
。这也很大程度缓解了前端与运维的摩擦,毕竟前端愈来愈靠谱了,至少部署脚本没有问题了 (笑
这时候,前端再也不提供静态资源,而是提供服务,一个 http
服务
前端写的 dockerfile
大体长这个样子
FROM node:alpine # 表明生产环境 ENV PROJECT_ENV production # 许多 package 会根据此环境变量,作出不一样的行为 # 另外,在 webpack 中打包也会根据此环境变量作出优化,可是 create-react-app 在打包时会写死该环境变量 ENV NODE_ENV production WORKDIR /code ADD . /code RUN npm install && npm run build && npm install -g http-server EXPOSE 80 CMD http-server ./public -p 80
单单有 dockerfile
也跑不起来,另外前端也开始维护一个 docker-compose.yaml
,交给运维执行命令 docker-compose up -d
启动前端应用。前端第一次写 dockerfile
与 docker-compose.yaml
,在部署流程中扮演的角色愈来愈重要。想着本身基础盘进一步扩大,前端又不由开心地笑了
version: "3" services: shici: build: . expose: - 80
运维的 nginx
配置文件大体长这个样子
server { listen 80; server_name shanyue.tech; location / { proxy_pass http://static.shanyue.tech; } location /api { proxy_pass http://api.shanyue.tech; } }
运维除了配置 nginx
以外,还要执行一个命令: docker-compose up -d
这时候再思考文章最前面两个问题
http-server
不太适合作这件事情)nginx
中配置前端能够作他应该作的事情中的一部分了,这是一件使人开心的事情
固然,前端对于 dockerfile
的改进也是一个慢慢演进的过程,那这个时候镜像有什么问题呢?
这中间其实经历了很多坎坷,其中过程如何,详见个人另外一篇文章: 如何使用 docker 部署前端应用。
其中主要的优化也是在上述所提到的两个方面
FROM node:alpine as builder ENV PROJECT_ENV production ENV NODE_ENV production WORKDIR /code ADD package.json /code RUN npm install --production ADD . /code # npm run uploadCdn 是把静态资源上传至 oss 上的脚本文件,未来会使用 cdn 对 oss 加速 RUN npm run build && npm run uploadCdn # 选择更小体积的基础镜像 FROM nginx: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
那它怎么作的
ADD package.json /code
, 再 npm install --production
以后 Add
全部文件。充分利用镜像缓存,减小构建时间另外还能够有一些小优化,如
npm cache
的基础镜像或者 npm
私有仓库,减小 npm install
时间,减少构建时间npm install --production
只装必要的包前端看着本身优化的 dockerfile
,想着前几天还被运维吵,说什么磁盘一半的空间都被前端的镜像给占了,想着本身节省了前端镜像几个数量级的体积,为公司好像省了很多服务器的开销,想着本身的基础盘进一步扩大,又不由开心的笑了
这时候再思考文章最前面两个问题
nginx
中配置此时前端成就感爆棚,运维呢?运维还在一遍一遍地上线,重复着一遍又一遍的三个动做用来部署
docker-compose up -d
运维以为不再能这么下去了,因而他引进了 CI
: 与现有代码仓库 gitlab
配套的 gitlab ci
CI
,Continuous Integration
,持续集成CD
,Continuous Delivery
,持续交付重要的不是 CI/CD
是什么,重要的是如今运维不用跟着业务上线走了,不须要一直盯着前端部署了。这些都是 CI/CD
的事情了,它被用来作自动化部署。上述提到的三件事交给了 CI/CD
.gitlab-ci.yml
是 gitlab
的 CI 配置文件,它大概长这个样子
deploy: stage: deploy only: - master script: - docker-compose up --build -d tags: - shell
CI/CD
不只仅更解放了业务项目的部署,也在交付以前大大增强了业务代码的质量,它能够用来 lint
,test
,package
安全检查,甚至多特性多环境部署,我将会在我之后的文章写这部分事情
个人一个服务器渲染项目 shfshanyue/shici 之前在个人服务器中就是以 docker
/docker-compose/gitlab-ci
的方式部署,有兴趣的能够看看它的配置文件
若是你有我的服务器的话,也建议你作一个本身感兴趣的前端应用和配套的后端接口服务,而且配套 CI/CD
把它部署在本身的本身服务器上
若是没有的话,新人能够点击 个人连接 购买
而你若是但愿结合 github
作 CI/CD
,那能够试一试 github
+ github action
另外,也能够试试 drone.ci
,如何部署能够参考我之前的文章: github 上持续集成方案 drone 的简介及部署
随着业务愈来愈大,镜像愈来愈多,docker-compose
已经不太能应付,kubernetes
应时而出。这时服务器也从1台变成了多台,多台服务器就会有分布式问题
一门新技术的出现,在解决之前问题的同时也会引进复杂性。
k8s 部署的好处很明显: 健康检查,滚动升级,弹性扩容,快速回滚,资源限制,完善的监控等等
那如今遇到的新问题是什么?
构建镜像的服务器,提供容器服务的服务器,作持续集成的服务器是一台!
须要一个私有的镜像仓库,这是运维的事情,harbor
很快就被运维搭建好了,可是对于前端部署来讲,复杂性又提升了
先来看看之前的流程:
dockerfile
与 docker-compose
CI runner
拉代码(能够看作之前的运维),docker-compose up -d
启动服务。而后再重启 nginx
,作反向代理,对外提供服务之前的流程有一个问题: 构建镜像的服务器,提供容器服务的服务器,作持续集成的服务器是一台!,因此须要一个私有的镜像仓库,一个可以访问 k8s
集群的持续集成服务器
流程改进以后结合 k8s
的流程以下
dockerfile
,构建镜像,推到镜像仓库k8s
的资源配置文件,kubectl apply -f
时会从新拉取镜像,部署资源运维问前端,需不须要再扩大下你的基础盘,写一写前端的 k8s
资源配置文件,而且列了几篇文章
前端看了看后端十几个 k8s 配置文件以后,摇摇头说算了算了
这个时候,gitlab-ci.yaml
差很少长这个样子,配置文件的权限由运维一人管理
deploy: stage: deploy only: - master script: - docker build -t harbor.shanyue.tech/fe/shanyue - docker push harbor.shanyue.tech/fe/shanyue - kubectl apply -f https://k8s-config.default.svc.cluster.local/shanyue.yaml tags: - shell
这时候再思考文章最前面两个问题
k8s
资源的配置文件中控制 Ingress
这时前端与运维已不太往来,除了偶尔新起项目须要运维帮个忙之外
但好景不长,忽然有一天,前端发现本身连个环境变量都无法传!因而常常找运维修改配置文件,运维也不胜其烦
因而有了 helm
,若是用一句话解释它,那它就是一个带有模板功能的 k8s
资源配置文件。做为前端,你只须要填参数。更多详细的内容能够参考我之前的文章 使用 helm 部署 k8s 资源
假如咱们使用 bitnami/nginx 做为 helm chart
,前端可能写的配置文件长这个样子
image: registry: harbor.shanyue.tech repository: fe/shanyue tag: 8a9ac0 ingress: enabled: true hosts: - name: shanyue.tech path: / tls: - hosts: - shanyue.tech secretName: shanyue-tls # livenessProbe: # httpGet: # path: / # port: http # initialDelaySeconds: 30 # timeoutSeconds: 5 # failureThreshold: 6 # # readinessProbe: # httpGet: # path: / # port: http # initialDelaySeconds: 5 # timeoutSeconds: 3 # periodSeconds: 5
这时候再思考文章最前面两个问题
values.yaml
中到了这时前端和运维的职责所在呢?
前端须要作的事情有:
dockerfile
,这只是一次性的工做,并且有了参考helm
部署时指定参数那运维要作的事情呢
helm chart
,甚至不用提供,若是运维比较懒那就就使用 bitnami/nginx 吧。也是一次性工做helm
的工具,禁止业务过多的权限,甚至不用提供,若是运维比较懒那就直接使用 helm
这时前端能够关注于本身的业务,运维能够关注于本身的云原生,职责划分从未这般清楚
后来运维以为前端应用的本质是一堆静态文件,较为单一,容易统一化,来避免各个前端镜像质量的良莠不齐。因而运维准备了一个统一的 node
基础镜像,作了一个前端统一部署平台,而这个平台能够作什么呢
CI/CD
: 当你 push 代码到仓库的特定分支会自动部署http headers
: 你能够定制资源的 http header
,从而能够作缓存优化等http redirect/rewrite
: 若是一个 nginx
,这样能够配置 /api
,解决跨域问题hostname
: 你能够设置域名CDN
: 把你的静态资源推到 CDNhttps
: 为你准备证书Prerender
: 结合 SPA
,作预渲染前端不再须要构建镜像,上传 CDN 了,他只须要写一份配置文件就能够了,大体长这个样子
build: command: npm run build dist: /dist hosts: - name: shanyue.tech path: / headers: - location: /* values: - cache-control: max-age=7200 - location: assets/* values: - cache-control: max-age=31536000 redirects: - from : /api to: https://api.shanyue.tech status: 200
此时,前端只须要写一份配置文件,就能够配置缓存,配置 proxy
,作应该属于前端作的一切,而运维也不再须要操心前端部署的事情了
前端看着本身刚刚写好的配置文件,怅然若失的样子...
不过通常只有大厂会有这么完善的前端部署平台,若是你对它有兴趣,你能够尝试下 netlify
,能够参考个人文章: 使用 netlify 部署你的前端应用
大部分前端应用本质上是静态资源,剩下的少部分就是服务端渲染了,服务端渲染的本质上是一个后端服务,它的部署能够视为后端部署
后端部署的状况更为复杂,好比
environment variables
, consul
或者 k8s configmap
中维护我将在之后的文章分享如何在 k8s 中部署一个后端
随着 devops
的发展,前端部署愈来愈简单,可控性也愈来愈高,建议全部人都稍微学习一下 devops
的东西。
道阻且长,行则将至。
我是山月,一个喜欢跑步与登山的程序员,我会按期分享全栈文章在我的公众号中。若是你对全栈面试,前端工程化,graphql,devops,我的服务器运维以及微服务感兴趣的话,能够关注我
本文由博客一文多发平台 OpenWrite 发布!