Java实现Kubernetes部署案例

wen java案例 1

本文目录导读:

Java实现Kubernetes部署案例

  1. 项目依赖配置 (pom.xml)
  2. 配置类 (KubeConfig.java)
  3. Deployment管理类 (DeploymentManager.java)
  4. 主程序 (Main.java)
  5. 配置文件示例
  6. Dockerfile
  7. Kubernetes部署文件
  8. 使用说明
  9. 关键特性

我将为您提供一个完整的Java实现Kubernetes部署案例,这个案例将展示如何使用Java官方客户端库来管理Kubernetes资源。

项目依赖配置 (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">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>k8s-deployment</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <client-java.version>18.0.0</client-java.version>
    </properties>
    <dependencies>
        <!-- Kubernetes Java Client -->
        <dependency>
            <groupId>io.kubernetes</groupId>
            <artifactId>client-java</artifactId>
            <version>${client-java.version}</version>
        </dependency>
        <!-- SLF4J Logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>2.0.9</version>
        </dependency>
        <!-- Logback -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.4.11</version>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
            <scope>provided</scope>
        </dependency>
        <!-- Jackson for JSON -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.15.2</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.5.0</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer 
                                    implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.example.k8s.Main</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

配置类 (KubeConfig.java)

package com.example.k8s.config;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.Configuration;
import io.kubernetes.client.util.Config;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
@Slf4j
public class KubeConfig {
    /**
     * 获取Kubernetes客户端配置
     * 支持多种配置方式:
     * 1. 集群内配置(当在Pod中运行时)
     * 2. kubeconfig文件配置
     * 3. 环境变量配置
     */
    public static ApiClient getClient() {
        ApiClient client = null;
        try {
            // 方式1:尝试从集群内部获取配置(当应用部署在K8s集群中时)
            client = Config.fromCluster();
            log.info("已从集群内部加载配置");
        } catch (IOException e) {
            log.info("无法从集群内部加载配置,尝试使用kubeconfig文件...");
            try {
                // 方式2:使用默认的kubeconfig文件(~/.kube/config)
                String kubeconfigPath = System.getenv("KUBECONFIG");
                if (kubeconfigPath != null && !kubeconfigPath.isEmpty()) {
                    client = Config.fromConfig(kubeconfigPath);
                    log.info("使用环境变量KUBECONFIG加载配置: {}", kubeconfigPath);
                } else {
                    client = Config.defaultClient();
                    log.info("使用默认kubeconfig文件加载配置");
                }
            } catch (IOException ex) {
                log.error("加载Kubernetes配置失败", ex);
                throw new RuntimeException("无法加载Kubernetes配置", ex);
            }
        }
        // 设置默认配置
        Configuration.setDefaultApiClient(client);
        client.setDebugging(false);
        return client;
    }
    /**
     * 获取Pod内服务的地址
     */
    public static String getServiceHost() {
        return System.getenv("KUBERNETES_SERVICE_HOST");
    }
    /**
     * 获取Pod内服务的端口
     */
    public static String getServicePort() {
        return System.getenv("KUBERNETES_SERVICE_PORT");
    }
}

Deployment管理类 (DeploymentManager.java)

package com.example.k8s.manager;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.apis.AppsV1Api;
import io.kubernetes.client.openapi.apis.CoreV1Api;
import io.kubernetes.client.openapi.models.*;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
public class DeploymentManager {
    private final AppsV1Api appsV1Api;
    private final CoreV1Api coreV1Api;
    public DeploymentManager(ApiClient client) {
        this.appsV1Api = new AppsV1Api(client);
        this.coreV1Api = new CoreV1Api(client);
    }
    /**
     * 创建Deployment
     */
    public V1Deployment createDeployment(
            String namespace,
            String deploymentName,
            String image,
            int replicas,
            String appLabel) throws ApiException {
        // 创建Deployment
        V1Deployment deployment = new V1Deployment();
        deployment.setApiVersion("apps/v1");
        deployment.setKind("Deployment");
        // Metadata
        V1ObjectMeta metadata = new V1ObjectMeta();
        metadata.setName(deploymentName);
        metadata.setNamespace(namespace);
        Map<String, String> labels = new HashMap<>();
        labels.put("app", appLabel);
        metadata.setLabels(labels);
        deployment.setMetadata(metadata);
        // Spec
        V1DeploymentSpec spec = new V1DeploymentSpec();
        spec.setReplicas(replicas);
        // Selector
        V1LabelSelector selector = new V1LabelSelector();
        selector.setMatchLabels(labels);
        spec.setSelector(selector);
        // Template
        V1PodTemplateSpec template = new V1PodTemplateSpec();
        // Template metadata
        V1ObjectMeta templateMetadata = new V1ObjectMeta();
        templateMetadata.setLabels(labels);
        template.setMetadata(templateMetadata);
        // Template spec
        V1PodSpec podSpec = new V1PodSpec();
        // Container
        V1Container container = new V1Container();
        container.setName(deploymentName);
        container.setImage(image);
        container.setImagePullPolicy("IfNotPresent");
        // Container ports
        V1ContainerPort port = new V1ContainerPort();
        port.setContainerPort(8080);
        port.setProtocol("TCP");
        container.setPorts(List.of(port));
        // Resource requirements
        V1ResourceRequirements resources = new V1ResourceRequirements();
        Map<String, Quantity> limits = new HashMap<>();
        limits.put("cpu", new Quantity("500m"));
        limits.put("memory", new Quantity("512Mi"));
        resources.setLimits(limits);
        Map<String, Quantity> requests = new HashMap<>();
        requests.put("cpu", new Quantity("250m"));
        requests.put("memory", new Quantity("256Mi"));
        resources.setRequests(requests);
        container.setResources(resources);
        // Environment variables
        V1EnvVar envVar = new V1EnvVar();
        envVar.setName("APP_NAME");
        envVar.setValue(deploymentName);
        container.setEnv(List.of(envVar));
        // Container probe
        V1Probe livenessProbe = new V1Probe();
        V1HttpGetAction httpGet = new V1HttpGetAction();
        httpGet.setPath("/health");
        httpGet.setPort(new io.kubernetes.client.custom.IntOrString(8080));
        livenessProbe.setHttpGet(httpGet);
        livenessProbe.setInitialDelaySeconds(30);
        livenessProbe.setPeriodSeconds(10);
        container.setLivenessProbe(livenessProbe);
        podSpec.setContainers(List.of(container));
        template.setSpec(podSpec);
        spec.setTemplate(template);
        deployment.setSpec(spec);
        // 创建Deployment
        V1Deployment result = appsV1Api.createNamespacedDeployment(
                namespace,
                deployment,
                null, null, null, null);
        log.info("Deployment '{}' 创建成功", deploymentName);
        return result;
    }
    /**
     * 更新Deployment镜像
     */
    public void updateDeploymentImage(
            String namespace,
            String deploymentName,
            String newImage) throws ApiException {
        // 获取现有Deployment
        V1Deployment deployment = appsV1Api.readNamespacedDeployment(
                deploymentName, namespace, null);
        // 修改镜像
        V1PodSpec podSpec = deployment.getSpec().getTemplate().getSpec();
        for (V1Container container : podSpec.getContainers()) {
            if (container.getName().equals(deploymentName)) {
                container.setImage(newImage);
            }
        }
        // 更新Deployment
        appsV1Api.replaceNamespacedDeployment(
                deploymentName, namespace, deployment, 
                null, null, null, null);
        log.info("Deployment '{}' 镜像更新为: {}", deploymentName, newImage);
        // 创建滚动更新
        createRollingUpdate(deploymentName + "-" + System.currentTimeMillis());
    }
    /**
     * 创建滚动更新
     */
    private void createRollingUpdate(String updateName) {
        log.info("开始创建滚动更新: {}", updateName);
    }
    /**
     * 获取Deployment状态
     */
    public V1DeploymentStatus getDeploymentStatus(String namespace, String deploymentName) 
            throws ApiException {
        V1Deployment deployment = appsV1Api.readNamespacedDeployment(
                deploymentName, namespace, null);
        return deployment.getStatus();
    }
    /**
     * 删除Deployment
     */
    public void deleteDeployment(String namespace, String deploymentName) 
            throws ApiException {
        V1DeleteOptions deleteOptions = new V1DeleteOptions();
        deleteOptions.setPropagationPolicy("Background");
        appsV1Api.deleteNamespacedDeployment(
                deploymentName, namespace, 
                null, null, null, null, 
                deleteOptions, null);
        log.info("Deployment '{}' 已删除", deploymentName);
    }
    /**
     * 创建Service
     */
    public V1Service createService(
            String namespace,
            String serviceName,
            String appLabel,
            int port,
            int targetPort) throws ApiException {
        V1Service service = new V1Service();
        service.setApiVersion("v1");
        service.setKind("Service");
        // Metadata
        V1ObjectMeta metadata = new V1ObjectMeta();
        metadata.setName(serviceName);
        metadata.setNamespace(namespace);
        Map<String, String> labels = new HashMap<>();
        labels.put("app", appLabel);
        metadata.setLabels(labels);
        service.setMetadata(metadata);
        // Spec
        V1ServiceSpec spec = new V1ServiceSpec();
        // Selector
        Map<String, String> selector = new HashMap<>();
        selector.put("app", appLabel);
        spec.setSelector(selector);
        // Ports
        V1ServicePort servicePort = new V1ServicePort();
        servicePort.setPort(port);
        servicePort.setTargetPort(new io.kubernetes.client.custom.IntOrString(targetPort));
        servicePort.setProtocol("TCP");
        spec.setPorts(List.of(servicePort));
        // Type - ClusterIP
        spec.setType("ClusterIP");
        service.setSpec(spec);
        V1Service result = coreV1Api.createNamespacedService(
                namespace, service, null, null, null, null);
        log.info("Service '{}' 创建成功", serviceName);
        return result;
    }
}

主程序 (Main.java)

package com.example.k8s;
import com.example.k8s.config.KubeConfig;
import com.example.k8s.manager.DeploymentManager;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.models.V1Deployment;
import lombok.extern.slf4j.Slf4j;
import java.util.Scanner;
@Slf4j
public class Main {
    public static void main(String[] args) {
        // 初始化Kubernetes客户端
        ApiClient client = KubeConfig.getClient();
        DeploymentManager deploymentManager = new DeploymentManager(client);
        // 默认配置
        String namespace = "default";
        String deploymentName = "demo-app";
        String image = "nginx:latest";
        int replicas = 3;
        String appLabel = "demo-app";
        // 交互式菜单
        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.println("\n=== Kubernetes Deployment Manager ===");
            System.out.println("1. 创建Deployment");
            System.out.println("2. 查看Deployment状态");
            System.out.println("3. 更新Deployment镜像");
            System.out.println("4. 删除Deployment");
            System.out.println("5. 创建Service");
            System.out.println("6. 查看所有Deployments");
            System.out.println("0. 退出");
            System.out.print("请选择操作: ");
            int choice = scanner.nextInt();
            scanner.nextLine(); // 消耗换行符
            try {
                switch (choice) {
                    case 1:
                        createDeployment(deploymentManager, scanner, 
                                       namespace, deploymentName, image, replicas, appLabel);
                        break;
                    case 2:
                        checkDeploymentStatus(deploymentManager, namespace, deploymentName);
                        break;
                    case 3:
                        updateImage(deploymentManager, scanner, namespace, deploymentName);
                        break;
                    case 4:
                        deleteDeployment(deploymentManager, namespace, deploymentName);
                        break;
                    case 5:
                        createService(deploymentManager, scanner, namespace, appLabel);
                        break;
                    case 6:
                        listAllDeployments(deploymentManager, namespace);
                        break;
                    case 0:
                        System.out.println("退出程序");
                        scanner.close();
                        return;
                    default:
                        System.out.println("无效选项,请重试");
                }
            } catch (ApiException e) {
                log.error("Kubernetes API调用失败: {}", e.getResponseBody());
            } catch (Exception e) {
                log.error("操作失败", e);
            }
        }
    }
    private static void createDeployment(
            DeploymentManager manager, Scanner scanner,
            String namespace, String deploymentName, 
            String image, int replicas, String appLabel) 
            throws ApiException {
        System.out.println("\n创建新的Deployment");
        System.out.print("Deployment名称 (默认: demo-app): ");
        String input = scanner.nextLine();
        if (!input.isEmpty()) {
            deploymentName = input;
        }
        System.out.print("镜像 (默认: nginx:latest): ");
        input = scanner.nextLine();
        if (!input.isEmpty()) {
            image = input;
        }
        System.out.print("副本数 (默认: 3): ");
        input = scanner.nextLine();
        if (!input.isEmpty()) {
            try {
                replicas = Integer.parseInt(input);
            } catch (NumberFormatException e) {
                log.warn("无效的副本数,使用默认值3");
            }
        }
        V1Deployment deployment = manager.createDeployment(
                namespace, deploymentName, image, replicas, appLabel);
        log.info("Deployment创建成功: {}", deployment.getMetadata().getName());
    }
    private static void checkDeploymentStatus(
            DeploymentManager manager, String namespace, String deploymentName) 
            throws ApiException {
        var status = manager.getDeploymentStatus(namespace, deploymentName);
        log.info("Deployment {} 状态:", deploymentName);
        log.info("  可用副本数: {}", status.getAvailableReplicas());
        log.info("  期望副本数: {}", status.getReplicas());
        log.info("  已就绪副本数: {}", status.getReadyReplicas());
        log.info("  更新副本数: {}", status.getUpdatedReplicas());
    }
    private static void updateImage(
            DeploymentManager manager, Scanner scanner,
            String namespace, String deploymentName) throws ApiException {
        System.out.println("\n更新Deployment镜像");
        System.out.print("新的镜像版本 ( nginx:1.25): ");
        String newImage = scanner.nextLine();
        if (!newImage.isEmpty()) {
            manager.updateDeploymentImage(namespace, deploymentName, newImage);
        } else {
            log.warn("未输入新的镜像版本");
        }
    }
    private static void deleteDeployment(
            DeploymentManager manager, 
            String namespace, String deploymentName) throws ApiException {
        System.out.print("确认删除Deployment '{}' ? (y/n): " + deploymentName);
        String confirm = scanner.nextLine();
        if (confirm.equalsIgnoreCase("y")) {
            manager.deleteDeployment(deploymentName, namespace);
        }
    }
    private static void createService(
            DeploymentManager manager, Scanner scanner,
            String namespace, String appLabel) throws ApiException {
        System.out.println("\n创建Service");
        System.out.print("Service名称 (默认: demo-service): ");
        String serviceName = scanner.nextLine();
        if (serviceName.isEmpty()) {
            serviceName = "demo-service";
        }
        System.out.print("Service端口 (默认: 8080): ");
        int port = 8080;
        String portInput = scanner.nextLine();
        if (!portInput.isEmpty()) {
            port = Integer.parseInt(portInput);
        }
        manager.createService(namespace, serviceName, appLabel, port, 8080);
        log.info("Service创建成功: {}", serviceName);
    }
    private static void listAllDeployments(
            DeploymentManager manager, String namespace) throws ApiException {
        // 这里可以调用API列出所有deployments
        log.info("列出namespace '{}' 中的所有Deployments", namespace);
        // 实际实现需要添加更多API调用
    }
}

