導入 Configuration as code,完成三位一體 (All Codes!)

Neil Wei
BlendVision
Published in
12 min readJun 14, 2018
credit: https://en.wikipedia.org/wiki/Fujiko_Fujio

在好久好久以前,我們是這樣 deploy code 的…

當 developer 寫好程式後,我們將程式碼存放在自架的 gitlab 上,透過內部自架的 Jenkins 打包成 RPM,放到內部自架的 yum server 上面,接著打開內部自架的 wiki,寫一份安裝文件,裡面包含了詳細的 step by step 安裝說明,要先裝 A,再裝 B,然後把什麼 config 放到什麼位置,staging 的 config file 該長什麼樣,production 的 config file又該長什麼樣,完完整整的列出來。

接著敲 Service Operation 同事,來開一個交接會議吧,把我的心血和文件交接出去,等待他們排時程部署上 staging,沒問題後再等他們排時間上 production…就完成啦…咦…不對..

Dev:「啊…中間有個小 bug 忘記修,等我再包一次,更新一下文件請你再 deploy 一次,版號記得是 1.0.1002 喔!」

Ops:「文件有誤啦!你少寫一個 apt install xxxx,而且 RPM 有問題,裝完後跑不起來喔,你自己連進來看」

Dev: 「怎麼會…在我這邊明明就…啊.. 原來 production 沒有裝 xxx,我補一下文件」

(如此,半個月過了,service 終於上線了!! 不知各位是否有似曾相識的感覺)

即便後來變得比較先進,開發團隊架了一套 deploy 系統,不過仍然有許多不便的地方,那又是另一個故事了…

source: http://observer.com/2013/05/nerd-fight-cops-called-to-fight-between-star-wars-and-doctor-who-fans-at-sci-fi-convention/

事情終於結束(x) 真正的挑戰開始 (o)。

面對真實世界的流量以及是否 “easy for operation”,考驗接踵而來,終於修修補補將 application 來到了 1.0.1030 版本,一切的問題都修正了!不過,Ops 也快被你搞死了…

其實,對很多公司來說,這已經是一個算及格的 CI 自動化流程了

(聽過更吐血的,用 ftp 放 code,放 package,production 環境直接連 ftp 抓 package)

以上真實的小故事,有什麼樣潛藏的問題,可能是三五年後才會爆發?

  • 太多為了一時方便自架的東西:有 Gitlab、Jenkins、Yum Server、Wiki system,勢必造成未來維護人力提升。
  • 文件常常會過時:所有人都覺得文件很重要,但是沒有人愛寫文件。
  • Ops 花太多手動工作在幫忙 deploy / debug,有自動化 CI,沒自動化 CD
  • dev/staging/production 環境的差異很大。

這是很典型的 「wall of confusion 」文化或是「穀倉效應」,Dev team 和 Ops team 各自為陣,只專注在自己部門的績效,互相不知道對方在做什麼,在忙什麼,互相責難,為什麼 bug 總是不能一次到位修好,為什麼 deploy 總是缺東缺西…導至整個開發週期拉得很長。

Wall of Confusion, Source: https://www.devops.ch/2017/05/10/devops-explained/

大概在去年八月,KKStream 開始了一個新的專案,在沒有歷史包袱的情況下,剛加入團隊的我幸運地得到老闆 Ava Chen 的大力支持,一起導入 DevOps 文化,目標是希望加速開發週期,減少人力成本,團隊內可以獨自運作,在這個大方向之下,我們推行三點原則:

「自己的 code,自己 deploy」

「能自動的東西絕不手動」

「在 AWS 上,我們不再造輪子」

在這個專案裡,我們沒有專職的 Service Operation,換句話說,人人都是自己服務的 operation,為自己的服務負責,於是我們開發團隊的流程如下,在最需大量人力的 Deploy 階段,選用的是 AWS OpsWorks

我們是高度依存於 AWS 的服務,而且選用的是 EC2 solution,在這樣的情境之下,我知道 OpsWorks 會很適合我們。

開發流程略圖

什麼是 OpsWorks

OpsWorks 是 AWS 上的一個服務,官方文件有很詳細的解釋,但相信我,看完後一定還是不懂他是做什麼的,換成白話文來說:

OpsWorks 是一個把 CM tool (Configuration Management tool)包裝起來的服務,讓使用者不用自己架設/管理 CM tool,並且提供了和其他 AWS 服務高度(如 ELB, RDS, CloudFormation, …)整合的特性,可以很容易串接。

可以把他想成 EC2 + user data 的超級進階版,或是 Elastic BeansTalk + code deploy 的完整版

常見的 CM tool 有:Chef, Puppet, Ansible, SaltStack。

為什麼是 OpsWorks

在之前寫過的文章 — Infrastructure-as-code 如何改善我們的生活品質? 中有提到,把 Infrastructure 當成 code 來看待可以獲得很多好處,如今,我們再把 configuration code 當成 software 來管理,三位一體的開發流程就到齊了!

三位一體: Infra, Code, Configuration

一個完成的服務要上線,必需包含三個元件,分別是 Infrastructure / Code / Configuration,而當這三個元件都被當成 code 來對待時,我們可以省下非常多的開發成本。

Infrastructure: Network, DB, Cache, Load Balancer, Queue, Access control, …
實作上可以選用原生的 CloudFormation 或是第三方 Terraform 來達成。

