Insta360容器化&DevOps之路

作為一個全景/VR創業公司,隨著公司人員增加以及全球化方向轉變,刀耕火種的CI/CD方式已經不能滿足當前的需求。綜合考慮當前的人員狀況與技術架構的拓展性後,我們採用一套以阿里云為基礎,Docker為核心,第三方服務為工具的開發、測試、部署流程,以及內部的代碼提交,版本管理規範。

一,作者

蘇依

高級前端工程師兼Web組技術負責人,專職前端技術選型與架構設計。

就職於Insta360(全球360°全景相機(VR相機)全景領跑品牌,深圳嵐鋒創視網路科技有限公司)

二,背景

我司是一家集硬體研發與軟體開發為一體的互聯網創業公司。2016被稱為全景/VR元年,預示了機遇到來的同時,也註定了我們將會面臨一些列前所未有的問題,其中坑點無數,但不在本文討論範圍呢,廢話不多說,我們直奔主題。

我司目前對用戶開放的業務為主要包含以下三塊:

  1. 視頻圖片分享(2C)
  2. 全景 / VR直播(2B)
  3. 新聞媒體合作(2B)

其中視頻圖像分享針對C端用戶,用戶遍布全球,要求各地用戶都能夠方便快速分享,同時也要求較好的瀏覽體驗,由於點對點分享的特性,該部分流量正常情況不會太大;但是新聞媒體又扮演了特殊角色,例如11月25日,由於鳳凰網首頁嵌入我司分享頁,從8:00至9:30期間,持續一小時多的(n)Gbps流量&以及每秒(n)K請求數幾乎扮演了DDOS身份,瞬間拖垮後端統計伺服器,導致普通用戶完全無法訪問。同理,全景 / VR直播目前雖然為測試功能,但仍存在潛在風險。故而要求我司能夠建立快速的相應機制,以及可用預備方案。

三,挑戰

面臨的挑戰簡單羅列如下:

  • 集群化部署
  • 差異化部署
  • 全球化部署
  • 環境差異大
  • 資源利用率低
  • 項目數量&語言增加

具體到各個內容本身,首先我們需要前端伺服器在各個region集群化部署,分攤訪問壓力,同時集群內在某些情況下需要同時提供線上測試環境(不同於常規的測試環境,是完全等同於正式環境的測試版),從而需要差異化部署能力支持。

其次,由於我司全球化戰略,業務不光要考慮國內用戶,同時也要為海外用戶提供一致的體驗,故而要求全球化部署。

環境差異大,是指採用前後端分離的方式進行開發後,前端及Web服務包含redis+nodejs環境,後端同時存在php+java+python+c等,傳統方式部署已經無法滿足快速響應的需求,採用ansible雖然能夠滿足需求,但配置繁瑣,故而也被放棄。

同時,考慮業務的拓展性,單機部署上述各種環境時,需要預留一定資源作儲備,突發情況;即使採用鏡像的方式對當前環境進行打包,在遇到突發情況時,還原依然需要較長時間,響應速度太慢;綜合前幾點考慮,採用了保證穩定性與可用性,降低資源利用率低的方式。

最後不得不說的是,從最初的幾個項目到如今的幾十個項目(日常更新10~20),如果繼續按照以往的方式,則只能專人專職負責部署業務。對於一家創業公司來說,將更多的精力用於開發新功能與為用戶提供更優體驗,顯然更為重要。綜上所述,所有問題都要求我們轉變原始的CI/CD方式,採用一種更加輕量,更加簡單的方案勢在必行

四,方案

  • ssh/fabric
  • ansible
  • docker

ssh/fabric是我最初嘗試的方案,但是需要進行一些列的開發,基本在實驗階段就被放棄;ansible固然強大,但是也依然不利用上述挑戰的解決,主要問題如下:

  1. 配置繁瑣
  2. 擴展性差(相對而言)
  3. 可靠性差(使用ssh方式,受網路影響大)

而Docker也就是在此時成為可選方案之一,其優勢不言而喻:

  1. 靈活 將應用於系統容器化,不需要額外依賴
  2. 便捷 任意linux發行版配置docker engine即可啟動
  3. 開源&免費 開源/免費低成本,linux內核驅動
  4. 輕量 僅需添加或減小鏡像即可,在一台伺服器上可以布署多個容器
  5. 環境一致性 鏡像本身即包含運行環境,避免由於環境不一致帶來的各種異常與風險

五,架構/容器化

第一代架構

  • ssh
  • fabric/ansible