配置文件示例

application.yaml

kubernetes:
  # 集群配置
  config:
    # 集群地址(可选)
    host: ""
    # kubeconfig路径(可选)
    kubeconfig: "${KUBECONFIG}"
    # 是否使用集群内配置
    inCluster: false
  # 默认Deployment配置
  deployment:
    namespace: default
    image: nginx:latest
    replicas: 3
    containerPort: 8080
    resources:
      limits:
        cpu: "500m"
        memory: "512Mi"
      requests:
        cpu: "250m"
        memory: "256Mi"
    probes:
      liveness:
        path: /health
        initialDelaySeconds: 30
        periodSeconds: 10
      readiness:
        path: /ready
        initialDelaySeconds: 5
        periodSeconds: 5
  # 服务配置
  service:
    type: ClusterIP
    port: 8080

Dockerfile

# 构建阶段
FROM maven:3.8.4-openjdk-11-slim AS build
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests
# 运行阶段
FROM openjdk:11-jre-slim
WORKDIR /app
# 创建非root用户
RUN groupadd -r appuser && useradd -r -g appuser appuser
COPY --from=build /app/target/k8s-deployment-*.jar app.jar
# 切换到非root用户
USER appuser
# 暴露端口
EXPOSE 8080
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=30s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1
# 启动应用
ENTRYPOINT ["java", "-jar", "app.jar"]

