Kubernetes官方java客戶端之四:內部應用

歡迎訪問我的GitHub

//github.com/zq2599/blog_demos

內容:所有原創文章分類匯總及配套源碼,涉及Java、Docker、Kubernetes、DevOPS等;

概覽

  1. 本文是《Kubernetes官方java客戶端》系列的第四篇,以下提到的java客戶端都是指client-jar.jar;

  2. 前文《Kubernetes官方java客戶端之三:外部應用》中,咱們開發了一個名為OutsideclusterApplication的SpringBoot應用,該應用並未部署在K8S環境,而是遠程訪問K8S環境內部的API Server,整體結構如下:
    在這裡插入圖片描述

  3. 除了前文中部署在外部的方式,還有一種常見場景:使用java客戶端的應用自身也部署在K8S環境中,如下圖所示,名為DemoApplication的SpringBoot應用部署在K8S環境內,調用java客戶端庫的API對K8S進行各種操作,整體結構如下:
    在這裡插入圖片描述

  4. 本文的內容就是開發上圖中名為DemoApplication的應用,並且部署在K8S環境中進行驗證;

額外準備

  1. SpringBoot製作成docker鏡像,首選官方推薦的方式,參考《體驗SpringBoot(2.3)應用製作Docker鏡像(官方方案)》《詳解SpringBoot(2.3)應用製作Docker鏡像(官方方案)》
  2. SpringBoot應用在K8S環境下的探針技術,參考《掌握SpringBoot-2.3的容器探針:基礎篇》《掌握SpringBoot-2.3的容器探針:深入篇》《掌握SpringBoot-2.3的容器探針:實戰篇》

