天天看點

帶你讀《Istio入門與實戰》之二:實驗說明第2章

點選檢視第一章 點選檢視第三章

第2章

實驗說明

為了能更好地示範和學習Istio,我們搭建了一個Istio的實驗環境,以便後續章節進行實驗。本章主要介紹實驗的環境,以及在建立實驗環境時需要注意的事項。實驗中使用的應用是我用多種程式設計語言編寫的簡單樣例程式,在本章中也會做詳細的介紹,最後簡單介紹一下應用的容器化鏡像建構方法。

2.1 實驗的環境

2.1.1 基礎環境

在沒有特殊說明的情況下,本書的實驗是在Windows 10系統下進行的,在MacOS和Linux系統下也可以進行實驗,并無太大差别。

考慮到不是每位讀者都有足夠的雲主機或者實體機,本實驗使用3台虛拟機來進行實驗。虛拟機管理軟體使用開源的Virtualbox,為了友善進行重複的快速實驗,我們會使用Vagrant配合Virtualbox來進行虛拟機的管理,包括建立、啟動、關閉虛拟機以及虛拟機的快照儲存恢複等操作。

本實驗對硬體有一些基本要求,否則可能會出現實驗無法成功的現象。對CPU并沒有太多要求,由于我們實驗時會建立3台虛拟機,每台虛拟機會配置設定至少2G記憶體,是以這就要求至少有6G的空閑記憶體,加上系統本身的記憶體占用,是以推薦在進行實驗時,電腦至少有8G記憶體。一般的機械硬碟就能滿足實驗條件,當然如果使用SSD硬碟會更好一些。硬碟推薦至少保留30G以上可用空間,虛拟機并不會占用這麼多存儲空間,但是由于我們會儲存多個快照來快速恢複實驗環境,這些快照需要占用大量的存儲空間,是以綜合起來可能需要30G的存儲空間。

關于Virtualbox和Vagrant的安裝不再較長的描述,具體安裝細節可以參考官方文檔或者通過搜尋引擎擷取安裝文檔。本書實驗時所使用的Virtualbox和Vagrant軟體安裝包以及後面會使用的Vagrant box檔案可以到如下位址下載下傳:

https://pan.baidu.com/s/1Q8s4mnhj2ROnUzW1ZTn44Q

由于在Kubernetes上部署Istio更加友善,并且能體驗到最全功能,是以本書的實驗會依賴Kubernetes環境。後面的章節會詳細介紹如何通過Kubeadm部署Kubernetes叢集。

實驗中還會涉及Git的基本使用,是以也需要提前在系統上安裝好對應作業系統的Git軟體。由于Windows系統下預設的指令行終端CMD并不好用,是以在Windows系統上我會使用Git Bash作為預設的指令行終端。Git Bash是Windows系統上安裝好Git軟體後就自帶的。當然,你也可以根據自己的喜好選擇終端軟體。

實驗時使用Xshell軟體來應用SSH遠端登入到實驗環境的Linux虛拟機,免費家用版本提供在一個視窗中最多可以同時打開4個會話終端,已經能滿足我們的實驗需求。Xshell隻提供了Windows系統版本的軟體,安裝時一直點選“下一步”按鈕就可以完成安裝,詳細安裝步驟請查閱相關文檔。MacOS和Linux系統的使用者可以直接使用系統自帶的終端來應用SSH遠端登入到實驗環境的Linux虛拟機。

預設情況下使用Virtualbox啟動虛拟機時,虛拟機目錄會存放在使用者的主目錄,如果Windows下C槽剩餘空間過小,可能會由于硬碟空間不夠,導緻建立虛拟機失敗。如果有需要,可以在指令行終端設定虛拟機的存放目錄,先建立D:virtualbox目錄。如果提示找不到VBoxManage指令,可能需要把Virtualbox的安裝目錄添加到系統的PATH環境變量中。使用如下指令設定:

$ VBoxManage setproperty machinefolder D:virtualbox

$ VBoxManage list systemproperties | grep machine

Default machine folder: D:virtualbox

2.1.2 指令說明

由于實驗使用Vagrant和Virtualbox來管理虛拟機叢集環境。使用Vagrant建立的虛拟機一般情況下登入使用者名為vagrant,當部署kubernetes叢集或者其他安裝軟體的操作時,由于需要root權限,我們有時會直接切換到root使用者來執行接下來的操作。當以vagrant使用者登入虛拟機環境的Linux主機後,使用sudo su - root指令可臨時切換到root使用者來執行接下來的操作,這也可以從執行指令的提示符中看出,當以vagrant使用者操作時,指令會以$符号來開頭;而當以root使用者操作時,指令會以#符号來開頭。如下所示:

