天天看點

前端oss上傳接口_前端進階進階:前端和運維之間的羁(ji)絆(qing))

前端一說起刀耕火種,那肯定緊随着前端工程化這一話題。随着

react

/

vue

/

angular

es6+

webpack

babel

typescript

以及

node

的發展,前端已經在逐漸替代過去

script

cdn

開發的方式了,掀起了工程化這一大浪潮。得益于工程化的發展與開源社群的良好生态,前端應用的可用性與效率得到了很大提高。

前端以前是刀耕火種,那前端應用部署在以前也是刀耕火種。那前端應用部署的發展得益于什麼,随前端工程化帶來的副産品?

這隻是一部分,而更重要的原因是

devops

的崛起。

為了更清晰地了解前端部署的發展史,了解部署時運維和前端(或者更廣泛地說,業務開發人員)的職責劃分,當每次前端部署發生改變時,可以思考兩個問題

  1. 緩存,前端應用中 http 的

    response header

    由誰來配?得益于工程化發展,可以對打包後得到帶有 hash 值的檔案可以做永久緩存
  2. 跨域,

    /api

    的代理配置由誰來配?在開發環境前端可以開個小服務,啟用

    webpack-dev-server

    配置跨域,那生産環境呢

這兩個問題都是前端面試時的高頻問題,但話語權是否掌握在前端手裡

時間來到

React

剛剛發展起來的這一年,這時已經使用

React

開發應用,使用

webpack

來打包。但是前端部署,仍是刀耕火種

本篇文章要求你有一定的 Docker,DevOps 以及前端工程化的知識儲備。如果沒有的話,本系列文章以及 個人伺服器運維指南[1] 中的 Docker 部分會對你有所幫助。

刀耕火種

一台跳闆機

一台生産環境伺服器

一份部署腳本

前端調着他的

webpack

,開心地給運維發了部署郵件并附了一份部署腳本,想着第一次不用套後端的模闆,第一次前端可以獨立部署。想着自己基礎盤進一步擴大,前端不禁開心地笑了

運維照着着前端發過來的部署郵件,一遍又一遍地拉着代碼,改着配置,寫着

try_files

, 配着

proxy_pass

這時候,前端靜态檔案由

nginx

托管,

nginx

配置檔案大緻長這個樣子

不過...經常有時候跑不起來

運維抱怨着前端的部署腳本沒有标好

node

版本,前端嚷嚷着測試環境沒問題

這個時候運維需要費很多心力放在部署上,甚至測試環境的部署上,前端也要費很多心力放在運維如何部署上。這個時候由于怕影響線上環境,上線往往選擇在深夜,前端和運維身心俱疲

不過向來如此

魯迅說,向來如此,那便對麼。

這個時候,無論跨域的配置還是緩存的配置,都是運維來管理,運維不懂前端。但配置方式卻是前端在提供,而前端并不熟悉 nginx

使用 docker 建構鏡像

docker

的引進,很大程度地解決了部署腳本跑不了這個大 BUG。

dockerfile

即部署腳本,部署腳本即

dockerfile

