如何使用 Docker、ECS、Terraform 重建基礎架構?
早期 Segment 基礎架構普遍組合在一起。我們通過 AWS 界面設定實例,使用許多閑散的 AMI,并且采用三種不同的部署方式。
然而隨著商業的飛速發展,工程師團隊的規模不斷擴大,基礎架構的復雜度也不斷提高。提高生產效率的方法仍舊只在一小部分人中間傳播,雖然生產效率在不斷提高,但是如果想一直保持高速增長,還要全面修整基礎架構。
因此,幾個月前,我的團隊一起討論:「如果今天重新設計基礎架構,會是怎樣一種結構?」。
10個星期后,我們徹底重構了基礎架構。我們放棄了幾乎所有實例與舊的配置,將我們的服務轉移到 Docker 容器中運行,并且轉而使用全新的 AWS 賬號。
在此我們花了很長時間思考如何將產品架構變得簡單、易用且可審計,同時保留擴展的靈活性。
以下是我們的解決方法。
使用不同的 AWS 賬號
我們并不使用 Region 和 Tag 來區分不同的階段如預發布環境和生產環境,而是使用完全不同的 AWS 賬號 。我們必須保證設定腳本不會影響正在運行的服務。同時,新的賬號就像白紙一樣,可以重新開始。
此處, ops 賬號作為跳躍點和集中登陸點。公司內的每個人有一個 IAM 賬號用于登陸。
其他環境有一組 IAM 角色可以相互切換。這意味著,管理賬號只有一個登陸點,也只有一個位置限制訪問。
比如:Alice 可能擁有所有三個環境的訪問權,但 Bob 只能訪問 dev(如果他刪除生產負載均衡器的話)。但是,他倆都可以進入 ops 賬號。
現在,不需要復雜的 IAM 設定以限制訪問權限,我們可以通過環境查看用戶通 role 進行分組。在界面使用各個賬戶就像切換當前活躍用戶一樣簡單。
我們無償地實現了真正的隔離,不需額外的配置,無須擔心預發布環境的安全性,或它對生產環境數據庫的改動。
能夠共享配置代碼的另一個好處是現在的 預發布環境成為了一個鏡像 。在配置上唯一的不同是實例的大小和容器的數量。
最后,我們也啟用了各個賬戶之間統一計費。每個月我們用同一張發票付費,同時能按照環境查看費用明細。
Docker 與 ECS
賬戶設定完畢后,就該設置服務的運行方式了。為此,我們使用了 Docker 與 EC2 容器服務(ECS) 。
現如今,我們大多數的服務都運行在 Docker 容器內,包括 API 與數據管道。容器每秒鐘接受成千上萬次請求,每個月處理500億事件。
Docker 的最大好處在于它使團隊能夠從零開始搭建服務。我們不再有一套復雜的設定腳本或 AMI ,我們只要給生產集群提供一張鏡像就行了。無需狀態性的實例,我們能保證在預發布環境和生產環境運行一模一樣的代碼。
設定服務在容器中運行后,我們選擇 ECS 為調度器。
在一個高水平上,ECS 實際負責在生產環境下運行容器。它負責調度服務、將它們置于不同的主機中,在與 ELB 關聯時零宕機重載。它甚至可以跨多個 AZs,從而達到更佳可用性。如果一個容器宕機了,ECS 會確保該容器在集群中的新實例上重啟。
切換到 ECS 之后,極大地簡化了運行服務的過程,無需再擔心啟動任務或設定實例。因為它很簡單,只需要添加一個 Dockerfile,設定 task,再將其與集群關聯即可。
在我們的配置中,Docker 鏡像由 CI(持續集成) 構建,之后推送到 Docker Hub。當某項服務啟動時,它從 Docker Hub 獲取鏡像,之后 ECS 在各個機器間調度之。
我們依照集群涉及的組件與負載間檔對他們分組(不同的集群用于不同的 API、CDN、App 等)。不同的集群意味著我們可見性更高,能為其配置不同的實例類型( ECS 沒有實例關聯度的概念)。
每項服務都包含一個特別的任務用于指明容器版本,運行的實例數量,以及該選擇的集群類型。
在運行時,服務會自行注冊 ELB,同時使用健康檢查確定容器是否可以運行。我們在 ELB 指定一個本地的 Route53,因此各個服務能相互通信,通過 DNS 就能相互引用。
因為不需要 任何 服務搜索,所以設置非常順利。本地的 DNS 幫助我們記錄一切。
ECS 運行所有服務,我們通過 ELB 就能獲取免費的云監控測量數據。這比在啟動時就要在中央注冊服務要簡單的多。而且,更棒的是,我們中央不需要再面對狀態沖突了。
使用 Terraform 模板
Docker 與 ECS 負責實現運行每一項服務,Terraform 是將他們聯合在一起的膠水。在高水平上,一系列腳本負責創建并更新基礎架構。你可以將其想作一個 Cloudformaition 模版,除了它不會讓你想自戳雙目。
現在,無需運行一系列服務器以維護狀態,只需一些腳本用來描述集群。配置在本地運行(未來通過 CI 運行),提交到 git 上。因此,我們能得到一系列記錄,能夠了解生產環境中基礎構架的實際情況。
以下是我們的 Terraform 模板中設置 bastion 結點的樣本代碼。該代碼創建所有的安全組,實例和 AMI,因此我們可以簡單地為未來的環境設定跳躍點。
// 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 }
我們在預發布環境與生產環境中使用同樣的模板設置單個 bastion。唯一需要修改的是 IAM 鍵。
修改也非常簡單,不需要修改整個基礎架構,Terraform 會在需要的時候更新內容。
當我們要將 ELB 超時時間改為60秒時,只需通過 terraform apply 簡單地查找/替換就好。兩分鐘之后,我們的 ELB 生產環境就完全改變了。
而且,這是可復制、可審計且自文檔化的,每一步都是可見的白盒操作。
我們將所有配置都放在一個中心的 infrastructure 庫,這樣很容易看清某一項給定的服務是如何配置的。
到目前為止,我們還未講到核心部分。我們希望利用模板轉變更多的 Terraform 配置,聯合獨立文件從而減少共享文件的數量。
同時,我們也發現了有關 .tfstate 的一些陷阱。Terraform 總是先從現存的基礎架構讀取數據,如果狀態不同步就會報錯。最后,我們將 .tfstate 放到庫中。我們希望能通過 Atlas 或使用 CI 來解決該問題。
使用 Datadog 監控
至此,我們已經搭好了基礎架構,開通了服務,做好了必要的隔離。最后要做的是監控生產環境中所有運行程序。
在新環境中,我們將所有的監控和指標都用 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 的目的。
更酷的是,該探針能夠圖形化展示環境中多個主機間的實例利用情況,因此我們能從更高角度了解可能出問題的實例或集群:
此外,我的隊友 Vince 寫了一個針對 Datadog 的 Terraform ,因此我們可以針對實際的生產配置設置報警腳本。我們的報警會被記錄,同時與生產環境中運行的程序保持同步。
按照慣例,我們會設定兩種報警級別: 預警 與 重要警告 。 預警 使線上的工程師了解任何可疑的問題,會在潛在問題發生以前發出。 重要警告 則是會在半夜把你喊起來的嚴重系統宕機。
此外,當我們完成向 Terraform 模塊的轉移,將 Datadog 提供程序加到服務描述層之后,所有的服務都會免費獲得告警。這些數據都是由內部工具箱與 Cloudwatch 指標驅動的。
讓好時光在 Docker 中繼續
當所有的組件都準備就緒后,切換的日子終于到來了。
首先,我們會在新的生產環境與原有環境間建立 VPC 對等連接 ——從而集群化數據庫并在兩者間進行復制。
其次,我們預熱新環境中的 ELB 使之能夠承受新的負載。亞馬遜無法提供自動更改大小的 ELB,因此我們不得不提前為其擴容以應對增加后的負載。
之后,我們只需使用加權的 Route53 路由平穩地將流量從舊環境導向新環境,并且持續監控確保一切正常。
現在,我們的 API 每秒處理成千上萬次請求,并且完全運行在 Docker 容器內。
但是還沒完,我們還在優化服務的創建方式,減少引用,使得團隊中的任何人都能簡便地創建服務,同時包含適度的監控與預警系統。此外,我們還想優化容器周邊的工具,因為現在的服務已不再圍繞實例進行了。
我們還會關注這一領域頗有發展的技術。 Convox 團隊真正創建圍繞 AWS 基礎架構的強大工具。盡管我們很喜歡 ECS 的簡單與集成,但 Kubernetes 、 Mesosphere 、 Nomad 與 Fleet 這些都是非常不錯的調度器。我們很期待看到他們的后續發展,并會考慮選擇一二進行使用。
經歷所有這些編排變化之后,我們比以前更加相信將基礎構架外包至 AWS 的策略。他們產品化了許多核心服務,完全改變了游戲規則,而且維持了一個極具競爭力的價格。這使得越來越多的初創企業能夠高效、低成本低開發產品,同時在維護上節省時間。我們相當看好這些建立在基礎生態系統之上的工具。
原文 Rebuilding Our Infrastructure with Docker, ECS, and Terraform 作者 Calvin French-Owen,本文由OneAPM 工程師翻譯整理。
OneAPM 能夠幫你查看Python 應用程序的方方面面,不僅能夠監控終端的用戶體驗,還能監控服務器性能,同時還支持追蹤數據庫、第三方 API 和 Web 服務器的各種問題。想閱讀更多技術文章,請訪問OneAPM 官方技術博客。