帶你讀《Istio入門與實戰》之二:實驗說明第2章

本書所有實驗中的指令執行操作如果沒有特殊說明,普通使用者的操作均是以vagrant使用者執行。

本書實驗内容的大部分代碼和使用的Kubernetes以及Istio的yaml檔案,都在

https://github.com/mgxian/istio-lab

倉庫中。可使用如下方式擷取源碼:

$ git clone

如果沒有安裝Git,需要提前安裝Git,可使用如下指令安裝:

$ sudo yum install -y git

本書後面的大部分實驗在執行kubectl和istioctl指令時,使用到的指令都是以倉庫的根目錄作為目前工作目錄的,也就是說,當執行這兩個指令時會先進入istio-lab目錄,然後再執行相應的指令。

第3章之後(不包含第3章)的大部分實驗操作,在沒有特殊說明的情況下,都是在使用Xshell登入到實驗環境虛拟機中後進行的操作,安裝Git和下載下傳實驗中使用的源代碼隻需要在一台虛拟機上進行即可,一般會選擇第一台虛拟機。隻有管理虛拟機相關的操作指令比如:啟動、停止、暫停虛拟機,才需要在Windows系統主控端上進行操作。

2.1.3 問題及解決方案

由于實驗虛拟機叢集資源與性能的問題,可能會出現實驗結果和書中展示的結果有所不同的情況,本小節主要介紹實驗中可能會遇到的問題及解決方法。

1. 路由不生效

在進行服務路由等功能驗證時,很有可能會出現路由不生效的問題。當建立路由後,由于機器性能問題,導緻服務路由資訊傳播速度慢,如果立即通路測試,就很有可能會出現與書中展示的結果不同的現象,此時可以稍等片刻,讓服務路由資訊傳播完成,再進行通路測試。或者删除路由規則,再重新建立。當然,你也可以重新開機Pilot元件,這通常是最快的解決方法。另外,也可以通過如下介紹的方式深入地排查問題。

建立路由後,可以通過如下指令檢視路由的分發情況:

帶你讀《Istio入門與實戰》之二:實驗說明第2章

當路由中的狀态都為SYNCED,不存在Stale狀态時,表明路由已經分發完成。此時再進行通路測試,一般情況下不會再出現問題。istio-egressgateway和istio-ingressgateway會有部分狀态為NOT SENT,這是正常的,因為如果沒有建立過Gateway,就不會發送RDS給istio-egressgateway和istio-ingressgateway,此時的狀态就為NOT SENT。

此外,還可以通過檢視Pod日志觀察Envoy有無接收到最新的路由規則,可以通過如下方式檢視日志:

$ INGRESS_GATEWAY_POD=$(kubectl get pod -n istio-system | grep istio-ingressgateway | awk '{print $1}')

$ kubectl logs -f $INGRESS_GATEWAY_POD -n istio-system

有時候也可能會出現使用istioctl proxy-status不能擷取全部Pod的路由同步狀态的情況,或者使用istioctl proxy-status擷取到的狀态都是正常狀态,但路由仍然沒有生效,此時可能是由于Pilot處于異常狀态。可以使用如下的方式重新開機Pilot執行個體:

帶你讀《Istio入門與實戰》之二:實驗說明第2章
帶你讀《Istio入門與實戰》之二:實驗說明第2章

當然,你也可以參考本書第12章中關于路由不生效的排錯步驟來進行問題排查。

2. 應用路由規則時出現逾時錯誤

在實驗中建立路由規則時,無法成功建立或更新,出現如下的逾時錯誤資訊:

帶你讀《Istio入門與實戰》之二:實驗說明第2章

這一般是由于Istio中的Galley元件出現了問題,使用如下指令重新開機Galley元件即可解決:

帶你讀《Istio入門與實戰》之二:實驗說明第2章

3. 自動注入失敗

建立Pod時,提示如下的錯誤資訊:

帶你讀《Istio入門與實戰》之二:實驗說明第2章

建立或擴容Deployment時,沒有建立出對應數量的Pod,檢視Deployment對應的ReplicaSet資訊,可以看到如下所示的錯誤資訊:

