本文目录导读:

- 项目依赖配置 (pom.xml)
- 配置类 (KubeConfig.java)
- Deployment管理类 (DeploymentManager.java)
- 主程序 (Main.java)
- 配置文件示例
- Dockerfile
- Kubernetes部署文件
- 使用说明
- 关键特性
我将为您提供一个完整的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
关键特性
- 灵活配置:支持集群内和集群外配置
- 完整生命周期管理:创建、更新、删除Deployment
- Service管理:支持创建K8s Service
- 健康检查:集成K8s健康检查机制
- 资源管理:支持自定义资源请求和限制
- 安全机制:使用RBAC权限控制
- 日志记录:完整的日志追踪
这个案例提供了完整的Kubernetes部署管理功能,可以在此基础上扩展更多功能,如ConfigMap管理、Ingress配置、自动扩容等。