K8S 服務(wù)發(fā)現(xiàn)與 Sping-cloud-kubernetes

1渴庆、項(xiàng)目介紹

本文章,旨在使用K8S中自身的服務(wù)發(fā)現(xiàn)功能刃滓,不使用其他的服務(wù)發(fā)現(xiàn)組件咧虎,通過(guò) Spring 的 spring-cloud-kubernetes 來(lái)搭建SpringCloud項(xiàng)目计呈。


2、k8s service概述

在介紹Svc之前总寒,首先簡(jiǎn)單說(shuō)明下Kubernetes中Pod概念尉间。
Pod是Kubernetes非常重要的基本概念哲嘲,代表著集群中運(yùn)行的進(jìn)程媳禁,Pod中封裝著應(yīng)用的容器(有情況下是多個(gè)容器)竣稽。

Kubernetes為每個(gè)Pod都分配了唯一的Ip地址,稱為Pod Ip娃弓,一個(gè)Pod里的多個(gè)容器共享Pod Ip地址台丛,這樣客戶端可以通過(guò)Pod Ip+ 容器端口來(lái)訪問(wèn)Pod(Pod Ip+ 容器端口砾肺,又被稱為Endpoint变汪,也是Kubernetes一種資源)。

我們知道Kubernetes在自動(dòng)資源調(diào)度時(shí)实胸,會(huì)頻繁的銷毀與創(chuàng)建番官,這樣就會(huì)導(dǎo)致Pod Ip會(huì)頻繁的變動(dòng)鲤拿,客戶端幾乎不可能以Pod Ip+端口直接訪問(wèn)Pod,這時(shí)候就需要Kubernetes的另一種資源來(lái)實(shí)現(xiàn)生音,這就是SVC缀遍。

SVC服務(wù)是Kubernetes里的核心資源對(duì)象之一,其實(shí)可以理解成我們微服務(wù)架構(gòu)中的一個(gè)微服務(wù)台谊。SVC一旦被創(chuàng)建锅铅,Kubernetes就會(huì)自動(dòng)為它分配一個(gè)可用的Cluster IP减宣,在svc的整個(gè)生命周期內(nèi),Cluster IP不會(huì)發(fā)生改變漆腌。


3贼邓、k8s 服務(wù)發(fā)現(xiàn)簡(jiǎn)介

任何分布式系統(tǒng)都會(huì)涉及“服務(wù)發(fā)現(xiàn)”這個(gè)基礎(chǔ)問(wèn)題,大部分分布式 系統(tǒng)都通過(guò)提供特定的API接口來(lái)實(shí)現(xiàn)服務(wù)發(fā)現(xiàn)功能闷尿,但這樣做會(huì)導(dǎo)致 平臺(tái)的侵入性比較強(qiáng)塑径,也增加了開(kāi)發(fā)、測(cè)試的難度填具。Kubernetes則采用 了直觀樸素的思路去解決這個(gè)棘手的問(wèn)題统舀。

首先,每個(gè)Kubernetes中的Service都有唯一的Cluster IP及唯一的名 稱灌旧,而名稱是由開(kāi)發(fā)者自己定義的,部署時(shí)也沒(méi)必要改變枢泰,所以完全可 以被固定在配置中描融。接下來(lái)的問(wèn)題就是如何通過(guò)Service的名稱找到對(duì)應(yīng) 的Cluster IP。
目前衡蚂, Kubernetes上的大部分應(yīng)用都已經(jīng)采用了DNS這種新興的服務(wù)發(fā)現(xiàn)機(jī)制窿克。


4、項(xiàng)目搭建

下面我們就使用k8s中的原生服務(wù)發(fā)現(xiàn)功能毛甲,不使用其他的注冊(cè)組件年叮,來(lái)搭建在spring-cloud微服務(wù)架構(gòu),從而達(dá)到服務(wù)調(diào)用目的玻募。

現(xiàn)在對(duì)spring-cloud-kubernetes基本原理做簡(jiǎn)單介紹只损。通過(guò)上述描述,我們知道在K8S其實(shí)已經(jīng)維護(hù)了服務(wù)實(shí)例列表,每個(gè)服務(wù)對(duì)應(yīng)的Endpoint也保存在K8S集群etc數(shù)據(jù)庫(kù)中跃惫,所以spring-cloud-kubernetes所做的工作叮叹,就是在服務(wù)調(diào)用時(shí),找到找到服務(wù)的Endpoint爆存,從而完成服務(wù)調(diào)用蛉顽。我們發(fā)現(xiàn)spring-cloud-kubernetes也是通過(guò)實(shí)現(xiàn)DiscoveryClient接口,實(shí)現(xiàn)類KubernetesDiscoveryClient先较,具體源碼這里就不敘述了携冤。

4.1項(xiàng)目目錄:
  • abc-gateway 網(wǎng)關(guān)服務(wù)者
  • abc-service-provider 服務(wù)提供者
  • abc-service-consumer 服務(wù)消費(fèi)者
    這個(gè)三個(gè)項(xiàng)目都是非常簡(jiǎn)單的SpringBoot工程,但是都需要引用以下關(guān)鍵jar包闲勺,具體的版本跟隨SpringCloud版本即可曾棕。