帶你讀《Istio入門與實戰》之二:實驗說明第2章
帶你讀《Istio入門與實戰》之二:實驗說明第2章

這一般是由于Istio中的Sidecar-injector元件出現了問題,使用如下指令重新開機Sidecar-injector元件即可解決:

帶你讀《Istio入門與實戰》之二:實驗說明第2章

有時也可能碰到其他異常問題,比如:拉取鏡像失敗,可能是由于Virtualbox的nat網絡出了問題,這些問題一般都無法快速解決,甚至沒有辦法解決,不用浪費太多時間在這些異常問題上。可以嘗試使用虛拟機的快照功能,直接恢複虛拟機環境到建立好Istio叢集的初始狀态,再重新進行實驗。

2.2 實驗的應用

2.2.1 應用架構說明

為了充分展示Istio的功能,我們使用不同的語言來模拟數個微服務,服務之間存在相應的調用關系,服務之間通過HTTP協定通信。我們并沒有寫一個實際的綜合應用,例如:購物網站、論壇等,來模拟生産環境的情況,我們隻是簡單地模拟服務間的調用關系來進行Istio相關的功能實驗,目的是通過示範Istio相關功能來學習Istio。每個服務以其使用的程式設計語言為服務名,例如:使用Python語言編寫的服務命名為service-python。各服務的調用關系如圖2-1所示。

service-js服務是一個由Vue/React實作的前端應用,當使用者通路前端Web頁面時,使用者會看到一個靜态頁面。當使用者點選相應的按鈕時,前端頁面會通過浏覽器異步請求後端service-python服務提供的API接口,service-python調用後端service-lua服務和service-node服務,而service-node服務又會調用service-go服務,最終,所有服務配合來完成使用者的請求,并把結果合并處理之後發送給前端浏覽器。目前端頁面收到請求的響應資料時會渲染出新的頁面呈現給使用者。

帶你讀《Istio入門與實戰》之二:實驗說明第2章

應用架構說明:

  • 本應用采用目前比較流行的前後端分離架構。
  • 前端項目使用Vue/React實作。
  • 前端調用Python實作的API接口。
  • Python服務調用後端Node實作的服務和Lua實作的服務。
  • Node服務調用Go實作的服務。

2.2.2 應用詳細說明

1. service-js服務

service-js服務分别使用Vue和React各實作一套Web界面,主要用于服務路由中的A/B測試,可以讓不同的終端使用者看到不同的前端Web界面。service-js服務主要負責根據service-python服務的響應資料,使用ECharts圖表庫在浏覽器上展示出後端服務的具體調用關系和各個服務的調用耗時,具體的代碼在實驗源碼根目錄的service/js目錄下。

v1版本使用React架構實作,源碼目錄如下:

.

├── Dockerfile

├── package.json

├── package-lock.json

├── public

│ ├── favicon.ico

│ ├── index.html

│ └── manifest.json

├── README.md

└── src

├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── logo.svg
└── registerServiceWorker.js           

v2版本使用Vue架構實作,源碼目錄如下:

├── build

│ ├── build.js

│ ├── check-versions.js

│ ├── logo.png

│ ├── utils.js

│ ├── vue-loader.conf.js

│ ├── webpack.base.conf.js

│ ├── webpack.dev.conf.js

│ └── webpack.prod.conf.js

├── config

│ ├── dev.env.js

│ ├── index.js

│ └── prod.env.js

├── index.html

├── src

│ ├── App.vue

│ ├── assets

│ │ └── logo.png

│ ├── components

│ │ └── HelloWorld.vue

│ └── main.js

└── static

用于容器化的Dockerfile檔案如下所示:

帶你讀《Istio入門與實戰》之二:實驗說明第2章

2. service-python服務

service-python服務是一個用Python編寫的API服務,負責接收前端的API請求,調用整合後端其他服務的響應資料,傳回給前端使用。service-python服務分别使用Python2和Python3實作了兩個版本的服務,具體代碼在實驗源碼根目錄的service/python目錄下。service-python服務使用Flask架構實作,具體源碼如下:

帶你讀《Istio入門與實戰》之二:實驗說明第2章
帶你讀《Istio入門與實戰》之二:實驗說明第2章

第11~28行定義的getForwardHeaders函數是為了從請求中提取出用于Istio調用鍊追蹤的頭資訊,用于傳遞給service-python要調用的其他後端服務。

