天天看點

Kubernetes微服務架構應用實踐

谷歌于2015年正式推出的kubernetes開源項目目前已經吸引了衆多it公司的關注,這些公司包括redhat、coreos、ibm、惠普等知名it公司,也包括國内如華為、時速雲等公司。為什麼kubernetes會引發這麼多公司的關注?最根本的原因是kubernetes是新一代的基于先進容器技術的微服務架構平台,它将目前火爆的容器技術與微服務架構兩大吸引眼球的技術點完美的融為一體,并且切切實實的解決了傳統分布式系統開發過程中長期存在的痛點問題。

本文假設您已經很熟悉并掌握了docker技術,這裡不會再花費篇幅介紹它。正是通過輕量級的容器隔離技術,kubernetes實作了“微服務”化的特性,同時借助于docker提供的基礎能力,使得平台的自動化能力得以實作。

概念與原理

作為一個架構師來說,我們做了這麼多年的分布式系統,其實我們真正關心的并不是伺服器、交換機、負載均衡器、監控與部署這些事物,我們真正關心的是“服務”本身,并且在内心深處,我們渴望能實作圖1所示的下面的這段“願景”:

我的系統中有servicea、serviceb、servicec三種服務,其中servicea需要部署3個執行個體、而serviceb與servicec各自需要部署5個執行個體,我希望有一個平台(或工具)幫我自動完成上述13個執行個體的分布式部署,并且持續監控它們。當發現某個伺服器當機或者某個服務執行個體故障的時候,平台能夠自我修複,進而確定在任何時間點,正在運作的服務執行個體的數量都是我所預期的。這樣一來,我和我的團隊隻需關注服務開發本身,而無需再為頭疼的基礎設施和運維監控的事情而煩惱了。

圖1 分布式系統架構願景

直到kubernetes出現之前,沒有一個公開的平台聲稱實作了上面的“願景”,這一次,又是谷歌的神作驚豔了我們。kubernetes讓團隊有更多的時間去關注與業務需求和業務相關的代碼本身,進而在很大程度上提升了整個軟體團隊的工作效率與投入産出比。

kubernetes裡核心的概念隻有以下幾個:

service

pod

deployments(rc)

service表示業務系統中的一個“微服務”,每個具體的service背後都有分布在多個機器上的程序執行個體來提供服務,這些程序執行個體在kubernetes裡被封裝為一個個pod,pod基本等同于docker container,稍有不同的是pod其實是一組密切捆綁在一起并且“同生共死”的docker container,從模型設計的角度來說,的确存在一個服務執行個體需要多個程序來提供服務并且它們需要“在一起” 的情況。

kubernetes的service與我們通常所說的“service”有一個明顯的的不同,前者有一個虛拟ip位址,稱之為“clusterip”,服務與服務之間“clusterip+服務端口”的方式進行通路,而無需一個複雜的服務發現的api。這樣一來,隻要知道某個service的clusterip,就能直接通路該服務,為此,kubernetes提供了兩種方式來解決clusterip的發現問題:

第一種方式是通過環境變量,比如我們定義了一個名稱為order_service 的service ,配置設定的clusterip為10.10.0.3 ,則在每個服務執行個體的容器中,會自動增加服務名到clusterip映射的環境變量:order_service_service_host=10.10.0.3,于是程式裡可以通過服務名簡單獲得對應的clusterip。

第二種方式是通過dns,這種方式下,每個服務名與clusterip的映射關系會被自動同步到kubernetes叢集裡内置的dns元件裡,于是直接通過對服務名的dns lookup機制就找到對應的clusterip了,這種方式更加直覺。

由于kubernetes的service這一獨特設計實作思路,使得所有以tcp /ip 方式進行通信的分布式系統都能很簡單的遷移到kubernetes平台上了。如圖2所示,當用戶端通路某個service的時候,kubernetes内置的元件kube-proxy透明的實作了到後端pod的流量負載均衡、會話保持、故障自動恢複等進階特性。

圖2 kubernetes負載均衡原理

kubernetes是如何綁定service與pod的呢?它如何區分哪些pod對應同一個service?答案也很簡單——“貼标簽”。每個pod都可以貼一個或多個不同的标簽(label),而每個service都一個“标簽選擇器”,标簽選擇器(label selector)确定了要選擇擁有哪些标簽的對象,比如下面這段yaml格式的内容定義了一個稱之為ku8-redis-master的service,它的标簽選擇器的内容為“app: ku8-redis-master”,表明擁有“app= ku8-redis-master”這個标簽的pod都是為它服務的。