。這也很大程度緩解了前端與運維的摩擦,畢竟前端越來越靠譜了,至少部署腳本沒有問題了 (笑

這時候,前端不再提供靜态資源,而是提供服務,一個

http

服務

前端寫的

dockerfile

大緻長這個樣子

FROM node:alpine
           

單單有

dockerfile

也跑不起來,另外前端也開始維護一個

docker-compose.yaml

,交給運維執行指令

docker-compose up -d

啟動前端應用。前端第一次寫

dockerfile

docker-compose.yaml

,在部署流程中扮演的角色越來越重要。想着自己基礎盤進一步擴大,前端又不禁開心地笑了

version: 
           

運維的

nginx

配置檔案大緻長這個樣子

運維除了配置

nginx

之外,還要執行一個指令:

docker-compose up -d

這時候再思考文章最前面兩個問題

  1. 緩存,由于從靜态檔案轉換為服務,緩存開始交由前端控制 (但是鏡像中的

    http-server

    不太适合做這件事情)
  2. 跨域,跨域仍由運維在

    nginx

    中配置

前端可以做他應該做的事情中的一部分了,這是一件令人開心的事情

當然,前端對于

dockerfile

的改進也是一個慢慢演進的過程,那這個時候鏡像有什麼問題呢?

  1. 建構鏡像體積過大
  2. 建構鏡像時間過長

使用多階段建構優化鏡像

這中間其實經曆了不少坎坷,其中過程如何,詳見我的另一篇文章: 如何使用 docker 部署前端應用[2]。

其中主要的優化也是在上述所提到的兩個方面

  1. 建構鏡像體積由 1G+ 變為 10M+
  2. 建構鏡像時間由 5min+ 變為 1min (視項目複雜程度,大部分時間在建構時間與上傳靜态資源時間)
FROM node:alpine as builder
           

那它怎麼做的

  1. ADD package.json /code

    , 再

    npm install --production

    之後

    Add

    所有檔案。充分利用鏡像緩存,減少建構時間
  2. 多階段建構,大大減小鏡像體積

另外還可以有一些小優化,如

  • npm cache

    的基礎鏡像或者

    npm

    私有倉庫,減少

    npm install

    時間,減小建構時間
  • npm install --production

    隻裝必要的包

前端看着自己優化的

dockerfile

,想着前幾天還被運維吵,說什麼磁盤一半的空間都被前端的鏡像給占了,想着自己節省了前端鏡像幾個數量級的體積,為公司好像省了不少伺服器的開銷,想着自己的基礎盤進一步擴大,又不禁開心的笑了

這時候再思考文章最前面兩個問題

  1. 緩存,緩存由前端控制,緩存在 oss 上設定,将會使用 cdn 對 oss 加速。此時緩存由前端寫腳本控制
  2. 跨域,跨域仍由運維在

    nginx

    中配置

CI/CD 與 gitlab

此時前端成就感爆棚,運維呢?運維還在一遍一遍地上線,重複着一遍又一遍的三個動作用來部署

  1. 拉代碼
  2. docker-compose up -d

  3. 重新開機 nginx

運維覺得再也不能這麼下去了,于是他引進了

CI

: 與現有代碼倉庫

gitlab

配套的

gitlab ci

  • CI

    Continuous Integration

    ,持續內建
  • CD

    Continuous Delivery

    ,持續傳遞

重要的不是

CI/CD

是什麼,重要的是現在運維不用跟着業務上線走了,不需要一直盯着前端部署了。這些都是

CI/CD

的事情了,它被用來做自動化部署。上述提到的三件事交給了

CI/CD

.gitlab-ci.yml

gitlab

的 CI 配置檔案,它大概長這個樣子

deploy:
           

CI/CD

不僅僅更解放了業務項目的部署,也在傳遞之前大大加強了業務代碼的品質,它可以用來

lint

test

package

安全檢查,甚至多特性多環境部署,我将會在我以後的文章寫這部分事情

我的一個伺服器渲染項目 shfshanyue/shici[3] 以前在我的伺服器中就是以

docker

/

docker-compose/gitlab-ci

的方式部署,有興趣的可以看看它的配置檔案

  • shfshanyue/shici:Dockerfile[4]
  • shfshanyue/shici:docker-compose.yml[5]
  • shfshanyue/shici:gitlab-ci.yml[6]

如果你有個人伺服器的話,也建議你做一個自己感興趣的前端應用和配套的後端接口服務,并且配套

CI/CD

把它部署在自己的自己伺服器上

而你如果希望結合

github

CI/CD

,那可以試一試

github

+

github action

另外,也可以試試

drone.ci

,如何部署可以參考我以前的文章: github 上持續內建方案 drone 的簡介及部署[7]

使用 kubernetes 部署

随着業務越來越大,鏡像越來越多,

docker-compose

已經不太能應付,

kubernetes

應時而出。這時伺服器也從 1 台變成了多台,多台伺服器就會有分布式問題

一門新技術的出現,在解決以前問題的同時也會引進複雜性。

k8s 部署的好處很明顯: 健康檢查,滾動更新,彈性擴容,快速復原,資源限制,完善的監控等等

那現在遇到的新問題是什麼?

建構鏡像的伺服器,提供容器服務的伺服器,做持續內建的伺服器是一台!

需要一個私有的鏡像倉庫,這是運維的事情,

harbor

很快就被運維搭建好了,但是對于前端部署來說,複雜性又提高了

先來看看以前的流程:

  1. 前端配置

    dockerfile

    docker-compose

  2. 生産環境伺服器的

    CI runner

    拉代碼(可以看做以前的運維),

    docker-compose up -d

    啟動服務。然後再重新開機

    nginx

    ,做反向代理,對外提供服務

以前的流程有一個問題: 建構鏡像的伺服器,提供容器服務的伺服器,做持續內建的伺服器是一台!,是以需要一個私有的鏡像倉庫,一個能夠通路

k8s

叢集的持續內建伺服器

流程改進之後結合

k8s

的流程如下

  1. 前端配置

    dockerfile

    ,建構鏡像,推到鏡像倉庫
  2. 運維為前端應用配置

    k8s

    的資源配置檔案,

    kubectl apply -f

    時會重新拉取鏡像,部署資源

運維問前端,需不需要再擴大下你的基礎盤,寫一寫前端的

k8s

資源配置檔案,并且列了幾篇文章

  • 使用 k8s 部署你的第一個應用: Pod,Deployment 與 Service[8]
  • 使用 k8s 為你的應用配置域名: Ingress[9]
  • 使用 k8s 為你的域名加上 https[10]

前端看了看後端十幾個 k8s 配置檔案之後,搖搖頭說算了算了

這個時候,

gitlab-ci.yaml

差不多長這個樣子,配置檔案的權限由運維一人管理

deploy:
           

這時候再思考文章最前面兩個問題

  1. 緩存,緩存由前端控制
  2. 跨域,跨域仍由運維控制,在後端

    k8s

    資源的配置檔案中控制

    Ingress

使用 helm 部署

這時前端與運維已不太往來,除了偶爾新起項目需要運維幫個忙以外

但好景不長,突然有一天,前端發現自己連個環境變量都沒法傳!于是經常找運維修改配置檔案,運維也不勝其煩

于是有了

helm

,如果用一句話解釋它,那它就是一個帶有模闆功能的

k8s

資源配置檔案。作為前端,你隻需要填參數。更多詳細的内容可以參考我以前的文章 使用 helm 部署 k8s 資源[11]

假如我們使用 bitnami/nginx[12] 作為

helm chart

,前端可能寫的配置檔案長這個樣子

image:
           

這時候再思考文章最前面兩個問題

  1. 緩存,緩存由前端控制
  2. 跨域,跨域由後端控制,配置在後端 Chart 的配置檔案

    values.yaml

到了這時前端和運維的職責所在呢?

前端需要做的事情有:

  1. 寫前端建構的

    dockerfile

    ,這隻是一次性的工作,而且有了參考
  2. 使用

    helm

    部署時指定參數

那運維要做的事情呢

  1. 提供一個供所有前端項目使用的

    helm chart

    ,甚至不用提供,如果運維比較懶那就就使用 bitnami/nginx[13] 吧。也是一次性工作
  2. 提供一個基于

    helm

    的工具,禁止業務過多的權限,甚至不用提供,如果運維比較懶那就直接使用

    helm

這時前端可以關注于自己的業務,運維可以關注于自己的雲原生,職責劃分從未這般清楚

統一前端部署平台

後來運維覺得前端應用的本質是一堆靜态檔案,較為單一,容易統一化,來避免各個前端鏡像品質的參差不齊。于是運維準備了一個統一的

node

基礎鏡像,做了一個前端統一部署平台,而這個平台可以做什麼呢

  1. CI/CD

    : 當你 push 代碼到倉庫的特定分支會自動部署
  2. http headers

    : 你可以定制資源的

    http header

    ,進而可以做緩存優化等
  3. http redirect/rewrite

    : 如果一個

    nginx

    ,這樣可以配置

    /api

    ,解決跨域問題
  4. hostname

    : 你可以設定域名
  5. CDN

    : 把你的靜态資源推到 CDN
  6. https

    : 為你準備證書
  7. Prerender

    : 結合

    SPA

    ,做預渲染

前端再也不需要建構鏡像,上傳 CDN 了,他隻需要寫一份配置檔案就可以了,大緻長這個樣子

build:
           

此時,前端隻需要寫一份配置檔案,就可以配置緩存,配置

proxy

,做應該屬于前端做的一切,而運維也再也不需要操心前端部署的事情了

前端看着自己剛剛寫好的配置檔案,怅然若失的樣子...

不過一般隻有大廠會有這麼完善的前端部署平台,如果你對它有興趣,你可以嘗試下

netlify

,可以參考我的文章: 使用 netlify 部署你的前端應用[14]

服務端渲染與後端部署

大部分前端應用本質上是靜态資源,剩下的少部分就是服務端渲染了,服務端渲染的本質上是一個後端服務,它的部署可以視為後端部署

後端部署的情況更為複雜,比如

  1. 配置服務,後端需要通路敏感資料,但又不能把敏感資料放在代碼倉庫。你可以在

    environment variables

    consul

    或者

    k8s configmap

    中維護
  2. 上下鍊路服務,你需要依賴資料庫,上遊服務
  3. 通路控制,限制 IP,黑白名單
  4. RateLimit
  5. 等等

小結

随着

devops

的發展,前端部署越來越簡單,可控性也越來越高,建議所有人都稍微學習一下

devops

的東西。

參考資料

[1]

個人伺服器運維指南: https://github.com/shfshanyue/blog#%E4%B8%AA%E4%BA%BA%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BF%90%E7%BB%B4%E6%8C%87%E5%8D%97

[2]

如何使用 docker 部署前端應用: https://juejin.im/post/5c83cbaa6fb9a04a0f65fdaa

[3]

shfshanyue/shici: https://github.com/shfshanyue/shici

[4]

shfshanyue/shici:Dockerfile: https://github.com/shfshanyue/shici/blob/master/Dockerfile

[5]

shfshanyue/shici:docker-compose.yml: https://github.com/shfshanyue/shici/blob/master/docker-compose.yml

[6]

shfshanyue/shici:gitlab-ci.yml: https://github.com/shfshanyue/shici/blob/master/.gitlab-ci.yml

[7]

github 上持續內建方案 drone 的簡介及部署: https://juejin.im/post/5dc0b563f265da4cef190b8a

[8]

使用 k8s 部署你的第一個應用: Pod,Deployment 與 Service: https://juejin.im/post/5db8c2b46fb9a020256692dc

[9]

使用 k8s 為你的應用配置域名: Ingress: https://juejin.im/post/5db8da4b6fb9a0204520b310

[10]

使用 k8s 為你的域名加上 https: https://juejin.im/post/5db8d94be51d4529f73e2833

[11]

使用 helm 部署 k8s 資源: https://juejin.im/post/5dbf7909f265da4d4b5fe7b4

[12]

bitnami/nginx: https://hub.helm.sh/charts/bitnami/nginx

[13]

bitnami/nginx: https://hub.helm.sh/charts/bitnami/nginx

[14]

使用 netlify 部署你的前端應用: https://shanyue.tech/op/deploy-fe-with-netlify.html

前端oss上傳接口_前端進階進階:前端和運維之間的羁(ji)絆(qing))
前端oss上傳接口_前端進階進階:前端和運維之間的羁(ji)絆(qing))

在看點這裡

前端oss上傳接口_前端進階進階:前端和運維之間的羁(ji)絆(qing))

繼續閱讀