第31~33行表示每個請求在被處理前,調用getForwardHeaders函數,從請求中提取出Istio調用鍊追蹤的頭資訊,并儲存到全局對象g的forwardHeaders變量中。

第36~46行定義了用于擷取後端服務響應資料的get_url_response函數。

第49~63行定義了真正的業務路由,使用線程池的方式并發請求後端服務,并把後端服務的響應資料組合處理後傳回給調用方。

第66~68行定義了用于服務健康檢查的路由。

第71~72行表示服務啟動在0.0.0.0位址的80端口。

v1版本和v2版本源碼隻有第61行有略微差别,在v2版本中"python v1"修改為"python v2"。

帶你讀《Istio入門與實戰》之二:實驗說明第2章
帶你讀《Istio入門與實戰》之二:實驗說明第2章

v1版本和v2版本的Dockerfile隻有使用的基礎鏡像版本不同,其他保持一緻。

3. service-lua服務

service-lua服務使用OpenResty的不同版本用Lua語言分别實作了兩個版本的服務。具體的代碼在實驗源碼根目錄的service/lua目錄下。源代碼如下:

帶你讀《Istio入門與實戰》之二:實驗說明第2章

第8行表示服務啟動在0.0.0.0位址的80端口。

第9~14行定義了通路服務的/連結時傳回"hello world"。

第16~21行定義了用于服務健康檢查的/status連結。

第23~37行定義了真正的業務邏輯,當通路/env連結時,響應服務的版本資訊。

v1版本和v2版本源碼隻有第30行有略微差别,在v2版本中"lua v1"修改為"lua v2"。

帶你讀《Istio入門與實戰》之二:實驗說明第2章

4. service-node服務

service-node服務使用Node的不同版本分别實作了兩個版本的服務。具體的代碼在實驗源碼根目錄的service/node目錄下。源代碼如下:

帶你讀《Istio入門與實戰》之二:實驗說明第2章
帶你讀《Istio入門與實戰》之二:實驗說明第2章

第8~28行定義的getForwardHeaders函數是為了從請求中提取出用于Istio調用鍊追蹤的頭資訊,用于傳遞給service-node要調用的其他後端服務。

第32~34行定義了用于服務簡單健康檢查的路由。

第36~63行定義了真正的業務路由,請求後端服務,并把後端服務的響應資料組合處理後傳回給調用方。

第65~66行表示服務啟動在0.0.0.0位址的80端口。

v1版本和v2版本源碼隻有第54和59行有略微差别,在v2版本中"node v1"修改"node v2"。

用于容器化的Dockerfile檔案如下:

帶你讀《Istio入門與實戰》之二:實驗說明第2章

5. service-go服務

service-go服務使用Go語言的不同版本分别實作了兩個版本的服務,具體的代碼在實驗源碼根目錄的service/go目錄下。源代碼如下:

帶你讀《Istio入門與實戰》之二:實驗說明第2章

第10~14行定義了真正的業務路由,以及傳回服務的版本資訊。

第16~18行定義了用于服務健康檢查的路由。

第20行表示服務啟動在0.0.0.0位址的80端口。

v1版本和v2版本源碼隻有第12行有略微差别,在v2版本中"go v1"修改為"go v2"。

帶你讀《Istio入門與實戰》之二:實驗說明第2章
帶你讀《Istio入門與實戰》之二:實驗說明第2章

你可能已經注意到,上面的Dockerfile代碼使用了兩次FROM關鍵詞和一個不太一樣的COPY用法,這展現了Docker鏡像的多階段建構功能,可以在一個鏡像中編譯代碼,然後複制編譯後的産物到另一個鏡像中,這樣可以非常有效地減小應用的Docker鏡像大小,特别是Go、Java這類編譯型靜态語言,因為這類語言編譯之後就不再需要原來編譯時的依賴庫,可以把編譯後的産物直接放在一個極小運作環境中啟動運作。由于Go語言可以編譯為在作業系統上直接運作的二進制檔案,是以可以把編譯後的檔案直接複制到alpine這類極簡的作業系統鏡像中,這種優化使得service-go服務編譯建構後的鏡像體積可縮小到10M級别,進而使服務鏡像的分發效率大幅度提升。

6. service-redis服務

service-redis服務是使用Go語言實作的服務,用于從Redis伺服器擷取資訊,具體的代碼在實驗源碼根目錄的service/redis目錄下。源代碼如下:

