發展企業是艱難的,發展一個支撐企業前行的工程團隊可以說是更加困難的。但是沒有一套穩定的基礎設施,做這兩件事基本是不可能的。特別是對于高速發展的企業,必須授權每一個工程師在編碼、測試和交付代碼方面具有高度的自主權。
segment是一家客戶數據中心,致力于幫助數千家公司收集、處理數據,本文主要講了segment在自動化基礎設施方面的實踐,主要包括同步開發環境、映射開發環境和生產環境、本地開發和部署到生產環境。
過去的一年中,我們增加了達60個新的系統集成環境(總數超過160個),為合作伙伴建立了一個平臺,用以編寫他們自己的集成,發布了Redshift(紅移)集成,同時發表了幾個重大的產品公告。那段時間,圍繞多環境管理、部署代碼和通常的開發工作流程,我們經歷了許多成長的煩惱。之后,我們的工程師是最幸福、最具生產力的,因為他們的時間都花在發布商品,打造工具和擴展服務上。開發流程和它所支持的基礎設施簡單易用、擴展靈活是至關重要的。
這就是為什么我們自動化了自己的基礎設施的眾多方面。下面我將分享關于我們當下的一些更加詳細的設置,主要包括這幾個領域:
同步開發環境
映射開發環境和生產環境
本地開發
部署到生產環境
一起來深入的探討一下吧!
同步開發環境
由于代碼的復雜性的增長和工程團隊的擴大,在所有的工程師中保持開發環境的一致會變得更加困難。
在我們現有解決方案出現之前,我們的工程師所面臨的一個大問題是同步開發環境。我們有一個Github庫,里面有一組shell腳本,所有新來的工程師執行這些腳本,將必要的工具和身份驗證令牌裝到他們本地的機器上,這些腳本也會建立Vagrant和一個虛擬機。
但是這個虛擬機是在每臺電腦上進行本地構建,如果你修改了虛擬機的狀態,那么為了使得讓它恢復到與其他工程師的虛擬機同樣的狀態,你必須從頭構建一切。而當有工程師更新了虛擬機,你必須在Slack上告訴每個人,讓他們從Github VM庫中拉取代碼并重新構建。這是一個痛苦的過程,因為 Vagrant很慢。
對于一個竭盡全力快速前行的發展中團隊來說,上面的方法并不是一個好的解決方案。
每次運行時,我們會通過查詢Docker Hub API來確保虛擬機是最新的。這個過程會更新工程師每天所需的包、工具等。這將耗費5秒鐘,為了確保一切運行正常,這也是必要的。
此外,由于我們的工程師使用Mac電腦,我們從boot2dockerVirtualBox虛擬機切換到了托管于boot2docker實例的Vagrant,以便我們可以充分利用NFS的優勢來共享主機和客戶機的volumn。在本地部署的時候,使用NFS,性能得到大大提升。最后一點,NFS允許工程師在虛擬機外部所做的改變可以即時地在虛擬機內部反映出來。
通過這個解決方案,我們大大減少了需要在宿主機上安裝依賴的數目。現在唯一需要的是Docker、Docker Compose、Go和GOPATH配置。
映射開發環境和生產環境
理想的情況是在開發環境和生產環境中運行相同的代碼,然而這樣分離,開發環境中的代碼可能永遠不會對生產環境中的代碼產生影響。
之前我們將AWS狀態(由Terraform生成)存儲在Terraform的文件中,但它并不是一個完美的系統。例如,如果兩個人異步操作并應用了不同的改變,狀態將會改變,最后推送代碼的人將很難搞定合并沖突。
我們盡可能以最簡單的方式實現了staging和production環境的映射:
從一個文件夾復制文件到另一個文件夾。Terraform使我們在修訂基礎設施、部署新服務和做出改進方面節省了大把時間。
在應用之前,我們通過編寫定制的構建過程以及確保恰當的安全因素已考慮在內來集成Terraform和CircleC。
目前,我們在Github上有一個名為基礎設施的單一庫,其中包含了Terraform的腳本集合,用以為每一個容器配置環境變量和設置容器。
當我們想要改變基礎設施中的某些東西時,將必要的修改寫進Terraform腳本,并在新的pull請求之前運行它們以便基礎設施團隊中的其他成員來review它。一旦pull請求合并到主分支,CircleCI就會啟動部署進程:狀態變為pulled,本地被修改,并再次存入到S3。
本地部署
種子庫
本地開發的時候,使用虛擬數據填充本地數據庫是很重要的,這樣會讓我們的應用看起來更真實。所以,種子庫是配置開發環境的共同組成部分。
我們依賴CircleCI、Docker和volumn容器來提供獲取虛擬數據的便捷途徑。volume容器是靜態數據的便攜鏡像。我們決定使用volume容器,因為數據模型和邏輯越來越松耦合而且容易維護。這樣做也是以防萬一,在我們的基礎設施的其他地方可以用到這些數據(比如測試等,誰知道呢)。
當我們在開發過程中啟動app服務器時,就會自動加載種子數據到我們的本地開發環境中。例如,當app(我們的主應用)容器在開發環境中啟動,app的docker-compose.yml腳本就會從Docker Hub中拉取最新的種子鏡像,并在虛擬機中掛載原生數據。
Docker Hub中的種子鏡像產生自Github倉庫中的種子,作為我們導入到數據庫中的原生對象,它就是一組JSON文件。為了更新種子數據,我們將 CircleCI配置到倉庫上,以便任何到主分支的推送都會構建(從Docker Hun中賺錢我們的mongodb容器和redis容器)并向Docker Hub中推送新的種子鏡像,這樣我們就能在app中使用這個容器了。
生成微服務
由于Segment數據密集型的特性,我們的app已經依賴幾個微服務(db,redis,nsq等)。為了使我們的工程師可以開發app,我們需要一個簡單的方法在本地構建這些服務。
Docker再一次使得這種工作流變的非常容易。
類似于我們使用種子volume容器掛載數據到本地虛擬機那樣,我們以同樣方式來使用微服務。我們使用doker compose文件從Docker Hub抓取鏡像來進行本地構建、設置地址并最終將復雜性降低到一條終端命令就可以讓一切啟動并運行。
部署到生產環境
你編寫代碼,但從不將代碼部署都生產環境,這種情況真的發生過嗎?
部署代碼到生產環境是開發工作流程中的一個組成部分。在Segment,圍繞部署代碼到生產環境,我們優先考慮難易程度和靈活性,因為這使得工程師可以快速的行動而富有成效。我們還創造了足夠多的工具來為處理錯誤,回滾和監視構建的狀態保駕護航。
我們使用Docker、ECS、CircleCI和Terraform來盡可能地自動化持續部署。
當我們初次嘗試使用Docker時,我們很喜歡其在一個可復用和隔離的環境中運行代碼的能力。我們想要復用Docker的這些原則和經驗,從而在不斷擴大的工程團隊中保持開發環境的一致。
我們寫了一堆工具為新來的工程師配置虛擬機,從基礎鏡像狀態升級或是重置。當我們的工程師初次配置虛擬機的時候,需要Github憑證和AWS令牌,然后從Docker Hub中拉取最新的鏡像并構建。
相關文章