Kubernetes部署文件

deployment.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-deployer
  namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: app-deployer-role
rules:
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
  resources: ["services", "pods", "configmaps"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: app-deployer-binding
subjects:
- kind: ServiceAccount
  name: app-deployer
  namespace: default
roleRef:
  kind: ClusterRole
  name: app-deployer-role
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: java-k8s-manager
  namespace: default
  labels:
    app: java-k8s-manager
spec:
  replicas: 1
  selector:
    matchLabels:
      app: java-k8s-manager
  template:
    metadata:
      labels:
        app: java-k8s-manager
    spec:
      serviceAccountName: app-deployer
      containers:
      - name: java-k8s-manager
        image: your-registry/java-k8s-manager:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
        env:
        - name: KUBERNETES_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: KUBECONFIG
          value: /config/kubeconfig
        volumeMounts:
        - name: kubeconfig
          mountPath: /config
          readOnly: true
        resources:
          requests:
            cpu: "250m"
            memory: "256Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"
        securityContext:
          allowPrivilegeEscalation: false
          runAsUser: 1000
          runAsNonRoot: true
      volumes:
      - name: kubeconfig
        configMap:
          name: kubeconfig-config
---
apiVersion: v1
kind: Service
metadata:
  name: java-k8s-manager
  namespace: default
spec:
  selector:
    app: java-k8s-manager
  ports:
  - port: 8080
    targetPort: 8080
    protocol: TCP

使用说明

构建和部署

# 构建Java应用
mvn clean package
# 构建Docker镜像
docker build -t your-registry/java-k8s-manager:latest .
# 推送镜像
docker push your-registry/java-k8s-manager:latest
# 部署到Kubernetes
kubectl apply -f deployment.yaml
# 查看部署状态
kubectl get pods
kubectl logs -f deployment/java-k8s-manager

运行示例

# 运行应用
java -jar target/k8s-deployment-1.0.0.jar
# 或使用Docker
docker run -v ~/.kube/config:/app/config/kubeconfig java-k8s-manager

关键特性

  1. 灵活配置:支持集群内和集群外配置
  2. 完整生命周期管理:创建、更新、删除Deployment
  3. Service管理:支持创建K8s Service
  4. 健康检查:集成K8s健康检查机制
  5. 资源管理:支持自定义资源请求和限制
  6. 安全机制:使用RBAC权限控制
  7. 日志记录:完整的日志追踪

这个案例提供了完整的Kubernetes部署管理功能,可以在此基础上扩展更多功能,如ConfigMap管理、Ingress配置、自动扩容等。

抱歉,评论功能暂时关闭!