帶你讀《Istio入門與實戰》之二:實驗說明第2章
帶你讀《Istio入門與實戰》之二:實驗說明第2章

第23~29行定義了真正的業務路由,以及傳回Redis伺服器的資訊。

第30~32行定義了用于服務健康檢查的路由。

第33行表示服務啟動在0.0.0.0位址的80端口。

帶你讀《Istio入門與實戰》之二:實驗說明第2章

7. httpbin服務

httpbin服務是一個用于HTTP測試的開源服務。它既提供了線上的測試服務,也可以通過源碼或者使用Docker鏡像在本地部署運作,這兩種使用方式在後續章節的實驗中都有涉及。

2.3 應用的建構

如果隻是跟着本書做實驗,本節可以跳過,本節屬于應用鏡像建構部分,不會影響後面的Istio實驗。了解本節内容需要掌握Docker的基礎知識。

由于本書的實驗重點在于如何使用Istio,如何使用本地Docker私有鏡像倉庫部署服務并不是我們關注的重點,是以本書實驗所使用的鏡像均采用阿裡雲鏡像服務免費提供的鏡像建構功能。當然,你也可以使用Docker Hub提供的鏡像建構功能。下面以阿裡雲鏡像服務為例實作鏡像建構,具體步驟如下。

1.建構應用鏡像

(1)上傳代碼到GitHub

此步驟不做詳細說明,請參考相關文檔了解Git和GitHub的基本使用。

(2)在阿裡雲上的鏡像建構

阿裡雲鏡像服務位址:

https://cr.console.aliyun.com/

,如下操作均在這個連結的Web上進行。

1)建立命名空間。

命名空間不能重複,請注意修改命名空間名稱,如圖2-2所示,可建立名為istio-lab的命名空間。

帶你讀《Istio入門與實戰》之二:實驗說明第2章

2)建立鏡像倉庫。

選擇命名空間為上個步驟中建立的命名空間,填寫要建立的鏡像倉庫名和簡介,如service-go。注意選擇倉庫類型為公開,如圖2-3所示。

選擇已經綁定的GitHub賬号和要建構的源碼倉庫,由于建構時需要通路國外資源,是以勾選使用海外機器建構,并取消“選擇代碼變更時自動建構鏡像”(如果首次使用需要先綁定GitHub賬号),如圖2-4所示。

帶你讀《Istio入門與實戰》之二:實驗說明第2章

3)添加鏡像建構規則。

選擇要建構規則的鏡像倉庫,并點選“管理”按鈕,出現如圖2-5所示的界面。

帶你讀《Istio入門與實戰》之二:實驗說明第2章

選擇“建構”頁籤上的“添加規則”按鈕,添加鏡像建構規則,如圖2-6所示。

帶你讀《Istio入門與實戰》之二:實驗說明第2章

添加如圖2-7所示的版本建構規則,實驗中會使用兩個版本,是以需要建立兩個版本的建構規則。

帶你讀《Istio入門與實戰》之二:實驗說明第2章

4)建構鏡像。

點選“立即建構”按鈕開始建構,如果建構失敗,可以通過點選日志連結檢視建構日志,找出失敗原因,如圖2-8所示。

帶你讀《Istio入門與實戰》之二:實驗說明第2章

2. 本地拉取鏡像驗證

鏡像建構完成後,拉取到本地測試鏡像是否能正常工作。具體步驟如下。

1)拉取鏡像:

帶你讀《Istio入門與實戰》之二:實驗說明第2章

2)啟動容器:

帶你讀《Istio入門與實戰》之二:實驗說明第2章

3)通路測試:

帶你讀《Istio入門與實戰》之二:實驗說明第2章

4)清理:

帶你讀《Istio入門與實戰》之二:實驗說明第2章

2.4 本章小結

要掌握Istio,我們需要一步一步地實驗Istio的功能特性,是以我們先建立一個實驗環境,而實驗時最有可能遇到的問題就是實驗環境的機器性能不足,進而出現Istio路由功能生效緩慢,甚至導緻後續實驗失敗的問題,這也是我們需要特别關注的。我也在本章中說明了這種情況,并介紹了幾種解決方法。為了更好地模拟生産環境中多服務調用的場景,我使用多種程式設計語言實作了多個服務的不同版本,這也能幫助我們在後續章節更好地展示Istio的相關功能特性。