刀耕火種的ssh方案與docker實驗階段,目前已經全面棄用。

第二代架構

  1. 使用阿里雲VPC,內部使用ansible管理伺服器
  2. 通過ansible運行docker命令進行容器進行部署
  3. 後端服務&rabbitmq,依然使用傳統方式部署

第三代架構

第三代架構仍處於完善階段,上圖簡單描述了我司三個region服務於應用的分布:

  • 杭州/美西
    • 前端服務
    • 數據存儲
    • 鏡像倉庫
    • 圖像處理/視頻轉碼 worker
    • 配置服務 redis slave
      • 服務ip地址
      • 服務域名信息
      • 服務配置信息
  • 香港
    • 數據中心(資料庫)
    • 中間件(第三方服務)
    • 統計系統
    • 消息隊列
    • 配置服務 redis master

前端服務

其中前端服務為主要為瀏覽服務,由cdn + slb + (nodejs+redis) 組成:

用戶訪問域名後通過dns-load-balancer進行第一次負載,解析到cdn的不同cname,cdn判斷請求類型:

  1. 資源 mp4/mp3/jpg/png返回客戶端
  2. 請求轉發到slb,slb通過加權輪訓方式進行二次負載
  3. 請求到達前端伺服器(nodejs),通過內部redis集區獲取數據
  4. 數據存在則返回,不存在則請求數據中心並緩存,再返回客戶端
  5. 作為cdn源站,通過nginx/haproxy反向代理oss,走阿里雲內網對外提供媒體資源

數據存儲

我司業務目前分為兩類:

  • oss 使用aliyun oss存儲服務,存儲媒體資源如視頻與圖片
  • volume,使用阿里雲ossfs搭建的docker volume,存放持久化數據

圖像處理

視頻處理目前使用了阿里雲mts轉碼服務做普通視頻視頻轉碼,同時,由於行業特殊性,需要對全景視頻和圖像進行一些列處理,由python+celery+c配置的worker處理,該部分內容由香港數據中心的rabbitmq進行統一管理,消息到達rabbitmq後自動進行分發,由空閑的worker處理並通過mq返回結果(之前也有嘗試過http方式進行返回,但由於網路環境較為惡劣,可能出現http請求無法達到,自行處理錯誤邏輯較為麻煩,因而使用mq,設置一定過期時間,如果無法獲取結果,則重新發送任務),當前架構的優化版本mq已經由kafka代替。

kafka在內存佔用上,大大超出rabbitmq,單機部署rabbitmq,當queue數量達到1w左右則開始出現無法繼續處理的情況,同配置機器安裝kafka,測試期間100w左右任務,內存狀況依然完好。

配置服務

配置服務其實是簡單的redis主從,主要功能是維護一些配置信息,如服務的ip地址(實測結果中,海外各類運營商dns解析有嚴重問題,故而放棄域名使用ip);服務的配置信息,如服務名稱,前端服務請求數據結果變更等;使用redis的原因也是一樣,能夠自我維護狀態的,盡量放棄人工干預,因為該部分佔用資源較小,master做持久化,slave直接運行即可,使用alpine鏡像,僅僅10m左右。

數據中心

該部分的數據為資料庫存儲的數據:

  1. Aliyun RDS (以後業務量增加後可以考慮過渡到DRDS)
  2. Aliyun Mongodb

任務隊列/消息隊列

  • rabbitmq
  • zookeeper 集群
  • kafka (目前單機,存儲使用ossfs)

六,規範/流程

開發

項目結構:

  • Dockerfile
  • src放置項目代碼
  • root存放docker配置信息,覆蓋容器內部系統配置

代碼提交

  • 分支/branch
    • dev 開發分支,構建開發鏡像(本地構建測試)
    • test 測試分支,用於構建線上測試鏡像
    • master 主分支,構建latest鏡像
  • 版本/tag
    • 規則:release-v{version}.{month}.{date}.{order}
    • 示例:release-v5.12.05.02

這裡的版本參考了阿里雲鏡像服務的自動構建規則。

構建

構建服務目前我們有總體包含三套:

  • Aliyun 鏡像服務,自動構建,用於正式環境的鏡像發布
  • CircleCi,自動構建與測試,用於github項目的自動構建
  • DroneCI,用於內部構建,主要用於內網的自動構建與測試

構建成功後使用webhook推送到Bearychat通知Web組成員:

hook介面處理會返回:

  • 時間
  • 名稱
  • 版本
  • 命名空間
  • 鏡像全名

