如何系统搭建现代 Web CI/CD
大家好,我是若川。今天分享一篇00后寫的CI/CD直播文字稿。之前發(fā)過他的故事:一位00后前端2年經(jīng)驗(yàn)的成長歷程。我最近組織了源碼共讀活動,感興趣的加我微信 ruochuan12。
本次直播錄播鏈接:https://live.juejin.cn/4354/595741[1]
開始
歡迎大家來到掘金小冊8月的首場直播,我是本次直播的主講人王圣松
今天給大家?guī)淼闹黝}是:如何系統(tǒng)搭建CICD。話不多說,咱們就立刻開始
自我介紹
那么在開始之前呢,我先做個自我介紹。我叫 Janlay,目前任職于 Gitee Devops產(chǎn)品前端團(tuán)隊(duì),是一位前端開發(fā)工程師,主要負(fù)責(zé)參與團(tuán)隊(duì) Devops 產(chǎn)品的前端開發(fā)。曾經(jīng)主導(dǎo)過 CI/CD 相關(guān)產(chǎn)品的前端開發(fā),同時也是掘金小冊《從 0 到 1 實(shí)現(xiàn)一套 CI/CD 流程》的作者。
現(xiàn)狀與困境
在開始之前呢,我們先來聊一聊前端的CICD掌握現(xiàn)狀。
現(xiàn)狀
這是我在之前和其他的一個前端開發(fā)工程師的聊天。可以看到,前端工程師對于 CI/CD 的方向的興趣還是比較大的。但是也比較焦慮。并且有的大廠面試還會問到相關(guān)的問題,里面也有涉及 Kubernetes 相關(guān)的技術(shù)。
那么大家對此的掌握度又如何呢?
對 162 個前端 CI/CD 工具的掌握度調(diào)查
我在去年寫小冊之前,對 162 個中高級前端做了個關(guān)于 CI/CD 工具的一個掌握調(diào)查。其中有一部分同學(xué)已經(jīng)在大廠,或者已經(jīng)是一個前端的一個 leader 了。
大家 Docker 的實(shí)踐程度以及掌握度是非常非常低的,兩成都不到只有19%。這其中對于 Kubernetes 的掌握程度甚至不到 1%。162 個人里面,僅僅只有一個人實(shí)踐過。
對于制品庫這類比較新鮮的概念了解更少了,不了解的人有很多,自研的人也有一部分。構(gòu)建工具,部署工具,這些大家可能聽的比較多,常見的比較多,掌握程度還算好。但是也有相當(dāng)一部分同學(xué)對這部分還不是很清楚,或者說在采用手動部署。其實(shí)不是很適應(yīng)時代發(fā)展和不利于提高效率的。
Devops 工具鏈
這個是某咨詢公司對于 Devops 工具鏈的一個統(tǒng)計(jì)圖譜。從全貌上來看呢,這些工具其實(shí)還是比較多的。除了持續(xù)構(gòu)建持續(xù)部署之外,還有像監(jiān)控運(yùn)維,自動化測試,流程管理,容器編排這些內(nèi)容。
代碼托管 Git 庫就有七種。CI 也不止 Jenkins,Gitlab CI 這幾個。里面還存在著其他的一些工具鏈,其實(shí)是比較多比較雜的,這些都是 CI/CD 相關(guān)的一個工具生態(tài)。有了這些工具生態(tài),我們才能夠?qū)I/CD的價值完全釋放出來。
那么這樣看來,CICD只是作為自動化工具。那么它的意義有多大呢
為什么要有自動化?
那么為什么要自動化呢?大家可能聽說過一個開發(fā)模式,叫做瀑布流。
左上角就是瀑布流開發(fā)的方式。傳統(tǒng)瀑布流的開發(fā)方式是:把需求的排期給固定住,中間是不允許修改需求的,直到最后完全上線。測試的流程也是比較復(fù)雜的,上線流程也是比較復(fù)雜的。
我們大家可以看到,在這個圖里面開發(fā)和測試之間隔著一堵墻,測試和運(yùn)維之間也隔著一堵墻。那么在所有的功能開發(fā)完畢之后才能交給測試,測試測完所有功能之后才能再交給運(yùn)維上線。那么這種開發(fā)模式在今天的互聯(lián)網(wǎng)時代的話,其實(shí)已經(jīng)嚴(yán)重脫節(jié)了。
互聯(lián)網(wǎng)時代的產(chǎn)品需求變動是很頻繁的,瀑布流是根本適應(yīng)不了的,所以就有了敏捷開發(fā)這么一種方式。將原有瀑布流的一大塊的需求,進(jìn)行了一個拆分,拆成了一個一個迭代。每個迭代里面,有這個迭代相關(guān)的需求,一次迭代的需求開發(fā)完畢之后,交給測試,原有的一個整個大的流程變成了一個小步快跑的方式。研發(fā)做一部分需求測試,測試就測一部分,上線就上一部分。產(chǎn)品在早期的話就可以得到一個市場的快速驗(yàn)證。
當(dāng)然需求的頻繁變化,在當(dāng)今是迫不得已。因?yàn)闀r代發(fā)展是比較快的。如果要是說大家都能看到未來的市場走向和用戶需求的話,可能京東淘寶也不會允許拼多多存在。
但是敏捷的劣勢隨即而來了。由于上線的流程不是自動化且是比較復(fù)雜的,所以當(dāng)開發(fā)和測試完成了之后,需求依然要等到固定的時間去進(jìn)行上線。因?yàn)榘l(fā)布流程較多且復(fù)雜,還是無法把第一時間把需求統(tǒng)一驗(yàn)證,因?yàn)樽詣踊@道門檻卡在了這里。
于是 Devops 就來了,他把運(yùn)維和開發(fā)測試的墻也打破了。我們上線部署構(gòu)建的事情。可以去實(shí)現(xiàn)一個自動上線,自動構(gòu)建,自動部署。這樣的話,我們發(fā)布的成本就變小了,產(chǎn)品發(fā)布的周期也加快了。上線的權(quán)利從運(yùn)維就轉(zhuǎn)變成了研發(fā),轉(zhuǎn)變?yōu)榱藰I(yè)務(wù)方。這也就是自動化構(gòu)建部署的意義,它可以讓需求更快的投入市場驗(yàn)證。
所以說,自動化不僅是在研發(fā)層面提效,更可以影響業(yè)務(wù)的快速發(fā)展迭代。所以從研發(fā)同學(xué)角度來講,掌握自動化構(gòu)建和部署比較吃香。
演進(jìn)歷程
在剛才,我們了解了自動化在業(yè)務(wù)中的意義。接下來我們就看下 CI/CD 的演進(jìn)歷程,看下為了盡可能地自動化,技術(shù)層面都是如何一步步演進(jìn)發(fā)展的
遠(yuǎn)古時代 FTP + Tomcat / Nginx
首先是遠(yuǎn)古時代的構(gòu)建部署。其實(shí)說早也不是很早,我在 18 年參加某次技術(shù)分享時,與一位后端工程師有聊到這部分,他告訴我就是在使用 FTP 方式進(jìn)行部署。很多學(xué)校教材中甚至還會教學(xué)這部分。的確,在早期的網(wǎng)站部署中,FTP 的確比較常見。
首先是在本地將代碼構(gòu)建。
在 FTP 盛行的年代,Webpack 那個時候可能都沒有,可能只有幾個 JQuery 頁面,或者是靜態(tài)頁面,將頁面文件直接扔到服務(wù)器。
很多的做法都是和后端的代碼都放一塊兒。比如像 Tomcat、Apache。
隨著時代的發(fā)展,FTP 的方式實(shí)在是太落后了。我之前有講到:產(chǎn)品需求需要快速投入市場驗(yàn)證,除了需求要進(jìn)行拆分之外,上線的流程也要做到自動化,才能實(shí)現(xiàn)快速投入的市場的這么一個目標(biāo)。
沒有自動化的操作,風(fēng)險也是比較大的。比如說有時候眼花沒有操作好、不小心誤觸、或者不小心刪除了文件,導(dǎo)致服務(wù)和系統(tǒng)出現(xiàn)問題。這種情況在歷史上發(fā)生了 n 多次。而且自動化也解決了很多重復(fù)的一些人力。
一個操作,機(jī)器可以自動化去執(zhí)行,但人去執(zhí)行,這個對于成本而言就是一個浪費(fèi)。
自動化序章 Shell + Nginx
于是人們對于自動化最初的探索就是寫 Shell 腳本,可以通過編寫 Shell 腳本來實(shí)現(xiàn)自動化操作。首先在腳本里面我們將代碼拉下來,這里面少了一步 git fetch 的命令,上面大家可以腦補(bǔ)一下哈哈。將代碼拉取下來之后,進(jìn)行一個 npm run build,編譯之后扔到對應(yīng)的服務(wù)目錄。
上圖這個就是有獨(dú)立部署服務(wù)器,我們可以考慮采用 SCP 的方式將編譯后的壓縮包扔到目標(biāo)服務(wù)器。使用 SSH 命令遠(yuǎn)程操控服務(wù)器進(jìn)行一個解壓。比如上面第10行: tar zxvf,將 tar 包解壓后,再 mv 移動到對應(yīng)目錄。
這就是我們對于自動化最初的一個探索,那么在今天也有相當(dāng)一部分業(yè)務(wù)還是在使用這種方式。包括像我們之前的一些內(nèi)部的、一些小的業(yè)務(wù),也是在使用這些方式進(jìn)行部署。這也側(cè)面印證這部分方式的成本還是比較低的。
那么,這方面成本是比較低的,而且不需要額外的服務(wù)依賴,不需要多么復(fù)雜的操作。也不需要多么復(fù)雜的架構(gòu)。
但是隨著業(yè)務(wù)增長和團(tuán)隊(duì)人數(shù)擴(kuò)張,就可能變得不是多么很友好。
首先你可以在服務(wù)器上執(zhí)行這個腳本,就說明了你有服務(wù)器的權(quán)限。那么大家都想去構(gòu)建的話,密碼公鑰的泄密的風(fēng)險就加大。人人都可以去訪問服務(wù)器,萬一有人想使壞刪庫跑路;或者說不小心刪除了某個文件,不小心誤操作導(dǎo)致了服務(wù)模塊,也是一個災(zāi)難性的問題。
其次,他的操作交互也不是很友好。那么我們是不是可以利用軟件開發(fā)的一個思想,將這些真實(shí)的操作去做一個上層的封裝呢?提供給用戶一個統(tǒng)一的入口,用戶只能夠執(zhí)行你給的一個操作范圍,可以在界面上進(jìn)行一鍵執(zhí)行。
于是像很多公司,選用了 Jenkins,這個是非常經(jīng)典的一個構(gòu)建工具,擁有像可視化操作。而且它是有賬號體系的,你可以根據(jù)賬號去分配權(quán)限。不同的人看到不同的任務(wù),可以去執(zhí)行不同的任務(wù)。當(dāng)然他也有豐富的插件也可以進(jìn)行一個拓展,比如說像 git plugin、node plugin。也有非常開放的 API,可以去做一個自定義拓展。
可視化執(zhí)行 Jenkins + Nginx
我們用進(jìn)行一個自動化改造之后呢,一切看起來是比較美好的。在提前寫好 Shell 之后呢,我們一鍵執(zhí)行就可以完成你想執(zhí)行的腳本。
甚至 Jenkins,還給你提供給你像定時執(zhí)行這樣的一個功能。你還可以去搭配 Git 平臺的 Webhook 鉤子,在你提交代碼,或者說合并某個 pull request 的時候,Git 就會利用 Webhook,去調(diào)用你 Jenkins 的構(gòu)建觸發(fā)鏈接,對代碼進(jìn)行一個構(gòu)建觸發(fā)。
大家可以看到上面兩張圖片:左上角就是 Shell 腳本的編寫區(qū)域,右邊就是編譯的一個日志,這些都是可以在網(wǎng)頁中進(jìn)行編寫和實(shí)現(xiàn)的。
那么下面就是這個整體的流程。當(dāng)我們把代碼提交到倉庫時,這時候打開 Jenkins,去點(diǎn)擊這樣的一個構(gòu)建按鈕,接著就構(gòu)建完成了。或者說我們直接 push 到倉庫,觸發(fā) Webhook 鉤子,最后直接構(gòu)建完成。這是更加便捷的一種方式。
可是,有一天服務(wù)。不止你們自己用。例如現(xiàn)在很多公司在做 tob,你的服務(wù)不只是你自己在用,你要把你的服務(wù)拿到客戶那里進(jìn)行部署。
在這種情況下,如果你的服務(wù)需要非常復(fù)雜的環(huán)境安裝的話,是比較頭疼的。尤其在客戶變多的情況下,安裝環(huán)境也是非常的費(fèi)時費(fèi)力的,甚至說還會遇到說操作系統(tǒng)不一致的問題。例如在你自己的開發(fā)環(huán)境上是 Ubuntu,到了客戶那里就變成了 CentOS,有些環(huán)境依賴的安裝方式是不兼容的。
版本歸納也是一個大問題。尤其是每次版本包非常大,安裝部署都需要拉去特別重的安裝包,也非常費(fèi)時間。最理想的情況,是說我拿一個虛擬機(jī)一樣的東西,直接到客戶現(xiàn)場直接跑了起來。
Docker 在這個地方就派上用場了。它可以將你的運(yùn)行環(huán)境、服務(wù)代碼等之類的東西高度集成為一個鏡像。在你想要的地方,如果那個地方有 Docker 運(yùn)行環(huán)境,我們可以將 Docker 鏡像跑起來,就擁有了全套的一個運(yùn)行環(huán)境體驗(yàn)。
而且 Docker 的每個鏡像的更新都是增量的,只拿去拉取修改的那一部分,不需要每次都拉取全量的鏡像,也非常省空間省時省力。
容器時代 Jenkins + Docker + Nexus + Nginx 容器
于是我們將原有的服務(wù)用 Docker 鏡像跑了起來,然后構(gòu)建編譯構(gòu)建包變成了編譯鏡像。在這里還會引入一個新東西 —— 制品庫,右邊這張圖就是制品庫。我們將每次編譯后的產(chǎn)出都被稱為制品,存放這些制品的文件存儲系統(tǒng)就叫制品庫。
右上角這張截圖是 Nexus 的一個制品庫。像Java也有自己的包規(guī)范 Maven、Node 的包規(guī)范 NPM、Docker 的鏡像,這些 Nexus 都可以去進(jìn)行一個創(chuàng)建和托管。所以對于一些中小團(tuán)隊(duì)而言,Nexus 還是比較萬能的,也是比較省成本的。有這么一套東西前后端都可以去用。
于是流程就變成了:當(dāng)我們?nèi)?gòu)建鏡像的時候,構(gòu)建完畢,接著就會去 push 鏡像到鏡像庫。原有的構(gòu)建代碼變成構(gòu)建鏡像,push 到鏡像庫后告訴遠(yuǎn)程服務(wù)器你要拉取鏡像。
像左邊這張圖最下面里面有一個 SSH 命令:這時候它就會操作 151 服務(wù)器利用 Docker 命令將鏡像拉下來,然后將容器停止掉,刪掉,再跑一個新鏡像。那么這樣的話,我們的服務(wù)和它所需要的運(yùn)行環(huán)境是高度集成的,你不需要擔(dān)心去分發(fā),也不需要受到操作系統(tǒng)的一個影響。
可是問題也來了。有一天用戶量變大了,你需要加服務(wù)器,一臺服務(wù)器不夠就要去加。最頭疼的莫過于我要批量對服務(wù)器進(jìn)行新版本更新,或者說要去加新服務(wù)器。如果我們加一臺還好,如果加 5 臺、加 10 臺呢?擴(kuò)展下去的話,總會變得無邊無際。
我們需要一種通用的策略去解決問題,不僅可以批量操作這個服務(wù)器,更希望說在我們?nèi)ヌ砑舆@個服務(wù)器的時候,也可以去變得特別的便捷。就好像寫個配置文件一樣,寫個清單我們就可以寫一個操作。
那么在這里有一個非常知名的工具叫 Ansible。Ansible 是紅帽推出的一個自動化運(yùn)維工具,它可以去根據(jù)你提前預(yù)制好的服務(wù)器清單,對服務(wù)器進(jìn)行一個批量的操作和部署。
你可以去像寫一個記事本一樣,寫一個 yaml 文件,json 文件一樣去寫入:你的第一個服務(wù)器的 IP 多少,賬號密碼多少、第二個服務(wù)器賬號密碼是多少....這樣就形成了一個清單。把這個清單交給它后,他就會按照你清單上面寫好的賬號和密碼、服務(wù)器地址去對我們遠(yuǎn)程服務(wù)器去操作腳本執(zhí)行任務(wù)。
本質(zhì)上還是一個自動化一個運(yùn)維工具,它是可以自動化幫你去執(zhí)行命令的一個工具,不僅僅是用來部署。包括像后面我們有提到說 Kubernetes 去安裝 Node 的時候,如果你的 Node 的機(jī)器比較多,都需要安裝環(huán)境的話,Ansible 是能夠派上用場的,用場還很大。而且這個是 Python 寫的,性能比較快一些。
基于配置清單服務(wù)器批量操作 Ansible
那么這個就是 Ansible 操作的 Playbook 腳本集。
右邊這張圖大家可以看到:這是一個樣本文件,里面有一個 task 字段。Ansible,他將你的腳本里面每一條要執(zhí)行的命令都產(chǎn)生了一條條 task。并且第一條 task,第二條 task 之間還可以去支持異步執(zhí)行,還可以支持錯誤中斷。比如說我中間的執(zhí)行出錯退出,我還可以去忽略這個錯誤繼續(xù)執(zhí)行。
整個 Playbook 腳本集還可以根據(jù)變量去進(jìn)行一個實(shí)例化。比如我這個地方在用 timestamp 變量,上面可以通過 var 字段去定義一個是 timestamp,后面的 value 就是給它的變量默認(rèn)值。我在左邊去執(zhí)行 ansible-playbook 命令的時候,用 -e 這個參數(shù)就可以去把 timestamp 變量可以傳進(jìn)來,每次都會生成一個新的構(gòu)建的操作實(shí)例。
那么在這種情況下,我們對原有的服務(wù)器替換鏡像,也變成了去操作 Ansible,讓 Ansible 去操作對應(yīng)的機(jī)器進(jìn)行一個鏡像的替換。那么大家可以看到:鏡像 push 到鏡像庫之后,接著去操作 Ansible 批量操作服務(wù)器,受控的服務(wù)器去拉取鏡像,然后再把原有的容器刪除掉,基于新版本運(yùn)行新容器。
那么,Ansible 幫我們實(shí)現(xiàn)了批量操作服務(wù)器的夢想,但是它的做法是比較生硬的,因?yàn)樗皇且粋€自動化的運(yùn)維工具。
我們運(yùn)行的是一個容器,有的時候可能會碰到說負(fù)載均衡需要配置 upstream,環(huán)境變量的情況。尤其像 toB,大家在做微前端,或者說服務(wù)之間有互相引用的地方,都少不了一系列的環(huán)境變量。比如這些 nginx upstream 的值其實(shí)都是不固定的。
舉個例子,我現(xiàn)在有一個系統(tǒng),前端頁面我們要訪問 /user 的時候,要去訪問 /user 配置的機(jī)器;那么訪問 /a 的時候,要去訪問 /a 的容器。這個時候如果你只有自己用還好,假設(shè)到了客戶現(xiàn)場的話,客戶現(xiàn)場的環(huán)境是比較復(fù)雜的,你根本不知道他會用什么情況去部署。Nginx 的 upstream 那么在這種情況下,你把具體的值寫死,完全不利于后面的部署。這個值真正部署是不固定的,環(huán)境的網(wǎng)段和 DNS 都會去影響這個值。
所以我們希望有一個給運(yùn)容器運(yùn)行的環(huán)境生態(tài),容器高度隔離的一個土壤。容器在自己的生態(tài)里面就能去解決這些繁雜的七七八八的一些問題。那么我們再去給客戶部署的時候,只需要帶著這一套環(huán)境生態(tài)去客戶那里部署,這個環(huán)境生態(tài)就可以去完美的去實(shí)現(xiàn) 1:1 的一個還原。
其實(shí)在我們前面去更新容器的時候,都會將原有的容器刪掉,再創(chuàng)建新容器。中間的時間如果用戶去訪問,就是宕機(jī),服務(wù)沒有起來就訪問不到。這種情況下,其實(shí)相對而言還算是好一些的。如果連你的新版本的容器因?yàn)槌鲥e都沒有起來,那么你這個時候問題就大了,就算是一個事故了。回滾也是一個比較麻煩的事情。
所以說我們希望服務(wù)發(fā)布的時候不要停機(jī)。新發(fā)布失敗了,還可以自動終止新版本發(fā)布,回滾到舊版本。
在保證上面的一個運(yùn)行生態(tài)的時候,還希望去做一個最大化的機(jī)器資源利用。比如說我們有多套環(huán)境,而且之間都是隔離的,互相不受影響。例如我們?nèi)粘i_發(fā)有測試環(huán)境,開發(fā)環(huán)境。希望服務(wù)器資源利用最大化,一組高配置的服務(wù)器就可以去部署解決這兩套環(huán)境。
我們希望去達(dá)到這樣一種理想的狀態(tài)。在這種情況下,選擇了 Kubernetes,簡稱 k8s。
Kubernetes 是一個容器編排工具,他給你容器提供一個很好的環(huán)境生態(tài),就像提供一個完整的家一樣,所以說它叫容器編排工具。在 Kubernetes 里面是以它去管理你要運(yùn)行容器的服務(wù)器,是以集群的方式去管理的。你的每一臺服務(wù)器都是一個節(jié)點(diǎn),它可以根據(jù)你集群內(nèi)的節(jié)點(diǎn)的一個剩余資源,還有你人工給他的標(biāo)簽等影響因素,對服務(wù)的部署進(jìn)行了自動的調(diào)度,最大化的利用我們的服務(wù)器資源。
對于應(yīng)用更新,也可以采用滾動發(fā)布服務(wù)的方式,在發(fā)布期間不會影響新版和舊版的一個訪問,也就是說不會宕機(jī)。這個技術(shù)也是比較熱門的,現(xiàn)在很多公司大廠也是在用。
容器集群編排 Jenkins + K8S + Docker + Nginx
那么左上角就是 k8s 運(yùn)行時的情況。左上角圖是滾動發(fā)布,可以看到,k8s 在啟動一個全新的容器之后,他會確保說新容器沒有問題有待殺死原有的一個容器。這樣保證了一個可訪問性,保證不會因?yàn)榉?wù)重啟而導(dǎo)致宕機(jī)。
左下角圖是 k8s 加入一個新節(jié)點(diǎn)的方式。可以看到,只需要通過 API 操作一個遠(yuǎn)程訪問,就可以加入集群,而且都是服務(wù)化。基于密鑰、IP、端口加入就可以。它和集群內(nèi)的其他節(jié)點(diǎn)和集群內(nèi)的主控制節(jié)點(diǎn)其實(shí)都是解耦的。想刪除就刪除,想添加就添加,只是把它當(dāng)成了一個服務(wù)。
右邊是 k8s 集成后的一個流程圖。從最下面可以看到,當(dāng)用戶提交代碼到 Git 了之后,這時候會去觸發(fā) Webhook。或者你手動去觸發(fā) Jenkins。這時候 Jenkins 就構(gòu)建鏡像,上傳鏡像到了制品庫,接著去調(diào)用了 k8s 集群進(jìn)行一個制品的部署。
這時候告訴 k8s:我的鏡像版本更新了,給你新版本的鏡像地址。這時候 k8s 就把鏡像版本在配置文件中進(jìn)行一個修改。這個時候就會拿新版本去鏡像庫拉取新鏡像,拉取之后就會對原有的 pod 進(jìn)行刪除替換。
你可以大致理解為,pod 約等于一個容器,但是它其實(shí)不等于容器。k8 s當(dāng)中的 pod 不只是擁有容器的這個概念,它里面還可以擁有多個容器,他也是 k8s 當(dāng)中可調(diào)度的一個最小節(jié)點(diǎn),也擁有網(wǎng)絡(luò)的分配權(quán)限,所以它不等于一個容器。
可以看到滾動升級的策略。左邊這個圖原有是 4 個藍(lán)色的 pod,我們先把其中 1 個藍(lán)色的給下掉,那么下來之后把新的給創(chuàng)建進(jìn)來,ok 完成;然后剩下三個,再把其中一個給干掉,再上一個新的;再剩下兩個再把其中一個干掉,再上新的,最后完成全部的部署,這就是滾動發(fā)布的這么一個方式。
升級完畢之后,k8s 當(dāng)中還帶來了一種概念 ingress,這個有點(diǎn)類似于 Nginx 的負(fù)載均衡。大家可以看到這張圖,瀏覽器去訪問的時候,經(jīng)過一堆轉(zhuǎn)發(fā),走到了 k8s 集群;k8s 集群進(jìn)來之后,首先是走到了 ingress。根據(jù)路徑左邊是 path = /,然后去根據(jù)路徑走到了 service。右邊這個不僅有 path = /,還有灰度的 cookie。說明他是灰度用戶,給他了灰度的一個服務(wù)的訪問。ingress 的作用就是在這里,他可以去做灰度發(fā)布,也可以做 path 轉(zhuǎn)發(fā)。
k8s 就給容器去提供了這么一個完整的運(yùn)行生態(tài)。國內(nèi)大廠基本上都有在使用 k8s 包括像 serverless,也有的通過 k8s 進(jìn)行一個底層實(shí)現(xiàn)。這種編排方式比較省時省力省心的。
當(dāng)然 k8s 也不是最好的解決方案。未來 Serverless 的部署會更加便捷。
例如左下角的彈性伸縮,按需付費(fèi)。我們現(xiàn)有k8s的 Node 節(jié)點(diǎn)還是需要去手動加入、手動刪除。它并不能根據(jù)你的服務(wù)的流量情況對節(jié)點(diǎn)進(jìn)行一個自動的增加伸縮。不過在 Serverless 里是可以做到的,因?yàn)檎嬲膶ξ锢碣Y源進(jìn)行一個伸縮的時候,這個時候才會真正達(dá)到省錢的目的。無服務(wù)器的函數(shù)計(jì)算,也應(yīng)對了一部分的一個無狀態(tài)的操作和服務(wù),也是比較省錢且快速方便的。當(dāng)然,他的基礎(chǔ)也是Docker
國內(nèi)的云服務(wù)器廠商也對一些常用的前后端框架進(jìn)行了一個快速部署的支持。比如像 Next.js、Koa.js、Egg.js 這些都支持實(shí)現(xiàn)一個常用框架的快速部署。部署起來會更加的方便。
回到開始
以上是我們的一個演進(jìn)流程。可以看到,前人為了提升工程效能,想盡了一切辦法來優(yōu)化提升。
接著讓我們回到主題:為什么要用自動化?
自動化不是為了偷懶,也不是為了做而做,更不是為了刷KPI/OKR。而是為了讓產(chǎn)品和需求可以更快速上線驗(yàn)證,更加早期地分析用戶信息,需求更加匹配用戶。那么這就是我們要做自動化的一個目標(biāo)。
現(xiàn)實(shí)很殘酷
現(xiàn)實(shí)是比較殘酷的。上線實(shí)現(xiàn)了自動化,然而需求從開發(fā)到上線的時間絲毫沒有一點(diǎn)影響。那么這時候你就要考慮:像測試的時間占了多少?有沒有大量的人工測試?
無法打通上線的最后一公里,就像比較經(jīng)典的小程序。小程序的上線就不同于以往的開發(fā)上線,最后一公里怎么打通?
投入和產(chǎn)出不成正比,本來你的業(yè)務(wù)不是多么很熱門的業(yè)務(wù),一個月部署不了幾次,還有必要去做 CI/CD 嗎?它的意義有多大呢?
對于一些特殊的場景,目前的開源工具依然沒法去打通這么一個構(gòu)建。最后一公里還是要去手動操作。而且自動化做了,影響有時候也是不大。所以我們就要根據(jù)業(yè)務(wù)進(jìn)行一個對癥下藥,選擇合適的工具進(jìn)行一個改造,包括像不限于對現(xiàn)有的工具進(jìn)行拓展,或者說可以考慮到自研。
做平臺,而不是做工具
那么還是那句話,做平臺而不是做工具。我分別來舉個例子,像 IDE 集成:就小程序 ide 支持的一鍵發(fā)布,就是一個很好的例子。它把 IDE 和 CI/CD 進(jìn)行了一個聯(lián)動,包括像很多大廠也在研發(fā) WebIDE,也是出于這方面的一個考慮。還有我們?nèi)粘H蝿?wù)卡片進(jìn)行一個關(guān)聯(lián)和綁定,可以更好的追蹤需求的開發(fā)情況。
像自動化測試:我們的上線時間有縮短,但是測試時間沒有變短。大量的人工測試還是比較浪費(fèi)成本的,這個我們也可以考慮去優(yōu)化;
根據(jù)不同用戶的灰度發(fā)布的一個策略:比如說基于用戶畫像的地域,基于其他的一些因素進(jìn)行灰度發(fā)布;還有像服務(wù)的一個監(jiān)控,告警。
像數(shù)據(jù)度量平臺:比如我們可以統(tǒng)計(jì)構(gòu)建時長、發(fā)布時長等等,為了更好地去做優(yōu)化。甚至非常 nice 的流程可視化的拖動:CI/CD 的流程編排現(xiàn)在也是比較火的。這些都是說 CI/CD 去適應(yīng)業(yè)務(wù)的一些例子。
工具是一個比較抽象的平臺,但業(yè)務(wù)場景是復(fù)雜多變的,我們需要使用工具去演變成自己的平臺。之前我們所說的 ?Docker、Jenkins、Nexus、Kubernetes 都有自己的 OpenAPI,你完全可以根據(jù)自己的業(yè)務(wù)需求進(jìn)行一個自定義的封裝。
持續(xù)精進(jìn)
那么總結(jié)一下:自動化是解決問題的手段,而不是一個結(jié)果;適當(dāng)?shù)娜プ鰯?shù)據(jù)度量統(tǒng)計(jì),可以更好的幫助你去對流程的一個改進(jìn);要選擇自己合適的工具去做自動化。
Q&A
接下來是問答:
移步至錄播:https://live.juejin.cn/4354/595741[2] 39分53秒
小冊推廣
然后在這里推廣一下我寫的小冊。傳送門:https://juejin.cn/book/6897616008173846543[3]
推薦書籍
這里推薦兩本書。
第一本是 k8s 的進(jìn)階實(shí)戰(zhàn),個人在查閱相關(guān)知識點(diǎn)的時候經(jīng)常用,不過官網(wǎng)的文檔還要看的
第二本是《Devops 實(shí)驗(yàn)指南》,對于你的一些自動化的流程的建設(shè),Devops 文化的建設(shè),度量平臺建設(shè)也是非常有幫助的。
推薦平臺 & 項(xiàng)目
這是一個推薦參考的平臺和項(xiàng)目。這里沒有打廣告,大家如果有自研興趣需求的話,可以參考上面這些平臺的功能設(shè)計(jì)。
第一個是華為云的 DevCloud。個人感覺他們的 CI/CD 方面做的還比較全的,包括像 CI/CD 可視化拖拽,還支持流水線的中斷執(zhí)行。我們一條條的任務(wù)就可以去組成一個流水線,就像工廠流水線一樣。流水線里面的 task 還可以支持并行執(zhí)行。
第二個百度效率云。這個維護(hù)的頻率比較低,它們的特點(diǎn)是研發(fā)數(shù)據(jù)鏈。比如提交代碼時候,commit 的 message 填入卡片 ID,這時候在卡片里面可以監(jiān)控到,需求的代碼已經(jīng)提交到代碼庫里面了。接下來進(jìn)行構(gòu)建的時候,也會去和需求卡片進(jìn)行一個綁定。業(yè)務(wù)方就可以去清楚的看到需求的一個開發(fā)和上線的一個狀態(tài)與進(jìn)度。一個卡片就可以去串聯(lián)所有的進(jìn)度狀態(tài)。
第三個 KubeSphere 是針對于 k8s 的一個集群管理。包括對 k8s 的服務(wù)監(jiān)控,CI/CD 的編排。這個是開源的,也是國產(chǎn)的。
Thanks
我的分享就到這里,感謝大家!
參考資料
[1]
https://live.juejin.cn/4354/595741: https://live.juejin.cn/4354/595741
[2]https://live.juejin.cn/4354/595741: https://live.juejin.cn/4354/595741
[3]https://juejin.cn/book/6897616008173846543: https://juejin.cn/book/6897616008173846543
最近組建了一個江西人的前端交流群,如果你是江西人可以加我微信?ruochuan12?私信 江西?拉你進(jìn)群。
推薦閱讀
我在阿里招前端,該怎么幫你(可進(jìn)面試群)
我讀源碼的經(jīng)歷
面對 this 指向丟失,尤雨溪在 Vuex 源碼中是怎么處理的
老姚淺談:怎么學(xué)JavaScript?
·················?若川簡介?·················
你好,我是若川,畢業(yè)于江西高校。現(xiàn)在是一名前端開發(fā)“工程師”。寫有《學(xué)習(xí)源碼整體架構(gòu)系列》多篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結(jié),已經(jīng)寫了7篇,點(diǎn)擊查看年度總結(jié)。
同時,活躍在知乎@若川,掘金@若川。致力于分享前端開發(fā)經(jīng)驗(yàn),愿景:幫助5年內(nèi)前端人走向前列。
識別上方二維碼加我微信、拉你進(jìn)源碼共讀群
今日話題
略。歡迎分享、收藏、點(diǎn)贊、在看我的公眾號文章~
總結(jié)
以上是生活随笔為你收集整理的如何系统搭建现代 Web CI/CD的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Taro+react开发(39)taro
- 下一篇: 深度操作系统 V15.11——心随意动