【萬字長文】K8s部署前后端分離的web應(yīng)用避坑系列指南之一:在本地開發(fā)環(huán)境、本地docker compose和k8s云集群里跑通購物清單應(yīng)用(macOS-2023版)

做軟件的人:“工作體驗好,好事才能來。”

1 太長不讀

從2023年8月到10月,我花了3個月自學(xué)docker和k8s。踩了一路坑,到10月22日終于把一個帶有vue.js 3前端、spring boot后端以及postgres數(shù)據(jù)庫的shopping list web app,部署到azure k8s service云上,并能正常運行。

之所以說踩了一路坑,是因為網(wǎng)上分享的k8s部署web app的樣例,都是部署一個web服務(wù)。講ingress nginx controller的樣例雖然會涉及兩個微服務(wù),但在這種根據(jù)path設(shè)定將請求分配給兩個hello world的web微服務(wù)場景中,兩個微服務(wù)之間,是沒有前后端之間的依賴關(guān)系的。另外前后端之間的CORS跨源資源共享該如何解決,也找不到我這種前后端分離的web app場景下的直接資料,只能自己摸索。

在爬出坑后,很愿意寫一系列避坑指南文章分享給大家。雖然不知小伙伴們是否愿意讀,但我很想把這一系列文章,寫成網(wǎng)上通過實例講docker和k8s入門的最好的文章,而且每年至少更新一次。

這一系列文章的目標(biāo)讀者,是對docker或k8s不太熟悉的做軟件的人,不僅包括常寫代碼的程序員,也包括不常寫代碼的測試工程師和運維工程師,如圖1所示。

圖1 做軟件的人包括程序員、測試工程師和運維工程師

K8s和Docker能解決做軟件的人的什么痛點?這也是我為啥要花這么多時間寫這一系列文章的原因。因為k8s和Docker可以讓咱們做軟件的人,能體驗更好地做軟件。

“工作體驗好,好事才能來?!?/p>

想想咱們做軟件的人常說的下面幾句話。

“在我這運行得好好的,怎么你那兒不行?” docker image能將代碼的所有依賴庫都打包到一起,并能讓代碼在容器中獨立運行。這樣就能實現(xiàn)你在測試環(huán)境中所測試的image,就是你在生產(chǎn)環(huán)境所部署的,從而能在很大程度上解決因為依賴庫在不同環(huán)境下的差異,而導(dǎo)致這里能運行,那里不能運行的問題。

“這是誰改了配置又不告訴大家?” Docker和k8s都強調(diào)基礎(chǔ)設(shè)施即代碼,即配置不是靠做軟件的人拍腦袋臨時手工敲的,而是靠寫成與代碼同等地位的配置文件,通過團隊代碼評審,保存到版本庫中,并讓機器執(zhí)行。這樣能讓配置的更改廣而告之,配置的執(zhí)行有據(jù)可查。同時也便于讓機器讀取,自動執(zhí)行,而無須手工一遍一遍敲同樣的命令。

“測試環(huán)境太少得排隊使用?!?/strong> 有了本地docker compose,做軟件的人可以利用其占用存儲空間小,運行速度快的特點,在本地電腦以docker image的方式,最大限度模擬生產(chǎn)環(huán)境的方式,測試要發(fā)布的軟件,而無須排隊等公司共享的測試環(huán)境。這樣能更早地發(fā)現(xiàn)bug,減少因很晚才發(fā)現(xiàn)所導(dǎo)致的大量返工成本。同樣,在內(nèi)部使用了k8s云集群的企業(yè),也能利用云的多租戶特點,快速為需要測試環(huán)境的做軟件的人,分配測試環(huán)境,從而解決測試環(huán)境少的問題。

可見,Docker和k8s能讓咱們做軟件的人,工作體驗更好,好事才更能來。

“為何選用Shopping List Web app作為樣例項目?”這個樣例源自我在自學(xué)vue.js時所學(xué)的待辦清單todo list app樣例,如圖2所示。我把todo list改造為shopping list。兩者的功能近似,都是為用戶提供一個備忘清單,有一個web界面可以增刪改查。這容易理解。此外,這個樣例能代表前后端分離的web app典型架構(gòu)。另外,這個樣例能表現(xiàn)最小化的云原生微服務(wù)之間的依賴關(guān)系,比如前端微服務(wù)依賴后端微服務(wù),而后端微服務(wù)又依賴于數(shù)據(jù)庫微服務(wù)。這便于學(xué)習(xí)如何使用新興的故障注入實驗工具,進行混沌工程實踐。

圖2 購物清單shopping list web app頁面

“我對java和vue.js不熟,能讀懂這一系列文章嗎?”能。因為文章的代碼命名寫得足夠表意,一看就懂。另外,這一系列文章不涉及前后端具體的編程,而重點關(guān)注如何把開發(fā)好的代碼用docker打成image,并部署到本地docker compose和k8s云集群上。這些都與前后端所使用的編程語言關(guān)系不大,所以文章內(nèi)容適用于所有使用JSON/HTTP協(xié)議的前后端分離的web app的技術(shù)棧。

“我不會編程,能讀懂這一系列文章嗎?”能。因為文章不涉及前后端功能的代碼編寫,而主要涉及配置文件和命令行工具的使用,適合程序員、測試工程師和運維工程師閱讀。

“我是做測試或運維的,還需要按照文章的描述,在本地開發(fā)環(huán)境里跑通嗎?”需要。因為在本文所描述的避坑的過程中,你會發(fā)現(xiàn)之前代碼中的配置有問題。當(dāng)你需要在源代碼里更改配置,并重新構(gòu)建docker image時,你就需要知道如何操作。

這一系列文章的第一篇,會針對macOS、Windows10和Ubuntu這3種操作系統(tǒng),分別推出3個版本。

這一系列文章可以分為三篇。這三篇的標(biāo)題如下:

K8s部署前后端分離的web應(yīng)用避坑系列指南之一:在本地開發(fā)環(huán)境、本地docker compose和k8s云集群里跑通購物清單應(yīng)用(macOS/Windows10/Ubuntu-2023版分別寫)

K8s部署前后端分離的web應(yīng)用避坑系列指南之二:解讀購物清單應(yīng)用Dockerfile和docker-compose.yml文件

K8s部署前后端分離的web應(yīng)用避坑系列指南之三:解讀購物清單應(yīng)用k8s的deployment、service和ingress配置文件

這一系列指南相關(guān)的源代碼在這里下載:https://github.com/wubin28/shopping-list-web-app。

要想找到這一系列文章的最新版本,可以在知乎搜“體驗更好地做軟件”專欄。

