Spring Boot集成kubernetes客戶端實現(xiàn)API操作k8s集群的方案
1.什么是kubernetes?
Kubernetes(也稱 k8s 或 “kube”)是一個開源的容器編排平臺,可以自動化在部署、管理和擴展容器化應(yīng)用過程中涉及的許多手動操作。 Kubernetes 最初是由 Google 工程師作為 Borg 項目開發(fā)和設(shè)計的,后于 2015 年捐贈給 云原生計算基金會(CNCF)。紅帽® 是第一批與 Google 合作研發(fā) Kubernetes 的公司之一,作為 Kubernetes 上游項目的第二大貢獻者,我們甚至在這個項目啟動之前就已參與其中。
傳統(tǒng)部署時代:
早期,各個組織是在物理服務(wù)器上運行應(yīng)用程序。 由于無法限制在物理服務(wù)器中運行的應(yīng)用程序資源使用,因此會導(dǎo)致資源分配問題。 例如,如果在同一臺物理服務(wù)器上運行多個應(yīng)用程序, 則可能會出現(xiàn)一個應(yīng)用程序占用大部分資源的情況,而導(dǎo)致其他應(yīng)用程序的性能下降。 一種解決方案是將每個應(yīng)用程序都運行在不同的物理服務(wù)器上, 但是當(dāng)某個應(yīng)用程序資源利用率不高時,剩余資源無法被分配給其他應(yīng)用程序, 而且維護許多物理服務(wù)器的成本很高。
虛擬化部署時代:
因此,虛擬化技術(shù)被引入了。虛擬化技術(shù)允許你在單個物理服務(wù)器的 CPU 上運行多臺虛擬機(VM)。 虛擬化能使應(yīng)用程序在不同 VM 之間被彼此隔離,且能提供一定程度的安全性, 因為一個應(yīng)用程序的信息不能被另一應(yīng)用程序隨意訪問。 虛擬化技術(shù)能夠更好地利用物理服務(wù)器的資源,并且因為可輕松地添加或更新應(yīng)用程序, 而因此可以具有更高的可擴縮性,以及降低硬件成本等等的好處。 通過虛擬化,你可以將一組物理資源呈現(xiàn)為可丟棄的虛擬機集群。 每個 VM 是一臺完整的計算機,在虛擬化硬件之上運行所有組件,包括其自己的操作系統(tǒng)。
容器部署時代:
容器類似于 VM,但是更寬松的隔離特性,使容器之間可以共享操作系統(tǒng)(OS)。 因此,容器比起 VM 被認為是更輕量級的。且與 VM 類似,每個容器都具有自己的文件系統(tǒng)、CPU、內(nèi)存、進程空間等。 由于它們與基礎(chǔ)架構(gòu)分離,因此可以跨云和 OS 發(fā)行版本進行移植。 容器因具有許多優(yōu)勢而變得流行起來,例如:
- 敏捷應(yīng)用程序的創(chuàng)建和部署:與使用 VM 鏡像相比,提高了容器鏡像創(chuàng)建的簡便性和效率。
- 持續(xù)開發(fā)、集成和部署:通過快速簡單的回滾(由于鏡像不可變性), 提供可靠且頻繁的容器鏡像構(gòu)建和部署。
- 關(guān)注開發(fā)與運維的分離:在構(gòu)建、發(fā)布時創(chuàng)建應(yīng)用程序容器鏡像,而不是在部署時, 從而將應(yīng)用程序與基礎(chǔ)架構(gòu)分離。
- 可觀察性:不僅可以顯示 OS 級別的信息和指標(biāo),還可以顯示應(yīng)用程序的運行狀況和其他指標(biāo)信號。
- 跨開發(fā)、測試和生產(chǎn)的環(huán)境一致性:在筆記本計算機上也可以和在云中運行一樣的應(yīng)用程序。
- 跨云和操作系統(tǒng)發(fā)行版本的可移植性:可在 Ubuntu、RHEL、CoreOS、本地、 Google Kubernetes Engine 和其他任何地方運行。
- 以應(yīng)用程序為中心的管理:提高抽象級別,從在虛擬硬件上運行 OS 到使用邏輯資源在 OS 上運行應(yīng)用程序。
- 松散耦合、分布式、彈性、解放的微服務(wù):應(yīng)用程序被分解成較小的獨立部分, 并且可以動態(tài)部署和管理 - 而不是在一臺大型單機上整體運行。
- 資源隔離:可預(yù)測的應(yīng)用程序性能。
- 資源利用:高效率和高密度
為什么需要 Kubernetes,它能做什么?
容器是打包和運行應(yīng)用程序的好方式。在生產(chǎn)環(huán)境中, 你需要管理運行著應(yīng)用程序的容器,并確保服務(wù)不會下線。 例如,如果一個容器發(fā)生故障,則你需要啟動另一個容器。 如果此行為交由給系統(tǒng)處理,是不是會更容易一些? 這就是 Kubernetes 要來做的事情! Kubernetes 為你提供了一個可彈性運行分布式系統(tǒng)的框架。 Kubernetes 會滿足你的擴展要求、故障轉(zhuǎn)移你的應(yīng)用、提供部署模式等。 例如,Kubernetes 可以輕松管理系統(tǒng)的 Canary (金絲雀) 部署。
Kubernetes相關(guān)概念總結(jié)
k8s中配置客戶端訪問pod中應(yīng)用的流程如下:
client->ingress->service->pod->container
INGRESS
Ingress 是對集群中服務(wù)的外部訪問進行管理的 API 對象,典型的訪問方式是 HTTP。 Ingress 可以提供負載均衡、SSL 終結(jié)和基于名稱的虛擬托管。
SERVICE
將運行在一組 Pods 上的應(yīng)用程序公開為網(wǎng)絡(luò)服務(wù)的抽象方法。Kubernetes Service 定義了這樣一種抽象:邏輯上的一組 Pod,一種可以訪問它們的策略 —— 通常稱為微服務(wù)。 Service 所針對的 Pods 集合通常是通過選擇算符來確定的。
POD
Pod 是可以在 Kubernetes 中創(chuàng)建和管理的、最小的可部署的計算單元。 Pod (就像在鯨魚莢或者豌豆莢中)是一組(一個或多個) 容器; 這些容器共享存儲、網(wǎng)絡(luò)、以及怎樣運行這些容器的聲明。 Pod 中的內(nèi)容總是并置(colocated)的并且一同調(diào)度,在共享的上下文中運行。 Pod 所建模的是特定于應(yīng)用的“邏輯主機”,其中包含一個或多個應(yīng)用容器, 這些容器是相對緊密的耦合在一起的。 在非云環(huán)境中,在相同的物理機或虛擬機上運行的應(yīng)用類似于 在同一邏輯主機上運行的云應(yīng)用。
節(jié)點(Node)
Kubernetes 集群中其中一臺工作機器,是集群的一部分。
k8s-client-java選型
目前通過java操作k8s,開源版本共有兩個:
kubernetes-client/java和fabric8io/kubernetes-client對比
和官網(wǎng)API一致性 | 社區(qū)活躍度 | 代碼生成 | |
---|---|---|---|
kubernetes-client/java | 根據(jù)k8s-openapi隨之更新,一致性和更新頻率高 | 目前不活躍 | kubernetes-client/java提供了生成代碼的通用跨語言工具,該工具托管在 kubernetes-client / gen存儲庫中 |
fabric8io/kubernetes-client | 一致性低,更新慢;其中不支持k8s1.8和1.13 | 社區(qū)活躍,目前使用者多 | 暫無 |
鑒于kubernetes-client/java和官網(wǎng)API一致性好,本文決定采用它
2.環(huán)境部署
Download and run the installer for the latest release.
Or if using PowerShell, use this command:
New-Item -Path 'c:\' -Name 'minikube' -ItemType Directory -Force Invoke-WebRequest -OutFile 'c:\minikube\minikube.exe' -Uri 'https://github.com/kubernetes/minikube/releases/latest/download/minikube-windows-amd64.exe' -UseBasicParsing
Add the minikube.exe binary to your PATH.
Make sure to run PowerShell as Administrator.
$oldPath = [Environment]::GetEnvironmentVariable('Path', [EnvironmentVariableTarget]::Machine) if ($oldPath.Split(';') -inotcontains 'C:\minikube'){ [Environment]::SetEnvironmentVariable('Path', $('{0};C:\minikube' -f $oldPath), [EnvironmentVariableTarget]::Machine) }
If you used a terminal (like powershell) for the installation, please close the terminal and reopen it before running minikube
other plateform,
please visit at:https://minikube.sigs.k8s.io/docs/start/?arch=%2Fwindows%2Fx86-64%2Fstable%2F.exe+download
install kubectl
https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/
Start your cluster
minikube start
Interact with your cluster
kubectl get po -A
Alternatively, minikube can download the appropriate version of kubectl and you should be able to use it like this:
minikube kubectl -- get po -A
You can also make your life easier by adding the following to your shell config: (for more details see: kubectl)
alias kubectl="minikube kubectl --"
Initially, some services such as the storage-provisioner, may not yet be in a Running state. This is a normal condition during cluster bring-up, and will resolve itself momentarily. For additional insight into your cluster state, minikube bundles the Kubernetes Dashboard, allowing you to get easily acclimated to your new environment:
minikube dashboard
3.代碼工程
實驗?zāi)繕?biāo)
- 實現(xiàn)java api獲取pod信息
- 實現(xiàn)java api創(chuàng)建ingress
- 實現(xiàn)java api創(chuàng)建service
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>springboot-demo</artifactId> <groupId>com.et</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>Kubernetes</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.kubernetes</groupId> <artifactId>client-java</artifactId> <version>12.0.1</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> </project>
kubernetes工具類
package com.et.k8s.client; import io.kubernetes.client.custom.IntOrString; import io.kubernetes.client.openapi.ApiClient; import io.kubernetes.client.openapi.ApiException; import io.kubernetes.client.openapi.apis.CoreV1Api; import io.kubernetes.client.openapi.apis.ExtensionsV1beta1Api; import io.kubernetes.client.openapi.apis.NetworkingV1Api; import io.kubernetes.client.openapi.models.*; import io.kubernetes.client.util.ClientBuilder; import io.kubernetes.client.util.KubeConfig; import lombok.extern.slf4j.Slf4j; import java.io.FileReader; import java.io.IOException; import java.util.Map; @Slf4j public class K8sClient { private ApiClient apiClient; /** * loading the in-cluster config, including: * 1. service-account CA * 2. service-account bearer-token * 3. service-account namespace * 4. master endpoints(ip, port) from pre-set environment variables */ public K8sClient() { try { this.apiClient = ClientBuilder.cluster().build(); } catch (IOException e) { log.error("build K8s-Client error", e); throw new RuntimeException("build K8s-Client error"); } } /** * loading the out-of-cluster config, a kubeconfig from file-system * * @param kubeConfigPath */ public K8sClient(String kubeConfigPath) { try { this.apiClient = ClientBuilder.kubeconfig(KubeConfig.loadKubeConfig(new FileReader(kubeConfigPath))).build(); } catch (IOException e) { log.error("read kubeConfigPath error", e); throw new RuntimeException("read kubeConfigPath error"); } catch (Exception e) { log.error("build K8s-Client error", e); throw new RuntimeException("build K8s-Client error"); } } /** * get all Pods * * @return podList */ public V1PodList getAllPodList() { // new a CoreV1Api CoreV1Api api = new CoreV1Api(apiClient); // invokes the CoreV1Api client try { V1PodList list = api.listPodForAllNamespaces(null, null, null, null, null, null, null, null, null, null); return list; } catch (ApiException e) { log.error("get podlist error:" + e.getResponseBody(), e); } return null; } /** * create k8s service * * @param namespace * @param serviceName * @param port * @param selector * @return */ public V1Service createService(String namespace, String serviceName, Integer port, Map<String, String> selector) { V1Service svc = new V1ServiceBuilder() .withNewMetadata() .withName(serviceName) .endMetadata() .withNewSpec() .addNewPort() .withProtocol("TCP") .withPort(port) .withTargetPort(new IntOrString(port)) .endPort() .withSelector(selector) .endSpec() .build(); // Deployment and StatefulSet is defined in apps/v1, so you should use AppsV1Api instead of CoreV1API CoreV1Api api = new CoreV1Api(apiClient); V1Service v1Service = null; try { v1Service = api.createNamespacedService(namespace, svc, null, null, null); } catch (ApiException e) { log.error("create service error:" + e.getResponseBody(), e); } catch (Exception e) { log.error("create service system error:", e); } return v1Service; } /** * create k8s V1Ingress * * @param namespace * @param ingressName * @param annotations * @param path * @param serviceName * @param servicePort * @return */ public V1Ingress createV1Ingress(String namespace, String ingressName, Map<String, String> annotations, String path, String serviceName, Integer servicePort) { //build ingress yaml V1Ingress ingress = new V1IngressBuilder() .withNewMetadata() .withName(ingressName) .withAnnotations(annotations) .endMetadata() .withNewSpec() .addNewRule() .withHttp(new V1HTTPIngressRuleValueBuilder().addToPaths(new V1HTTPIngressPathBuilder() .withPath(path) .withPathType("Prefix") .withBackend(new V1IngressBackendBuilder() .withService(new V1IngressServiceBackendBuilder() .withName(serviceName) .withPort(new V1ServiceBackendPortBuilder() .withNumber(servicePort).build()).build()).build()).build()).build()) .endRule() .endSpec() .build(); NetworkingV1Api api = new NetworkingV1Api(apiClient); V1Ingress v1Ingress = null; try { v1Ingress = api.createNamespacedIngress(namespace, ingress, null, null, null); } catch (ApiException e) { log.error("create ingress error:" + e.getResponseBody(), e); } catch (Exception e) { log.error("create ingress system error:", e); } return v1Ingress; } /** * create k8s ExtensionIngress * * @param namespace * @param ingressName * @param annotations * @param path * @param serviceName * @param servicePort * @return */ public ExtensionsV1beta1Ingress createExtensionIngress(String namespace, String ingressName, Map<String, String> annotations, String path, String serviceName, Integer servicePort) { //build ingress yaml ExtensionsV1beta1Ingress ingress = new ExtensionsV1beta1IngressBuilder() .withNewMetadata() .withName(ingressName) .withAnnotations(annotations) .endMetadata() .withNewSpec() .addNewRule() .withHttp(new ExtensionsV1beta1HTTPIngressRuleValueBuilder().addToPaths(new ExtensionsV1beta1HTTPIngressPathBuilder() .withPath(path) .withBackend(new ExtensionsV1beta1IngressBackendBuilder() .withServiceName(serviceName) .withServicePort(new IntOrString(servicePort)).build()).build()).build()) .endRule() .endSpec() .build(); ExtensionsV1beta1Api api = new ExtensionsV1beta1Api(apiClient); ExtensionsV1beta1Ingress extensionsV1beta1Ingress = null; try { extensionsV1beta1Ingress = api.createNamespacedIngress(namespace, ingress, null, null, null); } catch (ApiException e) { log.error("create ingress error:" + e.getResponseBody(), e); } catch (Exception e) { log.error("create ingress system error:", e); } return extensionsV1beta1Ingress; } }
以上只是一些關(guān)鍵代碼,所有代碼請參見下面代碼倉庫
代碼倉庫
- https://github.com/Harries/springboot-demo(Kubernetes)
4.測試
獲取pods
@Test public void getAllPodListTest() { String kubeConfigPath = "C:\\Users\\Dell\\.kube\\config"; if (!new File(kubeConfigPath).exists()) { System.out.println("kubeConfig not exist,jump over"); return; } K8sClient k8sClient = new K8sClient(kubeConfigPath); V1PodList podList = k8sClient.getAllPodList(); for (V1Pod item : podList.getItems()) { System.out.println(item.getMetadata().getNamespace() + ":" + item.getMetadata().getName()); } }
輸出結(jié)果
default:nginx-6b5775b9c6-kqh5j kube-system:coredns-5dd5756b68-7f4mj kube-system:etcd-minikube kube-system:kube-apiserver-minikube kube-system:kube-controller-manager-minikube kube-system:kube-proxy-pnt5q kube-system:kube-scheduler-minikube kube-system:metrics-server-7c66d45ddc-4jp25 kube-system:storage-provisioner kubernetes-dashboard:dashboard-metrics-scraper-7fd5cb4ddc-bpvvs kubernetes-dashboard:kubernetes-dashboard-8694d4445c-98vfm middleware:mongodb-enterprise-operator-6dcd58f895-tmcr8 middleware:ops-manager-0 middleware:ops-manager-1 middleware:ops-manager-2 middleware:ops-manager-db-0 middleware:ops-manager-db-1 middleware:ops-manager-db-2
創(chuàng)建Ingress
@Test public void createV1IngressTest() { String kubeConfigPath = "C:\\Users\\Dell\\.kube\\config"; if (!new File(kubeConfigPath).exists()) { System.out.println("kubeConfig not exist,jump over"); return; } K8sClient k8sClient = new K8sClient(kubeConfigPath); String namespace = "default"; String ingressName = "my-nginx-ingress"; Map<String, String> annotations = new HashMap<>(); annotations.put("nginx.ingress.kubernetes.io/rewrite-target", "/"); String path = "/my-nginx"; String serviceName = "my-nginx-service"; Integer servicePort = 80; V1Ingress v1Ingress = k8sClient.createV1Ingress(namespace, ingressName, annotations, path, serviceName, servicePort); System.out.println(v1Ingress != null ? v1Ingress.getMetadata() : null); }
創(chuàng)建Service
@Test public void createServiceTest() { String kubeConfigPath = "C:\\Users\\Dell\\.kube\\config"; if (!new File(kubeConfigPath).exists()) { System.out.println("kubeConfig not exist,jump over"); return; } K8sClient k8sClient = new K8sClient(kubeConfigPath); String namespace = "default"; String serviceName = "my-nginx-service"; Integer port = 80; Map<String, String> selector = new HashMap<>(); selector.put("run", "my-nginx"); V1Service v1Service = k8sClient.createService(namespace, serviceName, port, selector); System.out.println(v1Service != null ? v1Service.getMetadata() : null); }
5.引用
- https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/
- http://www.liuhaihua.cn/archives/711229.html
到此這篇關(guān)于Spring Boot集成kubernetes客戶端實現(xiàn)API操作k8s集群的文章就介紹到這了,更多相關(guān)Spring Boot集成kubernetes內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解servlet調(diào)用的幾種簡單方式總結(jié)
這篇文章主要介紹了詳解servlet調(diào)用的幾種簡單方式總結(jié),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-012020最新IDEA SpringBoot整合Dubbo的實現(xiàn)(zookeeper版)
這篇文章主要介紹了2020最新IDEA SpringBoot整合Dubbo(zookeeper版),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09淺談DetachedCriteria和Criteria的使用方法(必看)
下面小編就為大家?guī)硪黄獪\談DetachedCriteria和Criteria的使用方法(必看)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-05-05java用靜態(tài)工廠代替構(gòu)造函數(shù)使用方法和優(yōu)缺點
這篇文章主要介紹了java用靜態(tài)工廠代替構(gòu)造函數(shù)使用方法和優(yōu)缺點,需要的朋友可以參考下2014-02-02Java8中Stream?API的peek()方法詳解及需要注意的坑
這篇文章主要給大家介紹了關(guān)于Java8中Stream?API的peek()方法詳解及需要注意的坑,Java 中的 peek 方法是 Java 8 中的 Stream API 中的一個方法,它屬于中間操作,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2024-06-06詳解 Java Maximum redirects (100) exceeded
這篇文章主要介紹了詳解 Java Maximum redirects (100) exceeded的相關(guān)資料,需要的朋友可以參考下2017-05-05spring boot中interceptor攔截器未生效的解決
這篇文章主要介紹了spring boot中interceptor攔截器未生效的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09Java簡化復(fù)雜系統(tǒng)調(diào)用的門面設(shè)計模式
Java門面模式是一種結(jié)構(gòu)性設(shè)計模式,它為復(fù)雜系統(tǒng)提供了一個簡單的接口,使得系統(tǒng)的客戶端能夠更加方便地使用系統(tǒng)功能。門面模式通過封裝復(fù)雜的子系統(tǒng),隱藏系統(tǒng)的實現(xiàn)細節(jié),提高了系統(tǒng)的易用性和靈活性2023-04-04