apiversion: v1

kind: service

metadata:

name: ku8-redis-master

spec:

ports:

port: 6379

selector:

app: ku8-redis-master

下面是對應的pod的定義,注意到它的labels屬性的内容:

kind: pod

labels:

containers:

name: server

image: redis

containerport: 6379

restartpolicy: never

最後,我們來看看deployment/rc的概念,它的作用是用來告訴kubernetes,某種類型的pod(擁有某個特定标簽的pod)需要在叢集中建立幾個副本執行個體,deployment/rc的定義其實是pod建立模闆(template)+pod副本數量的聲明(replicas):

kind: replicationcontroller

name: ku8-redis-slave

replicas: 2

template:

app: ku8-redis-slave

image: devopsbq/redis-slave

env:

name: master_addr

value: ku8-redis-master

kubernetes開發指南

本節我們以一個傳統的java應用為例,來說明如何将其改造遷移到kubernetes的先進微服務架構平台上來。

如圖3所示,我們的這個示例程式是一個跑在tomcat裡的web應用,為了簡化,沒有用任何架構,直接在jsp頁面裡通過jdbc操作資料庫。

圖3 待改造的java web應用

上述系統中,我們将mysql服務與web應用分别模組化為kubernetes中的一個service,其中mysql服務的service定義如下:

name: mysql

port: 3306

app: mysql_pod

mysql服務對應的deployment/rc的定義如下:

name: mysql-deployment

replicas: 1

image: mysql

imagepullpolicy: ifnotpresent

containerport: 3306

name: mysql_root_password

value: "123456"

下一步,我們需要改造web應用中擷取mysql位址的這段代碼,從容器的環境變量中擷取上述mysql服務的ip與port:

string ip=system.getenv("mysql_service_host");

string port=system.getenv("mysql_service_port");

ip=(ip==null)?"localhost":ip;

port=(port==null)?"3306":port;

conn = java.sql.drivermanager.getconnection("jdbc:mysql://"+ip+":"+port+"?useunicode=true&characterencoding=utf-8", "root","123456");

接下來,将此web應用打包為一個标準的docker鏡像,名字為k8s_myweb_image,這個鏡像直接從官方tomcat鏡像上添加我們的web應用目錄demo到webapps目錄下即可,dockerfile比較簡單,如下所示:

from tomcat

maintainer bestme

add demo /usr/local/tomcat/webapps/demo

類似之前的mysql服務定義,下面是這個web應用的service定義:

name: hpe-java-web

type: nodeport

port: 8080

nodeport: 31002

app: hpe_java_web_pod

下面是web應用的service對應的deployment/rc的定義:

name: hpe-java-web-deployement

name: myweb

image: k8s_myweb_image

containerport: 8080

定義好所有service與對應的deployment/rc描述檔案後(總共4個yaml檔案),我們可以通過kubernetes的指令行工具kubectrl –f create xxx.yaml送出到叢集裡,如果一切正常,kubernetes會在幾分鐘内自動完成部署,你會看到相關的資源對象都已經建立成功:

-bash-4.2# kubectl get svc

name cluster-ip external-ip port(s) age

hpe-java-web 10.254.183.22 nodes 8080/tcp 36m

kubernetes 10.254.0.1 443/tcp 89d

mysql 10.254.170.22 3306/tcp 36m

-bash-4.2# kubectl get pods

name ready status restarts age

hpe-java-web-deployement-q8t9k 1/1 running 0 36m

mysql-deployment-5py34 1/1 running 0 36m

-bash-4.2# kubectl get rc

name desired current age

hpe-java-web-deployement 1 1 37m

mysql-deployment 1 1 37m

結束語

從上面步驟來看,傳統應用遷移改造到kubernetes上還是比較容易的,而借助于kubernetes的優勢,即使一個小的開發團隊,也能在系統架構和運維能力上迅速接近一個大的研發團隊的水準。

圖4 基于kubernetes的paas平台架構

作者簡介:吳治輝,惠普公司系統架構師,擁有超過15年的軟體研發經驗,專注于電信軟體和雲計算方面的軟體研發,同時也是《kubernetes權威指南》作者之一。

本文轉自d1net(轉載)

繼續閱讀