天天看點

前端oss上傳接口_前端部署發展史

前端oss上傳接口_前端部署發展史

前端一說起刀耕火種,那肯定緊随着前端工程化這一話題。随着 React/Vue/Angular,ES6+,Webpack,Babel,TypeScript 以及 Node.js 的發展,前端已經在逐漸替代過去 Script 引 CDN 開發的方式了,掀起了工程化這一大浪潮。得益于工程化的發展與開源社群的良好生态,前端應用的可用性與效率得到了很大提高。前端以前是刀耕火種,那前端應用部署在以前也是刀耕火種。那前端應用部署的發展得益于什麼,随前端工程化帶來的副産品?這隻是一部分,而更重要的原因是 DevOps 的崛起。為了更清晰地了解前端部署的發展史,了解部署時運維和前端(或者更廣泛地說,業務開發人員)的職責劃分,當每次前端部署發生改變時,可以思考兩個問題:

  1. 緩存,前端應用中 http 的 response header 由誰來配?得益于工程化發展,可以對打包後得到帶有 hash 值的檔案可以做永久緩存。
  2. 跨域,/api 的代理配置由誰來配?在開發環境前端可以開個小服務,啟用 webpack-dev-server 配置跨域,那生産環境呢?

這兩個問題都是前端面試時的高頻問題,但話語權是否掌握在前端手裡。時間來到 React 剛剛發展起來的這一年,這時已經使用 React 開發應用,使用 Webpack 來打包。但是前端部署,仍是刀耕火種。刀耕火種

前端oss上傳接口_前端部署發展史
  • 一台跳闆機
  • 一台生産環境伺服器
  • 一份部署腳本

前端調着他的 Webpack,開心地給運維發了部署郵件并附了一份部署腳本,想着第一次不用套後端的模闆,第一次前端可以獨立部署。想着自己基礎盤進一步擴大,前端不禁開心地笑了。運維照着着前端發過來的部署郵件,一遍又一遍地拉着代碼,改着配置,寫着 tryfiles, 配着 proxypass。這時候,前端靜态檔案由 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 建構鏡像

前端oss上傳接口_前端部署發展史

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。這時候再思考文章最前面兩個問題:

  1. 緩存,由于從靜态檔案轉換為服務,緩存開始交由前端控制(但是鏡像中的 http-server 不太适合做這件事情)
  2. 跨域,跨域仍由運維在 Nginx 中配置

前端可以做他應該做的事情中的一部分了,這是一件令人開心的事情。當然,前端對于 Dockerfile 的改進也是一個慢慢演進的過程,那這個時候鏡像有什麼問題呢?

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

使用多階段建構優化鏡像

前端oss上傳接口_前端部署發展史

這中間其實經曆了不少坎坷,其中過程如何,詳見我的另一篇文章:《如何使用 Docker 部署前端應用》。其中主要的優化也是在上述所提到的兩個方面:

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

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,想着前幾天還被運維吵,說什麼磁盤一半的空間都被前端的鏡像給占了,想着自己節省了前端鏡像幾個數量級的體積,為公司好像省了不少伺服器的開銷,想着自己的基礎盤進一步擴大,又不禁開心的笑了。這時候再思考文章最前面兩個問題:

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

CI/CD 與 GitLab

前端oss上傳接口_前端部署發展史

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

  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:

stage: deploy

only:

- master

script:

- docker-compose up --build -d

tags:

- shell

CI/CD 不僅僅更解放了業務項目的部署,也在傳遞之前大大加強了業務代碼的品質,它可以用來 lint,test,package 安全檢查,甚至多特性多環境部署,我将會在我以後的文章寫這部分事情。我的一個伺服器渲染項目 https://github.com/shfshanyue/shici 以前在我的伺服器中就是以 docker/docker-compose/gitlab-ci 的方式部署,有興趣的可以看看它的配置檔案:

  • https://github.com/shfshanyue/shici/blob/master/Dockerfile
  • https://github.com/shfshanyue/shici/blob/master/docker-compose.yml
  • https://github.com/shfshanyue/shici/blob/master/.gitlab-ci.yml

如果你有個人伺服器的話,也建議你做一個自己感興趣的前端應用和配套的後端接口服務,并且配套 CI/CD 把它部署在自己的自己伺服器上。 而你如果希望結合 GitHub 做 CI/CD,那可以試一試 GitHub + GitHub Action。使用 Kubernetes 部署

前端oss上傳接口_前端部署發展史