測試

Hook服務收到信息後,根據tag判斷應該發送到Bearychat的何種分組:

測試組成員收到提示後,與開發確認測試要點後,可登錄內部測試平台(使用rancher搭建),選擇對應的應用測試,並反饋結果給產品&項目經理,通過則驗收完成。

部署

開發打Tag並推送到阿里雲鏡像服務,鏡像構建完成後Hook系統根據Tag調用Api進行自動部署(阿里雲服務目前未使用api,為控制風險,仍然採用人工更新的方式)

七,思考

1.如何進一步完善工作流?

完善更多自動化服務,進一步減少人工交流成本如:開發提交後,自動獲取git commit信息,並發送到測試組。

2.其他

QA

Q:請問為什麼不直接使用阿里雲提供的容器服務?

這個原因也是因為全球化目標,當時阿里雲的服務還不夠完善,美西和香港還沒有節點;香港至今仍然沒有,所以我們香港數據中心是使用rancher自行搭建的。

Q: 有用jenkins 嗎

沒有,我司nodejs和python是重度服務,我們在github上做了一些基礎的鏡像包,項目內直接引用就好

Q:請問生產環境使用docker部署的話。在性能方面有什麼要注意的么?業界很多人都對docker的網路比較詬病

這個問題要好好回答一下(因為最近剛被坑過..)

  1. 網路部分,overlay 我們放棄了,其中一個很重要的原因是無法獲取真實ip,同時也發現在達到一定數量級的時候,訪問速度變慢,具體的測試結果後面會發出來。
  2. 性能,目前發現的,是rabbitmq性能比較差;我司nodejs比較重,nodejs在前端服務上的性能還是值得信賴的,剛才的例子里說過鳳凰的事情,後端完全掛起,前端因為redis的存在,完全沒有出現異常。

Q: Docker swarm 呢

swarm目前只在內部網路進行測試,還沒正式大規模部署,比如無法獲取ip的問題,就直接被pass了

Q: 請問您對於容器日誌和業務日誌是如何收集的?採用什麼方案?

日誌我們目前有主要有兩種:第一種是阿里雲容器服務的日誌,是通過api導出,然後在私有的elk上進行分析;另外一部分是容器的日誌,這裡我們是用了kafka,elk進一步從kafka獲取日誌,然後處理並返回統計系統

Q: Grunt 構建是打入鏡像 還是在容器啟動時運行

完全沒有用到,nodejs項目是基於webpack進行打包的,在項目發布的時候會進行一次編譯,然後node_modules+static_res一起放在鏡像內

Q: 不使用overlay的話。用路由規則么?還是?

我們雲服務以阿里雲和aws為主,其中阿里雲伺服器使用slb進行負載,這裡要說的是,我們是通過給應用本身加上數字標籤,例如a服務是80,則使用8080表示其使用80埠;b是81,8180同理

Q:看到分享的同事在用rancher做測試環境,如果可能的話,可以分享下使用心得嗎?

稍後我會分享出來,有問題我們可以後續交流

Q: nginx和kafka在線上都採用了容器模式嗎?性能如何?謝謝

kafka是完全使用容器來部署的,剛才有提到過,單容器百萬任務完全無壓力;nginx的話,我們目前cdn回源全部是通過nginx反向代理到oss內網的,nTB靜態資源,目前還沒有遇到性能問題。

Q:你們是針對源碼編譯打包並放到景象里么?還是鏡像啟動的時候到某個存儲服務上拉取?

我們代碼放在git里,在構建的時候去編譯和打包,講編譯後的代碼放入鏡像;後者考慮過,但是網路情況多變,不穩定性太多,建議不要這樣做;

這裡補充一下,為了加快構建速度,我們做了分包處理;例如一個python應用,使用到了PIL,則構建一個基礎的python鏡像,並編譯好PIL;應用以該鏡像為基礎繼添加pkg並啟動

Q: 環境變數是在鏡像內設置 還是在容器啟動時賦值

這個看情況,一般情況是容器內部存在默認的環境變數,如不設置則啟動默認參數(針對某一region),啟動時的環境變數優先順序最高,可以覆蓋內部環境變數

推薦閱讀:

TAG:电影 | 集體宿舍 | 宿舍生活 | 各种想法 | 异国他乡 | 海外 | 墨西哥 | 恋爱 | 恋爱心理 | 恋爱技巧 | 力量举 | 健身 | 运动 | 精酿啤酒 | WMI | Docker |