<!-- 核心jar包,具體版本可參考官方網(wǎng)站-->
<!--服務(wù)間調(diào)用都是采用feign方式霉翔,所以需要加上相關(guān)jar包-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-all</artifactId>
</dependency>
4.2項(xiàng)目調(diào)用流程:
flow

4.3關(guān)鍵代碼

1睁蕾、abc-gateway 就是一個(gè)簡(jiǎn)單的springboot工程苞笨,pom文件添加相關(guān)jar包债朵,然后添加以下配置

# 配置文件配置
server:
  port: 30000
spring:
  application:
    name: abc-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
    kubernetes:
      reload:
        enabled: true
        mode: polling
        period: 5000

logging:
  level:
    org.springframework.cloud.gateway: debug
    org.springframework.cloud.loadbalancer: debug

2、abc-service-provider與abc-service-consumer 也是一個(gè)簡(jiǎn)單的SpringBoot工程瀑凝,與通常的工程沒(méi)有區(qū)別序芦,唯一需要修改的就是在POM文件中,添加上上述jar包粤咪。

/**
 * [abc-service-consumer] 啟動(dòng)類
 * 與通常的SpringBoot工程沒(méi)有區(qū)別
 */
@Slf4j
@RestController
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class AbcServiceConsumerApplication {
    
    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private FeignDemo demo;

    /**
     * 通過(guò)Feign調(diào)用服務(wù)提供者[abc-service-provider]的接口
     */
    @GetMapping("/get")
    public String feignDemo(){
        return demo.getMessage();
    }

    /**
     * KubernetesDiscoveryClient核心類實(shí)現(xiàn)了DiscoveryClient
     * 通過(guò)getServices()方法可以獲取k8s中的服務(wù)實(shí)例
     */
    @GetMapping("/abc-service-consumer/index")
    public String indexService() {
        log.info("消費(fèi)服務(wù):abc-service-consumer");
        List<String> services = discoveryClient.getServices();
        services.forEach(System.out::println);
        return "消費(fèi)服務(wù):abc-service-consumer";
    }

    public static void main(String[] args) {
        SpringApplication.run(AbcServiceConsumerApplication.class, args);
    }
}

------------

/**
 *[abc-service-consumer]服務(wù)Feign調(diào)用類谚中,通過(guò)Feign調(diào)用服務(wù)提供者abc-service-provider
 */
@FeignClient(value = "abc-service-provider")
public interface FeignDemo {

    @GetMapping("/get")
    String getMessage();
}

/**
 * [abc-service-provider]服務(wù)提供者啟動(dòng)類
 */
@SpringBootApplication
@RestController
@EnableDiscoveryClient
public class AbcServiceProviderApplication {

    @GetMapping("/get")
    public String get() {
        return "服務(wù)提供者";
    }

    public static void main(String[] args) {
        SpringApplication.run(AbcServiceProviderApplication.class, args);
    }
}

3、K8S 中資源創(chuàng)建模板:


# 注意: 由于我是本地已經(jīng)搭建好K8S環(huán)境與gitlab的CICD,所以該文件中包含多個(gè)腳本變量寥枝。如果使用該文件宪塔,只需要替換成自己項(xiàng)目信息即可。
# PROJECT_NAME:SpringBoot工程的服務(wù)名稱
# REPLACE_IMAGE: Docker鏡像
# PROJECT_PORT: SpringBoot工程的服務(wù)端口

# 定義Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: PROJECT_NAME
  labels:
    app: PROJECT_NAME
spec:
  replicas: 1
  template:
    metadata:
      name: PROJECT_NAME
      labels:
        app: PROJECT_NAME
    spec:
      containers:
        - name: PROJECT_NAME
          image: REPLACE_IMAGE
          ports:
            - containerPort: PROJECT_PORT
          imagePullPolicy: IfNotPresent
#     我使用的是阿里云的公共鏡像倉(cāng)庫(kù)囊拜。更簡(jiǎn)單的方式某筐,是將對(duì)應(yīng)的服務(wù)鏡像COPY到K8S的節(jié)點(diǎn)中。
#     (COPY到從節(jié)點(diǎn)冠跷,K8S如果沒(méi)有設(shè)置南誊,是不會(huì)調(diào)度Pod到master節(jié)點(diǎn)上)
      imagePullSecrets:
        - name: regcred-aliyun
      restartPolicy: Always
  selector:
    matchLabels:
      app: PROJECT_NAME

---
# 定義SVC
apiVersion: v1
kind: Service
metadata:
  name: PROJECT_NAME
spec:
  selector:
    app: PROJECT_NAME
  ports:
    - port: PROJECT_PORT
      targetPort: PROJECT_PORT
      nodePort: PROJECT_PORT
  type: NodePort

5、項(xiàng)目部署流程

