SegmentFault 基於 Kubernetes 的容器化與持續交付實踐

本文是根據 KubeSphere 雲原生 Meetup 杭州站講師祁寧分享內容整理而成。php

SegmentFault 是一家綜合性技術社區,因爲它的內容跟編程技術緊密相關,所以訪問量的波動也和這一羣體的做息時間深度綁定。一般狀況下 web 頁面的請求量峯值在 800 QPS 左右,但咱們還作了先後端分離,因此 API 網關的峯值 QPS 是請求量峯值的好幾倍。node

架構歷史

SegmentFault 做爲一個技術社區的系統架構變化,裏面有些東西仍是頗有意思的。react

  • 2012 年當時我還在北京的一家公司打工,當我在出租屋裏寫下它的第一行代碼時,我不會想象到它到後面會成爲個人事業。當時個人想法很簡單,就是想幫助中文開發者用母語在像 StackOverflow 這樣的網站上提問,所以它的第一個版本很是簡陋,考慮到它的訪問量不多以及本身的經濟能力不足,我將它放在了國外的 VPS 託管商 Linode 上,全部的應用、數據庫、緩存都擠在一個實例上。
  • 2013-2014 年,單獨出來創業,業務逐漸步入正軌。咱們選擇了本身購買服務器去機房託管,固然服務器也是從淘寶上購買的二手服務器,常常遇到問題,咱們團隊在外地又去不了機房,只能等管理員去機房幫咱們解決。正好在2014年咱們的網站被 DDos 攻擊了,機房爲了避免連累其餘服務器,直接把把咱們的網線拔掉了。
  • 2014-2019 年,中國的雲計算也開始起步了,因而咱們把整個網站從物理服務器遷移到了雲服務上。固然使用上並無什麼不一樣,只是把物理機器替換成了虛擬主機。
  • 2020 年至今,隨着雲原生理念的興起,咱們的業務模式也發生了很大變化,爲了讓系統架構適應這些變化,咱們把網站的主要業務都遷移到了 KubeSphere 上。

遇到的挑戰

緊接着,咱們遇到了很多挑戰,促使使咱們不得不往 K8s 架構上遷移。web

  • 首先,雖然咱們是一家小公司,可是業務線卻很是複雜,整個公司只有 30 人左右,技術人員只佔其中三分之一左右,因此承載這麼大的業務量負擔仍是很重的。並且創業公司的業務線調整很是頻繁,臨時性工做也比較多,傳統的系統架構在應對這種伸縮性要求比較高的場景是比較吃力的。數據庫

  • 其次,複雜的場景引起了複雜的配置管理,不一樣的業務要用到不一樣的服務,不一樣的版本,即便用自動化腳本效率也不高。編程

  • 另外,咱們內部人員不足,因此沒有專職運維,如今 OPS 的工做是由後端開發人員輪值的。但後端開發人員還有本身本職工做要作,因此對咱們最理想的場景是能把運維工做所有自動化。segmentfault

  • 最後也是最重要的一點就是咱們要控制成本,這是高情商的說法,低情商就是一個字「窮」(笑)。固然,若是資金充足,以上的問題都不是問題,可是對於創業公司(特別是像咱們這種訪問量比較大,可是又不像電商,金融那些掙錢的公司)來講,咱們必將處於且長期處於這個階段。所以可否控制好成本,是一個很是重要的問題。後端

先後端分離

2020 年之前,SegmentFault 的網站仍是很是傳統的後端渲染頁面的方法,因此服務端的架構也很是簡單。服務端將瀏覽器的 http 請求轉發到後端的 php 服務,php 服務渲染好頁面後再返回給瀏覽器。這種架構用原有的部署方法還能支撐,也就是在各個實例上部署 php 服務,再加一層負載均衡就基本知足需求了。瀏覽器

然而隨着業務的持續發展,後端渲染的方式已經不適合咱們的項目規模了,所以咱們在 2020 年作了架構調整,準備將先後端分離。先後端分離的技術特色我在這裏就不贅述了,這裏主要講它給咱們帶來了哪些系統架構上的挑戰。一個是入口增多,由於先後端分離不只涉及到客戶端渲染(CSR),還涉及到服務端渲染(SSR),因此響應請求的服務就從單一的服務變成了兩類服務,一類是基於 node.js 的 react server 服務(用來作服務端渲染),另外一類是 基於 php 寫的 API 服務(用來給客戶端渲染提供數據)。而服務端渲染自己還要調用 API,而咱們爲了優化服務端渲染的鏈接和請求響應速度,還專門啓用了了使用專有通信協議的內部 API 服務。緩存

因此實際上咱們的 WEB SERVER 有三類服務,每種服務的環境各不相同,所需的資源不一樣,協議不一樣,各自之間可能還有相互鏈接的關係,還須要負載均衡來保障高可用。在快速迭代的開發節奏下,使用傳統的系統架構很難再去適應這樣的結構。

咱們迫切須要一種可以快速應用的,方便部署各類異構服務的成熟解決方案。

