Insta360容器化&DevOps之路
作為一個全景/VR創業公司,隨著公司人員增加以及全球化方向轉變,刀耕火種的CI/CD方式已經不能滿足當前的需求。綜合考慮當前的人員狀況與技術架構的拓展性後,我們採用一套以阿里云為基礎,Docker為核心,第三方服務為工具的開發、測試、部署流程,以及內部的代碼提交,版本管理規範。
一,作者
蘇依
高級前端工程師兼Web組技術負責人,專職前端技術選型與架構設計。
就職於Insta360(全球360°全景相機(VR相機)全景領跑品牌,深圳嵐鋒創視網路科技有限公司)
二,背景
我司是一家集硬體研發與軟體開發為一體的互聯網創業公司。2016被稱為全景/VR元年,預示了機遇到來的同時,也註定了我們將會面臨一些列前所未有的問題,其中坑點無數,但不在本文討論範圍呢,廢話不多說,我們直奔主題。
我司目前對用戶開放的業務為主要包含以下三塊:
- 視頻圖片分享(2C)
- 全景 / VR直播(2B)
- 新聞媒體合作(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固然強大,但是也依然不利用上述挑戰的解決,主要問題如下:
- 配置繁瑣
- 擴展性差(相對而言)
- 可靠性差(使用ssh方式,受網路影響大)
而Docker也就是在此時成為可選方案之一,其優勢不言而喻:
- 靈活 將應用於系統容器化,不需要額外依賴
- 便捷 任意linux發行版配置docker engine即可啟動
- 開源&免費 開源/免費低成本,linux內核驅動
- 輕量 僅需添加或減小鏡像即可,在一台伺服器上可以布署多個容器
- 環境一致性 鏡像本身即包含運行環境,避免由於環境不一致帶來的各種異常與風險
五,架構/容器化
第一代架構
- ssh
- fabric/ansible
刀耕火種的ssh方案與docker實驗階段,目前已經全面棄用。
第二代架構
- 使用阿里雲VPC,內部使用ansible管理伺服器
- 通過ansible運行docker命令進行容器進行部署
- 後端服務&rabbitmq,依然使用傳統方式部署
第三代架構
第三代架構仍處於完善階段,上圖簡單描述了我司三個region服務於應用的分布:
- 杭州/美西
- 前端服務
- 數據存儲
- 鏡像倉庫
- 圖像處理/視頻轉碼 worker
- 配置服務 redis slave
- 服務ip地址
- 服務域名信息
- 服務配置信息
- 香港
- 數據中心(資料庫)
- 中間件(第三方服務)
- 統計系統
- 消息隊列
- 配置服務 redis master
前端服務
其中前端服務為主要為瀏覽服務,由cdn + slb + (nodejs+redis) 組成:
用戶訪問域名後通過dns-load-balancer進行第一次負載,解析到cdn的不同cname,cdn判斷請求類型:
- 資源 mp4/mp3/jpg/png返回客戶端
- 請求轉發到slb,slb通過加權輪訓方式進行二次負載
- 請求到達前端伺服器(nodejs),通過內部redis集區獲取數據
- 數據存在則返回,不存在則請求數據中心並緩存,再返回客戶端
- 作為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左右。
數據中心
該部分的數據為資料庫存儲的數據:
- Aliyun RDS (以後業務量增加後可以考慮過渡到DRDS)
- 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的網路比較詬病
這個問題要好好回答一下(因為最近剛被坑過..)
- 網路部分,overlay 我們放棄了,其中一個很重要的原因是無法獲取真實ip,同時也發現在達到一定數量級的時候,訪問速度變慢,具體的測試結果後面會發出來。
- 性能,目前發現的,是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 |