Segment:使用Docker、ECS和Terraform重建基礎設施
本文 轉帖自 Segment公司CTO以及聯合創始人 Calvin French-Owen發表的文章。Segment公司采用獨立的AWS賬戶進行真正意義上的隔離,采用Docker和ECS運行服務,并采用Terraform配置腳本進行整合并為服務描述添加Datadog供應商獲得免費的監控告警信息。
Segment 于 2012年 在舊金山成立,一開始就因其整合數據的能力倍受關注,去年6月,Segment 把自己的服務拓展到移動領域,發布了允許開發者將數據一鍵分送給多家數據分析服務提供商的 SDK(包含 iOS 和 Android 版)。對于用戶,尤其是開發者來說,Segment 能讓他們在接入不同數據追蹤服務中節省不少時間,以前要對提供者給定的 API 逐個進行配置,而 Segment 搭建的底層系統,讓用戶只進行簡單地開關切換。接入基于 SOAP XML 協議 API 相比 REST 更為復雜,而 Segment 能對此進行有利整合,開發者們也可以從 API 中解放出來去專注產品打磨。本文翻譯自其官方博客。
在Segment早期,我們的基礎設施是拼裝的,我們通過AWS的用戶界面提供實例,有一個由從未使用的AMI組成的組件,以及通過三種不同方式實現的配置。
隨著公司業務開始騰飛,我們的工程師團隊開始擴充,架構也開始日益復雜,但是生產環境的相關工作仍然局限于我們少數這些知道神秘陷阱的人。我們一直在逐步改善過程,但我們需要給我們的基礎設施更深層次的改革以保持快速發展。
因此,幾個月前,我們坐下來問自己:“ 如果我們今天設計,那么基礎設施設置會是什么樣子?”
在10周的過程后,我們完全重新設計了基礎設施,我們撤下了幾乎每一個實例和舊的配置,將我們的服務移到Docker容器中運行,并且切換為使用全新的AWS賬號。
我們花了很多時間考慮如何使生產環境設置變得可審計、簡單并且易用,同時仍然不失可擴展的彈性。
下面就是我們的解決方案。
獨立的AWS賬戶
我們切換到了完全獨立的AWS賬戶,而不是使用Region或者Tag來分離不同的預生產環境和生產環境實例,我們需要確保提供的腳本不會影響當前運行的服務,并且使用全新的賬戶意味著我們將從一張白紙開始。?
運維賬戶提供了跳轉和集中登錄服務,團隊中的每個人都有一個AWS IAM賬戶。
其它環境擁有一系列IAM角色來進行切換,這意味著只能有一個登錄點來管理賬戶,也只有一個地方限制訪問。
舉個例子來說,Alice也許可以訪問上圖中的所有三個環境,Bob只能訪問開發環境(哪怕他刪除了生產環境中的負載均衡器),但是他們都是通過同一個運維賬戶登錄的。
作為對于復雜的IAM設置限制訪問的替代,我們只是簡單地通過環境來鎖定用戶并且通過角色來分組,從界面上使用每一個賬戶就像切換當前的活躍角色一樣方便。
?
我們可以免費獲得真正意義上的隔離,無需額外配置,而不是擔心預生產環境沙盒會不安全或者會改動生產環境數據庫。
分享配置代碼帶來的額外好處就是我們的預生產環境事實上將會成為生產環境的一個鏡像,配置中僅有的區別只有實例大小和日期數目。
最后,我們也可以跨賬戶合并賬單。我們使用相同的發票來支付月付賬單,可以看到一個按照環境來分割的詳細分解后的費用。
Docker和ECS
一旦我們設置好了賬戶,接下來就是輪到如何設計服務真正運行了,為此,我們轉向了 Docker和 EC2容器服務(ECS)。截止今天為止,我們大部分的服務都運行在Docker容器里,包括我們的API和數據流管道。容器每秒鐘都會接收數千次請求,每月處理500億條事件。
Docker的最大好處就是可以一定程度上授權團隊從無到有構建服務,我們不再有一組復雜的配置腳本或AMIs——我們只需交給生產集群一個鏡像然后運行即可。不會再有有狀態的實例了,我們可以保證預生產環境和生產環境運行的是一模一樣的代碼。
配置完我們的服務如何運行在容器里后,我們選擇了ECS作為調度器。
在一個較高的水平,ECS負責在生產環境中實際運行我們的容器。ECS關注服務的調度,即將服務放置在單獨的主機上運行,并且在當連接到ELB時 確保零宕機重載服務。ECS甚至可以通過AZs調度提供更好的可用性,如果某個容器掛了,ECS會確保在集群中重新調度一個新的實例。
切換到ECS極大地簡化了運行服務的工作,從而不需要擔心Upstart工作或者配置實例。添加 Dockerfile、設置任務定義以及將其和集群關聯都是非常容易的。
在我們的設置中,Docker鏡像通過CI(持續集成)來構建,然后再推送到Docker Hub。當一個服務啟動時,會從Dokcer Hub上拉取鏡像,接著ECS就可以跨機器調度了。
?
我們將服務集群按照它們的關注領域和負載profile(比如針對API、CDN、APP等的不同的集群)分組,擁有分離的集群意味著更好的可見性以及針對每一個集群都可以決定如何使用不同的實例類型(因為ECS沒有實例關聯的概念)。
每一個服務都有一個特定的任務定義,指出了運行在哪一個版本的容器里、運行多少實例以及選擇哪一個集群。
在運行過程中,服務通過ELB注冊它自身,使用健康檢查來確認容器是否準備好運行。我們在ELB中指向一個本地的Route53條目,這樣服務借助于DNS可以互相通信和簡單地引用。
?
設置非常的棒,因為我們不需要任何服務發現,本地的DNS就完成了所有的記賬工作。
ECS可以運行所有的服務,我們從ELB獲得了免費的CloudWatch監控指標,這比起在啟動階段就不得不通過一個中央認證授權中心注冊服務要簡單多了,并且最大的好處還是在于我們不需要親自處理服務狀態沖突了。
Terraform模板化
Docker和ECS描述了如何運行我們的每一個服務,而Terraform就像膠水一樣把它們整合在了一起。在高級別上,它是一組配置腳本,可以創建和更新我們的基礎設施。你可以認為它像一個建造中的CloudFormation版本,但不會讓你想要戳你的眼睛。Terraform不是運行一組服務來維護狀態,而是只通過一組腳本來描述集群,配置腳本在本地運行(將來也是這樣,借助于持續集成)并且提交給Git,所以我們擁有了關于生產環境基礎設施實際運行的持續記錄。
這里就是一個我們Terraform模塊設置Bastion節點的樣本,該樣本創建了所有的安全組、實例和AMIs,這樣我們就可以很容易地為將來的環境設置跳躍點。
// Use the Ubuntu AMI module "ami" { source = "github.com/terraform-community-modules/tf_aws_ubuntu_ami/ebs" region = "us-west-2" distribution = "trusty" instance_type = "${var.instance_type}" }// Set up a security group to the bastion resource "aws_security_group" "bastion" { name = "bastion" description = "Allows ssh from the world" vpc_id = "${var.vpc_id}"
ingress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] }
egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] }
tags { Name = "bastion" } }
// Add our instance description resource "aws_instance" "bastion" { ami = "${module.ami.ami_id}" source_dest_check = false instance_type = "${var.instance_type}" subnet_id = "${var.subnet_id}" key_name = "${var.key_name}" security_groups = ["${aws_security_group.bastion.id}"] tags { Name = "bastion-01" Environment = "${var.environment}" } }
// Setup our elastic ip resource "aws_eip" "bastion" { instance = "${aws_instance.bastion.id}" vpc = true } </pre>
我們在預生產環境和生產環境中都使用相同的模塊來設置我們各自的Bastion節點,我們唯一需要換掉的是IAM keys,我們準備好了。
改變這些也絲毫沒有痛苦,不需要拆了已有的整個基礎設施,Terraform只在需要更新的地方更新。
當我們需要修改ELB Draining超時60秒時,只需要在Terraform apply后跟隨一個簡單的find/replace操作,這樣兩分鐘后我們就會擁有一個對于我們所有的ELB都是完全調整了的生產環境設置。
Terraform是可復制的、可審計的并且自注釋的,沒有任何黑箱。
我們將所有的配置都放在一個中央的基礎設施Repo,其可以非常容易發現一個服務是如何設置的。
我們還沒有完全拿到圣杯。我們想要轉換更多的Terraform配置來利用模塊的優勢,這樣可以合并單個文件,減少共享樣本的數量。
一路上我們發現了一些關于.tfstate的陷阱,Terraform總是一開始讀取現有的基礎設施,然后當狀態變得不同步時就會抱怨,我們通過將.tfstate提交到Repo的方式終止了這種情況,然后在有任何改變之后再推送回去,但是我們正在調研 Atlas,或者通過持續集成來解決這個問題。移動到Datadog
通過這一點,我們有了我們的基礎設施,我們的供應和我們的隔離。剩下的最后一件事是度量和監控,用以追蹤生產環境中運行的一切東西。
在我們的新的環境中,我們已經將所有的度量和監控切換到了Datadog上,這是非常奇妙的。
?
我們一直非常滿意Datadog的界面、API以及其與AWS的完全集成,但從工具中獲得最多的還是來自于一些關鍵的設置。
我們做的第一件事是將AWS與Cloudtrail集成,這個給出了一個居高臨下鳥瞰的視角來觀察我們的每一個環境如何演化的,因為我們要與 ECS集成,Datadog feed每次都會在任務定義更新的時候更新,所以我們最終得到了免費部署的通知。尋找Feed是出奇的快,而且很容易追溯到上一次的服務部署或重新調度。
接下來,我們確保添加Datadog-agent作為基礎AMI的容器( Datadog/Docker-dd-agent), 它不僅可以從主機(CPU、內存等)收集度量指標,還可以作為Statsd指標庫。每個服務收集自定義的基于查詢、延遲和錯誤的度量指標,這樣我們可以在 Datadog里探查指標和發送告警。我們的Go工具箱(很快就會開源)自動收集Ticker的pprof輸出并且發送,所以我們可以監控內存和協程 (Goroutines)。
更酷的是,Datadog-agent可以在環境中跨主機將實例利用率可視化,所以我們可以得到一個高層次的實例或集群概述,也許會有下面的一些議題:
?
另外,我的隊友Vince創建了“ Terraform provider for Datadog”,所以我們完全可以針對生產配置編寫告警腳本。我們的告警將會記錄下來并且與生產環境運行的系統保持同步。
resource "datadog_monitor_metric" "app.internal_errors" { name = "App Internal Errors" message = "App Internal Error Alerts"metric = "app.5xx" time_aggr = "avg" time_window = "last_5m" space_aggr = "avg" operator = ">"
warning { threshold = 10 notify = "@slack-team-infra" }
critical { threshold = 50 notify = "@slack-team-infra @pagerduty" } } </pre>
按照慣例,我們指定了兩個告警級別:Waring和Critical。Waring級別可以讓任何在線的用戶知道有什么東西看起來可疑,并針對任何潛在的問題提前做好預案。Critical級別的告警被保留為“喚醒你在深夜的問題”亦即一個嚴重的系統故障。
更重要的是,一旦我們過渡到Terraform模塊并為我們的服務描述添加Datadog供應商,接著所有的服務最終都會免費獲得告警信息,數據將直接由我們的內部工具箱和Cloudwatch度量指標來驅動處理。讓Docker運行的美好時光
一旦我們有了上述所有的這些組件,切換的這一天終于來臨了。
我們首先在新的生產環境和遺留環境之間設置一個 VPC的對等連接——允許我們在它們之間集群化數據庫和復制。
接下來我們在新的生產環境中預熱ELBs,確保它們可以處理負載。亞馬遜沒有提供ELBs的自動調整排列功能,所以我們不得不咨詢亞馬遜來提前準備(或者緩慢擴展自身)來處理增加的負載。
從那里開始,這只是一個使用加權Route53路由從老環境到新環境穩步增加流量的問題,持續監控,一切都看起來不錯。
今天,我們的API像蜂群一樣辛勤工作,每秒處理成千上萬的請求,并且完全運行在Docker容器里。
但是我們還沒有完成,我們仍然在微調我們的服務創建方式,并減少樣板,這樣團隊里的任何人都可以非常容易地構建具有適當的監控和告警功能的服務,并且我們想改進與容器工作相關的工具,因為服務不再與實例關聯了。
我們還計劃為這個項目留意有前途的技術。 Convox團隊正在圍繞AWS基礎設施構建很棒的工具。雖然我們喜歡ECS的簡單以及集成特性,但是 Kubernetes、 Mesosphere、 Nomad和 Fleet看起來也都是非常酷的資源調度系統,看看它們都是如何打開市場局面的將是令人興奮的,我們會一直跟蹤它們,看看有什么可以采用借鑒的。
在所有這些業務流程的變化后,我們比以往更強烈的認為應將我們的基礎設施外包給AWS。他們已經通過將大量核心服務產品化改變了游戲規則,同時保 持一個非常有競爭力的價格點。這一點帶來了一種新的類型的創業公司,它們可以高效地構建產品,廉價同時花費更少的時間進行維護,我們看好在AWS的生態系 統上構建工具。
原文鏈接:Segment: Rebuilding Our Infrastructure With Docker, ECS, And Terraform (翻譯:胡震)
來自:http://dockone.io/article/764