Kubernetes 帶來了什麼?

開箱即用

首先是開箱即用,理論上來講這應該是 KubeSphere 的優勢,咱們直接點一點鼠標就能夠打造一個高可用的 K8s 集羣。這一點對咱們這種沒有專職運維的中小團隊來講很重要。根據個人親身經歷,要從零開始搭建一個高可用的 K8s 集羣仍是有點門檻的,沒有接觸過這方面的運維人員,一時半會是搞不定的,其中的坑也很是多。

若是雲廠商能提供這種服務是最好的,咱們不用在服務搭建與系統優化上花費太多時間,能夠把更多的精力放到業務上去。以前咱們還本身搭建數據庫,緩存,搜索集羣,後來所有都使用雲服務了。這也讓咱們的觀念有了轉變,雲時代的基礎服務,應該把它視爲基礎設施的一部分加以利用。

用代碼管理部署

若是能把運維工做所有用代碼來管理,那就再理想不過了。而目前 K8s 確實給咱們提供了這樣一個能力,如今咱們每一個項目都有一個 Docker 目錄,裏面放置了不一樣環境下的 Dockerfile,K8s 配置文件等等。不一樣的項目,不一樣的環境,不一樣的部署,一切均可以在代碼中描述出來加以管理。

好比咱們以前提到的一樣的 API 服務,使用兩種協議,變成了兩個服務。在這如今的架構下,就能夠實現後端代碼一次書寫,分開部署。其實這些文件就代替了不少部署操做,咱們須要作的只是定義好之後執行命令把它們推送到集羣。

而一旦將這些運維工做代碼化之後,咱們就能夠利用現有的代碼管理工具,像寫代碼同樣來調整線上服務。更關鍵的一點是,代碼化以後無形中又增長了版本管理功能,這離咱們理想中的全自動化運維又更近了一步。

持續集成,快速迭代

持續集成標準化了代碼發佈流程,若是能將持續集成和 K8s 的部署能力結合起來,無疑能大大加快項目迭代速度。而在使用 K8s 以前咱們就一直用 GitLab 做爲版本管理工具,它的持續集成功能對咱們來講也比較適用。在作了一些腳本改造以後,咱們發現它也能很好地服務於現有的 K8s 架構,因此也沒有使用 K8s 上諸如 Jenkins 這樣的服務來作持續集成。

步驟其實也很簡單,作好安全配置就沒什麼問題。咱們本地跑完單元測試以後,會自動上線到本地的測試環境。在代碼合併到上線分支後,由管理員點擊確認進行上線步驟。而後在本地 build 一個鏡像推送到鏡像服務器,通知 K8s 集羣去拉取這個鏡像執行上線,最後執行一個腳原本檢查上線結果。整個流程都是可視化可追蹤的,並且在代碼管理界面就能夠完成,方便開發者查看上線進度。

總結經驗

管理好基礎鏡像

目前咱們用一個專門的倉庫來管理這些基礎鏡像,這可使開發人員擁有與線上一致的開發環境,並且後續的版本升級也能夠在基礎鏡像中統一完成。

除了將 Dockerfile 文件統一管理之外,咱們還將鏡像 build 服務與持續集成結合起來。每一個 Dockerfile 文件都有一個所屬的 VERSION 文件,每次修改裏面的版本號並提交,系統都會自動 build 一個相應的鏡像並推送到倉庫。基礎鏡像的管理工做徹底自動化了,大大減小了人爲操做帶來的錯誤與混亂。

KubeSphere 使用

  1. 別把日誌服務放到集羣裏。這一點在 KubeSphere 文檔中就有說起。具體到日誌服務,主要就是一個 Elastic 搜索服務,自建一個Elastic 集羣便可。由於日誌服務自己負載比較大,並且對硬盤的持續性需求高,若是你會發現日誌服務自己就佔據了集羣裏至關大的資源,就得不償失了。
  2. 若是生產環境要保證高可用,仍是要部署 3 個或以上的節點。從咱們使用的經驗來看,主節點偶爾會出現問題。特別是遇到節點機器要維護或者升級的時候,多個主節點能夠保證業務的正常運行。
  3. 若是你自己不是專門提供數據庫或緩存的服務商,這類高可用服務就不要上K8s,由於要保證這類服務高可用自己就要耗費你大量的精力。我建議仍是儘可能用雲廠商的服務。
  4. 副本的規模和集羣的規模要匹配。若是你的容器只有幾個節點,但一個服務裏面擴展了上百個副本,系統的調度會過於頻繁從而把資源耗盡。因此這二者要相匹配,在系統設計的時候就要考慮到。

最後是一點感想:當作完容器化後,會發現應用在集羣裏運行的時候並不須要佔用那麼多臺服務器。這是由於下降了資源的粒度,因此能夠作更多的精細化規劃,所以使用效率也提升了。

本文由博客一文多發平臺 OpenWrite 發佈!

相關文章
相關標籤/搜索