源碼下載

  1. 如果您不想編碼,可以在GitHub下載所有源碼,地址和鏈接資訊如下表所示(//github.com/zq2599/blog_demos):
名稱 鏈接 備註
項目主頁 //github.com/zq2599/blog_demos 該項目在GitHub上的主頁
git倉庫地址(https) //github.com/zq2599/blog_demos.git 該項目源碼的倉庫地址,https協議
git倉庫地址(ssh) [email protected]:zq2599/blog_demos.git 該項目源碼的倉庫地址,ssh協議
  1. 這個git項目中有多個文件夾,本章的應用在kubernetesclient文件夾下,如下圖紅框所示:
    在這裡插入圖片描述

開發K8S環境內的應用:DemoApplication

  1. 打開《Kubernetes官方java客戶端:準備》中創建的的kubernetesclient工程,在裡面創建子工程,名為helloworld,這是個SpringBoot工程,pom.xml內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0" xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.bolingcavalry</groupId>
        <artifactId>kubernetesclient</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>

    <groupId>com.bolingcavalry</groupId>
    <artifactId>helloworld</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>helloworld</name>
    <description>Demo project for Spring Boot</description>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        
        <dependency>
            <groupId>io.kubernetes</groupId>
            <artifactId>client-java</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.0.RELEASE</version>
                <!--該配置會在jar中增加layer描述文件,以及提取layer的工具-->
                <configuration>
                    <layers>
                        <enabled>true</enabled>
                    </layers>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
  1. 編寫java程式碼,創建DemoApplication.java,這裡為了簡單起見,將引導類和web controller的程式碼都寫在DemoApplication類中:
package com.bolingcavalry.demo;

import com.google.gson.Gson;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.Configuration;
import io.kubernetes.client.openapi.apis.CoreV1Api;
import io.kubernetes.client.openapi.models.V1PodList;
import io.kubernetes.client.util.Config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.stream.Collectors;

@SpringBootApplication
@RestController
@Slf4j
public class DemoApplication {

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

    @RequestMapping(value = "/hello")
    public List<String> hello() throws Exception {
        ApiClient client = Config.defaultClient();
        Configuration.setDefaultApiClient(client);

        CoreV1Api api = new CoreV1Api();

        // 調用客戶端API取得所有pod資訊
        V1PodList v1PodList = api.listPodForAllNamespaces(null, null, null, null, null, null, null, null, null);

        // 使用Gson將集合對象序列化成JSON,在日誌中列印出來
        log.info("pod info \n{}", new Gson().toJson(v1PodList));

        return v1PodList
                .getItems()
                .stream()
                .map(value ->
                        value.getMetadata().getNamespace()
                        + ":"
                        + value.getMetadata().getName())
                .collect(Collectors.toList());
    }
}
  1. 還記得《Kubernetes官方java客戶端之二:序列化和反序列化問題》提到的序列化問題嗎?上述程式碼中,log.info那段程式碼里對V1PodList執行序列化的是Gson,並且hello方法返回的也不是V1PodList實例,而是新做的一個List實例,這樣做是因為jackson對V1PodList做序列化會導致異常,這裡要避免jackson參與序列化操作;
  2. 應用的程式碼已經寫完,接下來是鏡像製作用到的Dockerfile文件,該文件和剛才創建的pom.xml文件在同一個目錄下(即子工程helloworld的文件夾下),Dockerfile文件內容如下:
# 指定基礎鏡像,這是分階段構建的前期階段
FROM openjdk:8u212-jdk-stretch as builder
# 執行工作目錄
WORKDIR application
# 配置參數
ARG JAR_FILE=target/*.jar
# 將編譯構建得到的jar文件複製到鏡像空間中
COPY ${JAR_FILE} application.jar
# 通過工具spring-boot-jarmode-layertools從application.jar中提取拆分後的構建結果
RUN java -Djarmode=layertools -jar application.jar extract

# 正式構建鏡像
FROM openjdk:8u212-jdk-stretch
WORKDIR application
# 前一階段從jar中提取除了多個文件,這裡分別執行COPY命令複製到鏡像空間中,每次COPY都是一個layer
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
  1. 在子工程pom.xml文件所在目錄執行以下命令完成編譯構建:
mvn clean package -U -DskipTests
  1. 接下來要製作鏡像文件了,請確保當前電腦已經安裝並運行了docker,另外構建docker鏡像的操作我僅在macOS和Linux作業系統下執行成功,在Windows環境能否成功請自行嘗試;
  2. 在Dockerfile所在目錄執行以下命令即可創建docker鏡像文件:
docker build -t 192.168.50.43:5888/common/helloworld:1.0-SNAPSHOT .
  1. 上述命令執行成功後,鏡像文件還只是在本機的docker倉庫中,請放置到K8S環境可以訪問的地方,我這裡是在內網部署了鏡像倉庫Harbor,執行以下命令即可從本地倉庫推送到Harbor(可能需要先登錄,與Harbor的設置有關):
    在這裡插入圖片描述

  2. 鏡像準備完成,接下來就是在K8S環境部署了,在K8S環境創建名為helloworld.yaml的文件,內容如下,可見deployment和service都配置好了,另外請注意serviceAccountName屬性的值為kubernates-client-service-account,此serviceAccountName是在《Kubernetes官方java客戶端之一:準備》一文中創建好的RBAC資源,令咱們開發的helloworld應用有許可權請求API Server:

apiVersion: v1
kind: Service
metadata:
  name: helloworld
  namespace : kubernetesclient
spec:
  type: NodePort
  ports:
    - port: 8080
      nodePort: 30100
  selector:
    name: helloworld
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  namespace : kubernetesclient
  name: helloworld
spec:
  replicas: 1
  template:
    metadata:
      labels:
        name: helloworld
    spec:
      serviceAccountName: kubernates-client-service-account
      containers:
        - name: helloworld
          image: 192.168.50.43:5888/common/helloworld:1.0-SNAPSHOT
          tty: true
          livenessProbe:
            httpGet:
              path: /actuator/health/liveness
              port: 8080
            initialDelaySeconds: 5
            failureThreshold: 10
            timeoutSeconds: 10
            periodSeconds: 5
          readinessProbe:
            httpGet:
              path: /actuator/health/readiness
              port: 8080
            initialDelaySeconds: 5
            timeoutSeconds: 10
            periodSeconds: 5
          ports:
            - containerPort: 8080
          resources:
            requests:
              memory: "512Mi"
              cpu: "100m"
            limits:
              memory: "1Gi"
              cpu: "1000m"
  1. helloworld.yaml所在目錄執行命令:kubectl apply -f helloworld.yaml
    在這裡插入圖片描述

  2. 我這邊,上圖中的Pod所在宿主機IP地址是192.168.50.135,因此用瀏覽器訪問//192.168.50.135:30100/hello,如下圖,可見當前K8S環境下所有Pod名稱都返回了:
    在這裡插入圖片描述

至此,SpringBoot應用通過K8S官方java客戶端,成功獲取了自身所在K8S環境的資訊,通過前文和本章,咱們對K8S官方java客戶端已經有了基本的認識,接下來的實戰會開啟這個客戶端更豐富的能力;

你不孤單,欣宸原創一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 資料庫+中間件系列
  6. DevOps系列

歡迎關注公眾號:程式設計師欣宸

微信搜索「程式設計師欣宸」,我是欣宸,期待與您一同暢遊Java世界…
//github.com/zq2599/blog_demos