數人云上海&深圳兩地「容器之Mesos/K8S/Swarm三國演義」的嘉賓精彩實錄第一彈來啦。今天是廣發銀行數據中心的運維老兵沈偉康關於傳統運維與容器適配的全方位分享,萬字長文傾情奉上~java
沈偉康,廣發銀行數據中心程序員
運維中年人,經歷傳統運維,建設自動化運維,嘗試雲計算運維web
你們好!我是廣發銀行的沈偉康,從傳統行業出身,如今還在傳統行業的坑裏,今天分享的內容是在傳統運維會遇到的各類想作可是不必定能作,又不得不去作的事情。算法
不管是傳統運維仍是自動化運維, CMDB是一個很重要的核心。若是Docker沒有本身的CMDB,也會有不少用起來不自在的地方。數據庫
從環境這方面來談一下CMDB對Docker的做用。若是全部事物都能標準化,那事情都會很簡單、很便利,這是一個很好的理想,但在現實裏尤爲傳統行業想把標準化進行推廣,實現起來有必定的難度。編程
它會面臨一個問題:差別化。差別化多了之後,Docker就會有各類各樣的鏡像,不一樣應用之間會有不一樣的鏡像。即使是同一個應用,不一樣的月度版本下都有不一樣的鏡像,好比升級了某一個庫,鏡像也是不同的,這時候應該怎麼作呢?這時按正常邏輯,會給它作自定義。若是要自定義Docker的一個鏡像,能夠經過DockerFile來作。服務器
如今各大廠商的產品裏面幾乎都有一個WebUI的界面讓用戶去選擇一些內容,能夠自主編程一個DockerFile。若是隻是單純地把裏面一些FROM、ADD參數直接加到頁面上去選的話,至少要有必定的適配過程。網絡
因此借鑑你們慣用的傳統運維思路,並配有一個與之前傳統CMDB對接的點,廣發銀行有以下幾個作法:架構
第一,操做系統。對着DockerFile的FROM,讓它在列表裏選擇這個應用要跑在什麼樣的OS裏面,包括它的版本等。app
第二,經常使用軟件。在下拉框選完以後是一個ADD,例如選了JAVA,要在Docker運行環境裏面給它環境變量,容器裏要找到JAVA相關的命令。Tomcat或者其它軟件,都會有一些環境變量。因此在經常使用軟件這塊,如今打包的大部分是Tomcat或者JAVA類軟件,把一些特定要使用的環境變量,根據這個頁面選完以後,用ADD添加軟件包的同時,用ENV把它設到環境變量中。
第三,需求包上傳,對於差別化來講很重要。例如這個項目組的應用依賴某個Python版本,另外一個項目組又依賴另外一個版本的Python,又如OS自帶的一些so庫,它到下個月度版本的時候又要依賴不一樣的版本,可是不想把這麼多版本都作成不一樣的鏡像提供不一樣的服務市場,就會有一個需求包上傳,這個包裏把項目組應用需求的除了經常使用軟件跟OS基本的套件以外的其餘庫或者軟件打包,好比Python的安裝包,RPM包,還有一些應用自身的東西,如啓動的時候須要加載的證書之類都打包在這個包裏。
第四,執行安裝。這個包打完以後,爲它定義一個執行安裝過程的入口,即一個安裝腳本,約定的時候讓它將安裝腳本放在壓縮包的第一個目錄下。這個包就至關於有了setup.sh的一個入口,這個入口讓應用去定義安裝什麼、如何安裝以及安裝順序。
第五,映射端口。對應DockerFile的EXPOSE,應用、服務或者容器啓動完以後,會對外暴露哪一些端口。
第六,存儲使用。存儲路徑選擇對應VOLUMN,若是IO要求比較高就不用容器內部的AUFS,若是要求持久化就用外掛路徑,若是宿主機之間共享就須要放到一些分佈式存儲或者NAS這種共享存儲裏面。
第七,啓動運行。等價於CMD,讓項目組在一個頁面設置完以後,把它放到與傳統CMDB對接的一個Docker專屬的CMDB裏。
這個CMDB主要的內容總結有三部分:環境需求配置,配置文件管理,應用運行配置。應用運行配置是項目組在一個頁面作完配置後,運行和編譯的時候就不用再填參數了,全部不一樣的項目都在這裏一次性設置好。
管理的緯度,配置是一個應用加一個項目標識。這個項目標識能夠理解成是按月度或者是按照本身喜歡的命名的規則,如海外版本和國內版本。但對於廣發來講,用得比較多的是月度的標識,例如一個應用有ABC環境,分別對應幾月份版本。
這裏把鏡像分紅三類:第一類,基礎環境鏡像,上面只有OS還有一些依賴庫的安裝,一個運行的中間件。它會有一個命名規則, 「應用名+項目標識」,好比「ABC_」,而後「201701」,就是2017年1月份版本,「base」表示鏡像的tag是base,表示這是它的一個基礎環境鏡像。
第二類是應用版本鏡像,在第一個基礎環境鏡像上加了編譯後的目標碼,不帶環境差別的配置文件。這時命名規則是「應用名+項目標識」,tag變成了目標碼的時間戳,在持續集成整條線下有一個惟一的標識,就是時間戳。固然,你們也會有其它各類各樣的惟一標識選擇。
第三種叫應用運行鏡像,它是上面應用版本鏡像再加上環境配置文件。開發環境有它本身的數據庫,各類不一樣的環境都會有本身的數據庫配置,這個配置是不同的。若是說抽象成配置中心的話,它能夠管理,但仍是用配置文件。命名規則是「應用名+項目標識」,再加「目標碼時間戳」和「環境」。環境包括DEV開發環境、TEST測試環境以及PROD生產環境。最後是「配置文件時間戳」,一個項目組在項目初始的時候定義的配置文件內容有四個配置項,過了一段時間可能變成五個配置項,因此仍是一個時間戳,即配置文件的時間戳,以此去標識一個完整的運行鏡像。
與傳統的過程項目相比,廣發的過程主要是搭建一個應用的OS環境,安裝相應的中間件,而後部署相關的應用目標碼。用Jenkins去持續集成出它整個應用版本鏡像。整個過程就是應用版本鏡像,加上測試的環境配置,它就變成測試環境的應用運行鏡像,加上生產的配置就變成生產環境的應用運行鏡像。
爲何作配置文件而不作配置中心?推廣配置中心的話,應用要改不少內容。傳統應用裏面不少配置都是寫在配置文件裏面的。若是要把配置文件改爲從一個庫裏面讀出來,舉例開發環境,它的IP要有一個配套的插件從數據庫裏面把配置抽取出來,取代它本來的配置文件,才能在環境裏面作它的開發;或者也能夠作一個相似Eclipse插件去作這個事情,但配套的東西仍是要不少。若是爲了上Docker要去推進這個事,它會變得很現實:第一,時間長;第二,阻力大。
另一個方法就是環境變量。相對數據庫形式的配置中心來講,環境變量稍微簡單了一點,可是它要求項目組有一我的去抽離出配置文件裏面各項的配置,而後轉變成環境變量,再告訴項目組 「本來的DBURL配置」,代碼裏面須要變成System.getEnv()來獲取DBURL,而再也不用getProperty讀出來。
因此廣發使用了一個配置文件包。這個配置文件包是一個tar,不會限制它有一個很嚴肅的名字,可是它的目錄格式規則有一個限制的規則,它的第一個目錄是最終訪問的子URL,也就是TOMCAT的webapps下看到的目錄。而後將全部的配置,假設最下面示例,應用有三個配置文件,要求它嚴格按照相對路徑,把最終的相對路徑打包好,打包成一個tar。
它按照war包的相對路徑將配置文件打包成一個tar。而後把這個tar上傳到不一樣的環境目錄,例如它有三個階段,一個是開發,一個是測試,一個是生產,那它就會有三個目錄,這三個目錄由不一樣的運維人員編輯,開發環境的原則上不用改,由於原本就是從開發來的;測試環境要由測試環境的運維同窗,把那些DBURL、數據庫用戶等配置按實際狀況修改,生產環境也相似。
以後用一個最簡單的DockerFile,即FROM應用版本鏡像,再ADD,將配置文件到指定路徑,假設是Tomcat就是webapps目錄下,由於ADD會自動解壓,自動地把它覆蓋成一個真正的相應測試環境的運行鏡像、測試環境的運行鏡像、生產環境的運行鏡像。項目組只要找一我的把這些配置文件抽出來就能夠了。好久之前咱們已經謝絕全部把配置硬解到代碼裏面去,因此這種場景不適合。在JAVA裏面直接寫一個環境的數據庫連接上面,可是它應該適用於把配置全部都抽離出一個文件裏面或者說某個文件裏面。
這是廣發銀行持續集總的框架。代碼用Git,有一個目標碼庫,以及配置庫。雖然上了Docker,可是沒有捨去傳統的環境。WAR包是持續集成編譯一次後的war包,存起來並開放給傳統部署的同事下載使用。配置庫是剛纔提到的存配置文件的地方。測試鏡像庫是獨立的,它們之間的同步是經過腳本去自動同步的,即export出來的鏡像,一個pull,一個push。
開發人員寫代碼,寫完代碼以後提交,提交完會由Jenkins自動下載回來編譯。在這個過程當中有一個FindBugs來作的代碼審查。而後編譯生成一個war包,這個war包到這一階段理論上與正常持續集成過程或者是人工編譯後的war包同樣。這時若是須要傳統部署,能夠經過FTP把war包下載回來,投產直接使用。
若是要用Docker,這個war包會加上它的第一個鏡像:應用基礎環境鏡像,生成它的一個應用版本鏡像;應用版本鏡像生成完以後,加上測試環境的配置文件,它就會變成測試環境的運行鏡像;這個測試環境的鏡像只要運行起來,就會變成一個測試環境;測試環境是由測試員測試的,或者由一個自動化的工具作自動化測試。
測試環境的運行到生產上來講也是一樣一個過程,廣發還有一個準生產環境,整個過程也都是相似的,準生產環境是與測試環境共用的。生產環境也是由版本鏡像加上配置文件。全部從應用版本鏡像生成運行鏡像的過程都是能夠不斷迭代自動化的,運行的時候就會在環境裏面跑起來。
在傳統運維裏若是拿到一個虛擬機,它有固定的IP或者DNS域名,想對它作什麼就能夠進去作,能夠查看數據或者性能,尤爲是在查性能問題的時候要看OS裏面的資源使用狀況,還有一些應用的狀態,包括OS的狀態。而這些東西到了Docker裏面,就會變得有不少的阻力。
若是Docker容器裏出了性能問題的話,要如何查?若是按照傳統的觀念,要SSH到容器裏面去作,例如說有一個應用,Tomcat到了90%,那是否必定要在生產環境要保留這個環境,讓應用開發的人去查?仍是直接毀掉它,從新起一個或者兩個,業務量就不受任何影響,這種事情因人而異。
另外一個方法,能夠把這些簡單的交互分紅兩類,一是查看類型的需求,嘗試經過外掛目錄,由於假設要查看生成的javacore、heapdump文件等,之前作法是在OS裏面使用kill-3生成heapdump文件,但若是把這些生成heapdump的動做歸結爲第三點操做類的話,是否是能夠直接在宿主機上放一個agent,要對哪一個容器作heapdump至關於讓用戶在頁面上直接選一個生成heapdump或者一個動做,而後由agent經過EXEC命令跑到容器裏面去作,儘可能禁止用戶直接跟容器進行交互。固然也有比較粗暴的,好比WebSSH。
應用更新的概念是服務沒有中斷。人們常說的滾動升級,在不少產品裏面都實現了。可是實現的層面或許是這樣的:假設有五個容器,滾動升級是按批的,第一批升級兩個,升級完以後毀掉舊容器,用新的兩個容器去換掉舊的兩個容器,隔一段時間再升級後面的三個。這種按批升級會有一個須要關注的地方——容器銷燬的時機。
常見的雲平臺調度算法裏,容器狀態OK的時候,調度平臺會把本來的容器替換掉,但這個時候容器狀態OK並不等於服務可用,由於容器裏的Tomcat端口起來以後,它就會說這個容器是已經OK了,可是Tomcat起來以後的服務加載這個過程,快的話能夠幾秒,慢的話例如一個很龐大沒有作任何微服務化改造的應用,就會是一分鐘。但這一分鐘之間,新的容器已經替換掉舊容器,那麼這一分鐘就悲劇了。因此服務加載的時間不可以忽略。容器銷燬的時機是要大於容器狀態OK的時間加上應用自啓動的時間,在容器的調度上至少要用戶每一個項目組加上服務要起的時間,要十秒就填十秒,十秒鐘以後再按照按批滾動升級的過程去作。
如今傳統運維裏面一個應用可不可用,尤爲是在銀行裏可不可用影響是很大的,因此廣發銀行在運維體系裏有不少應用對外暴露的一些服務接口,而後經過自動化的監控工具去監控它的可用性。從這個角度來講,調度器能夠與傳統監控對接,經過調用傳統運維的內容獲取到一個服務狀態可用的時候纔去執行五個升級兩個,再升級三個這個動做。
第二要關注流量轉移,在服務啓動完以後,經過負載均衡自動去設置權重把新的流量轉移到新的容器裏面。由於有一個容器銷燬的時機,因此這個容器也不會銷燬,可是不要把新請求轉給它。在傳統行業,若是新容器或者服務好了、舊容器就立刻關掉的話,應用的架構不必定可以支持。在生產上尤爲是在銀行,例如在轉帳的時候有一個交易流程,在一個容器裏面規定要一、二、三、四、5步發生,並非第一步作完放到一個地方,而後由其餘任何一我的去調第二步均可以。若是把一、二、三、四、5都串到一個容器裏面,作到第三步的時候舊容器服務被停了,又沒有對外的轉帳接口去把錢轉到別人那裏去,後果就很嚴重,因此流量轉移工做包括銷燬的時間是要慎重的。
在不少廠商那裏都會聽到灰度發佈,可是大部分都只是說沒有中斷。這個中斷是否是真的沒有中斷,有待考究。廣發會強調另一個A/B TEST。若是經過負載均衡去設置,舉一個簡單的例子,經過F5或者其它LVS負載均衡去設置來源IP來選擇新版本仍是舊版本是沒問題的。可是來源IP是能夠欺騙的,像之前Pokemon go出來的時候,人不在國外,可是搞一個國外的IP也能夠上。因此在應用能夠接受的狀況下,灰度發佈應該由應用的人去作,例如每個帳號生成了惟一的ID,由ID決定他們是用新版本仍是用舊版本。儘可能不要用負載均衡來作灰度發佈。
如今彈性擴容至少會講到兩點:一個是業務時間點,好比九點到十點這個業務時間點,能夠把容器從十個變成二十個;另外一個是經過監控策略來自動化彈性擴容。擴其實很簡單,從十個變成二十個沒什麼問題。可是擴完以後要縮回來,好比要應對某一個節日「雙11」,找一個特定的時間點給它加OS,可是加完OS以後縮回來須要一個停機時間窗口,或者先從F5上Disable而後回收。
可是到了容器,若是聽任調度器自動回收、自動縮容,是否真的可取?和剛纔提到的銷燬時間同樣,是否要與傳統的監控、服務可用的平臺作一個對接後再縮?若是能夠作到纔是真正可以縮的,而不是如今頁面上選擇五個縮成三個,它就真的縮了兩個,至少咱們在生產當中是不敢這樣作的。
均衡資源。假設傳統運維裏,把Docker的宿主機交給傳統運維的監控平臺去監控,但這時監控平臺判斷這臺宿主機已經CPU使用率90%了, Docker調度器與傳統運維的監控平臺作對接的時候,爲了避免影響應用服務是否須要把容器給遷走,是所有遷走仍是把CPU消耗高的遷走,或者把啓動時間最長的遷走?做爲一個程序員永遠都不敢說本身寫的程序跑了一段時間以後會不會比剛剛跑起來的時候更穩定。這種策略在生產實踐是很關鍵的,須要一個博弈的過程。如今不少廠商自身支持各類各樣的彈性,可是彈性縮是否真的可以支持而不會有業務影響,是有待考究的。
目前來講,沒有任何一個廠商說「只要用個人平臺,包括把個人平臺堆積到傳統運維以後,能夠作到想縮就縮,不會讓用戶帳戶丟了錢」,不用讓業務員去作一個回滾的操做。在傳統運維裏面,若是應用開發的項目組能夠按照各類各樣優雅關閉的特性去寫應用,沒問題。但畢竟業務程序是由人寫的,人是不可控的。
在傳統的應用容器化運行後,會有一個歸檔和查看日誌的問題。目前項目組把它改爲標準輸出,再由自動的一個收集平臺,例如廣發銀行如今是用數人云的一個logagent去自動收logstash的,而後存儲到ES裏面,由Kibana去展現。若是要對接傳統運維,也可讓項目組把應用的目錄放到一個外掛的文件。傳統的監控裏面有一個外掛支持在某一個路徑下監測全部的配置文件,因此只要把它放到一個外掛的共享存儲或者分佈式存儲,而後再把這個外掛路徑做爲一個對接的入口到傳統的日誌管理平臺裏面就能夠了。
另外一種是之前作CloudFoundry時,他們會強調應用要把全部的日誌做爲流寫入到這個平臺裏面,例如FLUME。若是隻是簡單粗暴地把應用的日誌寫進去,會有時間亂序的問題,固然這個問題是能夠解決的,但若是A容器實例跟B容器實例都是屬於同一個應用,就會有這裏來了一句以後,那裏下一句話又來了的狀況。要截取某一個加密的日誌,須要開發人員配合在日誌裏面加各類各樣的標識,例如如今要查詢某一個業務量的日誌,要根據業務量的代碼去查,查完以後它可以抽取出來在同一個容器裏面的那一段日誌,那如何作到在同一個容器?無疑在寫日誌的時候,也須要把容器的標識放在日誌裏面。
若是作實時,用syslog就能夠。若是隻是日誌收集,ELK也是能夠知足的。爲了減小應用改造,單應用日誌時就重定向到標準輸出。若是是多個日誌,如今考慮的方案是把它放到一個外掛目錄,再由專門的容器去收上送,而不會經過其它的agent。外掛目錄也是能夠對接傳統的應用日誌監控平臺,傳統運維裏面能夠有一個監控平臺去監控這個日誌的增量更新裏面有沒有應用關注的關鍵字,若是有這個關鍵字的話,就會發短信提醒說應用出現了什麼異常。
在傳統行業裏面要對接傳統監控必定是必然的。對接的過程能夠分紅幾個緯度,一是Docker與平臺自身的監控,能夠經過接口去對接、上送數據。另外一個是宿主機的監控,宿主機是一個物理OS,傳統監控裏面如何折騰這個OS已是很標準或者很天然的動做。
容器監控,能夠嘗試cadvisor或者其它在業界應用比較多的東西。應用監控比較難,傳統運維會關注應用CPU和內存使用率,以及數據源的鏈接詞,或者一些線程數,當達到某一個值後,就進行告警。而到了容器裏面,要把它抽離出來。舉一個例子,它能夠把Tomcat裏面的Apache公佈的那一堆指標經過Tomcat的接口給暴露出來。暴露到哪裏,是須要額外去定製化、去收集容器裏面的Tomcat,因此對不一樣的工具要作一個對接的過程。
在容器化的網絡裏,除了一些對外暴露的端口, Docker DB就不用說了。可是在應用的端口裏面,假設是HaProxy, HAProxy的端口可用不表示相應容器的服務是可用的,能夠嘗試直接在監控HaProxy這些端口服務的同時直接讓應用暴露服務可用性的一個接口,直接監個應用接口的返回碼到底是200或是非200就能夠了。
應用改造只列了四點,並不表示應用改造只有四點,而是努力讓應用只作這四點,只關注這四點就能夠了。
第一是節點差別化,在環境裏假設有三臺應用服務器,其中一臺應用服務器作了一些其它兩臺應用服務器沒有的事情。這種狀況在廣發或者金融行業裏都是比較多的。到了Docker以後,就儘可能不要作這種事情。
第二是持久化,在廣發的環境裏面,舉一個數據,OS裏面的外掛存儲不多少於500G的。一個OS若是要作動態擴縮,裏面的存儲越少越好,由於不須要讓它作其它事情。若是要把一個文件持久化,是由於IO的性能問題須要把它外掛,仍是日誌不屬於容器銷燬而持久化?或是這個容器在A宿主機跑起來,下一次在B宿主機跑起來,都要讀寫一樣一份東西,那麼就搬到NFSDATA的一個文件裏面,選NAS data做爲一個volume,配置文件配上那個路徑。
在內存數據裏面,建議作一個剝離,好比剝離到REDIS,可是若是在有統一的應用開發框架狀況下要把一些東西剝離出來,只要有框架內的應用去改造就能夠。若是不是的話,能夠採用一些自然比較支持這種轉換的,例如把數據放到Redis,有一些框架直接支持改一下配置就能夠,另外一些框架則是不行的。
第三是可變性。之前傳統運維會把上游IP抓下來,下發到下游。但容器的OS環境變量是可變的, IP地址獲取方式,變成從環境變量獲取。Hostname是不建議使用的,之前看到把Hostname做爲一個標準傳到日誌裏面或者直接用來起日誌共享目錄的一個名字,到雲裏面跑得久越讀不懂,至少IP的名字都讀不懂,由於沒有一我的去幹預它的Hostname。
第四是易處理,快速啓動,優雅關閉。以微服務化改造來講,可以作到易處理,即隨時啓動的時間不會超過幾秒,隨時均可以關閉,若是應用上Docker而且要跑得很好的話,那必定要去考慮這方面的事情。
分享就到這裏,謝謝你們。