1.maven配置
<!-- k8s client --> <dependency> <groupId>io.kubernetes</groupId> <artifactId>client-java</artifactId> <version>12.0.1</version> </dependency>
2.工具類
/** * k8s客戶端 * * @author wanghuidong * @date 2021/6/18 14:14 */ @Slf4j public class K8sClient { /** * k8s-api客戶端 */ private ApiClient apiClient; /** * 構建集群POD內通過SA訪問的客戶端 * 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("構建K8s-Client異常", e); throw new RuntimeException("構建K8s-Client異常"); } } /** * 構建集群外通過UA訪問的客戶端 * loading the out-of-cluster config, a kubeconfig from file-system * * @param kubeConfigPath kube連接配置文件 */ public K8sClient(String kubeConfigPath) { try { this.apiClient = ClientBuilder.kubeconfig(KubeConfig.loadKubeConfig(new FileReader(kubeConfigPath))).build(); } catch (IOException e) { log.error("讀取kubeConfigPath異常", e); throw new RuntimeException("讀取kubeConfigPath異常"); } catch (Exception e) { log.error("構建K8s-Client異常", e); throw new RuntimeException("構建K8s-Client異常"); } } /** * 獲取所有的Pod * * @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("獲取podlist異常:" + e.getResponseBody(), e); } return null; } /** * 創建k8s service * * @param namespace 命名空間 * @param serviceName 服務名稱 * @param port 服務端口號(和目標pod的端口號一致) * @param selector pod標簽選擇器 * @return 創建成功的service對象 */ public V1Service createService(String namespace, String serviceName, Integer port, Map<String, String> selector) { //構建service的yaml對象 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("創建service異常:" + e.getResponseBody(), e); } catch (Exception e) { log.error("創建service系統異常:", e); } return v1Service; } /** * 創建k8s V1Ingress * * @param namespace 命名空間 * @param ingressName ingress名稱 * @param annotations ingress注解 * @param path 匹配的路徑 * @param serviceName 路由到的服務名稱 * @param servicePort 路由到的服務端口 * @return 創建成功的ingress對象 */ public V1Ingress createV1Ingress(String namespace, String ingressName, Map<String, String> annotations, String path, String serviceName, Integer servicePort) { //構建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(); //調用對應的API執行創建ingress的操作 NetworkingV1Api api = new NetworkingV1Api(apiClient); V1Ingress v1Ingress = null; try { v1Ingress = api.createNamespacedIngress(namespace, ingress, null, null, null); } catch (ApiException e) { log.error("創建ingress異常:" + e.getResponseBody(), e); } catch (Exception e) { log.error("創建ingress系統異常:", e); } return v1Ingress; } /** * 創建k8s ExtensionIngress * * @param namespace 命名空間 * @param ingressName ingress名稱 * @param annotations ingress注解 * @param path 匹配的路徑 * @param serviceName 路由到的服務名稱 * @param servicePort 路由到的服務端口 * @return 創建成功的ingress對象 */ public ExtensionsV1beta1Ingress createExtensionIngress(String namespace, String ingressName, Map<String, String> annotations, String path, String serviceName, Integer servicePort) { //構建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(); //調用對應的API執行創建ingress的操作 ExtensionsV1beta1Api api = new ExtensionsV1beta1Api(apiClient); ExtensionsV1beta1Ingress extensionsV1beta1Ingress = null; try { extensionsV1beta1Ingress = api.createNamespacedIngress(namespace, ingress, null, null, null); } catch (ApiException e) { log.error("創建ingress異常:" + e.getResponseBody(), e); } catch (Exception e) { log.error("創建ingress系統異常:", e); } return extensionsV1beta1Ingress; } }
3.測試類
/** * @author wanghuidong * @date 2021/6/18 14:33 */ public class K8sClientTest { // @Test public void getAllPodListTest() { String kubeConfigPath = "C:\\Users\\admin\\.kube\\config"; if (!new File(kubeConfigPath).exists()) { System.out.println("kubeConfig不存在,跳過"); return; } K8sClient k8sClient = new K8sClient(kubeConfigPath); V1PodList podList = k8sClient.getAllPodList(); for (V1Pod item : podList.getItems()) { System.out.println(item.getMetadata().getNamespace() + ":" + item.getMetadata().getName()); } } // @Test public void createServiceTest() { String kubeConfigPath = "C:\\Users\\admin\\.kube\\config"; if (!new File(kubeConfigPath).exists()) { System.out.println("kubeConfig不存在,跳過"); 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); } // @Test public void createV1IngressTest() { String kubeConfigPath = "C:\\Users\\admin\\.kube\\config"; if (!new File(kubeConfigPath).exists()) { System.out.println("kubeConfig不存在,跳過"); 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); } // @Test public void createExtensionIngressTest() { String kubeConfigPath = "C:\\Users\\admin\\.kube\\config"; if (!new File(kubeConfigPath).exists()) { System.out.println("kubeConfig不存在,跳過"); 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; ExtensionsV1beta1Ingress extensionsV1beta1Ingress = k8sClient.createExtensionIngress(namespace, ingressName, annotations, path, serviceName, servicePort); System.out.println(extensionsV1beta1Ingress != null ? extensionsV1beta1Ingress.getMetadata() : null); } }
4.附錄
4.1 創建pod應用
my-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
應用部署單,生成pod
kubectl apply -f ./my-nginx.yaml
查看相關pod信息
kubectl get pods -l run=my-nginx -o wide
4.2 創建service
my-nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx-service
labels:
run: my-nginx-service
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
run: my-nginx
應用service單,創建service
kubectl apply -f ./my-nginx-service.yaml
查看相關服務
kubectl get svc my-nginx-service
查詢服務詳情
kubectl describe svc my-nginx-service
查看service后端結點
kubectl get ep my-nginx-service
4.3 創建ingress(ExtensionV1beta1)
my-nginx-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-nginx-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /my-nginx
backend:
serviceName: my-nginx-service
servicePort: 80
應用ingress單,創建ingress
kubectl apply -f ./my-nginx-ingress.yaml
查看ingress
kubectl get ingress
4.4 創建Ingress(V1)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-nginx-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /my-nginx
pathType: Prefix
backend:
service:
name: my-nginx-service
port:
number: 80
4.5 相關概念總結
k8s中配置客戶端訪問pod中應用的流程如下:
client->ingress->service->pod->container
INGRESS
Ingress 是對集群中服務的外部訪問進行管理的 API 對象,典型的訪問方式是 HTTP。
Ingress 可以提供負載均衡、SSL 終結和基於名稱的虛擬托管。
SERVICE
將運行在一組 Pods 上的應用程序公開為網絡服務的抽象方法。Kubernetes Service 定義了這樣一種抽象:邏輯上的一組 Pod,一種可以訪問它們的策略 —— 通常稱為微服務。 Service 所針對的 Pods 集合通常是通過選擇算符來確定的。
POD
Pod 是可以在 Kubernetes 中創建和管理的、最小的可部署的計算單元。
Pod (就像在鯨魚莢或者豌豆莢中)是一組(一個或多個) 容器; 這些容器共享存儲、網絡、以及怎樣運行這些容器的聲明。 Pod 中的內容總是並置(colocated)的並且一同調度,在共享的上下文中運行。 Pod 所建模的是特定於應用的“邏輯主機”,其中包含一個或多個應用容器, 這些容器是相對緊密的耦合在一起的。 在非雲環境中,在相同的物理機或虛擬機上運行的應用類似於 在同一邏輯主機上運行的雲應用。
節點(Node)
Kubernetes 集群中其中一台工作機器,是集群的一部分。
集群(Cluster)
一組運行由 Kubernetes 管理的容器化應用程序的節點。 在此示例和在大多數常見的 Kubernetes 部署環境中,集群中的節點都不在公共網絡中。
