歐哥說說

說說興趣 ‧ 說說科技 ‧ 東說西說 ‧ 就是要說  

如何開始導入DevOps


        這幾年投入雲端計算的世界,一直在負責與數位轉型相關的主題,此中不外乎包含了DevOps流程改善與導入,一直想找個機會分享一下心得。我想就先從這篇文章做個開頭,分享整個流程改善的初始想法與基本的構想,希望能夠持續地分享在雲端數位轉型的相關議題。
        說到DevOps,我想最常見的切入要點便是組織文化、自動化、Silo與各種工具,但這篇文章並不打算從這角度直接地討論DevOps。在任何的新流程與技術導入之前,應該先討論的是—需求。這是一切改變與改善的基礎,不應該為了任何Buzz word而衝動地進行任何決策改變。因此,整篇文章打算從“精實思考”,開始討論整個DevOps導入的起點。


     
        從精實思考的角度切入,首要之務便是討論“價值”,到底整個生產過程所要轉換出的價值是甚麼,這個價值基本上與客戶所期待的價值有關。以目前科技服務市場來說,業務的樣貌與需求變化快速,為了能夠因應這樣的現況,並且協助業務單位快速地捕捉這樣的變動,工程必須找出一個更具效率,並且快速驗證需求的方法。因此,我們可以定義目前所需要的傳遞的價值是

        基於業務的需求,快速地實作並且改善服務的功能,以便能夠正確且有效地滿足終端使用者的需求。

        有了以上的設定後,所需要思考的便是整個價值傳遞所需步驟與資源為何?先看看在客觀情況下,整個價值製造所需要的步驟與資源。下圖以服務開發流程為例。


        從程式碼的建構到部署,所歷經的流程不外乎就是,開發—打包—測試—版控—發佈。從這流程中,可以辨識出整個流程必要的工作項目,接著便是工具的選用與組裝。工具的選用與組裝,最重要的就是省去重複人工的行為與流程的阻塞的問題。傳統的服務設計以大顆粒且複雜的系統結構作為其基礎,增加了服務上線前的測試複雜程度與準備時間,因此往往採用重重的簽核機制,確保服務的品質。然而,此舉卻導致無法應對快速變動的業務需求,因此,工程設計上,必須考量低耦合與容錯設計,讓各自的服務能夠被獨立且快速的驗測,提高服務的穩定與品質,而在此前提之下,傳統的變更流程也必然得面對簡化與自動化,品質的提高並非靠已習慣的簽核流程,而是靠流程的自動框架,確保每個檢查項能夠被正確且無誤的執行。換言之,簡化不需要的檢查項,並且加強且落實每個確認機制。如此一來,整個釋出流程才能快又有效,從月級轉移至分鐘級。

        至於工具的選用上,這部分就必須考量到組織內目前的工具樣貌與成員的技術能力狀況,建議上,採取單一且有效的工具即可,流程與工具的建立並非一朝一夕,沒必要非在一開始便是全副武裝,重點是因組織樣貌與市場需求,積極地改善整個流程,並且讓工程能夠基於需求開發。

        最後,仍然免不了要來討論一下文化問題,DevOps推動必須要基於需求,主要的原因在於這樣的改善才能有效地得到組織內決策者的支持,在流程改善過程中,必然會使得原先工作崗位上的人,面對工作項目的變動,而此現象也必然產生一些衝突與挑戰,建議上,可以先在新專案上採用,使用併軌的方式進行,然後再擴展至舊有流程的移轉與改善。這樣會讓整個推動上較為順遂。

         



疾駛

一臉蒼白地望著慘白的天空,
週圍閃爍的燈號,
催促著上路前行,
輕踩著油門,
伴隨著胸口的悸動,
喧囂漸離而去 · · ·

下一站,永遠。

啤酒的滋味 - Suntory 金麥 RICH MALT


這瓶啤酒是最近在日本超市尋寶時,發現的啤酒。口味上,有別於日系啤酒的苦味偏重。入喉後,突出的汽水感以及嘴中迅速漫開的香醇麥味,伴著非常輕微的苦味,更能襯托麥味與涼爽口感,十分清爽好喝的啤酒,適合下班後放鬆暢飲一杯的啤酒。

選擇

選擇在乍看下一點都不是難事,難的是不知道真的選擇往往停頓在選與不選之間,而無法有個心服口服的答案。最後也最讓人揪心的是沒真實地意識到選擇後的一切代價卻又做了選擇。

利用容器安裝 gitlab 與設置 insecure gitlab container registry


        本篇文章主要是說明如何利用Gitlab的Docker映象檔來建立自己的Gitlab主機,另外,Gitlab在8.8版後,也開始提供與container registry的整合功能。由於目前網路上的資源大多以secure container registry為主的Gitlab設置方法。本篇文章特別以insecure container registry來說明如何在Gitlab上設置insecure container registry,供內部私用的Gitlab主機免去處理簽證的設置。