Code: API,data process,商業邏輯、Data Model、User View,此處的 code 應該是要 environment free,code 裡不應該有任何關於環境的判斷。
我看過不少 code 會準備多份 config,然後判斷環境是 test ,staging 或是 production 來決定要載入哪一些設定檔,這是很直覺,但很不好的做法,應該交由下方的 configuration 來決定,Code 本身是無環境狀態的。

Configuration: 如何針對不同的環境部署不同的 config,如何把一台乾淨的 Ubuntu 或是 CentOS 裝好你想要的套件,部署你的 code,以及後續維運會用到的設定,例如 cron, monit, logrotate, syslog, Nginx/Aapche, CloudWatch agent 等等的設定。
實作上有 Chef, Puppet, SaltStack, Ansible 等工具

前面提過,在雲端時代上的設計原則之一就是 “不要再造輪子”,OpsWorks 就是因應 Application configuration 而生的服務,如果沒有特殊需求或偏好,使用 OpsWorks 會是一個不錯的選擇。

source: (http://bsnscb.com/chef-wallpapers/39324871.html) + AWS OpsWorks

OpsWorks 是一個以 Chef 為主的服務(現亦支援 Puppet),我們可以將自己撰寫的 CookbookApplication 的 repository URL 傳入 OpsWorks,由 OpsWorks 負責讓被托管的 EC2 ,針對不同的生命週期執行不同的 recipe,以達配置的目的。

同時,OpsWorks 也提供了 auto scaling 的功能,以及 ELB 的整合,是一個全方位的完整 EC2 solution。

OpsWorks 常用名詞解釋

Stack: 一個完整的 OpsWorks 生態系,由多個 Layer 組成,存放了 cookbook url, IAM Role, VPC, Subnet, Custom Json

Layer: 一個 Layer 代表一個 service,底下註冊 0至數個 EC2,可以想像成 Auto Scaling Group, 定義了不同的 Life Cycle 所要執行的 Recipe 為何。

Instance: 就是 EC2 本身

App: App 代表 EC2 所要安裝服務的 metadata,包含 package URL, credentials, 環境變數。

Custom JSON: 可以透過”外部”設定一些自定資料結構,讓 recipe 在執行時可以使用,避免 hard-code。 常用來將 instance 所要使用的 AWS 的 resource endpoint 傳入,或是所處的環境 (test/stag/prod)

Lifecycle: 指的是 EC2 的 Life Cycle,有以下五個: 1) Setup 2) Deploy 3) Configuration 4) Undeploy 5) Shutdown 每一個 Life Cycle 都可以指定 0 至多個 recipe
OpsWorks Instance Life Cycle: https://docs.aws.amazon.com/zh_tw/opsworks/latest/userguide/workingcookbook-events.html

有什麼缺點

在現在 serverless 與 container solution 興起的時間點,EC2 solution 相對比較沒有被投放主力資源在這邊,因此在使用 OpsWorks 多年的感覺,有以下幾點缺點:

  • 沒有原生 ALB 支援:OpsWorks 的生態系有整合 ELB,但沒有較新的 ALB,不過,仍然可以透過其他方法整合。
  • Auto Scaling 機制較陽春:OpsWorks 原生生態系是和 EC2 Auto Scaling Group 脫鉤的,使的有一些 ASG 好用的功能在 OpsWorks 用不到,不過有官方解法,而且也已經親測過可用。
  • 單台 EC2 上線時間較長:OpsWorks 會 launch 一個 AMI,然後將他裝好 OpsWorks client 的環境之後,交由 OpsWorks Lifecycle 去管理,因此可能會花費較為大量的時間在初期的配置,例如安裝 web server 與相關套件等等,這個問題可以配合 pre-build AMI 解決,先 build 好一個已安裝好基本套件的 AMI,再將其指派給 OpsWorks,如此一下就可以省下不少前置作業的時間。這也在先前的專案中實作過可行。

在目前雲端運算的的趨勢漸漸走向 serverless, 與 container solution 的浪潮下,仍然有許多追求穩定的公司選擇 EC2 solution,這背後有很多理由,成員的技術組成和新的工具的穩定性都是考量之一,老實說,AWS 在這一個領域仍然有不少進步空間。(ECS 不好用,至今 Fargate 和 EKS 仍未 global release)

結論

Steep Learning Curve (source: https://anitabrown3d.com/2016/06/03/starting-your-own-business/)

在本 team 取得第一個導入成功的案例後,往後新的專案也漸漸開始推行這樣的模式,甚至連舊的專案也在評估轉換的 effort,不過阻力往往不是技術問題,而是文化上的差異,大部份的 Developer 還是很習慣傳統式的 build 後不理模式,由 Service Operation team 來處理後續的部署,但是一來一往常常造成很多資源內耗,無法有效解決問題。

雖然學習 OpsWorks 的過程中有著不太平緩的學習曲線,但這也是學習的必經之路,過得不夠安逸才會使人成長嘛。

不過好在目前漸漸看到一些成效,經過 team member 與老闆的口耳相傳與文攻武嚇(?),已經慢慢地將 DevOps 的文化傳遞開來,這只是一個開端,一場文化轉變的開始,文化的轉變比起技術的改變要難上數倍,但我相信在 KKStream 本身年輕扁平的文化下,這是個好的徵兆。

--

--