2 深入閱讀

注意,本文一萬三千字。分享了8個避坑指南。需要拿著mac邊讀邊練。沒點決心堅持不下來。慎入。

2.1 需求描述

這一系列文章所選用的web app,是一個購物清單shopping list web app。它的用戶是有購物需求的顧客小吾。一天,小吾發(fā)現(xiàn)家里的瓶裝水快沒了,就想著晚上下班路過超市時,順便買幾瓶。但這時老板來微信喊他開會。他很快就把買瓶裝水的事情忘掉干干凈凈。等下班路過超市,他光顧著給老婆買打折的巧克力。等到家要喝水了,發(fā)現(xiàn)水沒買。咱們這個shopping list web app,就能為小吾解決上面的痛點。當(dāng)他想要買水時,就可以馬上在app里添加一條買水的購物項。過了一會兒又想買點香蕉,那就再加一條。等他到了超市,再查看一下這個清單,要買的東西就不會忘了。

2.2 從源代碼開始分三步部署到k8s

現(xiàn)在咱們有了這一系列指南相關(guān)的源代碼。該如何將它部署到k8s呢?

可以分三步:

第一步,在本地開發(fā)環(huán)境里跑通;

第二步,在本地docker compose里跑通;

第三步,在k8s云集群里跑通。

為何不能一次就從源代碼直接部署到k8s呢?當(dāng)然這樣做也可以,但前提是你確信部署上去后,將來再也沒有新需求或修bug而去修改源代碼并重新部署。對于坑坑洼洼的docker和k8s學(xué)習(xí)之旅,你覺得這可能嗎?

所以你需要知道當(dāng)新需求來了或要修bug時,該如何把修改過的代碼,在本地開發(fā)環(huán)境里調(diào)試通。這是進行第一輪自測。畢竟,本地電腦是你的地盤兒。在本地電腦上調(diào)試程序,比在k8w云集群里要方便得多。這是第一步的意義。

之后,你需要知道如何將通過了第一輪自測的代碼,構(gòu)建成docker image,并在本地docker compose里跑通,為之后將docker image部署到k8s做第二輪自測。畢竟,本地docker compose也在你的地盤兒上。這是第二步的意義。

最后,你需要知道如何將通過了第二輪自測的docker image,部署到k8s云集群并跑通,為之后部署到生產(chǎn)k8s云集群環(huán)境做第三輪自測。這個項目的k8s云集群,我選用了微軟的azure k8s service,免費使用1個月。這也算是我的地盤兒。在這里自測,會比在運維團隊地盤兒里的生產(chǎn)k8s云集群環(huán)境,要方便多了。這是第三步的意義。

2.3 在本地開發(fā)環(huán)境里跑通

2.3.1 在本地開發(fā)環(huán)境里的架構(gòu)

