1. 程式人生 > >一個關於不可變基礎設施的實踐案例

一個關於不可變基礎設施的實踐案例

不可變基礎設施(Immutable Infrastructure)是由Chad Fowler於2013年提出的一個很有的預見性的構想 ,其核心思想為任何基礎設施的例項一旦建立之後變成為只讀狀態,如需要修改和升級,則使用新的例項進行替換。
這種模式可以為我們減少配置管理的負擔,並使得 DevOps 更加容易實踐,基於 Packer、Terraform及Docker, 我們正在實踐和完善這種構想,現在給大家分享。
當前的不可變基礎設施實踐的主要內容有:
生產與開發環境的一致性系統
利用 Terraform 構建基礎設施
生產與開發環境的一致性系統
我們平時的開發和測試乃至部署中,最常出現的問題之一就是由於系統環境的不一致導致bug或者執行失敗, 這在長時間執行的伺服器進行緩慢升級時最為常見,而老舊的系統和軟體則帶來更多的問題和維護成本。
因此我們使用 Packer 及 Vagrant 來統一生產環境和開發環境,Packer 構建作業系統映象,供 Vagrant 執行虛擬開發環境,這樣所有的開發人員都會有一個統一併且持續更新的開發環境,更利於減少問題和協作。
Packer 構建的映象還可用於各大虛擬化平臺,如 KVM、Xen和ESXi,以及匯入到 AWS 等雲端計算平臺,我們這裡使用的就是 AWS。
構建的基礎映象會預裝好大部分需要的軟體如 Docker、Consul,一些常見的 Docker 容器映象也會拉取預裝好。
這樣我們在部署時就會有一個和開發環境幾乎沒有差別的統一基礎設施可用。
我已經把我們映象的構建指令碼提取開源出來 zealic/packer-boxes(

https://github.com/zealic/packer-boxes),構建的映象有 CentOS 及 Debian,大家可以參考以此構建自己的映象。
利用Terraform構建基礎設施
上面說過我們使用 AWS 作為基礎設施平臺,基於不可變基礎設施的理念,我們希望的是基礎設施是可以快速銷燬和重建的,
基於這個目的,我們使用了 Terraform 來完全託管 AWS 基礎設施。
在此之前,我需要介紹一下部分架構。
首先我們會為基礎設施分組,每個基礎設施組對應一整套 VPC 環境。
每組基礎設施我們根據功能場景分為兩種;ops-center組 及應用基礎設施組,ops-center 主要承載運維基礎設施,如 Mesos Master,Docker Registry,持續整合服務,VPN接入以及管理後臺都執行在 ops-center。
應用基礎設施組則執行主要業務的微服務、反向代理及 Marathon 節點。
而這些體現到 AWS 中,每組基礎設施組都會應對一個 VPC,通過 VPC Peering Connection 連線相關的基礎設施組。
基於這樣的前提,我們可以對此分出多個基礎設施組,比方我們有國內和新加坡的業務,則可分出如下基礎設施組:

ops-cn
prd-cn
ops-sg
prd-sg-master
prd-sg-slave

下面將介紹我們使用 Terraform 託管基礎設施時的一些細節。
我們寫了一套 Thor 指令碼來管理多個基礎設施組,每個組都是一個資料夾,資料夾中包含了對基礎設施組的 Terraform 定義, 這些定義檔案均被版本控制,可以進行對資源的快速回滾和改動。
當我們需要對 AWS 基礎設施做一些修改時,只需要修改定義並執行如下命令。
thor exec:terraform apply
通過管理配置檔案傳遞變數來關聯多個基礎設施組的關係。
目前通過 Terraform 託管了以下內容:

VPC
VPC Subnet
Route table
Security Groups
Route53 records

ELB
S3
Internet/NAT Gateways
以及上面提到的 ops-center 的中提供的各種功能伺服器,在定義 aws_instance 時,我們會為其分配 tag,我們的管理程式在接收到伺服器準備好的事件時,通過 tag 判斷該伺服器的角色,為其執行對應的 Ansible Playbook,從而完成自動化部署。
有時我們可能會有未受 Terraform 的資源需要納入其託管範圍,這裡我們用了terraforming,可以將已經存在的 VPC、S3 或者 EC2 例項納入 Terraform 的託管;當然Terraform 也承諾了將會在未來加入 import 功能以匯入已有資源。
應用基礎設施組則僅部署 Marathon 管理 Docker 容器叢集,由其管理業務服務及其他相關內容,由於我們的業務服務均會構建為 Docker 容器進行釋出,因此這裡僅僅只需要管理應用服務的配置,這裡我們使用了Consul和Confd來進行動態配置管理。
這樣,我們的基礎設施均以相同的模式執行和建立,均具有不可變性,系統更為簡單和可靠,並具有快速回滾的能力。
通過實施這套方案,我們可以獲得以下好處:
快速重建、銷燬基礎設施組,部署多個基礎設施組來實現災容、灰度釋出及快速升級。

Q&A
Q:你們這套方案中遇到過哪些坑讓你印象深刻,請舉一兩個具體例項說明?
A:使用 Packer 在國內進行構建時,因為眾所周知的網路原因,經常會有失敗的問題,這一點可以通過其他方式避免。此外由於 Terraform 並非完全支援所有的 AWS 資源管理,如 Cloudfront、Route53 Geo DNS,仍然需要手工管理這些,不過未來 Terraform 會加入這些的支援。
Q:每個vpc組是完全獨立的提供服務?能說下這套技術應對的業務層是哪個方面的麼?
A:每個 VPC 組提供的是一個完整的應用功能實現,上面也提高了我們會有 prd-sg-master,prd-sg-slave,可用於災容。業務層提供的主要是 HTTP 服務及內部依賴的微服務。
Q:請問為什麼選用Consul?很多類似方案用的etcd。
A:Consul 對於 agent 的節點的失效更友好,此外 Vagrant、Consul、Terraform 都是由 HashiCorp 公司開發的,其文件和技術棧都很全面,值得應用實踐。
Q:如果我用了Kubernetes,對大資料Hadoop、Spark都沒啥需求,是否還有用Mesos的必要呢?換句話說Mesos和Kubernetes結合針對純容器平臺有什麼好處,使用場景是什麼?
A:Kubernetes和Mesos都是容器管理排程的框架,Mesos的優勢是更具可開發擴充套件性。
Q:請問對於PHP這種可以動態載入程式碼的服務,在這套系統裡應該怎麼應用呢?
A:動態載入程式碼的程式碼源建議使用微服務的方式提供。
Q:Vagrant在宿主機使用的是NAT模式還是bridge ?Packer相對於vagrant package 命令,優勢是哪些?Vagrant 在宿主機使用 NAT 模式,這樣可以減少 DNS 出問題的機率。
A:Packer 可以從ISO映象開始構建你的系統,相對於Vagrant更純粹;實際上Vagrant的大多數 box 都是從Packer打包過來的。
Q:我在上期分享時,介紹過類似的Packer+Terraform工具。在使用Terraform管理AWS資源時,你提到另外的指令碼管理(thor exec:terraform apply)。請問,你為何不直接執行Terraform 的命令,用thor的目的是什麼,你的哪個repo了有用到thor,我可以參考一下?
A:我們在執行Terraform時需要傳遞很多變數以及硬編碼引數,同時我們使用了AWS國內區域和 AWS 國際區域,他們是分開的,對應的 AWS Access Key 及 SecretKey 不同,Thor 指令碼的目的是講這些內容通過配置檔案和環境變數的的方式傳遞給 Terraform,使其能獲取正確的引數和定位正確的執行環境。
Q:請問持續整合採用的是Jenkins加外掛的方式嗎?持續整合的程式碼採用了什麼樣的分支管理策略?
A:是的,持續整合採用Jenkins及外掛,我們採用的分支是 Git Flow 的變種,基於pull的模型。
Q:單純的用於AWS的話,亞馬遜自家的CloudFormation支援的基礎設施應該更全面,如果不考慮跨平臺的能力,還有什麼理由選擇Terraform嗎?
A:CloudFormation 的設計並不友好,基於 JSON 的語法非常晦澀且難於維護,不像 Terraform 一樣一目瞭然。
Q:跨主機網路是咋解決的啊?是結合了Kubernetes和Mesos、Docker功能嗎?
A:我們採用的方案是 Weave,沒有使用Kubernetes。