随着業務越來越大,鏡像越來越多,docker-compose 已經不太能應付,Kubernetes 應時而出。這時伺服器也從 1 台變成了多台,多台伺服器就會有分布式問題。一門新技術的出現,在解決以前問題的同時也會引進複雜性。Kubernetes 部署的好處很明顯:健康檢查,滾動更新,彈性擴容,快速復原,資源限制,完善的監控等等。那現在遇到的新問題是什麼?建構鏡像的伺服器,提供容器服務的伺服器,做持續內建的伺服器是一台!需要一個私有的鏡像倉庫,這是運維的事情,Harbor 很快就被運維搭建好了,但是對于前端部署來說,複雜性又提高了。先來看看以前的流程:

  1. 前端配置 Dockerfile 與 docker-compose
  2. 生産環境伺服器的 CI runner 拉代碼(可以看做以前的運維),docker-compose up -d 啟動服務。然後再重新開機 Nginx,做反向代理,對外提供服務

以前的流程有一個問題:建構鏡像的伺服器,提供容器服務的伺服器,做持續內建的伺服器是一台!是以需要一個私有的鏡像倉庫,一個能夠通路 Kubernetes 叢集的持續內建伺服器。流程改進之後結合 Kubernetes 的流程如下:

  1. 前端配置 Dockerfile,建構鏡像,推到鏡像倉庫
  2. 運維為前端應用配置 Kubernetes 的資源配置檔案,kubectl apply -f 時會重新拉取鏡像,部署資源

前端看了看後端十幾個 Kubernetes 配置檔案之後,搖搖頭說算了算了。這個時候,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

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

  1. 緩存,緩存由前端控制
  2. 跨域,跨域仍由運維控制,在後端 Kubernetes 資源的配置檔案中控制 Ingress

使用 Helm 部署

前端oss上傳接口_前端部署發展史

這時前端與運維已不太往來,除了偶爾新起項目需要運維幫個忙以外。但好景不長,突然有一天,前端發現自己連個環境變量都沒法傳!于是經常找運維修改配置檔案,運維也不勝其煩。于是有了 Helm,如果用一句話解釋它,那它就是一個帶有模闆功能的 Kubernetes 資源配置檔案。作為前端,你隻需要填參數。假如我們使用 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

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

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

到了這時前端和運維的職責所在呢?前端需要做的事情有:

  1. 寫前端建構的 Dockerfile,這隻是一次性的工作,而且有了參考
  2. 使用 Helm 部署時指定參數

那運維要做的事情呢?

  1. 提供一個供所有前端項目使用的 helm chart,甚至不用提供,如果運維比較懶那就就使用 Bitnami/Nginx 吧。也是一次性工作
  2. 提供一個基于 Helm 的工具,禁止業務過多的權限,甚至不用提供,如果運維比較懶那就直接使用 Helm

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

前端oss上傳接口_前端部署發展史

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

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。大部分前端應用本質上是靜态資源,剩下的少部分就是服務端渲染了,服務端渲染的本質上是一個後端服務,它的部署可以視為後端部署。後端部署的情況更為複雜,比如:

  1. 配置服務,後端需要通路敏感資料,但又不能把敏感資料放在代碼倉庫。你可以在 Environment variables, Consul 或者 Kubernetes ConfigMap 中維護
  2. 上下鍊路服務,你需要依賴資料庫,上遊服務
  3. 通路控制,限制 IP,黑白名單
  4. RateLimit
  5. 等等

我将在以後的文章分享如何在 Kubernetes 中部署一個後端。小結

前端oss上傳接口_前端部署發展史

随着 DevOps 的發展,前端部署越來越簡單,可控性也越來越高,建議所有人都稍微學習一下 DevOps 的東西。道阻且長,行則将至。文章來源:山月行,點選檢視原文。基于Kubernetes的DevOps實戰教育訓練

前端oss上傳接口_前端部署發展史

基于Kubernetes的DevOps實戰教育訓練将于2019年12月27日在上海開課,3天時間帶你系統掌握Kubernetes,學習效果不好可以繼續學習。本次教育訓練包括:容器特性、鏡像、網絡;Kubernetes架構、核心元件、基本功能;Kubernetes設計理念、架構設計、基本功能、常用對象、設計原則;Kubernetes的資料庫、運作時、網絡、插件已經落地經驗;微服務架構、元件、監控方案等,點選下方圖檔或者閱讀原文連結檢視詳情。

前端oss上傳接口_前端部署發展史

繼續閱讀