我在 github 上新建了一個倉庫 每日一題,天天一道面試題,歡迎交流。javascript
前端一提及刀耕火種,那確定緊隨着前端工程化這一話題。隨着 react
/vue
/angular
,es6+
,webpack
,babel
,typescript
以及 node
的發展,前端已經在逐漸替代過去 script
引 cdn
開發的方式了,掀起了工程化這一大浪潮。得益於工程化的發展與開源社區的良好生態,前端應用的可用性與效率獲得了很大提升。css
前端之前是刀耕火種,那前端應用部署在之前也是刀耕火種。那前端應用部署的發展得益於什麼,隨前端工程化帶來的副產品?html
這只是一部分,而更重要的緣由是 devops
的崛起。前端
爲了更清晰地理解前端部署的發展史,瞭解部署時運維和前端(或者更普遍地說,業務開發人員)的職責劃分,當每次前端部署發生改變時,能夠思考兩個問題vue
response header
由誰來配?得益於工程化發展,能夠對打包後獲得帶有 hash 值的文件能夠作永久緩存/api
的代理配置由誰來配?在開發環境前端能夠開個小服務,啓用 webpack-dev-server
配置跨域,那生產環境呢這兩個問題都是前端面試時的高頻問題,但話語權是否掌握在前端手裏java
時間來到 React
剛剛發展起來的這一年,這時已經使用 React
開發應用,使用 webpack
來打包。可是前端部署,還是刀耕火種node
本篇文章要求你有必定的 Docker,DevOps 以及前端工程化的知識儲備。若是沒有的話,本系列文章以及 我的服務器運維指南 中的 Docker 部分會對你有所幫助。react
一臺跳板機webpack
一臺生產環境服務器nginx
一份部署腳本
前端調着他的 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
的東西。
道阻且長,行則將至。
掃碼添加個人機器人微信,將會自動(自動拉人程序正在研發中)把你拉入前端高級進階學習羣
推薦一個關於大廠招聘的公衆號【互聯網大廠招聘】,做者將在公衆號裏持續推送各個大廠的招聘職位及要求,並與大廠面試官以及招聘負責人直通,感興趣的能夠直接與負責人交流。
另外,做者也將持續推送優質的大廠面試經驗,各類大廠獨家面試題以及優秀文章分享,不限於前端,後端,運維和系統設計。
我在 github 上新建了一個倉庫 每日一題,天天一道面試題,歡迎交流。