1)安裝環(huán)境支持 netsh interface ipv6 install (2)查看已配置的“端口映射”清單 netsh interface portproxy show v4tov4 (3)添加“端口映射” netsh interface portproxy add v4tov4 listenaddress=192.168.2.210 listenport=8080 connectaddress=192.168.2.222 connectport=8080 (4)刪除“端口映射” netsh interface portproxy delete v4tov4 listenaddress=192.168.222.145 listenport=15001
者 | Magalix
譯者 | 火火醬 責(zé)編 | Carol
來源 | 架構(gòu)師技術(shù)聯(lián)盟
封圖 | CSDN付費(fèi)下載于IC photo
CI/CD要解決的是什么問題?
CI/CD(CI全名Continuous Integration,持續(xù)集成;CD全名Continuous Deployment,持續(xù)部署)這個(gè)術(shù)語常常和DevOps、Agile、Scrum以及Kanban、自動(dòng)化等其他術(shù)語一起出現(xiàn)。
有時(shí),人們只將它看作是工作流的一部分,而沒有真正理解它是什么或采用它的意義是什么。年輕的DevOps工程師經(jīng)常將CI/CD視作理所當(dāng)然的事情,他們可能沒有見過“傳統(tǒng)的”軟件發(fā)布周期,因此,Get不到CI/CD的好處。
CI/CD代表持續(xù)集成、持續(xù)交付和部署。未實(shí)現(xiàn)CI/CD的團(tuán)隊(duì)在創(chuàng)建新軟件產(chǎn)品時(shí)必須經(jīng)歷以下幾個(gè)階段:
產(chǎn)品經(jīng)理(代表客戶的利益)提供產(chǎn)品應(yīng)該具有的特性和應(yīng)該實(shí)現(xiàn)的行為。該環(huán)節(jié)必須盡可能全面和具體。
開發(fā)人員借助業(yè)務(wù)分析師的幫助,通過編寫代碼,運(yùn)行單元測(cè)試并將結(jié)果提交到版本控制系統(tǒng)(例如Git)。
開發(fā)階段結(jié)束后,項(xiàng)目將被轉(zhuǎn)移到QA(Quality Assurance,質(zhì)量保證)。針對(duì)產(chǎn)品運(yùn)行幾個(gè)測(cè)試,比如用戶驗(yàn)收測(cè)試、集成測(cè)試、性能測(cè)試等等。在此期間,在QA階段完成之前,不會(huì)對(duì)代碼庫進(jìn)行任何更改。如果有任何bug,他們會(huì)返還給開發(fā)人員進(jìn)行修復(fù),然后修改后的產(chǎn)品將被再次交給QA。
QA結(jié)束后,操作團(tuán)隊(duì)會(huì)將代碼部署到生產(chǎn)環(huán)境中。
但上述工作流程存在很多缺點(diǎn):
首先,從產(chǎn)品經(jīng)理提出要求到產(chǎn)品準(zhǔn)備投入生產(chǎn)之間,需要花費(fèi)很長(zhǎng)的時(shí)間。
對(duì)于開發(fā)人員來說,要想解決一個(gè)月或更久以前編寫的代碼中的bug可不容易。要記得,只有在開發(fā)階段結(jié)束和QA階段開始之后才會(huì)發(fā)現(xiàn)bug。
當(dāng)需要緊急更改代碼(比如需要熱修復(fù)的嚴(yán)重bug)時(shí),因?yàn)樾枰M快部署,所以往往會(huì)縮短QA階段。
由于不同的團(tuán)隊(duì)之間的溝通協(xié)作很少,所以當(dāng)bug發(fā)生時(shí),人們就會(huì)開始相互指責(zé)。每個(gè)人都只會(huì)關(guān)心他自己負(fù)責(zé)的那部分,而忽略了共同的目標(biāo)。
CI/CD通過引入自動(dòng)化來解決上述問題。每次將代碼更改推送到版本控制系統(tǒng)后,都將進(jìn)行測(cè)試,然后將其部署到stagingUAT環(huán)境,進(jìn)行進(jìn)一步的測(cè)試,之后才會(huì)將其部署到生產(chǎn)環(huán)境中供用戶使用。自動(dòng)化能夠確保整個(gè)過程快速、可靠、可重復(fù),并且減少出錯(cuò)的概率。
既然如此,什么是CI/CD?
一些相關(guān)書籍已經(jīng)介紹得很清楚了。如何、為什么以及何時(shí)在你的基礎(chǔ)架構(gòu)中實(shí)現(xiàn)CI/CD。然而,我們總是喜歡少一點(diǎn)理論,多一點(diǎn)實(shí)踐。既然如此,我們將簡(jiǎn)要描述在提交代碼更改后應(yīng)該執(zhí)行的自動(dòng)化步驟:
持續(xù)集成(CI):第一步中不包括QA。換句話說,它并不關(guān)注代碼是否提供了客戶要求的特性。相反,它關(guān)注的是要確保代碼質(zhì)量。通過單元測(cè)試、集成測(cè)試,可以將任何有關(guān)代碼質(zhì)量的問題通知給開發(fā)人員。我們可以進(jìn)一步通過代碼覆蓋率和靜態(tài)分析來強(qiáng)化測(cè)試,從而進(jìn)一步保證代碼質(zhì)量。
用戶驗(yàn)收測(cè)試:這是CD流程中的第一部分。在此階段,將對(duì)代碼進(jìn)行自動(dòng)化測(cè)試,以確保其滿足客戶的期望。例如,一款web應(yīng)用程序或許能夠正常運(yùn)行,不引發(fā)任何錯(cuò)誤,但是客戶希望訪客能夠在進(jìn)入主頁之前先經(jīng)過一個(gè)包含推廣的登陸頁。當(dāng)前的代碼會(huì)將訪客直接帶到主頁面,這與客戶的實(shí)際要求是有偏差的,UAT測(cè)試會(huì)可以指出這類問題。在非CD環(huán)境中,該工作需要QA測(cè)試人員人工完成。
部署:這是CD流程中的第二部分。它涉及到對(duì)將承載應(yīng)用程序的服務(wù)器/容器進(jìn)行更改,使其能夠反映更新后的版本。這項(xiàng)工作應(yīng)該以自動(dòng)化的方式完成,最好是通過諸如Ansible、Chef或Puppet等配置管理工具來完成。
什么是管道(Pipeline)?
管道是一個(gè)擁有簡(jiǎn)單概念的高級(jí)術(shù)語。當(dāng)你為實(shí)現(xiàn)一個(gè)共同目標(biāo),可能需要按照一定的順序執(zhí)行很多個(gè)腳本,而這些腳本被統(tǒng)稱為“管道”。
例如,在Jenkins中,一個(gè)管道可能包含一個(gè)或多個(gè)必須全部完成才能實(shí)現(xiàn)成功構(gòu)建的階段。使用多個(gè)階段能夠?qū)⒄麄€(gè)過程可視化,了解每個(gè)階段所花費(fèi)的時(shí)間,并清楚了解構(gòu)建在何處失敗。
實(shí)驗(yàn)室:為Golang App創(chuàng)建管道
在該實(shí)驗(yàn)室中,我們將構(gòu)建一個(gè)持續(xù)交付(CD)管道。我們使用的是一個(gè)用Go語言編寫的非常簡(jiǎn)單的應(yīng)用程序。為了簡(jiǎn)單起見,我們僅對(duì)代碼運(yùn)行一種類型的測(cè)試。該實(shí)驗(yàn)的前提條件如下:
正在運(yùn)行的Jenkins實(shí)例??梢允窃茖?shí)例、虛擬機(jī)、裸機(jī)或docker容器。它必須能夠從網(wǎng)絡(luò)上進(jìn)行公開訪問,以便存儲(chǔ)庫可以通過webhook連接到Jenkins。
鏡像注冊(cè)表:你可以使用Docker Registry,這是一種基于云的產(chǎn)品,如ECR或GCR,甚至也可以使用自定義注冊(cè)表。
ECR:https://aws.amazon.com/ecr/
GCR:https://cloud.google.com/container-registry/
一個(gè)GitHub上的賬戶。雖然我們?cè)诒纠惺褂昧薌itHub,但是這個(gè)過程可以與其他存儲(chǔ)庫(比如Bitbucket)一樣進(jìn)行細(xì)微的修改。
該管道可描述如下:
步驟一:應(yīng)用文件
我們的示例應(yīng)用程序?qū)?duì)任何GET請(qǐng)求作出“Hello World”響應(yīng)。創(chuàng)建一個(gè)名為main.go的新文件,并在文件中添加以下內(nèi)容:
由于我們要構(gòu)建一個(gè)CD管道,所以應(yīng)該進(jìn)行一些測(cè)試。我們的代碼非常簡(jiǎn)單,只需要一個(gè)測(cè)試用例即可,確保我們?cè)邳c(diǎn)擊根URL時(shí)能夠收到正確的字符串。在相同目錄中創(chuàng)建一個(gè)名為main_test.go的新文件,并添加以下內(nèi)容:
還有其他幾個(gè)文件可以幫助我們部署應(yīng)用程序,這些文件名為:
The Dockerfile
我們?cè)诖藢?duì)應(yīng)用程序進(jìn)行打包:
Dockerfile是一個(gè)多階段構(gòu)建文件,它可以使鏡像盡可能得小一些。它開始于一個(gè)以golang:alpine為基礎(chǔ)的構(gòu)建鏡像。生成的二進(jìn)制文件將被用于第二個(gè)鏡像,這只是一scratch鏡像,不包含依賴項(xiàng)或庫,只包含啟動(dòng)應(yīng)用程序的二進(jìn)制文件。
scratch: https://hub.docker.com/_/scratch/
The Service
由于我們使用Kubernetes作為承載此應(yīng)用程序的平臺(tái),因此至少需要一項(xiàng)服務(wù)和部署。我們的service.yml文件如下所示:
這沒有什么特別之處。只是一個(gè)使用NodePort作為其類型的服務(wù)。它將監(jiān)聽任何集群節(jié)點(diǎn)的IP地址上的32000端口。傳入的連接將中繼到8080端口上的吊艙(pod)。內(nèi)部通信方面,服務(wù)將監(jiān)聽80端口。
The deployment
一旦應(yīng)用程序本身進(jìn)行了docker化,就可以通過Deployment資源將其部署到Kubernetes。該deployment.yml文件如下所示:
這個(gè)部署定義最有趣的地方是鏡像部分。我們沒有硬編碼圖像名稱和標(biāo)簽,而是使用了一個(gè)變量。稍后,我們將看到如何使用該定義作為Ansible的模板,并通過命令行參數(shù)替換鏡像名稱(以及部署的任何其他參數(shù))。
The playbook
在該實(shí)驗(yàn)中,我們使用Ansible作為部署工具。部署Kubernetes資源有許多種方法,包括Helm Charts,但我認(rèn)為使用Ansible更簡(jiǎn)單一些。Ansible使用playbook來組織其指令。我們的playbook.yml文件如下所示:
Ansible已經(jīng)包含了用于處理與Kubernetes API服務(wù)器通信的k8s模塊。因此,我們不需要安裝kubectl,但是我們需要一個(gè)有效的kubeconfig文件來連接到集群(稍后會(huì)詳細(xì)介紹)。我們來快速瀏覽一下playbook:
k8s模塊: https://docs.ansible.com/ansible/latest/modules/k8s_module.html
kubectl: https://kubernetes.io/docs/reference/kubectl/overview/
playbook的主要功能是用于將服務(wù)和資源部署到集群。
因?yàn)槲覀冃枰趫?zhí)行時(shí)將數(shù)據(jù)動(dòng)態(tài)地注入到定義文件中,所以需要使用我們的定義文件作為模板,其中可以從外部提供變量。
為此,Ansible提供了查找功能,你可以在其中傳遞有效的YAML文件作為模板。Ansible支持多種將變量注入到模板的方法。在本特定實(shí)驗(yàn)中,我們將使用命令行方法。
步驟二:安裝Jenkins、Ansible和Docker
現(xiàn)在,我們可以安裝Ansible,并通過它來自動(dòng)部署一個(gè)Jenkins服務(wù)器和Docker運(yùn)行時(shí)環(huán)境。我們還需要安裝openshift Python模塊以啟用與Kubernetes的Ansible連接。
Ansible的安裝過程非常簡(jiǎn)單,只需安裝Python,然后使用pip安裝Ansible就可以了:
1. 登錄到Jenkins實(shí)例。
2. 安裝Python 3、Ansible和openshift模塊:
sudo apt update && sudo apt install -y python3 && sudo apt install -y python3-pip && sudo pip3 install ansible && sudo pip3 install openshift
3. 默認(rèn)情況下,pip會(huì)將二進(jìn)制文件安裝在用戶主文件夾中的一個(gè)隱藏目錄下。我們需要將此目錄添加到$PATH變量中,以便輕松調(diào)用命令:
echo "export PATH=$PATH:~/.local/bin" >> ~/.bashrc && . ~/.bashrc
4. 安裝部署Jenkins實(shí)例所需的Ansible角色:
ansible-galaxy install geerlingguy.jenkins
5. 安裝Docker角色:
ansible-galaxy install geerlingguy.docker
6. 創(chuàng)建一個(gè)playbook.yaml文件并添加以下內(nèi)容:
7. 通過以下命令運(yùn)行該playbook文件:
ansible-playbook playbook.yaml.
這里要注意,我們實(shí)例使用的公共IP地址作為Jenkins使用的主機(jī)名。如果你使用的是DNS,那么可能需要替換成實(shí)例的DNS名稱。另外,請(qǐng)注意,在運(yùn)行playbook之前,必須在防火墻上啟用8080端口 (如果有的話)。
8. 幾分鐘后,Jenkins應(yīng)該就安裝好了。你可以通過導(dǎo)航到計(jì)算機(jī)的IP地址(或者DNS名稱)并指定8080端口來進(jìn)行檢查:
9. 單擊“登陸”,填寫“admin”作為用戶名和密碼。注意,這些是我們使用Ansible角色設(shè)置的默認(rèn)憑據(jù),在生產(chǎn)環(huán)境中使用Jenkins時(shí),你可以(也應(yīng)該)對(duì)其進(jìn)行更改??梢酝ㄟ^設(shè)置角色變量來完成。詳情參見角色官方頁面。
官方頁面:https://galaxy.ansible.com/geerlingguy/jenkins
10. 你最后要做的是安裝將在實(shí)驗(yàn)中使用到的以下插件:git、pipeline、CloudBees Docker Build和Publish、GitHub
步驟三:配置Jenkins用戶以連接到集群
如上所述,本實(shí)驗(yàn)假設(shè)你已經(jīng)安裝并運(yùn)行了一個(gè)Kubernetes集群。為了使Jenkins能夠連接到這個(gè)集群,我們需要添加必要的kubeconfig文件。在本特定實(shí)驗(yàn)中,我們將使用一個(gè)托管在Google Cloud上的Kubernetes集群,因此我們將使用gcloud命令。你的具體情況可能有所不同。但在所有情況中,我們都必須將kubeconfig文件復(fù)制到Jenkins的用戶目錄,如下所示:
請(qǐng)注意,你在此處使用的帳戶必須具有創(chuàng)建和管理部署(Deployments)和服務(wù)(Services)所需的權(quán)限。
步驟04:創(chuàng)建Jenkins Pipeline 作業(yè)
創(chuàng)建一個(gè)新的Jenkins作業(yè)并選擇管道類型。作業(yè)設(shè)置如下所示:
我們更改的設(shè)置是:
我們使用Poll SCM作為構(gòu)建觸發(fā)器,此設(shè)置將會(huì)指導(dǎo)Jenkins定期檢查Git存儲(chǔ)庫(按*****指示的每分鐘檢查一次)。如果倉庫自上次poll以來已經(jīng)更改過,那么將觸發(fā)作業(yè)。
在管道本身,我們指定了存儲(chǔ)庫URL和憑據(jù)。分支是master。
在本實(shí)驗(yàn)中,我們將作業(yè)的所有代碼添加到一個(gè)Jenkinsfile中,該文件與代碼存儲(chǔ)在相同的存儲(chǔ)庫中。本文稍后將討論該Jenkinsfile。
步驟五:為GitHub和Docker Hub配置Jenkins憑據(jù)
轉(zhuǎn)到/credentials/store/system/domain/_/newCredentials并將憑據(jù)添加到兩個(gè)目標(biāo)中。確保提供有效的ID和描述,因?yàn)樯院髮⒁盟鼈儯?/p>
/credentials/store/system/domain/_/newCredentials:
http://35.238.224.64:8080/credentials/store/system/domain/_/newCredentials
步驟六:創(chuàng)建Jenkinsfile
Jenkinsfile指導(dǎo)Jenkins如何構(gòu)建、測(cè)試、docker化、發(fā)布并交付我們的應(yīng)用程序。我們的Jenkinsfile如下所示:
pipeline {
agent any
environment {
registry="magalixcorp/k8scicd"
GOCACHE="/tmp"
}
stages {
stage('Build') {
agent {
docker {
image 'golang'
}
}
steps {
// Create our project directory.
sh 'cd ${GOPATH}/src'
sh 'mkdir -p ${GOPATH}/src/hello-world'
// Copy all files in our Jenkins workspace to our project directory.
sh 'cp -r ${WORKSPACE}/* ${GOPATH}/src/hello-world'
// Build the app.
sh 'go build'
}
}
stage('Test') {
agent {
docker {
image 'golang'
}
}
steps {
// Create our project directory.
sh 'cd ${GOPATH}/src'
sh 'mkdir -p ${GOPATH}/src/hello-world'
// Copy all files in our Jenkins workspace to our project directory.
sh 'cp -r ${WORKSPACE}/* ${GOPATH}/src/hello-world'
// Remove cached test results.
sh 'go clean -cache'
// Run Unit Tests.
sh 'go test ./... -v -short'
}
}
stage('Publish') {
environment {
registryCredential='dockerhub'
}
steps{
script {
def appimage=docker.build registry + ":$BUILD_NUMBER"
docker.withRegistry( '', registryCredential ) {
appimage.push
appimage.push('latest')
}
}
}
}
stage ('Deploy') {
steps {
script{
def image_id=registry + ":$BUILD_NUMBER"
sh "ansible-playbook playbook.yml --extra-vars \"image_id=${image_id}\""
}
}
}
}
}
?文件構(gòu)建起來比看上去容易。管道基本上包含四個(gè)階段:
1. 在Build階段構(gòu)建Go二進(jìn)制,并且確保在構(gòu)建過程中沒有任何錯(cuò)誤。
2. 在Test階段應(yīng)用簡(jiǎn)單的UAI測(cè)試來確保應(yīng)用程序按預(yù)期工作。
3. 在Publish階段構(gòu)建Docker鏡像,并將其推送到注冊(cè)表。此后,其可供任何環(huán)境使用。
4. 在Deploy階段調(diào)用Ansible來聯(lián)系Kubernetes并應(yīng)用定義文件。
現(xiàn)在,我們來討論一下此Jenkinsfile的關(guān)鍵部分。
前兩個(gè)階段大致相似。它們都用了Golang Docker鏡像來構(gòu)建應(yīng)用程序。讓階段在已經(jīng)準(zhǔn)備好所有必需的構(gòu)建和測(cè)試工具的Docker容器中運(yùn)行始終是一個(gè)好習(xí)慣。另一個(gè)選擇是在主服務(wù)器上或者從服務(wù)器上安裝這些工具。當(dāng)你需要針對(duì)不同的工具版本進(jìn)行測(cè)試時(shí),問題就來了。例如,我們可能希望使用Go 1.9構(gòu)建和測(cè)試我們的代碼,因?yàn)槲覀兊膽?yīng)用程序還沒有準(zhǔn)備好使用最新版本的Golang。鏡像中包含所有內(nèi)容,因此更改版本甚至鏡像類型就變得像更改字符串一樣簡(jiǎn)單。
Publish階段(從第42行開始)首先指定一個(gè)環(huán)境變量,該變量將在后面的步驟中使用。該變量指向在先前步驟中添加到Jenkins的Docker Hub憑據(jù)的ID。
第48行:我們使用docker插件來構(gòu)建鏡像。它默認(rèn)在注冊(cè)表中使用Dockerfile,并將構(gòu)建編號(hào)添加為鏡像標(biāo)簽。當(dāng)你需要確定哪個(gè)Jenkins構(gòu)建是當(dāng)前正在運(yùn)行的容器的源代碼時(shí),這就變得非常重要。
第49-51行:鏡像構(gòu)建成功之后,我們使用構(gòu)建編號(hào)將其推入Docker Hub。此外,我們將“最新的”標(biāo)簽添加到鏡像中(第二個(gè)標(biāo)簽),這樣一來,如果用戶需要,就可以在不指定構(gòu)建編號(hào)的情況下提取鏡像。
第56-60行: 在部署階段,我們將部署和服務(wù)定義文件應(yīng)用到集群。我們使用之前討論過的playbook來調(diào)用Ansible。需要注意,我們將image_id作為命令行變量傳遞。此值將自動(dòng)替換部署文件中的鏡像名稱。
測(cè)試我們的CD管道
本文的最后一部分進(jìn)行了實(shí)例測(cè)試。我們將把代碼提交給GitHub,并確保我們的代碼能夠在管道中順利運(yùn)行到集群:
1. 添加文件:
git add *
2. 提交更改:
git commit -m "Initial commit"
3.推送至GitHub:
git push
4. 在Jenkins上,我們可以等待作業(yè)自動(dòng)觸發(fā),也可以直接點(diǎn)擊“立刻構(gòu)建(Build Now)”。
5. 如果作業(yè)運(yùn)行成功,我們可以使用以下命令來檢查部署的應(yīng)用程序。
6. 獲取節(jié)點(diǎn)IP地址:
7. 現(xiàn)在,讓我們向應(yīng)用程序發(fā)起一個(gè)HTTP請(qǐng)求:
可以看到,我們的應(yīng)用程序運(yùn)行正常。下面,讓我們?cè)诖a中故意犯一個(gè)錯(cuò)誤,并確保管道不會(huì)將錯(cuò)誤代碼發(fā)送到目標(biāo)環(huán)境:
將應(yīng)該顯示的消息更改為“Hello World!”(我們將每個(gè)單詞的第一個(gè)字母大寫,并在后面加上感嘆號(hào))。因?yàn)槲覀兊目蛻艨赡懿幌M⒁赃@種方式顯示,所以管道應(yīng)該在Test測(cè)試階段停止。
首先,我們進(jìn)行了更改。現(xiàn)在,main.go文件應(yīng)如下所示:
接下來,讓我們提交并推送代碼:
回到Jenkins,我們可以看到最后一次構(gòu)建失敗了:
通過單擊失敗的作業(yè),我們可以看到其失敗的原因:
該錯(cuò)誤代碼永遠(yuǎn)不會(huì)到達(dá)目標(biāo)環(huán)境。
TL;DR
CI/CD是所有遵循Agile方法的現(xiàn)代環(huán)境的組成部分。
通過管道,你能夠確保代碼從版本控制系統(tǒng)到目標(biāo)環(huán)境(testing/staging/production/etc.)的平穩(wěn)過渡,同時(shí)應(yīng)用所有必要的測(cè)試和質(zhì)量控制實(shí)踐。
在本文中,我們進(jìn)行了真實(shí)的實(shí)驗(yàn),構(gòu)建了一個(gè)持續(xù)交付管道來部署Golang應(yīng)用程序。
通過Jenkins,我們能夠從存儲(chǔ)庫中提取代碼,使用相關(guān)的Docker鏡像對(duì)其進(jìn)行構(gòu)建和測(cè)試。
接下來,我們對(duì)應(yīng)用程序進(jìn)行Docker化并將其推送到Docker Hub——因?yàn)樗ㄟ^了我們的測(cè)試。
最后,我們使用Ansible將應(yīng)用程序部署到運(yùn)行Kubernetes的目標(biāo)環(huán)境中。
使用Jenkins管道和Ansible令更改工作流變得非常簡(jiǎn)單和靈活,幾乎不會(huì)產(chǎn)生什么摩擦問題。例如,我們可以在Test階段中添加更多的測(cè)試,可以更改用于構(gòu)建和測(cè)試代碼的Go版本,還可以使用更多的變量來更改部署和服務(wù)中的其他方面。
最棒的一點(diǎn)是我們使用了Kubernetes部署,這能夠確保在更改容器鏡像時(shí),應(yīng)用程序的停機(jī)時(shí)間為0。因?yàn)镈eployments在默認(rèn)情況下使用滾動(dòng)更新方法來終止和重新創(chuàng)建容器。只有當(dāng)新容器啟動(dòng)并且運(yùn)行狀況良好時(shí),Deployment才會(huì)終止舊容器。
原文:https://hackernoon.com/how-to-create-a-cd-pipeline-with-kubernetes-ansible-and-jenkins-i6c03yp2
本文為 CSDN 翻譯,轉(zhuǎn)載請(qǐng)注明來源出處。
可用HA(High Availability)是分布式系統(tǒng)架構(gòu)設(shè)計(jì)中必須考慮的因素之一,它通常是指,通過設(shè)計(jì) 減少系統(tǒng)不能提供服務(wù)的時(shí)間。我們都知道,單點(diǎn)是系統(tǒng)高可用的大敵,單點(diǎn)往往是系統(tǒng)高可用最大的 風(fēng)險(xiǎn)和敵人,應(yīng)該盡量在系統(tǒng)設(shè)計(jì)的過程中避免單點(diǎn)。方法論上,高可用保證的原則是“集群化”,或者 叫“冗余”:只有一個(gè)單點(diǎn),掛了服務(wù)會(huì)受影響;如果有冗余備份,掛了還有其他backup能夠頂上。
我們實(shí)際使用 Spring Cloud Gateway 的方式如上圖,不同的客戶端使用不同的負(fù)載將請(qǐng)求分發(fā)到后端 的 Gateway,Gateway 再通過HTTP調(diào)用后端服務(wù),最后對(duì)外輸出。因此為了保證 Gateway 的高可用 性,前端可以同時(shí)啟動(dòng)多個(gè) Gateway 實(shí)例進(jìn)行負(fù)載,在 Gateway 的前端使用 Nginx 或者 F5 進(jìn)行負(fù)載 轉(zhuǎn)發(fā)以達(dá)到高可用性。
(1) 準(zhǔn)備多個(gè)GateWay工程
修改 shop_gateway_server 的application.yml。添加如下配置
spring:
application:
name: api-gateway #指定服務(wù)名
cloud:
gateway:
routes:
- id: product-service
uri: lb://shop-service-product
predicates:
- Path=/product-service/**
filters:
- RewritePath=/product-service/(?<segment>.*), /$\{segment}
eureka:
client:
serviceUrl:
defaultZone: http://eureka1:8761/eureka/
registry-fetch-interval-seconds: 5 # 獲取服務(wù)列表的周期:5s
instance:
preferIpAddress: true
ip-address: 127.0.0.1
---
spring:
profiles: gateway01
server:
port: 8080 #服務(wù)端口
---
spring:
profiles: gateway02
server:
port: 8081 #服務(wù)端口
通過不同的profiles配置啟動(dòng)兩個(gè)網(wǎng)關(guān)服務(wù),請(qǐng)求端口分別為8080和8081。瀏覽器驗(yàn)證發(fā)現(xiàn)效果是一致 的。
(2) 配置ngnix
找到ngnix添加負(fù)載均衡配置
#配置多臺(tái)服務(wù)器(這里只在一臺(tái)服務(wù)器上的不同端口)
upstream gateway {
server 127.0.0.1:8081;
server 127.0.0.1:8080;
}
#請(qǐng)求轉(zhuǎn)向mysvr 定義的服務(wù)器列表
location / {
proxy_pass http://gateway;
}
在瀏覽器上通過訪問http://localhost/order-service/order/buy/1請(qǐng)求的效果和之前是一樣的。這次關(guān) 閉一臺(tái)網(wǎng)關(guān)服務(wù)器,還是可以支持部分請(qǐng)求的訪問。
Spring Cloud Gateway 核心處理流程如上圖所示,Gateway的客戶端向 Spring Cloud Gateway 發(fā) 送請(qǐng)求,請(qǐng)求首先被 HttpWebHandlerAdapter 進(jìn)行提取組裝成網(wǎng)關(guān)上下文,然后網(wǎng)關(guān)的上下文會(huì)傳遞 到 DispatcherHandler 。 DispatcherHandler 是所有請(qǐng)求的分發(fā)處理器, DispatcherHandler 主要 負(fù)責(zé)分發(fā)請(qǐng)求對(duì)應(yīng)的處理器。比如請(qǐng)求分發(fā)到對(duì)應(yīng)的 RoutePredicateHandlerMapping (路由斷言處 理映射器)。路由斷言處理映射器主要作用用于路由查找,以及找到路由后返回對(duì)應(yīng)的 FilterWebHandler 。 FilterWebHandler 主要負(fù)責(zé)組裝Filter鏈并調(diào)用Filter執(zhí)行一系列的Filter處理, 然后再把請(qǐng)求轉(zhuǎn)到后端對(duì)應(yīng)的代理服務(wù)處理,處理完畢之后將Response返回到Gateway客戶端。