1蜜托、構(gòu)建鏡像抄囚。java代碼準(zhǔn)備好之后,使用DockerFile構(gòu)建好3個(gè)服務(wù)鏡像橄务,然后Copy到k8s的node節(jié)點(diǎn)幔托。使用命令docker images查看鏡像

#如果想Pod能夠調(diào)度到master節(jié)點(diǎn),在master節(jié)點(diǎn)運(yùn)行
kubectl taint node k8s-master node-role.kubernetes.io/master-

#如果要恢復(fù)Master Only狀態(tài)蜂挪,執(zhí)行如下命令:
kubectl taint node k8s-master node-role.kubernetes.io/master=""

2重挑、構(gòu)建K8S服務(wù)迫肖。使用命令kubectl apply -f deployment文件名啟動(dòng)3個(gè)服務(wù),使用命令kubectl get svc查看攒驰。我們看到3個(gè)服務(wù)已經(jīng)成功啟動(dòng)蟆湖。

3、訪問(wèn)服務(wù)玻粪。因?yàn)镵8S中的服務(wù)是nodeport類型隅津,可以通過(guò)nodeIP來(lái)進(jìn)行訪問(wèn)。注意劲室,NodeIP與截圖中的Cluster-IP這個(gè)兩個(gè)IP有很大區(qū)別伦仍。樸素的數(shù),NodeIP是真實(shí)存在的IP很洋,是可以Ping通充蓝;而Cluster-IP是K8S獨(dú)有的,是虛擬IP喉磁,是Ping不通的谓苟。具體的大家可查看相關(guān)書(shū)籍。通過(guò)kubectl get node -o wide 可以查看到具體的NodeIP协怒,然后通過(guò)NodeIP來(lái)訪問(wèn)網(wǎng)關(guān)涝焙,從而驗(yàn)證結(jié)果。

4孕暇、驗(yàn)證結(jié)果仑撞。截圖中已經(jīng)打印出,服務(wù)提供者[abc-service-provider]中的信息妖滔。


6隧哮、項(xiàng)目總結(jié)

我們發(fā)現(xiàn)在使用spring-cloud-kubernetes組件后,不依賴于其他的服務(wù)注冊(cè)組件座舍,可以在K8S集群中正常運(yùn)行沮翔。所以,對(duì)應(yīng)那些在K8S集群中部署的SpringCloud服務(wù)簸州,可以擺脫服務(wù)發(fā)現(xiàn)組件的限制鉴竭。但是對(duì)于開(kāi)發(fā)人員來(lái)說(shuō),在開(kāi)發(fā)過(guò)程中本地的測(cè)試將是一個(gè)問(wèn)題岸浑,因?yàn)槲覀儼l(fā)現(xiàn)搏存,在項(xiàng)目啟動(dòng)過(guò)程中是要依賴K8S環(huán)境的,所以目前的spring-cloud-kubernetes對(duì)開(kāi)發(fā)來(lái)說(shuō)并不是太友好矢洲,希望后續(xù)版本能解決這個(gè)痛點(diǎn)璧眠。

我們知道K8S的服務(wù)有自身的負(fù)載均衡功能,在使用spring-cloud-kubernetes后,服務(wù)間調(diào)用的實(shí)質(zhì)是使用的Ribbon,Ribbon也是有負(fù)載均衡功能的责静,那么這兩者有沒(méi)有什么聯(lián)系呢袁滥?待我們下次討論。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末灾螃,一起剝皮案震驚了整個(gè)濱河市题翻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌腰鬼,老刑警劉巖嵌赠,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異熄赡,居然都是意外死亡姜挺,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)彼硫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)炊豪,“玉大人,你說(shuō)我怎么就攤上這事拧篮〈什常” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵他托,是天一觀的道長(zhǎng)掖肋。 經(jīng)常有香客問(wèn)我仆葡,道長(zhǎng)赏参,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任沿盅,我火速辦了婚禮把篓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘腰涧。我一直安慰自己韧掩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布窖铡。 她就那樣靜靜地躺著疗锐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪费彼。 梳的紋絲不亂的頭發(fā)上滑臊,一...
    開(kāi)封第一講書(shū)人閱讀 51,182評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音箍铲,去河邊找鬼雇卷。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的关划。 我是一名探鬼主播小染,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼贮折!你這毒婦竟也來(lái)了裤翩?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤调榄,失蹤者是張志新(化名)和其女友劉穎岛都,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體振峻,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡臼疫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了扣孟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片烫堤。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖凤价,靈堂內(nèi)的尸體忽然破棺而出鸽斟,到底是詐尸還是另有隱情,我是刑警寧澤利诺,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布富蓄,位于F島的核電站,受9級(jí)特大地震影響慢逾,放射性物質(zhì)發(fā)生泄漏立倍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一侣滩、第九天 我趴在偏房一處隱蔽的房頂上張望口注。 院中可真熱鬧,春花似錦君珠、人聲如沸寝志。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)材部。三九已至,卻和暖如春唯竹,著一層夾襖步出監(jiān)牢的瞬間乐导,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工摩窃, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留兽叮,地道東北人芬骄。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鹦聪,于是被迫代替她去往敵國(guó)和親账阻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353