写点什么

Fabric8 Kubernetes 教程——客户端基础

作者:FunTester
  • 2025-03-20
    河北
  • 本文字数:8851 字

    阅读完需:约 29 分钟

初始化 Kubernetes 客户端

俗话说,工欲善其事,必先利其器。在使用 Kubernetes 时,首先需要初始化客户端。通常情况下,我们可以这样创建 Kubernetes 客户端:


try (final KubernetesClient client = new KubernetesClientBuilder().build()) {  // 使用客户端进行操作}
复制代码


这种方式会使用默认设置,从 ~/.kube/config 目录或 KUBECONFIG 环境变量定义的路径读取 kubeconfig 文件。但如果你想自定义客户端的创建,也可以通过传递一个 Config 对象给构建器来实现:


Config kubeConfig = new ConfigBuilder()  .withMasterUrl("https://192.168.42.20:8443/")  .build();try (final KubernetesClient client = new KubernetesClientBuilder().withConfig(kubeConfig).build()) {  // 使用客户端进行操作}
复制代码

Kubernetes 客户端 DSL 使用

俗话说,熟能生巧。本节将介绍 Kubernetes 客户端库中所有支持资源的 DSL 使用示例。尽管大多数资源的使用方式大同小异,但我们仍然将其一一列出,方便大家查阅:

Pods

Pods 可以通过 client.pods() 访问。以下是一些常见的 Pod 资源使用示例:


  • yaml 文件加载 PodPod 对象:


Pod myPod = client.pods().load(new FileInputStream("some-pod.yml")).item();
复制代码


  • 列出某个特定命名空间中的所有 Pod 对象:


PodList podList = client.pods().inNamespace("FunTester").list();
复制代码


  • 列出所有命名空间中的 Pod 对象:


PodList podList = client.pods().inAnyNamespace().list();
复制代码


  • 列出包含某些标签的 Pod 对象:


PodList podList = client.pods().inNamespace("FunTester").withLabel("foo", "bar").list();
复制代码


  • 从服务器获取具有特定名称的 Pod


Pod myPod = client.pods().inNamespace("FunTester").withName("nginx-pod").get();
复制代码


  • 创建一个 Pod


Pod aPod = new PodBuilder().withNewMetadata().withName("demo-pod1").endMetadata()    .withNewSpec()    .addNewContainer()    .withName("nginx")    .withImage("nginx:1.7.9")    .addNewPort().withContainerPort(80).endPort()    .endContainer()    .endSpec()    .build();Pod createdPod = client.pods().inNamespace("FunTester").resource(aPod).create();
复制代码


  • Pod 应用到 Kubernetes 集群:


client.pods().inNamespace("FunTester").resource(pod).serverSideApply();
复制代码


  • 编辑 Pod 对象:


client.pods().inNamespace("FunTester").withName("nginx").edit(  p -> new PodBuilder(p).editOrNewMetadata().addToLabels("new","label").endMetadata().build());
复制代码


  • 获取 Pod 对象的日志:


String log = client.pods().inNamespace("FunTester").withName("test-pod").getLog();
复制代码


  • 监听 Pod 的日志:


LogWatch watch = client.pods().inNamespace(namespace).withName(podName).tailingLines(10).watchLog(System.out);
复制代码


  • 删除 Pod


client.pods().inNamespace("FunTester").withName("nginx").delete();
复制代码


  • 删除多个 Pod 对象:


client.resourceList(pod1, pod2).inNamespace("FunTester").delete();
复制代码


  • 等待 Pod 准备就绪:


Pod pod = client.pods().inNamespace("FunTester").withName("nginx").waitUntilReady(5, TimeUnit.MINUTES);
复制代码


  • 等待 Pod 满足特定条件:


Pod pod = client.pods().inNamespace("FunTester").withName("nginx").waitUntilCondition(pod -> pod.getStatus().getPhase().equals("Succeeded"), 1, TimeUnit.MINUTES);
复制代码


  • 端口转发 Pod


int containerPort =  client.pods().inNamespace("FunTester").withName("testpod").get().getSpec().getContainers().get(0).getPorts().get(0).getContainerPort();LocalPortForward portForward = client.pods().inNamespace("FunTester").withName("testpod").portForward(containerPort, 8080);
复制代码


  • 监听 Pod


final CountDownLatch deleteLatch = new CountDownLatch(1);Watch podWatch = client.pods().withName("pod1").watch(new Watcher<>() {    @Override    public void eventReceived(Action action, Pod resource) {      switch (action) {        case DELETED:          deleteLatch.countDown();      }    }
@Override public void onClose(WatcherException e) { }});deleteLatch.await(10, TimeUnit.MINUTES);
复制代码


  • 上传文件到 Pod


client.pods().inNamespace(currentNamespace).withName(pod1.getMetadata().getName())  .file("/tmp/toBeUploaded").upload(tmpFile.toPath());
复制代码


  • Pod 读取文件:


try (InputStream is = client.pods().inNamespace(currentNamespace).withName(pod1.getMetadata().getName()).file("/msg").read())  {  String result = new BufferedReader(new InputStreamReader(is)).lines().collect(Collectors.joining("\n"));}
复制代码


  • Pod 添加临时容器:


PodResource resource = client.pods().withName("pod1");resource.ephemeralContainers()  .edit(p -> new PodBuilder(p)    .editSpec()    .addNewEphemeralContainer()    .withName("debugger")    .withImage("busybox")    .withCommand("sleep", "36000")    .endEphemeralContainer()    .endSpec()    .build());
resource.waitUntilCondition(p -> p.getStatus() .getEphemeralContainerStatuses() .stream() .filter(s -> s.getName().equals("debugger")) .anyMatch(s -> s.getState().getRunning() != null), 2, TimeUnit.MINUTES);ByteArrayOutputStream out = new ByteArrayOutputStream();try (ExecWatch watch = resource.inContainer("debugger") .writingOutput(out) .exec("sh", "-c", "echo 'FunTester hello world!'")) { assertEquals(0, watch.exitCode().join()); assertEquals("hello world!\n", out.toString());}
复制代码


  • Pod 内部使用 Kubernetes 客户端:


当尝试从 Pod 内部访问 Kubernetes API 时,身份验证的方式与在本地系统中有所不同。客户端通过从 /var/run/secrets/kubernetes.io/serviceaccount/ 读取 ServiceAccount 并从环境变量 KUBERNETES_SERVICE_HOSTKUBERNETES_SERVICE_PORT 中读取 apiServer URL 来进行身份验证。使用 Fabric8 Kubernetes 客户端时,你无需担心这些细节,只需像这样使用即可:


// 从挂载的卷中读取 serviceaccount 并从环境变量中获取 apiServer URL。KubernetesClient client = new KubernetesClientBuilder().build();
复制代码

Service

Service 可以通过 client.services() 访问。以下是一些常见的 Service 使用示例:


  • 从 yaml 文件加载 Service


Service aService = client.services().load(new FileInputStream("service.yml")).item();
复制代码


  • 从 API 服务器获取 Service


Service service = client.services().inNamespace("FunTester").withName("some-service").get();
复制代码


  • 创建 Service


Service createdSvc = client.services().inNamespace("FunTester").resource(svc).create();
复制代码


  • Service 对象应用到 Kubernetes 集群:


Service createdSvc = client.services().inNamespace("FunTester").resource(svc).serverSideApply();
复制代码


  • 列出某个特定命名空间中的所有 Service 对象:


ServiceList svcList = client.services().inNamespace("FunTester").list();
复制代码


  • 列出所有命名空间中的 Service 对象:


ServiceList svcList = client.services().inAnyNamespace().list();
复制代码


  • 列出具有某些特定标签的 Service 对象:


ServiceList svcList = client.services().inNamespace("FunTester").withLabel("foo", "bar").list();
复制代码


  • 删除 Service


client.services().inNamespace("FunTester").withName("some-svc").delete();
复制代码


  • 监听 Service


client.services().inNamespace("FunTester").watch(new Watcher<>() {  @Override  public void eventReceived(Action action, Service resource) {    // 根据操作类型执行某些操作  }
@Override public void onClose(WatcherException cause) {
}});
复制代码

Deployment

Deployment 可以通过 client.apps().deployments() 访问。以下是一些常见的 Deployment 使用示例:


  • 从 yaml 文件加载 Deployment


Deployment aDeployment = client.apps().deployments().load(new FileInputStream("test-deployments.yml")).item();
复制代码


  • 从 API 服务器获取 Deployment


Deployment deploy = client.apps().deployments().inNamespace("FunTester").withName("deploy-1").get();
复制代码


  • 创建 Deployment


Deployment deployment1 = new DeploymentBuilder()   .withNewMetadata()      .withName("FunTesterdeployment1")      .addToLabels("test", "deployment")   .endMetadata()   .withNewSpec()      .withReplicas(1)      .withNewTemplate()        .withNewMetadata()        .addToLabels("app", "httpd")        .endMetadata()        .withNewSpec()          .addNewContainer()             .withName("busybox")             .withImage("busybox")             .withCommand("sleep","36000")          .endContainer()        .endSpec()      .endTemplate()      .withNewSelector()        .addToMatchLabels("app","httpd")      .endSelector()   .endSpec() .build();
client.apps().deployments().inNamespace("FunTester").resource(deployment1).create();
复制代码


  • Deployment 对象应用到 Kubernetes 集群:


Deployment createdDeployment = client.apps().deployments().inNamespace("FunTester").resource(deployObj).serverSideApply();
复制代码


  • 列出某个特定命名空间中的 Deployment 对象:


DeploymentList aDeploymentList = client.apps().deployments().inNamespace("FunTester").list();
复制代码


  • 列出所有命名空间中的 Deployment 对象:


DeploymentList aDeploymentList = client.apps().deployments().inAnyNamespace().list();
复制代码


  • 列出具有某些特定标签的 Deployment 对象:


DeploymentList aDeployList = client.apps().deployments().inNamespace("FunTester").withLabel("foo", "bar").list();
复制代码


  • 编辑 Deployment


// 将 Deployment 扩展到 2 个副本Deployment updatedDeploy = client.apps().deployments().inNamespace("FunTester")  .withName("deployment1").edit(    d -> new DeploymentBuilder(d).editSpec().withReplicas(2).endSpec().build()  );
复制代码


  • 更新 Deployment 中的单个容器镜像:


Deployment updatedDeployment = client.apps()  .deployments()  .inNamespace("FunTester")  .withName("ngix-controller")  .updateImage("docker.io/nginx:latest");
复制代码


  • 更新 Deployment 中的多个容器镜像:


Map<String, String> containerToImageMap = new HashMap<>();containerToImageMap.put("nginx", "nginx:perl");containerToImageMap.put("sidecar", "someImage:someVersion");Deployment updatedDeployment = client.apps().deployments()      .inNamespace("FunTester")      .withName("nginx-deployment")      .updateImage(containerToImageMap);
复制代码


  • 重启 Deployment


Deployment deployment = client.apps().deployments()      .inNamespace("FunTester")      .withName("nginx-deployment")      .rolling()      .restart();
复制代码


  • 暂停 Deployment 的滚动更新:


Deployment deployment = client.apps().deployments()      .inNamespace("FunTester")      .withName("nginx-deployment")      .rolling()      .pause();
复制代码


  • 恢复 Deployment 的滚动更新:


Deployment deployment = client.apps().deployments()      .inNamespace("FunTester")      .withName("nginx-deployment")      .rolling()      .resume();
复制代码


  • 回滚 Deployment


Deployment deployment = client.apps().deployments()      .inNamespace("FunTester")      .withName("nginx-deployment")      .rolling()      .undo();
复制代码


  • 删除 Deployment


client.apps().deployments().inNamespace("FunTester").withName("foo").delete();
复制代码


  • 监听 Deployment


client.apps().deployments().inNamespace("FunTester").watch(new Watcher<>() {  @Override  public void eventReceived(Action action, Deployment resource) {    // 根据操作类型执行某些操作  }
@Override public void onClose(WatcherException cause) {
}});
复制代码


  • 扩展 Deployment


client.apps().deployments().inNamespace("FunTester").withName("nginx-deployment").scale(1);
复制代码


  • 获取 Deployment 日志:


client.apps().deployments().inNamespace("FunTester").withName("nginx").watchLog(System.out);
复制代码

ReplicaSet

ReplicaSet 可以通过 client.apps().replicaSets() 访问。以下是一些常见的 ReplicaSet 使用示例:


  • 从 yaml 文件加载 ReplicaSet


ReplicaSet replicaSet = client.apps().replicaSets().inNamespace("FunTester")  .load(new FileInputStream("test-replicaset.yml")).item();
复制代码


  • 从 API 服务器获取 ReplicaSet


ReplicaSet rs = client.apps().replicaSets().inNamespace("FunTester").withName("rs1").get();
复制代码


  • 创建 ReplicaSet


ReplicaSet replicaset1 = new ReplicaSetBuilder()      .withNewMetadata()      .withName("replicaset1")      .addToLabels("app", "guestbook")      .addToLabels("tier", "frontend")      .endMetadata()      .withNewSpec()      .withReplicas(1)      .withNewSelector()      .withMatchLabels(Collections.singletonMap("tier", "frontend"))      .endSelector()      .withNewTemplate()      .withNewMetadata()      .addToLabels("app", "guestbook")      .addToLabels("tier", "frontend")      .endMetadata()      .withNewSpec()      .addNewContainer()      .withName("busybox")      .withImage("busybox")      .withCommand("sleep","36000")      .withNewResources()      .withRequests(requests)      .endResources()      .withEnv(envVarList)      .endContainer()      .endSpec()      .endTemplate()      .endSpec()      .build();
client.apps().replicaSets().inNamespace("FunTester").resources(replicaset1).create();
复制代码


  • ReplicaSet 对象应用到 Kubernetes 集群:


ReplicaSet rs = client.apps().replicaSets().inNamespace("FunTester").resource(replicaSet).serverSideApply();
复制代码


  • 列出某个特定命名空间中的 ReplicaSet 对象:


ReplicaSetList rsList = client.apps().replicaSets().inNamespace("FunTester").list();
复制代码


  • 列出所有命名空间中的 ReplicaSet 对象:


ReplicaSetList rsList = client.apps().replicaSets().inAnyNamespace().list();
复制代码


  • 列出具有某些特定标签的 ReplicaSet 对象:


ReplicaSetList rsList = client.apps().replicaSets().inNamespace("FunTester").withLabel("foo", "bar").list(); 
复制代码


  • 删除 ReplicaSet


client.apps().replicaSets().inNamespace("FunTester").withName("rs1").delete();
复制代码


  • 监听 ReplicaSet


client.apps().replicaSets().inNamespace("FunTester").watch(new Watcher<>() {  @Override  public void eventReceived(Action action, ReplicaSet resource) {    // 根据操作类型执行某些操作  }
@Override public void onClose(WatcherException e) {
}});
复制代码


  • 扩展 ReplicaSet


// 扩展到 3 个副本client.apps().replicaSets().inNamespace("FunTester").withName("nginx-rs").scale(3);
复制代码


  • 更新 ReplicaSet 中的镜像:


ReplicaSet replicaSet = client.apps().replicaSets()        .inNamespace("FunTester")        .withName("soaktestrs")        .updateImage("nickchase/soaktest");
复制代码


  • 更新 ReplicaSet 中的多个镜像:


Map<String, String> containerToImageMap = new HashMap<>();containerToImageMap.put("c1", "image1");containerToImageMap.put("c2", "image2");ReplicaSet replicaSet = client.apps().replicaSets()            .inNamespace("FunTester")            .withName("soaktestrs")            .updateImage(containerToImageMap);
复制代码

Show You Code

好的,下面是一个使用 Kubernetes Java 客户端的虚拟场景脚本示例。假设我们需要实现以下需求:


  1. 创建一个命名空间fun-tester)。

  2. 在该命名空间中部署一个 Nginx Pod

  3. 为该 Pod 创建一个 Service,以便外部可以访问。

  4. 监听 Pod 的状态,直到 Pod 准备就绪。

  5. 获取 Pod 的日志并打印到控制台。

  6. 删除命名空间及其所有资源


以下是实现上述需求的完整脚本:


import io.fabric8.kubernetes.api.model.*;import io.fabric8.kubernetes.client.*;import io.fabric8.kubernetes.client.dsl.LogWatch;import io.fabric8.kubernetes.client.dsl.PodResource;
import java.util.concurrent.TimeUnit;
public class KubernetesFunTesterDemo {
public static void main(String[] args) { // 初始化 Kubernetes 客户端 try (KubernetesClient client = new KubernetesClientBuilder().build()) { String namespace = "fun-tester";
// 1. 创建命名空间 Namespace ns = new NamespaceBuilder() .withNewMetadata() .withName(namespace) .endMetadata() .build(); client.namespaces().resource(ns).create(); System.out.println("命名空间 " + namespace + " 创建成功!");
// 2. 在命名空间中部署一个 Nginx Pod Pod nginxPod = new PodBuilder() .withNewMetadata() .withName("nginx-pod") .addToLabels("app", "nginx") .endMetadata() .withNewSpec() .addNewContainer() .withName("nginx-container") .withImage("nginx:1.21.0") .addNewPort().withContainerPort(80).endPort() .endContainer() .endSpec() .build(); client.pods().inNamespace(namespace).resource(nginxPod).create(); System.out.println("Nginx Pod 创建成功!");
// 3. 为 Pod 创建一个 Service Service nginxService = new ServiceBuilder() .withNewMetadata() .withName("nginx-service") .endMetadata() .withNewSpec() .addNewPort() .withPort(80) .withTargetPort(new IntOrString(80)) .endPort() .withSelector(nginxPod.getMetadata().getLabels()) .withType("LoadBalancer") .endSpec() .build(); client.services().inNamespace(namespace).resource(nginxService).create(); System.out.println("Nginx Service 创建成功!");
// 4. 监听 Pod 的状态,直到 Pod 准备就绪 PodResource<Pod> podResource = client.pods().inNamespace(namespace).withName("nginx-pod"); Pod readyPod = podResource.waitUntilReady(5, TimeUnit.MINUTES); System.out.println("Nginx Pod 已准备就绪,状态为: " + readyPod.getStatus().getPhase());
// 5. 获取 Pod 的日志并打印到控制台 String podLog = podResource.getLog(); System.out.println("Nginx Pod 日志如下:"); System.out.println(podLog);
// 6. 删除命名空间及其所有资源 client.namespaces().withName(namespace).delete(); System.out.println("命名空间 " + namespace + " 及其所有资源已删除!");
} catch (KubernetesClientException e) { System.err.println("Kubernetes 操作失败: " + e.getMessage()); e.printStackTrace(); } }}
复制代码

脚本说明

  1. 初始化客户端:使用 KubernetesClientBuilder 创建 Kubernetes 客户端。

  2. 创建命名空间:通过 NamespaceBuilder 创建一个名为 fun-tester 的命名空间。

  3. 部署 Nginx Pod:使用 PodBuilder 创建一个 Nginx Pod,并指定容器镜像为 nginx:1.21.0

  4. 创建 Service:通过 ServiceBuilder 创建一个 Service,将流量转发到 Nginx Pod 的 80 端口。

  5. 监听 Pod 状态:使用 waitUntilReady 方法等待 Pod 准备就绪。

  6. 获取日志:通过 getLog 方法获取 Pod 的日志并打印到控制台。

  7. 清理资源:删除命名空间及其所有资源,确保环境干净。

运行结果

运行脚本后,控制台会输出以下内容:


命名空间 fun-tester 创建成功!Nginx Pod 创建成功!Nginx Service 创建成功!Nginx Pod 已准备就绪,状态为: RunningNginx Pod 日志如下:(Nginx 的启动日志)命名空间 fun-tester 及其所有资源已删除!
复制代码

注意事项

  • 确保本地 Kubernetes 环境(如 Minikube 或 Kind)已启动,并且 kubectl 可以正常使用。

  • 如果 Kubernetes 集群中没有 LoadBalancer 支持,可以将 Service 类型改为 NodePort

  • 脚本中的等待时间(5 分钟)可以根据实际环境调整。

发布于: 刚刚阅读数: 3
用户头像

FunTester

关注

公众号:FunTester,800篇原创,欢迎关注 2020-10-20 加入

Fun·BUG挖掘机·性能征服者·头顶锅盖·Tester

评论

发布
暂无评论
Fabric8 Kubernetes 教程——客户端基础_FunTester_InfoQ写作社区