Shopping List Web App在本地開發(fā)環(huán)境里的架構(gòu),如果用c4 model(https://c4model.com/)畫出來,就如圖3和圖4所示。

圖3是站在整個web app的邊界,向外看的context圖。在系統(tǒng)外,有user和admin這兩種用戶在使用系統(tǒng)。User使用系統(tǒng)來管理購物清單。Admin使用系統(tǒng)來管理購物清單數(shù)據(jù)。

圖3 Shopping list web app在本地開發(fā)環(huán)境里的的context架構(gòu)圖

圖4是站在整個web app的邊界,向內(nèi)看的container圖。在系統(tǒng)內(nèi),有4個容器。注意c4 model里的container的概念,和docker的container的概念,是不同的。前者是代表架構(gòu)圖中運行的應(yīng)用或數(shù)據(jù)存儲系統(tǒng),后者代表封裝了所有代碼和依賴庫能獨立運行的軟件運行單元。User通過前端shopping-list-front-end來查看和修改購物清單。而前端shopping-list-front-end將用戶對購物清單的操作請求,發(fā)給后端shopping-list-api。后端shopping-list-api再訪問數(shù)據(jù)庫postgres查詢和更新數(shù)據(jù)。Admin通過使用pgadmin數(shù)據(jù)庫管理工具來直接管理postgres數(shù)據(jù)庫中的數(shù)據(jù)。

圖4 Shopping list web app在本地開發(fā)環(huán)境里的container架構(gòu)圖

2.3.2 本地開發(fā)環(huán)境準(zhǔn)備

我所使用的Mac,是Apple M1 Pro,32G內(nèi)存。對于在本機跑docker compose和前后端應(yīng)用,只要不同時開著intellij idea和webstorm,8G內(nèi)存應(yīng)該是夠用了。

[小心坑!不要直接使用官網(wǎng)安裝包安裝工具]

我之前安裝jdk的習(xí)慣,一直是先確定要裝哪個版本的jdk,比如jdk11,然后在oracle官網(wǎng)上找到j(luò)dk11的下載頁面,下載對應(yīng)操作系統(tǒng)的安裝包,然后解壓或安裝。

但后來發(fā)現(xiàn),jdk版本更新得很頻繁。如果想用現(xiàn)在的主流版本jdk17,就得再從官網(wǎng)下載并安裝jdk17,然后手工在/.zshrc或/.bashrc里修改JAVA_HOME和PATH環(huán)境變量。這樣才能從jdk11切換到j(luò)dk17。如果有老舊項目又需要用jdk11,又得手工修改環(huán)境變量。這太累了。

而像git這樣的工具,雖然版本更新得不那么頻繁,如果你也是從官網(wǎng)下載安裝包安裝,等過了幾個月,想升級版本時,經(jīng)常會忘記當(dāng)初是如何安裝的,導(dǎo)致難以卸載并重新安裝。

所以像jdk和node.js甚至git這樣的工具,一般情況下不建議直接從官網(wǎng)下載安裝包安裝,而是使用熱門的包管理器來安裝。這樣當(dāng)要切換同一工具的不同版本、升級版本和卸載時,就方便多了。

如果你在macOS上的git、jdk和node.js/npm之前是直接使用官網(wǎng)安裝包安裝的,而沒有使用包管理器來安裝,那么推薦你設(shè)法把它們先卸載,然后使用下面的包管理器來安裝。否則,你就要冒因工具版本與我所用的不一致,而導(dǎo)致各種問題的風(fēng)險。而我下面描述的工具版本,是經(jīng)過我測試過了的。

用包管理器homebrew安裝文件版本管理工具git 2.42.0以便下載本項目代碼

安裝homebrew方法參見:https://brew.sh/。我用的homebrew版本是4.1.16。

安裝git:brew install git,參見:https://formulae.brew.sh/formula/git。

驗證git是否工作:運行命令git -v,我用的git版本是2.42.0。

下載代碼:運行git clone https://github.com/wubin28/shopping-list-web-app.git,就能把代碼下載到項目文件夾shoppling-list-web-app中。

以后就把shoppling-list-web-app叫做項目文件夾。

進入到這個文件夾,運行命令ls -alF,你會看到,這個文件夾里有3個子文件夾。

drwx------ 15 binwu staff  480 Oct 23 16:22 back-end/
drwx------ 23 binwu staff  736 Oct 23 13:47 front-end/
drwx------  3 binwu staff 96 Oct 23 08:27 infrastructure/

其中,

infrastructure文件夾存放了運行docker compose和k8s的配置文件,如docker-compose.yml。

back-end存放了后端代碼、后端Dockerfile和其他配置文件。

front-end存放了前端代碼、前端Dockerfile和其他配置文件。

Dockerfile是一種配置文件,用于把源代碼構(gòu)建為docker image,以便以容器化的方式進行部署。

用包管理器sdkman安裝后端開發(fā)工具jdk 17.0.8.1-tem以便在本地進行后端構(gòu)建

安裝sdkman方法參見:https://sdkman.io/install。我用的sdkman的版本是script: 5.18.2,native: 0.4.2。

安裝jdk:sdk install java。

查看所安裝的jdk版本:sdk list java。

使用所安裝的jdk版本:sdk use java 17.0.8.1-tem,參見:https://sdkman.io/usage。

驗證jdk是否工作:java -version。我用的jdk版本是openjdk version "17.0.8.1" 2023-08-24。

用包管理器nvm安裝前端工具node.js和npm以便在本地進行前端構(gòu)建

安裝nvm方法參見:https://github.com/nvm-sh/nvm。我用的nvm版本是0.39.5。

安裝node.js/npm:nvm install --lts。

驗證前端工具node.js是否工作:node -v。我用的node.js版本是v18.18.0。

驗證前端構(gòu)建工具npm是否工作:npm -v。我用的npm版本是9.8.1。

安裝docker desktop以便用容器方式運行postgres數(shù)據(jù)庫及其管理工具

參見:https://docs.docker.com/desktop/install/mac-install/。我用的docker desktop for macOS版本是v4.24.2。

驗證docker desktop是否工作:看docker desktop是否能正常啟動。

2.3.3 在本地開發(fā)環(huán)境里跑通shopping list web app

啟動docker desktop

在容器中運行postgres數(shù)據(jù)庫和能查看數(shù)據(jù)庫中數(shù)據(jù)的pgadmin以便在本地開發(fā)環(huán)境里運行g(shù)radle構(gòu)建和測試

[小心坑!不要再使用官網(wǎng)安裝包安裝數(shù)據(jù)庫和管理工具]

在實現(xiàn)新功能和修bug的時候,如果能在本地運行一個數(shù)據(jù)庫和數(shù)據(jù)庫管理工具,就能很方便地進行自測。你當(dāng)然可以從官網(wǎng)下載數(shù)據(jù)庫和管理工具的安裝包,在本地電腦上安裝。但如前面安裝jdk類似,將來卸載或升級,會比較麻煩。在容器化的時代,如果想使用數(shù)據(jù)庫及其管理工具,你完全可以從http://hub.docker.com(又叫Docker hub)上,下載數(shù)據(jù)庫和管理工具的docker image文件,然后在本地電腦用簡單的一行命令,啟動相應(yīng)的容器,來使用數(shù)據(jù)庫及其管理工具。將來卸載或升級,也是運行一行命令的事兒,多方便。

有人會問:容器里跑數(shù)據(jù)庫,要是關(guān)閉或刪除容器,那數(shù)據(jù)不就丟了?其實不用擔(dān)心,你可以為數(shù)據(jù)庫容器設(shè)置一個位于本地硬盤中的volume,以便保存持久化的數(shù)據(jù)。只要你不刪除這個volume,數(shù)據(jù)庫容器關(guān)閉后再啟動,仍然能夠獲取之前的數(shù)據(jù)。

在本地開發(fā)環(huán)境里跑通shopping list web app,首先要把postgres數(shù)據(jù)庫和pgadmin管理工具啟動起來。因為之后的后端app在使用gradle進行構(gòu)建時,會運行自動化測試,需要訪問數(shù)據(jù)庫。如果在后端app構(gòu)建時不啟動postgres數(shù)據(jù)庫,那么gradle構(gòu)建會失敗。

要運行這兩個容器,需要下載代碼。在本地電腦的terminal里,進入項目文件夾,運行命令cd infrastructure進入這個子文件夾。然后再運行命令docker compose up postgres pgadmin啟動postgres數(shù)據(jù)庫和pgadmin管理工具。這個命令會讀取當(dāng)前文件夾下面的docker-compose.yml文件中的postgres和pgadmin服務(wù),并啟動起來。我會在系列文章的第二篇,解讀docker-compose.yml文件。

驗證容器:在docker desktop的container界面里,能看到運行起來的兩個容器,如圖5所示。

圖5 在docker desktop的container界面里,能看到與數(shù)據(jù)庫相關(guān)的兩個容器

驗證數(shù)據(jù)庫:

打開瀏覽器訪問pdadmin數(shù)據(jù)庫管理工具鏈接http://localhost:5050/,用戶名:admin@gmail.com,密碼:admin@gmail.com。這個用戶名和密碼是在docker-compose.yml文件中的pdadmin服務(wù)中設(shè)置好的。

鼠標(biāo)右擊Servers -> Register -> Server… -> General里的Name: 隨便寫一個,比如shopping-list -> Connection里面的Host name/address: postgres -> Port: 5432 -> Maintenance database: postgres -> Username: postgres -> Password: postgres -> 允許Save password -> 點擊Save按鈕 -> 點擊剛剛創(chuàng)建的shopping-list服務(wù)器,就能在數(shù)據(jù)庫出現(xiàn)問題時查看數(shù)據(jù)庫里的數(shù)據(jù),如圖6所示。這里的Username和Password也是在docker-compose.yml文件中的postgres服務(wù)中設(shè)置好的。

圖6 用pgadmin工具管理postgres數(shù)據(jù)庫

在本地開發(fā)環(huán)境啟動后端app

重新打開一個terminal,進入項目文件夾,然后進入后端代碼文件夾:cd back-end。啟動后端app:./gradlew bootRun。

驗證后端app:打開瀏覽器訪問http://localhost:8081/swagger-ui.html,如果能看到OpenAPI definition頁面,就表示后端已經(jīng)起了。可以在這個頁面試用一下GET /api/v1/shopping-items接口,應(yīng)該返回[]空記錄。

在本地開發(fā)環(huán)境啟動前端app

重新打開一個terminal,進入項目文件夾,然后進入前端代碼文件夾:cd front-end。先運行命令npm install,安裝package.json文件所設(shè)置的依賴庫。

只有等依賴庫安裝好了,才能運行命令npm run dev啟動前端app。之后,屏幕會出現(xiàn)提示諸如Local: http://localhost:5173/的信息。

驗證前端app:打開瀏覽器訪問http://localhost:5173,能看到ShoppingList頁面。在Item輸入框中輸入“a banana”,點擊Add按鈕,會出現(xiàn)什么結(jié)果?”a banana”竟然沒有出現(xiàn)在下面的清單里!

[小心坑!CORS問題導(dǎo)致前端無法訪問后端]

此時為何無法插入數(shù)據(jù)?可以用快捷鍵Cmd+Option+I打開Developer Tools界面,在Network頁簽的Console里,能看到前端訪問后端時出現(xiàn)了CORS錯誤信息Access to XMLHttpRequest at 'http://localhost:8081/api/v1/shopping-items' from origin 'http://localhost:5173' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

CORS(跨源資源共享)是瀏覽器的一種安全設(shè)置。如果后端app配置好了CORS,那么后端app就能告訴瀏覽器:“雖然訪問我的這個請求來自前端app,但我信任它,所以你可以放心地加載和展示我所提供的信息?!庇谑菫g覽器就能順利展示前端app訪問后端app所獲取的數(shù)據(jù)。而上面的錯誤信息表明,用戶從前端app的網(wǎng)址(http://localhost:5173)訪問后端app網(wǎng)址(http://localhost:8081)里的信息,被瀏覽器攔截了。這說明后端app沒有設(shè)置好CORS特定的權(quán)限來告訴瀏覽器:“前端這個請求是允許的,你可以放心接收?!?/p>

如何查看后端app的CORS配置呢?此時可以查看后端代碼back-end/src/main/java/com/wuzhenben/shoppinglist文件夾下的ShoppingListApplicationConfig.java文件。此文件的allowedOrigins(“http://localhost:8080”),設(shè)置了后端app允許前端app從http://localhost:8080這個origin來訪問它。而除此之外的origin,瀏覽器就給用戶報上面的CORS錯誤,并拒絕訪問。

此時要解決這個問題,該怎么辦?既然后端已經(jīng)允許前端app從http://localhost:8080這個origin來訪問,那么如果讓前端在8080號端口運行,是不是就能解決問題?

此時可以按Ctrl+C中止前端app。然后運行下面的命令,讓前端app在8080號端口啟動:npm run dev -- --port 8080 。屏幕出現(xiàn)提示Local: http://localhost:8080/。

再次驗證前端app:打開瀏覽器訪問http://localhost:8080,在Item輸入框中再次輸入“a banana”,點擊Add按鈕?!盿 banana”果真出現(xiàn)在下面的清單里!你也可以試試點擊a banana右邊的radio button,把這個購物項設(shè)置為已購買,或者點擊Delete按鈕,刪除這個購物項。

此時還可以用快捷鍵Cmd+Option+I打開Developer Tools界面,在Network頁簽的Console里,就看不到任何錯誤信息了。

你還可以用瀏覽器訪問http://localhost:5050/,用之前配置好的pgadmin數(shù)據(jù)庫管理工具,看看shoppingList數(shù)據(jù)庫中是否存入了你在前端app所添加的購物項。

[小心坑!docker desktop的kubernetes里的配置會搗亂]

有一天,我使用了上面的步驟,讓前端app在端口8080上啟動。但當(dāng)打開瀏覽器訪問http://localhost:8080時,又是前端無法訪問后端。打開瀏覽器chrome里的Developer Tools一看,發(fā)現(xiàn)network里的console報以下錯誤:Access to XMLHttpRequest at 'http://shopping-list-api-ingress:8081/api/v1/shopping-items' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.??雌饋碛质荂ORS問題。

我想試試后端的CORS配置是否起作用了。于是我在顯示前端頁面的Chrome瀏覽器的console里,輸入命令fetch(“http://localhost:8081/api/v1/shopping-items”).then(a => a.text()).then(console.log),來從后端app獲取所有購物項數(shù)據(jù),結(jié)果發(fā)現(xiàn)能夠獲取到,返回結(jié)果是[{“id":1,"item":"a banana”,”purchased”:true}]。因為我是從http://localhost:8080頁面的console里運行的fetch命令,這就說明后端代碼ShoppingListApplicationConfig類中的CORS的設(shè)置起作用了。

那究竟是什么原因?qū)е聢驝ORS問題呢?仔細(xì)再看錯誤信息,說來自前端的請求,要訪問后端http://shopping-list-api-ingress:8081/api/v1/shopping-items接口路徑時,出現(xiàn)了CORS問題。但后端接口路徑明明是http://localhost:8081/api/v1/shopping-items啊。這是怎么回事?另外,我的代碼里,也沒有出現(xiàn)過shopping-list-api-ingress這樣的字符串。那為何前端app在訪問后端app時,卻使用了http://shopping-list-api-ingress:8081/api/v1/shopping-items這樣的陌生路徑?

仔細(xì)回憶,才想起來,前兩天在docker desktop里試用了本地電腦kubernetes(簡稱k8s)集群功能,并在里面配置了名為shopping-list-api-ingress的ingress配置。ingress的解釋,參見本文2.5.2。

看起來前端在訪問后端時,使用了這個ingress,從而導(dǎo)致CORS錯誤。要是我把docker desktop里的kubernetes給關(guān)掉,是不是就會好了。于是在docker desktop的settings中,選擇Kubernetes,再把Enable Kubernetes的勾選項取消勾選,重啟docker desktop。這樣就刪除了那個ingress。為了保險,再清除一下瀏覽器cache。再次訪問前端。一切正常!

如果你有興趣,可以用Insomnia或postman驗證后端app接口。之前clone下來的代碼里,有一個Insomnia_2023-10-06.json文件,可以安裝Insomnia(參見:[https://insomnia.rest/),創(chuàng)建一個collection,并在里面import這個文件來驗證后端app接口。相比postman來說,Insomnia對于初學(xué)者更加輕量和易用。

至此,shopping list web app就已經(jīng)在本地開發(fā)環(huán)境里跑通了。

清理現(xiàn)場

如果不清理現(xiàn)場,一直讓兩個容器和兩個服務(wù)一直跑著,有點耗內(nèi)存。此時可以在前端、后端和運行本地docker compose命令的terminal界面里,按Ctrl+C,來終止這三個程序的運行。最后在運行本地docker compose命令的terminal界面里,運行命令docker compose down,來終止并刪除postgres和pgadmin容器以及相關(guān)網(wǎng)絡(luò)資源,然后在docker desktop界面里驗證一下。這兩個容器果然消失了。

2.4 在本地docker compose里跑通

2.4.1 在本地docker compose里的架構(gòu)

架構(gòu)圖沒變,還是見圖3和圖4.雖然Shopping list web app在本地docker compose里的架構(gòu),與在本地開發(fā)環(huán)境里的架構(gòu),在c4 model架構(gòu)圖中的畫法相同,但在實現(xiàn)層面有差異。前者的前端和后端app,是運行在docker container里的。而后者則運行在npm和gradle命令所啟動的服務(wù)中。

2.4.2 本地docker compose環(huán)境準(zhǔn)備

在macOS上,只要安裝好了docker desktop,你就準(zhǔn)備好了本地docker compose運行環(huán)境??梢栽赿ocker desktop界面里查看docker compose所啟動的容器,以及相應(yīng)的image。

2.4.3 在本地docker compose里跑通shopping list web app

免費注冊Docker hub賬號以便推送docker image為部署k8s做準(zhǔn)備

Docker hub是Docker公司搞的一個存儲docker image的公共注冊(registry)中心。Docker公司把容器化搞火了之后,很多做軟件的公司,就把它們的軟件產(chǎn)品,做成docker image,并推送到Docker hub。你之前所用的postgres和pgadmin的image,都是從這個中心拉取的。你在Docker hub上注冊賬號后,也可以把你構(gòu)建的docker image推送到Docker hub上。

這樣做有什么好處?因為這樣一來,在k8s云集群里跑通shopping list web app時,k8s云集群就能從Docker hub里拉取你所構(gòu)建的前后端app的docker image。免費注冊Docker hub賬號,參見:https://hub.docker.com/。

構(gòu)建后端docker image并推送到docker hub

構(gòu)建后端docker image,分為三步。

第一步,用gradle構(gòu)建后端app,生成jar包。

先生成jar包,再構(gòu)建docker image的好處,是能讓image僅包含運行后端所需要的jar包。這樣能讓image文件盡量小。

進入項目文件夾,運行命令cd infrastructure進入這個子文件夾。然后再運行命令docker compose up postgres pgadmin啟動postgres數(shù)據(jù)庫和pgadmin管理工具。

然后新打開一個terminal窗口,進入項目文件夾,運行cd ../back-end,進入后端文件夾。

運行命令./gradlew clean build構(gòu)建后端app。之后可以在文件夾build/libs里,找找所生成的jar包,文件名是shoppinglist-0.0.1-SNAPSHOT.jar。

第二步,構(gòu)建docker image。

運行命令docker buildx build --build-arg JAR_FILE=build/libs/shoppinglist-0.0.1-SNAPSHOT.jar -t <docker-hub-username>/shopping-list-api:v1.0.docker-compose .來構(gòu)建后端docker image。可以運行命令docker image ls查看新構(gòu)建的帶有v1.0.docker-compose tag的image。

這個命令中,docker buildx build是對舊的docker build命令的擴展,提供了后者所沒有的緩存的導(dǎo)入和導(dǎo)出,以及并發(fā)構(gòu)建多個image的功能。

在參數(shù)-t <docker-hub-username>/shopping-list-api:v1.0.docker-compose中,-t指給image加一個tag。這個tag就是參數(shù)中v1.0.docker-compose,用于標(biāo)識這個image。你要把<docker-hub-username>替換為你的Docker hub用戶名。而整個<docker-hub-username>/shopping-list-api,表示這個image將來推送到Docker hub上的鏡像庫(repository)名稱。</docker-hub-username>

[小心坑!docker buildx命令最后的那個小數(shù)點不要忘了]

上面命令最后有一個不起眼的小數(shù)點。千萬不要把它忘了。這代表把當(dāng)前文件夾作為build的上下文,以找到諸如jar文件這樣的構(gòu)建資源。

[小心坑!如何知道所構(gòu)建的image對應(yīng)的是代碼庫中的哪些代碼?]

我們知道,隨著不斷提交,代碼庫中的代碼總是在不斷變化。如果有一天,你推送到Docker hub中的image里有bug,你想打開對應(yīng)的源代碼看一下。但距離你構(gòu)建這個image已經(jīng)過去好幾天了,你也往代碼庫里提交了不少代碼。當(dāng)初構(gòu)建這個image的代碼也改了不少。此時你該如何在代碼庫中,還原當(dāng)初構(gòu)建這個image時的代碼?解決的辦法,就是你在運行上面的docker buildx命令,構(gòu)建了docker image后,就立即運行命令git tag -a v1.0.docker-compose -m “v1.0.docker-compose”,在git庫里打一個同名的tag。這樣通過識別這個tag,你就能把image和代碼對應(yīng)上了。最后別忘了運行命令git push origin v1.0.docker-compose把這個tag推送到遠(yuǎn)程git庫中。

第三步,把docker image推送到Docker hub。

運行命令docker login登錄Docker hub。然后運行命令docker push <docker-hub-username>/shopping-list-api:v1.0.docker-compose,將構(gòu)建好的image推送到Docker hub。你可以登錄Docker hub,看看后端帶有v1.0.docker-compose這個tag的image是否已經(jīng)在上面了。

構(gòu)建前端docker image并推送到docker hub

構(gòu)建前端docker image,分為兩步。

第一步,構(gòu)建docker image。

有人可能會問,為何不是先用命令npm run build來構(gòu)建前端app?答案是這個命令,以及納入前端的Dockerfile文件里了。我會在第二篇文章中,解讀這個文件。

運行cd ../front-end,進入前端文件夾。運行命令docker buildx build -t <docker-hub-username>/shopping-list-front-end:v1.0.docker-compose .來構(gòu)建后端docker image。這里的參數(shù)解讀和前面講的一樣??梢赃\行命令docker image ls查看新構(gòu)建的帶有v1.0.docker-compose tag的image。

第二步,把docker image推送到Docker hub。

運行命令docker push <docker-hub-username>/shopping-list-front-end:v1.0.docker-compose,將構(gòu)建好的image推送到Docker hub。你可以登錄Docker hub,看看前端帶有v1.0.docker-compose這個tag的image是否已經(jīng)在上面了。

在本地docker compose里跑通shopping list web app

在本地docker compose里跑通的命令很簡單,進入項目文件夾,運行命令cd infrastructure進入infrastructure子文件夾,再運行命令docker compose up來啟動postgres、pgadmin、shopping-list-api和shopping-list-front-end這四個容器即可。此時可以在docker desktop里查看這4個容器的運行狀態(tài)。還可以在瀏覽器里訪問http://localhost:8080/來試用購物列表web app。

至此,shopping list web app在本地docker compose里跑通了。

清理現(xiàn)場

進入項目文件夾,運行命令cd infrastructure進入infrastructure子文件夾,再運行命令docker compose down可以停止和刪除4個容器。

2.5 在k8s云集群里跑通

在k8s云集群里跑前后端分離的web app,有兩種選擇。

第一種,是使用云廠商所提供的免費試用的服務(wù)。

第二種,是使用在本地電腦上運行的諸如minikube這樣的單node的服務(wù)。

因為要真正體驗上云,所以我選擇了第一種。

各大云廠商都會提供1~3個月不等的k8s云集群免費試用。本文選用了微軟的azure k8s service。免費試用1個月,提供2個node。按照之前講解的習(xí)慣,此時應(yīng)該展示shopping list web app在k8s云集群里的架構(gòu)。但為了再現(xiàn)我踩坑的經(jīng)過,讓講解更有趣,我打算把架構(gòu)放到最后再講。

2.5.1 K8s云集群環(huán)境準(zhǔn)備

注冊Azure k8s service云平臺賬號

Azure k8s service云平臺免費注冊方法參見:https://azure.microsoft.com/。

注冊完后,可以創(chuàng)建一個名為my-k8s-cluster-1的k8s service,以及名為my-azure-resource-group-1的resource group。然后登錄主頁https://portal.azure.com/#home,就能看到你所擁有的資源,如圖7所示。

圖7 你在azure k8s service云平臺上所擁有的資源

打開docker desktop kubernetes讓kubectl能正常工作

接下來,你需要安裝工具kubectl,以便從macOS連上k8s云集群。做法是在docker desktop里,點擊settings,選擇Kubernetes,然后把Enable Kubernetes左邊的勾選框勾上。之后點擊Apply & reset按鈕。

驗證docker desktop k8s能否正常工作:等reset結(jié)束后,你能在docker desktop的主界面左下角的小鯨魚圖標(biāo)上方,看到一個綠色背景的小橫條,上面有k8s的舵輪圖標(biāo)。綠色背景,表示docker desktop k8s運行正常。另外,你可以打開一個terminal窗口,在里面輸入命令kubectl version -o yaml。如果能看到clientVersion和serverVersion,就說明操作k8s的命令kubectl能正常工作了。

連上azure k8s service云平臺

要從你的Mac連上azure k8s service云平臺,需要改一個配置文件。這個文件是你的mac電腦的~/.kube文件夾下的config文件。你可以用你喜歡用的編輯器,打開這個文件。里面只有你的docker desktop所提供的一個k8s集群,名字就是docker-desktop。你要連azure k8s service云平臺,就需要把這個文件,替換為azure k8s service云平臺的同名配置文件。或者在這個文件中,添加azure k8s service云平臺的配置。即這個文件可以有多個k8s集群的配置,此時就能用kubectl命令,在兩個k8s集群之間切換。因為在本文中,我們不用docker desktop k8s所提供的單node的本地集群,所以為簡單起見,可以把你mac上的~/.kube/config文件先備份,然后用azure k8s service云平臺的同名配置文件將其替換。

那如何獲取azure k8s service云平臺的配置文件?方法是你需要在瀏覽器里,登錄你的azure k8s service云平臺。在頁面上方搜索框的右側(cè),有一個Cloud shell圖標(biāo)。點擊這個圖標(biāo),就能在屏幕下方,看到一個黑色背景的命令行界面出現(xiàn)。點擊命令行界面上方的兩個大括號{}圖標(biāo)Open editor,就能在左側(cè)打開一個文件樹。在文件樹中,找到.kube文件夾并打開,然后點擊config文件。右側(cè)就會出現(xiàn)這個文件的內(nèi)容。你把這個文件的內(nèi)容全部復(fù)制出來,保存到mac電腦的~/.kube/config文件末尾,并把這個文件原先的內(nèi)容刪除。再次提醒,在刪除原內(nèi)容前,一定要備份。

一旦改好了config文件,你就可以連接azure k8s service云平臺了。

運行命令kubectl config get-contexts,可以看到你所連接的azure k8s service云平臺。

運行命令kubectl get nodes,可以查看azure k8s service云平臺給你分配了兩個node,狀態(tài)都是ready。

2.5.2 在k8s云集群里跑通shopping list web app時踩坑

我是如何踩坑的

初次在k8s上部署前后端分離的web app,最自然的方式,就是按照在docker compose里部署的架構(gòu),來部署。但這樣想,就踩進了一個坑。在討論坑之前,先看看在k8s云集群里跑通與在本地跑通之間的差異。

在k8s云集群里跑通shopping list web app,與在本地docker compose里跑通,有什么差異呢?有3個差異。

第一個差異,是后端app所依賴的數(shù)據(jù)庫主機名,不再是localhost,而是k8s云集群里postgres數(shù)據(jù)庫的內(nèi)部service名。這需要改動back-end/src/main/resources/application.properties文件,將里面的localhost,替換為${DB_HOST}。即通過在下面介紹的deployment配置文件設(shè)置的DB_HOST環(huán)境變量,來確定postgres數(shù)據(jù)庫的service名。

第二個差異,是后端的CORS的配置中的allowedOrigins,不再是http://localhost:8080,而應(yīng)該是前端app在k8s云集群中的對外域名和端口號。

第三個差異,前端前端app所依賴的后端app的主機名和端口,也不再是localhost:8081,同樣也變成了k8s云集群里后端app的service名。這需要改動前端代碼的3個文件。首先,front-end/src/components/ShoppingList.vue文件中的localhost:8081,需要改為%%API_URL%%。這也是通過在下面介紹的deployment配置文件設(shè)置的API_URL環(huán)境變量,來確定后端app的服務(wù)名。為了能夠在js代碼中,替換后端app的服務(wù)名,需要改動front-end/Dockerfile和新增front-end/entrypoint.sh文件。

第二個差異,就是一個坑。后端的CORS的配置中的allowedOrigins,該如何配前端app在k8s云集群中的對外域名和端口號?我沒有為這個項目申請域名。域名也不能寫成內(nèi)部service名,因為內(nèi)部名無法用于外部訪問。能把域名寫成ip地址嗎?在云集群中,ip地址經(jīng)常會發(fā)生變化。每次ip變了就去改配置,多麻煩。這個坑該如何爬出來?

我還真的把postgres、后端shopping-list-api和前端shopping-list-web-app都部署到k8s云集群里,并讓前端擁有一個外部IP。結(jié)果發(fā)現(xiàn),當(dāng)我用瀏覽器訪問前端外部IP的8080端口時,瀏覽器果然報了CORS錯誤:Access to XMLHttpRequest at ‘http://shopping-list-api/api/v1/shopping-items' from origin ‘http://20.72.168.185:8080’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resources.

后來也是查了很多資料,在朋友圈求助,經(jīng)過朋友們的提醒,并嘗試了一下,發(fā)現(xiàn)為shopping list web app配置ingress能解決這個難題。

在k8s里,ingress是一種規(guī)則和配置的集合,它能幫助外部的網(wǎng)絡(luò)請求,來查找到和訪問集群內(nèi)的服務(wù)??梢园阉胂蟪梢粋€交通指揮員,它知道如何根據(jù)特定的規(guī)則把外面來的車輛(網(wǎng)絡(luò)請求)引導(dǎo)到正確的停車位(服務(wù))。

2.5.3 在k8s云集群里的架構(gòu)

在k8s云集群里,就難以使用pgadmin數(shù)據(jù)庫管理工具了。所以圖8的context架構(gòu)圖只有user。

圖8 Shopping list web app在k8s云集群里的的context架構(gòu)圖

咱們這個web app,用戶不再直接訪問前端app的對外IP和端口,而是直接訪問ingress nginx controller的對外IP和端口。之后,ingress nginx controller會把用戶的請求,根據(jù)請求的path不同,分發(fā)給前端app和后端app。而前后端app就不必?fù)碛袑ν獾腎P和端口了。

既然用戶所使用的瀏覽器,只看到ingress nginx controller所對外暴露的IP和端口,那么之后前端app訪問后端app獲取數(shù)據(jù),就都在同一個ingress nginx controller所對外暴露的IP和端口下,這樣對瀏覽器來說,就不存在CORS的跨域問題了。如圖9所示。

圖9 Shopping list web app在k8s云集群里的的container架構(gòu)圖

2.5.4 如何從坑里爬出來

要從坑里爬出來,就需要新增k8s的deployment、service和ingress的配置文件,以便使用kubectl命令將ingress和postgres、shopping-list-api和shopping-list-front-end這3個微服務(wù)部署到k8s上。

注意,ingress不是微服務(wù),而是k8s里的一組規(guī)則。

另外,每個微服務(wù)的k8s部署,一般都需要一個deployment文件和一個service文件。前者供k8s為這個微服務(wù)創(chuàng)建pod,后者供k8s為這個微服務(wù)的pod分配穩(wěn)定的ip地址以及DNS名稱。即使容器實例被替換,ip地址以及DNS名稱也不會改變。

Pod是k8s管理的最小單元,里面推薦只運行一個docker container,這樣才算微服務(wù)。

配置ingress需要一個ingress配置文件。因為要在k8s里配置3個微服務(wù),所以需要新增3個deployment文件和3個service文件。

此外,原先在本地使用的pgadmin數(shù)據(jù)庫管理工具,在k8s云集群中,就不再使用了。

改動的代碼文件列表如下:

back-end/src/main/resources/application.properties(改動)
Back-end/src/main/ShoppingListApplicationConfig.java(改動)
front-end/Dockerfile(改動)
front-end/src/components/ShoppingList.vue(改動)
front-end/entrypoint.sh(新增)
infrastructure/deployment-postgres.yml(新增)
infrastructure/ingress.yml(新增)
infrastructure/deployment-shopping-list-api.yml(新增)
infrastructure/deployment-shopping-list-front-end.yml(新增)
infrastructure/service-postgres.yml(新增)
infrastructure/service-shopping-list-api.yml(新增)
infrastructure/service-shopping-list-front-end.yml(新增)

為了減輕你寫代碼的負(fù)擔(dān),我把這些改動和新增保存到了分支for-azure-k8s-service中。運行命令git checkout for-azure-k8s-service就能看到進行了這些改動和新增后的代碼。

由于代碼改動涉及后端和前端,所以要重新構(gòu)建后端和前端的docker image。

構(gòu)建后端docker image并推送到docker hub

首先把數(shù)據(jù)庫跑起來,以便構(gòu)建代碼時運行測試。進入項目文件夾,運行命令cd infrastructure進入這個子文件夾。然后再運行命令docker compose up postgres pgadmin啟動postgres數(shù)據(jù)庫和pgadmin管理工具。

然后新打開一個terminal窗口,進入項目文件夾,運行cd ../back-end,進入后端文件夾。因為后端app所依賴的數(shù)據(jù)庫主機名,現(xiàn)在已經(jīng)改為環(huán)境變量${DB_HOST}了,所以在構(gòu)建前,需要在terminal窗口中,運行命令export DB_HOST=localhost來設(shè)置環(huán)境變量。

之后,可以運行命令./gradlew clean build來生成后端jar包。

然后運行命令docker buildx build --build-arg JAR_FILE=build/libs/shoppinglist-0.0.1-SNAPSHOT.jar -t <docker-hub-username>/shopping-list-api:v1.1.k8s .來構(gòu)建后端docker image。注意,為了和之前為docker compose構(gòu)建image做區(qū)分,上面命令中的tag改為v1.1.k8s??梢赃\行命令docker image ls查看新構(gòu)建的帶有v1.1.k8s tag的image。

運行命令docker login登錄Docker hub。然后運行命令docker push <docker-hub-username>/shopping-list-api:v1.1.k8s,將構(gòu)建好的image推送到Docker hub。你可以登錄Docker hub,看看后端shopping-list-api帶有v1.1.k8s這個tag的image是否已經(jīng)在上面了。

構(gòu)建前端docker image并推送到docker hub

[小心坑!如果用arm64架構(gòu)的mac構(gòu)建image而不做架構(gòu)設(shè)定會怎樣?]

我按之前為docker compose構(gòu)建前端docker image的方式,為azure k8s service構(gòu)建了前端docker image。但等我把前端的deployment文件apply到k8s云集群時,pod在啟動時總是報一個奇怪的錯誤:exec /usr/local/bin/docker-entrypoint.sh: exec format error。

把這個image拉下來,運行一個容器,然后進去看文件docker-entrypoint.sh的內(nèi)容,也看不出所以然。后來查了半天,才知道原因在于我用arm64架構(gòu)的mac在構(gòu)建image時,沒有指定所構(gòu)建的image應(yīng)該是amd64架構(gòu)的。

如果用arm64架構(gòu)的mac構(gòu)建image,而不在命令中做架構(gòu)設(shè)定,那么所構(gòu)建的image就只能用于arm64架構(gòu)的容器運行系統(tǒng)里,這也是我之前能正常在mac上的docker compose里運行不帶架構(gòu)設(shè)定而構(gòu)建出的image的容器的原因。但我在azure k8s service云集群里所申請的資源,一般都是只能運行amd64架構(gòu)的容器。

要爬出這個坑需要做兩件事。

第一,需要在~/.docker/config.json文件中,增加下面的配置,以便讓docker buildx能夠支持在Mac arm64架構(gòu)的電腦上,構(gòu)建amd64架構(gòu)的image。

{ "experimental": "enabled" }

第二,在docker buildx命令中,增加指定架構(gòu)的參數(shù)??梢栽陧椖课募A中,運行cd ../front-end,進入前端文件夾。運行命令docker buildx build --platform linux/amd64 -t <docker-hub-username>/shopping-list-front-end:v1.1.k8s.amd64 .來構(gòu)建前端docker image。可以運行命令docker image ls查看新構(gòu)建的帶有v1.1.k8s.amd64 tag的image。還可以運行命令docker inspect wubin28/shopping-list-front-end:v1.1.k8s.amd64 | grep “Architecture"查看這個image是否真的是amd64架構(gòu)的。

運行命令docker push <docker-hub-username>/shopping-list-front-end:v1.1.k8s.amd64,將構(gòu)建好的image推送到Docker hub。你可以登錄Docker hub,看看前端shopping-list-front-end帶有v1.1.k8s.amd64這個tag的image是否已經(jīng)在上面了。

在k8s云集群上配置postgres、shopping-list-api和shopping-list-front-end三個微服務(wù)和ingress并運行

要在Mac的terminal里連上azure k8s service進行操作,需要安裝azure-cli工具??梢赃\行brew updatebrew install azure-cli進行安裝。安裝完后,可以運行命令az --version來驗證安裝是否成功。然后可以運行az login來登錄azure k8s service云平臺。

我們在k8s云集群里為這個web app所創(chuàng)建的資源,最好都放到一個namespace里,這樣便于管理。將來不用云服務(wù)了,要刪除一個namespace里所有資源以便省錢,也就是運行一條命令的事兒。具體如何做,見下文“清理現(xiàn)場”。

因為每個命令一般都有掛上NAMESPACE,所以把它設(shè)置到環(huán)境變量里比較方便:`export NAMESPACE=shopping-list-web-app`。然后可以運行`kubectl create namespaceNAMESPACE`來創(chuàng)建這個namespace。

前面講到,在一個操作系統(tǒng)里安裝工具,最好用包管理器。這樣便于維護工具的版本。對于云計算操作系統(tǒng)k8s來說,helm就是這樣的包管理工具。我們可以用helm來安裝ingress-nginx:

helm repo add ingress-nginx-repo https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx-release ingress-nginx-repo/ingress-nginx \
 -n $NAMESPACE \
 --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz

安裝完后,可以運行helm list -n $NAMESPACE驗證一下。

接下來就可以用kubectl,運行下面命令,來往k8s云集群里部署postgres、shopping-list-api、shopping-list-front-end和ingress了。

`cd ../infrastructure`
部署postgres的deployment:`kubectl apply -f ./deployment-postgres.yml --namespace $NAMESPACE`
驗證image是否正確:`kubectl get deployments -o wide -n $NAMESPACE`
驗證pod是否正常啟動:`kubectl get pods -o wide -n $NAMESPACE`
部署postgres的service:`kubectl apply -f ./service-postgres.yml --namespace $NAMESPACE`
驗證服務(wù)是否正常啟動:`kubectl get services -o wide -n $NAMESPACE`

部署shopping-list-api的deployment:`kubectl apply -f ./deployment-shopping-list-api.yml --namespace $NAMESPACE`
驗證image是否正確:`kubectl get deployments -o wide -n $NAMESPACE`
驗證pod是否正常啟動:`kubectl get pods -o wide -n $NAMESPACE`
部署shopping-list-api的service:`kubectl apply -f ./service-shopping-list-api.yml --namespace $NAMESPACE`
驗證服務(wù)是否正常啟動:`kubectl get services -o wide -n $NAMESPACE`

部署shopping-list-front-end的deployment:`kubectl apply -f ./deployment-shopping-list-front-end.yml --namespace $NAMESPACE`
驗證image是否正確:`kubectl get deployments -o wide -n $NAMESPACE`
驗證pod是否正常啟動:`kubectl get pods -o wide -n $NAMESPACE`
部署shopping-list-front-end的service:`kubectl apply -f ./service-shopping-list-front-end.yml --namespace $NAMESPACE`
驗證服務(wù)是否正常啟動:`kubectl get services -o wide -n $NAMESPACE`

部署ingress:`kubectl apply -f ./ingress.yml --namespace $NAMESPACE`
查看ingress的狀態(tài):kubectl get ingresses -n $NAMESPACE
查看ingress的詳情:kubectl describe ingress <ingress name> -n $NAMESPACE
如果一切順利,沒有出錯,那么就可以運行命令`kubectl get services -o wide -n $NAMESPACE`,查看ingress nginx controller對外暴露的IP和端口,以便讓我們試用web app。假設(shè)我們查看到的IP是20.72.130.209。而端口一般是80。

打開瀏覽器,訪問http://20.72.130.209/。如果一切正常,就能在上面愉快地管理購物項了。

清理現(xiàn)場

運行命令kubectl delete namespace $NAMESPACE,就可以刪除該namespace下所有資源。

如果你的azure k8s service云服務(wù)免費試用快到期了,記得刪除下面的資源:my-k8s-cluster-1、my-azure-resource-group-1和Azure subscription 1。

[小心坑!在免費期到期前不要忘記刪除k8s云集群中的所有資源]

在微軟、谷歌、亞馬遜、阿里、騰訊這樣的云平臺申請了帶有免費試用期的賬號,如果暫時不用,在試用期到期前,一定記得刪除k8s云集群中的所有資源,否則就太破費了。你會遇到云刺客。

本文Windows 10和ubuntu版,等我有空了再寫。

因篇幅所限,本文并未解讀所使用的docker compose和k8s的配置文件。我會在接下來的兩篇文章中,進行解讀。敬請關(guān)注。


要想找到這一系列文章的最新版本,可以在知乎搜“體驗更好地做軟件”專欄。

如果你喜歡這一系列文章,歡迎點贊和收藏,并在留言區(qū)寫下為何喜歡,以便我將來寫更多你喜歡的文章。

如果你不喜歡,也歡迎你留言告訴我哪里可以再改進。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容