Step 1. 安裝 Docker 運行的環境

          基本上只要參考Docker官網(https://docs.docker.com/install/)的安裝守則,大都能夠簡單地完成安裝的流程,有個比較需要注意的是,記得將自身的使用者帳號加入docker的群組內,避免每次都非得使用sudo來進行相關的操作。

sudo usermod -aG docker $USER ---將自身帳號加入docker群組

Step 2. 下載 Gitlab 最新映像檔

          首先先造訪一下Docker Hub官網了解一下目前Gitlab的釋出狀態。



        從Docker Hub的Gitlab專案頁可以知道目前最新的版本為10.2.8-ce.0, 這邊我們採用Community Edition作為我們的安裝的目標。在下載映像檔時,我偏好採取明確版號方式來指定要下載的版本,作為日後確認版本時的依據。請執行下述指令來下載映像檔
             
docker pull gitlab/gitlab-ce:10.2.8-ce.0

Step 3. 運行吧! Gitlab

             

        如上圖所示,先準備一個放置gitlab所有資料與組態的位置,按照上圖,gitlab相關的資料將置放於/srv/gitlab/server之下。待資料夾創建完畢後,便可以下達運行gitlab的指令。相關的執行設定,可以參考gitlab的官方說明(這裡)。 比較需要說明一下的便是ssh port的指定,很多時候虛擬機器的埠號22,常是被佔住的,因此這邊特地使用2022作為替代。 執行過程中,可以利用docker ps來觀察gitlab是否已經順利運行。以下為運行後,gitlab網站的樣貌與相關設定。

          一開始登入時,會被要求針對root帳號,進行密碼的設定。

          待設定完畢後,便可以利用root帳號與方才設定的密碼登入系統。以下我們便趕緊建立一個新專案來看看。


          利用右上的 + 號圖示,選擇 "New project" 開啟新專案,並輸入相關專案訊息後,點擊"Create project"來建立新專案。接著來看看新專案頁面上有什麼資訊。


        可以發現三件事,(一) 網誌名為127.0.0.1,當然這並不意外,因為gitlab運行在本地端;(二) 專案的連結為亂碼;(三) 並未有任何跟registry有關的資訊於左側的控制sidebar。 


Step 4. 有關再組態Gitlab的二三事

        以下將針對步驟三發現的問題hostname問題與存取位置亂碼來進行處理。 首先我們得先找到gitlab的設定檔案:gitlab.rb ,這個檔案會放置在掛載點有關config的地方,以這例子來說便是在 "/srv/gitlab/server/config 裡面,如下圖


         打開該設定檔,並且針對 "external_url" 與 "gitlab_shell_ssh_port"進行設定,如下圖 


         設定完後,重新啟動gitlab便能讓設定生效。在這之前,讓我們先針對container registry進行啟用設定。

Step 5. 啟動Gitlab Container Registry

        如步驟四所提,相關的registry設定也是在gitlab.rb檔案內進行。主要是針對下圖提及的五個參數進行設定:

  • registry_external_url : 主要是來設定gitlab內部的nginx有關映像庫的網路位址
  • registry_enabled: 用來告訴gitlab啟用registry
  • registry_path: 用來指定映像檔的存放位置
  • gitlab_default_projects_features_container_registry: 是否預設建立專案的所屬映像庫
  • lfs_enabled: 讓gitlab支援大檔案
          設定完成後,重啟gitlab讓一切設定生效。

       

          在等待gitlab重啟時,來設定一下hostname,以便讓系統能夠符合方才有關網路位置的設定。 開啟/etc/hosts,並且進行以下設定。(主要是在127.0.0.1後面加入方才定義到的網路位置)

         

Step 6. 查看結果

          打開系統的瀏覽器,並且利用方才設定的網路位置(augu.gitlab)進行存取。不僅git的存取連結正確反應設定,專案的registry也顯示出來了。


Kubernetes Port 配置


   Master

Worker

          在一個壁壘分明的網路環境下,安裝Kubernetes與相關套件時,必須要明確清楚通訊的埠號,以便進行防火牆的設定。除了基礎套件如官網所述的通訊埠號外, Kubernetes的一些套件安裝,主要是透過Deployment方式來進行佈署,比如說flannel, calico, kube-proxy, 等。在進行配置時,可以利用hostNetwork的屬性設置,來排查那些元件可能在運行時,在主機上直接開出聆聽接口,然後再到各元件的官網上去查詢預設埠號。上述兩張圖主要是基於基礎套件與目前網路上最常見的deployment配置,列出主節點應該要開通的埠號,以及工作節點需要開通的埠號,作為安裝者的參考。

什麼是微服務 (microservices) 架構

       
     

        微服務架構是一種設計軟體系統的方式與風格。有別於原有的單體式系統,它進一步的將所有軟體元件從運行在單一系統的框架,改變成為分散式的服務結構,進一步地去解決單體式系統的系統痛點。常見的單體式架構有以下的困擾 :

      1.  技術框架僵化

          囿限於大一統的系統框架下,讓各元件的實作方式必須單一化,無法去採用最適的實作語言或者是相關的軟體套件。

       2. 牽一髮而動全身的修改

          單體式系統的任何變更,都將涉及整個系統的更新與變動。大型系統的更新與變動,不僅是在編譯準備或者是測試,都會隨著系統變大而日益痛苦。

       3. 無效率擴容           

          單體式系統含括了系統所有功能項目,有些元件可能是高耗CPU,有些則是高耗I/O;有些工作比較繁重,有些則比較輕鬆。但擴容需求產生時,由於單體式系統的不可切分,通常只能面對全系統的擴容,而無法以有效且針對性的進行效能增加。

       微服務在上述的背景下被提出,並且試著解決這些困擾。本篇文章將以Martin Fowler的專欄內容為參考,簡單扼要地探索微服務的樣貌。

       從Martin fowler的專欄[1]裡可以看到以下簡短的描述:

      the microservice architectural style [2] is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.

     簡單地說就是微服務架構為一群有各自特定目標且獨立運行的服務元件所組成的系統。各元件有獨立的資料存儲空間與事務邏輯,而各元件之間利用標準而輕量的通訊協定進行系統層級的協作,因此各服務均能被獨立的佈署與替換。

     看完上述扼要的定義後,再從Martin Fowler專欄內所提及的微服務特徵來進一步了解微服務的概念,並且了解在建構微服務的系統時,應該考量的要素。系統的設計隨著需求與發展,往往會有相應的取捨,能夠符合所有特徵自然是好,但若無法符合,至少可以知道改善的方向或者是取捨了些什麼。

       1. Componentization via Services

           所謂的元件是指可被獨立升級與替換的軟體元件。因此在設計系統時,我們將有相同業務目標的功能聚集,並且獨立服務化。各服務因此可以被單獨地更換或者是升級,而不會進一步影響其它服務或者是系統的正常運作。以上的設計奠基於完善地介面設計與定義,因此在介面下的更新,並不會對系統或者是其它的元件造成太大的影響。

       2. Organized around Business Capabilities

           常見的組織分工往往會按人員技能不同而進行水平切割。比方說,有專業的UI/UX團隊、專業的前端團隊與專業的後端團隊等,這種分工模式往往會造成較高的溝通成本。基於康威定律,我們也可以進一步觀察到系統設計偏向水平切割,而難以採用微服務的設計概念。一個微服務設計架構下的團隊,可以明顯看見團隊內的技術完整性,也就是垂直分工的協作模式。各服務元件圍繞著本身的業務邏輯,並且由有完整技術鏈的小型團隊各自負責所屬服務元件的開發。小團隊的作戰模式,不僅降低了溝通成本也加深了團隊成員對於服務元件業務邏輯的專業度。說到此,肯定有人會對於微服務的團隊成員數目感到疑惑,到底一個以微服務作為設計原則的團隊有多大,這個答案其實很難有個明確的數字,因為這也牽涉到組織人力資源的配置和服務元件的顆粒度大小。舉個例子來說,Amazon提出所謂的「兩塊pizza」的概念,也就是說一個團隊大小剛好就是兩塊pizza能夠餵飽的大小。而以我自身的經驗來看,大致上是兩周可以妥善完成一個完整功能集的人數。

       3. Products not Projects

          常見資訊系統開發的分工結構為研發工程師負責系統開發,開發完畢後,開發團隊寫下完善的指導手冊,並且交付維運單位進行日後維護,然後研發團隊分派到新的研發專案上。這樣的分工結構,很難有效解決快速變更的開發需求。另外,在溝通成本以及責任釐清上也都會產生不效率的情況。因此在微服務設計架構思維上,強調將相關的服務元件開發當作產品開發而非專案開發,也就是說,由專責的開發團隊負責該元件的一切開發與維運責任直到產品日落為止。

       4. Smart endpoints around dumb pipes

           微服務架構下,更強調服務元件本身的內聚力。也就是說,服務元件應該更妥善地包裹負責的業務邏輯,然後進一步提供簡單的接口讓外部的其它服務取用,其它的服務只管知道如何從接口獲得它要的資訊以及自身的業務邏輯要如何善用該資訊。完善封裝的端口需要搭配的便是有效且簡單的通訊機制,通訊機制本身不應該載負業務邏輯且應該採用更輕量且中性的通訊模式,比方說RESTful或者是Message Queue。

       5. Decentralized Governance       

           有別於單體式系統,微服務架構允許服務去採用各自最適的技術方案解決服務內的業務功能需求,無須捆綁在單一技術堆疊之下而無法動彈。這是一個讓系統設計得到可以進行充份選擇的權利,鬆綁了原先的不自由,但這並不代表研發團隊非得因為這樣而擁抱多樣化的技術堆疊,因為這涉及了人員技術的熟稔程度與日後維護的成本。另外,這樣的概念能夠被落實也有賴於前述第三點所提及的特點,因為團隊對自身的服務元件有妥善負責的義務,因此可以讓元件在技術選擇上,得到一定的彈性與效率。

       6. Decentralized Data Management

           在單體式系統下,設計偏向於單一資料庫系統的建置,然而這往往會導致設計上的一些困擾,比方說一樣物品的屬性,從不同的角度去觀察往往有不同的意涵與表示的樣貌,然而在單體式系統資料庫上要顯示這樣不同的觀點其實並不容易。沿著各自服務邊界所設計的微服務有明確的功能範疇,搭配上獨立的資料庫,便可以輕鬆地以各自業務角度去解釋與存儲資料。然而這樣的好處其實也不是完全無成本,分散式的系統所要面對的就是所謂的資料「最終一致性」的取捨。由於服務資料各自存儲與管理,必然會產生同質不同義資料之間的同步遲延問題,這問題將有賴於各服務對於資料過期的處理方式與準則,讓資料管理去中心化與同步遲延兩者之間取得平衡。 

      7. Infrastructure Automation

           這項特性其實就是目前最為人所樂道的運維技術風格──CI/CD。隨著目前公有雲服務商提供越來越多高彈性的運維環境,將枯燥而重覆性高的運維工作自動化,可以說是一個重要的趨勢。但在自動化思維下,所必須要強調的一個前題則是服務元件的測試周全性。在進行運維佈署自動化的同時,針對測試的自動化執行與監測也相對重要。

      8. Design for failure

           微服務架構設計使得軟體系統內的溝通線更為複雜,使得服務在設計當下需要更積極地去考慮服務請求的失敗和相應的處理,以避免服務停擺、崩潰或者是資料錯誤。除此之外,對於各服務的監測與容錯測試也應該更為積極,讓錯誤的訊息能即早被發現並且處理,而運維系統也應該提供更妥善的自動復原的功能,來進一步加強系統的穩定性。

      9. Evolutionary Design

           由於系統需求的變化、功能演進與快速更迭的需求下,服務的拆分與合併在微服務的概念下,更容易被實現,而微服務的開發者也更能擁抱這種循序漸進地改變方式,讓系統的需求變更,能受到妥善的控制,而不使整體系統產生過大的衝擊。至於拆分的準則,可以從服務功能是否能被獨立替換或者是更新,作為其邊界的要件;抑或者是按照功能本身的業務關聯性進行拆解。如果遇到服務更新,屢屢會產生同時變動的情況下時,也可以進行合併,讓各自服務的內聚力有效地提升。俗話說的好,軟體系統唯一不變的就是它的易變性,漸進且逐步詳細的設計與實作方式,才能更有效地提高系統的完整性。


      微服務的發展既是系統設計上的需要,也是相關技術與流程改善下所催生出的結果。講到這邊,難免又會討論到是否微服務就是軟體的銀色子彈。答案應該仍然是明確的──不是。微服務雖然針對固有的單體式設計缺點而來,進一步改善了原有的缺點,但微服務本身所引進的成本也是明顯的,比方說,分散式系統的管理問題與開發資源問題等。相對於單體式系統的初期運維成本和門檻,微服務架構是明顯高了許多。因此,在系統設計初期,並不建議馬上從微服務架構起手,仍然得按照自身的需求,進行系統的設計並且在合適的時機,進行架構上的轉換與改善,讓業務發展與資訊系統可以相互配合,而此一合適時機則有賴於組織軟體能力的成熟度、軟體設計的模組化和真實需求的發展,才能找到答案。

    

------------------------------------------------------------------------------------------------------------------------- 1: https://martinfowler.com/articles/microservices.html
2: The term "microservice" was discussed at a workshop of software architects near Venice in May, 2011 to describe what the participants saw as a common architectural style that many of them had been recently exploring. In May 2012, the same group decided on "microservices" as the most appropriate name. James presented some of these ideas as a case study in March 2012 at 33rd Degree in Krakow in Microservices - Java, the Unix Way as did Fred George about the same time. Adrian Cockcroft at Netflix, describing this approach as "fine grained SOA" was pioneering the style at web scale as were many of the others mentioned in this article - Joe Walnes, Dan North, Evan Botcher and Graham Tackley.