公司準(zhǔn)備將應(yīng)用容器化部署,先使用了華為云的 Kubernetes 服務(wù),后面又使用阿里云的 Kubernetes 服務(wù)。并短期一個月內(nèi)無法判斷走哪個云商。而作為一個在公司內(nèi)部用于應(yīng)用發(fā)布,部署的應(yīng)用。在對接完華為云的 Kubernetes 服務(wù) Api 后。再對接阿里云發(fā)現(xiàn)阿里云并沒用像華為云一樣對 Kubernetes 的 Api 做簡易的封裝。其兩者的區(qū)別是華為云可以通過 ak , sk 再加 Kubernetes Api 獲取數(shù)據(jù)??梢岳斫鉃槿A為云多了一層代理。
添加依賴
本篇使用的是官方維護的 Kubernetes Java Client 包 。有興趣的可以了解下面的社區(qū)維護版
官方 SDK
官方 JAVA SDK GitHub
建議使用最新版本 maven 中央倉庫 :
<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java</artifactId>
<version>16.0.0</version>
</dependency>
準(zhǔn)備 kubeconfig 文件
用于配置集群訪問的文件稱為 kubeconfig 文件。默認情況下, kubectl 在 $HOME/.kube 目錄下查找名為 config 的文件。什么是 kubeconfig
阿里云
容器服務(wù) - Kubernetes 》 進入集群 》 集群信息 》 連接信息。復(fù)制內(nèi)容
華為云
云容器引擎 》 資源管理 》 集群管理 》 進入集群 》 基本信息右邊 kubectl 》 下載 kubectl 配置文件
可以使用 lens 工具管理 Kubernetes 集群
Java 連接 Kubernetes
首先將這個內(nèi)容文件重命名為 config 。
使用:官方例子獲取所有 NameSpaces 下的 Pod。
package io.kubernetes.client.examples;
import io.kubernetes.client.ApiClient;
import io.kubernetes.client.ApiException;
import io.kubernetes.client.Configuration;
import io.kubernetes.client.apis.CoreV1Api;
import io.kubernetes.client.models.V1Pod;
import io.kubernetes.client.models.V1PodList;
import io.kubernetes.client.util.ClientBuilder;
import io.kubernetes.client.util.KubeConfig;
import java.io.FileReader;
import java.io.IOException;
/**
* A simple example of how to use the Java API from an application outside a kubernetes cluster
*
* <p>Easiest way to run this: mvn exec:java
* -Dexec.mainClass="io.kubernetes.client.examples.KubeConfigFileClientExample"
*
*/
public class KubeConfigFileClientExample {
public static void main(String[] args) throws IOException, ApiException {
//file path to your KubeConfig (看你自己 config 文件放哪)
String kubeConfigPath = "~/.kube/config";
// loading the out-of-cluster config, a kubeconfig from file-system
ApiClient client =
ClientBuilder.kubeconfig(KubeConfig.loadKubeConfig(new FileReader(kubeConfigPath))).build();
// set the global default api-client to the in-cluster one from above
Configuration.setDefaultApiClient(client);
// the CoreV1Api loads default api-client from global configuration.
CoreV1Api api = new CoreV1Api();
// invokes the CoreV1Api client
V1PodList list = api.listPodForAllNamespaces(null, null, null, null, null, null, null, null, null);
System.out.println("Listing all pods: ");
for (V1Pod item : list.getItems()) {
System.out.println(item.getMetadata().getName());
}
}
}
但我不想使用第三方云存儲如阿里云的 OSS 或者在 Jar 包的相對路徑下放置一份 config
文件。所以我會把這個文件放在 Jar 包內(nèi)。也就是我放在 resources 下的自建目錄 kubernetes 下,所以改動如下。
// 注意導(dǎo)包不要導(dǎo)錯了
// import sun.security.util.Resources;
BufferedReader reader = new BufferedReader(new InputStreamReader(Resources.class.getResourceAsStream("/kubernetes/config")));
ApiClient client = ClientBuilder.kubeconfig(KubeConfig.loadKubeConfig(reader)).build();
解釋:因為當(dāng)打成 Jar 包后,文件就在包內(nèi)部了。
而 new FileReader(path) 實例化內(nèi)部底層會 new File(path) 再獲取 InputStream 。而 File 這個路徑是相對于包的相對路徑,并不是指向包內(nèi)的文件。如果繼續(xù)使用會出現(xiàn) idea 跑項目時沒有問題,打包部署時出錯
初始化 ApiClient
因為有四個環(huán)境,不能像官方例子使用 Configuration.setDefaultApiClient()
設(shè)置默認 client
public class KubernetesUtil {
public final static Map alyClusterMap = new HashMap(){
{
try {
BufferedReader reader = IoUtil.getReader(new ClassPathResource("kubernetes/aly-dev-config").getInputStream(), "utf-8");
put("DEV",ClientBuilder.kubeconfig(KubeConfig.loadKubeConfig(reader)).build());
put("TEST",null);
put("PRE",null);
put("PROD",null);
} catch (IOException e) {
e.printStackTrace();
}
}
};
}
例:獲取 pod 信息
首先通過 Client 獲取 CoreV1Api 對象用于調(diào)用相關(guān)接口
這里要提一句:Java Kubernetes SKD 操作 Api 不僅只有 CoreV1Api 這個類。如操作 Deployment 時用的是 AppsV1Api . 使用什么我是先到 Kubernetes Api 下找。然后將請求路徑在 SDK 源碼中查。如果有更好的方法,還請多多提點下 (●’?’●)
public static List getPodsByAppName(String appName,String env) {
// 按需獲取所需要的 Client
CoreV1Api api = new CoreV1Api(KubernetesUtil.alyClusterMap.get(env));
V1PodList list = null;
try {
list = api.listPodForAllNamespaces(null,null, null, "name="+appName+"-pod", null, null, null, null, null, null);
} catch (ApiException e) {
e.printStackTrace();
}
// JSONbject 是 Map 對象的實現(xiàn)類。來源是 Hutool 工具
List jsonObjectList = list.getItems().parallelStream().map(m -> {
JSONObject jsonObject = new JSONObject();
jsonObject.putOnce("podName", m.getMetadata().getName());
jsonObject.putOnce("podIp", m.getStatus().getPodIP());
V1Container v1Container = m.getSpec().getContainers().get(0);
String[] images = v1Container.getImage().split(":");
jsonObject.putOnce("imageVersion", images[images.length - 1]);
// 1048576 = 1024 * 1024 因為單位為 Byte 要轉(zhuǎn)換為 MB。 因為獲取到的是字節(jié),需要轉(zhuǎn)成 Mb
jsonObject.putOnce("specification", String.format("CPU:%s | MEM:%s",
v1Container.getResources().getLimits().get("cpu").getNumber(),
v1Container.getResources().getLimits().get("memory").getNumber().divide(new BigDecimal(1048576))));
jsonObject.putOnce("podStatus", m.getStatus().getPhase());
Optional.ofNullable(m.getStatus().getStartTime()).ifPresent(p -> {
// 時間是 UTC 的零時區(qū)。不是東八區(qū)
jsonObject.putOnce("startTime", p.plusHours(8).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
});
return jsonObject;
}).collect(Collectors.toList());
return jsonObjectList;
}
例:獲取 pod 內(nèi) Java 啟動日志
因為業(yè)務(wù)要求日志是從上往下看的。所以日志這塊 Kubernetes 的參數(shù)有點不搭,所以就用 sinceSeconds 。意思是距離現(xiàn)在最近的多少秒日志
接口詳情
public static StartLogVO getAppServerLogs(int startDate,String env,String podName,String endLog){
CoreV1Api api = new CoreV1Api(KubernetesUtil.alyClusterMap.get(env));
StartLogVO startLogVO = new StartLogVO("",0,null);
try {
int now = (int)LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
startLogVO.setStartDate(now +"");
// 加 5 秒防止日志丟失
int i = now - startDate + 5;
String logs = api.readNamespacedPodLog(podName, "default", null, null, null, null, "true", null, i, null, null);
startLogVO.setLineNum(logs.substring(logs.length()-20));
// 去除重復(fù)日志
if(StrUtil.isNotBlank(endLog)){
int end = logs.indexOf(endLog);
if(end!=-1){
logs = StrUtil.removePrefix(logs.substring(end),endLog);
}
}
startLogVO.setLogs(Optional.ofNullable(logs).orElse(""));
} catch (ApiException e) {
e.printStackTrace();
}
return startLogVO;
}
總結(jié)
因為華為云通過 ak , sk 再加 Kubernetes Api 請求地址。我這邊僅需發(fā)起 HTTPS 請求就行。以至于對接阿里云還需要使用 Kubernetes 的 SDK 有些抗拒。還要載入 kubeconfig 文件。最后不想學(xué)阿里云例子通過調(diào)用系統(tǒng)命令 curl 。所以還是使用了,結(jié)果第一次使用就報 NoSuchMethodError kotlin.collections.ArraysKt.copyInto([B[BIII)[B 這個錯誤,一看報沒方法錯誤,趕緊看下 Mavne 引入的依賴版本。原來是公司父級定義了舊版本,導(dǎo)致引入的最新 SDK 版本內(nèi)的 Kotlin 版本被覆蓋了。于是在最外層 pom.xml 下重新定義了版本約束。之后就是開發(fā)的小細節(jié)問題了。
感覺 Kubernetes 的 SDK 包還是很厲害的。下次也不知道有沒有機會搞個 WebShell 連下 Pod 。文章來源:http://www.zghlxwxcb.cn/news/detail-405809.html
參考鏈接:https://guicai.work/after-post/java/Java%E6%93%8D%E4%BD%9CKubernetes文章來源地址http://www.zghlxwxcb.cn/news/detail-405809.html
到了這里,關(guān)于Java操作k8s api示例:使用kubeconfig文件認證;獲取所有pod;獲取pod內(nèi)應(yīng)用容器的啟動日志的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!