Fabric8 操作 Kubernetes (II)
前言
在 Fabric8操作Kubernetes(一) 一文中我们介绍了初始化 KubernetesClient
的方法。今天我们一起来学习一下如果通过 KubernetesClient 创建各种资源对象
。
Pods
通过 client.pods()
可以实现对 Pods 的操作。下面是一些常用方法:
- 从yaml文件创建 Pod:
Pod myPod = client.pods().load(new FileInputStream("some-pod.yml")).get();
- 列出指定 Namespace 下的所有
Pod
对象:
PodList podList = client.pods().inNamespace("default").list();
- 列出所有 Namespace 下的所有
Pod
对象:
PodList podList = client.pods().inAnyNamespace().list();
- 列出所有包含指定标签的
Pod
对象:
PodList podList = client.pods().inNamespace("default").withLabel("foo", "bar").list();
- 根据名称获取
Pod
对象:
Pod myPod = client.pods().inNamespace("default").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("default").create(aPod);
- 创建或替换已存在的
Pod
对象:
client.pods().inNamespace("default").createOrReplace(aPod);
- Create or Replace some
Pod
on the fly withBuilder
:
client.pods().inNamespace("default").createOrReplaceWithNew()
.withNewMetadata().withName("demo-pod1").endMetadata()
.withNewSpec()
.addNewContainer()
.withName("nginx")
.withImage("nginx:1.7.9")
.addNewPort().withContainerPort(80).endPort()
.endContainer()
.endSpec()
.done();
- 编辑一个
Pod
对象:
client.pods().inNamespace("default").withName("nginx").edit()
.editOrNewMetadata().addToLabels("new","label").endMetadata().done()
- 获取
Pod
对象的日志输出:
String log = client.pods().inNamespace("default").withName("test-pod").getLog();
- 监听
Pod
日志输出:
LogWatch watch = client.pods().inNamespace(namespace).withName(podName).tailingLines(10).watchLog(System.out);
- 删除一个
Pod
:
Boolean isDeleted = client.pods().inNamespace("default").withName("nginx").delete();
- 删除多个
Pod
对象:
Boolean isDeleted = client.pods().inNamespace("default").delete(pod1, pod2);
- 等待
Pod
ready:
Pod pod = client.pods().inNamespace("default").withName("nginx").waitUntilReady(5, TimeUnit.MINUTES);
- 等待
Pod
达成某些条件:
Pod pod = client.pods().inNamespace("default").withName("nginx").waitUntilCondition(pod -> pod.getStatus().getPhase().equals("Succeeded"), 1, TimeUnit.MINUTES)
- 代理
Pod
的端口:
int containerPort = client.pods().inNamespace("default").withName("testpod").get().getSpec().getContainers().get(0).getPorts().get(0).getContainerPort();
LocalPortForward portForward = client.pods().inNamespace("default").withName("testpod").portForward(containerPort, 8080);
- 监听
Pod
:
final CountDownLatch deleteLatch = new CountDownLatch(1);
Watch watch = client.pods().withName("pod1").watch(new Watcher<Pod>() {
@Override
public void eventReceived(Action action, Pod resource) {
switch (action) {
case DELETED:
deleteLatch.countDown();
}
}
@Override
public void onClose(KubernetesClientException cause) { }
});
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"));
}
Service
通过 client.services()
可以实现对 Service 的操作。下面是一些常用方法:
- 从yaml文件中加载一个
Service
:
Service aService = client.services().load(new FileInputStream("service.yml")).get();
- 根据名称获取
Service
:
Service service = client.services().inNamespace("default").withName("some-service").get();
- 创建一个
Service
:
Service createdSvc = client.services().inNamespace("default").create(svc);
- 创建或替换一个已存在的
Service
:
Service createdSvc = client.services().inNamespace("default").createOrReplace(svc);
- 通过 Builders 创建或替换一个已存在的
Service
:
Service createdSvc = client.services().inNamespace("default").createOrReplaceWithNew()
.withNewMetadata().withName("svc2").endMetadata()
.withNewSpec().withType("ExternalName").withExternalName("my.database.example.com")
.addNewPort().withName("80").withProtocol("TCP").withPort(80).endPort()
.endSpec()
.withNewStatus()
.withNewLoadBalancer()
.addNewIngress()
.withIp("146.148.47.155")
.endIngress()
.endLoadBalancer()
.endStatus()
.done();
- 列出指定 namespace 下的所有
Service
对象:
ServiceList svcList = client.services().inNamespace("default").list();
- 列出所有 namespace 下的所有
Service
对象:
ServiceList svcList = client.services().inAnyNamespace().list();
- 列出包含指定标签的所有
Service
对象:
ServiceList svcList = client.services().inNamespace("default").withLabel("foo", "bar").list();
- 删除一个
Service
:
Boolean isDeleted = client.services().inNamespace("default").withName("some-svc").delete();
- 监听
Service
:
client.services().inNamespace("default").watch(new Watcher<Service>() {
@Override
public void eventReceived(Action action, Service resource) {
// Perform something depending upon action
}
@Override
public void onClose(KubernetesClientException cause) {
}
});
Deployment
通过 client.apps().deployment()
可以实现对 Deployment 的操作。下面是一些常用方法:
- 通过yaml文件生成
Deployment
对象:
Deployment aDeployment = client.apps().deployments().load(new FileInputStream("test-deployments.yml")).get();
- 通过名称获取
Deployment
对象:
Deployment deploy = client.apps().deployments().inNamespace("default").withName("deploy-1").get();
- 创建一个
Deployment
:
Deployment deployment1 = new DeploymentBuilder()
.withNewMetadata()
.withName("deployment1")
.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("default").create(deployment1);
- 创建或替换一个已存在的
Deployment
:
Deployment createdDeployment = client.apps().deployments().inNamespace("default").createOrReplace(deployObj);
- 通过 builders 创建或更新一个已存在的
Deployment
:
client.apps().deployments().inNamespace("default").createOrReplaceWithNew()
.withNewMetadata()
.withName("deployment1")
.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()
.done();
- 列出指定 Namespace 下的所有
Deployment
对象:
DeploymentList aDeploymentList = client.apps().deployments().inNamespace("default").list();
- 列出所有 Namespace 下的所有
Deployment
对象:
DeploymentList aDeploymentList = client.apps().deployments().inAnyNamespace().list();
- 列出包含指定标签的所有
Deployment
对象:
DeploymentList aDeployList = client.apps().deployments().inNamespace("default").withLabel("foo", "bar").list();
- 编辑
Deployment
:
// Scales Deployment to 2 replicas
Deployment updatedDeploy = client.apps().deployments().inNamespace("default")
.withName("deployment1").edit()
.editSpec().withReplicas(2).endSpec().done();
- 更新
Deployment
中一个容器的镜像:
Deployment updatedDeployment = client.apps().deployments().inNamespace("default").withName("ngix-controller")
.rolling().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("default")
.withName("nginx-deployment")
.rolling()
.updateImage(containerToImageMap);
- 滚动更新
Deployment
:
Deployment deployment = client.apps().deployments()
.inNamespace("default")
.withName("nginx-deployment")
.rolling()
.restart();
- 暂停滚动更新
Deployment
:
Deployment deployment = client.apps().deployments()
.inNamespace("default")
.withName("nginx-deployment")
.rolling()
.pause();
- 恢复滚动更新
Deployment
:
Deployment deployment = client.apps().deployments()
.inNamespace("default")
.withName("nginx-deployment")
.rolling()
.resume();
- 回滚
Deployment
:
Deployment deployment = client.apps().deployments()
.inNamespace("default")
.withName("nginx-deployment")
.rolling()
.undo();
- 删除
Deployment
:
Boolean isDeleted = client.apps().deployments().inNamespace("default").withName("foo").delete();
- 监听
Deployment
:
client.apps().deployments().inNamespace("default").watch(new Watcher<Deployment>() {
@Override
public void eventReceived(Action action, Deployment resource) {
// Do stuff depending upon action
}
@Override
public void onClose(KubernetesClientException cause) {
}
});
- 扩容或缩容
Deployment
:
client.apps().deployments().inNamespace("default").withName("nginx-deployment").scale(1);
- 查看
Deployment
日志输出:
client.apps().deployments().inNamespace("default").withName("nginx").watchLog(System.out);
ReplicaSet
通过 client.apps().replicaSets()
可以实现对 ReplicaSet 的操作。下面是一些常用方法:
- 通过yaml文件生成
ReplicaSet
对象:
ReplicaSet replicaSet = client.apps().replicaSets().inNamespace("default")
.load(new FileInputStream("test-replicaset.yml")).get();
- 根据名称获取
ReplicaSet
:
ReplicaSet rs = client.apps().replicaSets().inNamespace("default").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("default").create(replicaset1);
- 创建或替换一个已存在的
ReplicaSet
对象:
ReplicaSet rs = client.apps().replicaSets().inNamespace("default").createOrReplace(replicaSet);
- 通过 builders 创建或替换一个已存在的
ReplicaSet
对象:
ReplicaSet rs = client.apps().replicaSets().inNamespace("default").createOrReplaceWithNew()
.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()
.done();
- 列出指定 Namespace 下的所有
ReplicaSet
对象:
ReplicaSetList rsList = client.apps().replicaSets().inNamespace("default").list();
- 列出所有 Namespace 下的所有
ReplicaSet
对象:
ReplicaSetList rsList = client.apps().replicaSets().inAnyNamespace().list();
- 列出包含指定标签的
ReplicaSet
对象:
ReplicaSetList rsList = client.apps().replicaSets().inNamespace("default").withLabel("foo", "bar").list();
- 删除
ReplicaSet
:
Boolean isDeleted = client.apps().replicaSets().inNamespace("default").withName("rs1").delete();
- 监听
ReplicaSet
:
client.apps().replicaSets().inNamespace("default").watch(new Watcher<ReplicaSet>() {
@Override
public void eventReceived(Action action, ReplicaSet resource) {
// Do some stuff depending upon action type
}
@Override
public void onClose(KubernetesClientException cause) {
}
});
- 扩容或缩容
ReplicaSet
:
// Scale to 3 replicas
client.apps().replicaSets().inNamespace("default").withName("nginx-rs").scale(3);
- 更新
ReplicaSet
的镜像:
ReplicaSet replicaSet = client.apps().replicaSets()
.inNamespace("default")
.withName("soaktestrs")
.rolling()
.updateImage("nickchase/soaktest");
- 更新
ReplicaSet
中多个容器的镜像:
Map<String, String> containerToImageMap = new HashMap<>();
containerToImageMap.put("c1", "image1");
containerToImageMap.put("c2", "image2");
ReplicaSet replicaSet = client.apps().replicaSets()
.inNamespace("default")
.withName("soaktestrs")
.rolling()
.updateImage(containerToImageMap);
ReplicationController
通过 client.replicationControllers()
可以实现对 ReplicationController 的操作。下面是一些常用方法:
- 通过yaml文件生成
ReplicationController
对象:
ReplicationController aReplicationController = client.replicationControllers().inNamespace("default")
.load(new FileInputStream("/test-replicationcontroller.yml")).get();
- 根据名称获取
ReplicationController
对象:
ReplicationController rc = client.replicationControllers().inNamespace("default").withName("nginx-controller").get();
- 创建
ReplicationController
对象:
ReplicationController rc1 = new ReplicationControllerBuilder()
.withNewMetadata().withName("nginx-controller").addToLabels("server", "nginx").endMetadata()
.withNewSpec().withReplicas(3)
.withNewTemplate()
.withNewMetadata().addToLabels("server", "nginx").endMetadata()
.withNewSpec()
.addNewContainer().withName("nginx").withImage("nginx")
.addNewPort().withContainerPort(80).endPort()
.endContainer()
.endSpec()
.endTemplate()
.endSpec().build();
ReplicationController rc = client.replicationControllers().inNamespace("default").create(rc1);
- 创建或替换一个已存在的
ReplicationController
对象:
ReplicationController rc = client.replicationControllers().inNamespace("default").createOrReplace(rc1);
- 通过 builders 创建或替换一个已存在的
ReplicationController
对象:
ReplicationController rc = client.replicationControllers().inNamespace("default").createOrReplaceWithNew()
.withNewMetadata().withName("nginx-controller").addToLabels("server", "nginx").endMetadata()
.withNewSpec().withReplicas(3)
.withNewTemplate()
.withNewMetadata().addToLabels("server", "nginx").endMetadata()
.withNewSpec()
.addNewContainer().withName("nginx").withImage("nginx")
.addNewPort().withContainerPort(80).endPort()
.endContainer()
.endSpec()
.endTemplate()
.endSpec().done();
- 列出指定命名空间下的所有
ReplicationController
对象:
ReplicationControllerList rcList = client.replicationControllers().inNamespace("default").list();
- 列出所有命名空间下的所有
ReplicationController
对象:
ReplicationControllerList rcList = client.replicationControllers().inAnyNamespace("default").list();
- 列出包含指定标签的
ReplicationController
对象:
ReplicationControllerList rcList = client.replicationControllers().inNamespace("default").withLabel("foo", "bar").list();
- 删除
ReplicationController
:
Boolean isDeleted = client.replicationControlers().inNamespace("default").withName("nginx-controller").delete();
- 监听
ReplicationController
:
client.replicationControllers().inNamespace(currentNamespace).watch(new Watcher<ReplicationController>() {
@Override
public void eventReceived(Action action, ReplicationController resource) {
// Do something depending upon action type
}
@Override
public void onClose(KubernetesClientException cause) {
}
});
- 扩容或缩容
ReplicationController
:
ReplicationController rc = client.replicationControllers().inNamespace("default").withName("nginx-controller").scale(2);
- 更新
ReplicationController
的镜像:
ReplicationController rc = client.replicationControllers()
.inNamespace("default")
.withName("nginx")
.rolling()
.updateImage("nginx:latest");
- 更新
ReplicationController
多个容器的镜像:
Map<String, String> containerToImageMap = new HashMap<>();
containerToImageMap.put("c1", "image1");
containerToImageMap.put("c2", "image2");
ReplicationController rc = client.replicationControllers()
.inNamespace("default")
.withName("nginx")
.rolling()
.updateImage(controllerToImageMap);
ConfigMap
通过 client.configMaps()
可以实现对 ConfigMap 的操作。下面是一些常用方法:
- 通过 yaml 文件生成
ConfigMap
对象:
ConfigMap configMap = client.configMaps().load(new FileInputStream("configmap1.yml")).get();
- 根据名称获取
ConfigMap
对象:
ConfigMap configMap = client.configMaps().inNamespace("default").withName("configmap1").get();
- 创建
ConfigMap
:
ConfigMap configMap1 = new ConfigMapBuilder()
.withNewMetadata().withName("configmap1").endMetadata()
.addToData("1", "one")
.addToData("2", "two")
.addToData("3", "three")
.build();
ConfigMap configMap = client.configMaps().inNamespace("default").create(configMap1);
- 创建或替换一个已存在的
ConfigMap
:
ConfigMap configMap = client.configMaps().inNamespace("default").createOrReplace(configMap1);
- 通过 builders 创建或替换一个已存在的
ConfigMap
:
ConfigMap configMap = client.configMaps().inNamespace("default").createOrReplaceWithNew()
.withNewMetadata().withName("configmap1").endMetadata()
.addToData("1", "one")
.addToData("2", "two")
.addToData("3", "three")
.done();
- 列出指定 Namespace 下的所有
ConfigMap
对象:
ConfigMapList configMapList = client.configMaps().inNamespace("default").list();
- 列出所有 Namespace 下的所有
ConfigMap
对象:
ConfigMapList configMapList = client.configMaps().inAnyNamespace().list();
- 列出指定 Namespace 下包含指定标签的
ConfigMap
对象:
ConfigMapList configMapList = client.configMaps().inNamespace("default").withLabel("foo", "bar").list();
- 删除
ConfigMap
:
Boolean isDeleted = client.configMaps().inNamespace("default").withName("configmap1").delete();
- 监听
ConfigMap
:
client.configMaps().inNamespace("default").watch(new Watcher<ConfigMap>() {
@Override
public void eventReceived(Action action, ConfigMap resource) {
// Do something depending upon action type
}
@Override
public void onClose(KubernetesClientException cause) {
}
});
- 更新
ConfigMap
:
ConfigMap configMap1 = client.configMaps().inNamespace(currentNamespace).withName("configmap1").edit()
.addToData("4", "four").done();
Secret
通过 client.secrets()
可以实现对 Secret 的操作。下面是一些常用方法:
- 通过 yaml 文件生成
Secret
:
Secret aSecret = client.secrets().inNamespace("default").load(new FileInputStream("test-secret.yml")).get();
- 根据名称获取
Secret
:
Secret secret = client.secrets().inNamespace("default").withName("secret1").get()
- 创建
Secret
:
Secret secret1 = new SecretBuilder()
.withNewMetadata().withName("secret1").endMetadata()
.addToData("username", "guccifer")
.addToData("password", "shadowgovernment")
.build();
Secret secretCreated = client.secrets().inNamespace("default").create(secret1);
- 创建或替换一个已存在的
Secret
:
Secret createdSecret = client.secrets().inNamespace("default").createOrReplace(secret1);
- 通过 builder 创建或替换一个已存在的
Secret
:
Secret createdSecret = client.secrets().inNamespace("default").createOrReplaceWithNew()
.withNewMetadata().withName("secret1").endMetadata()
.addToData("username", "guccifer")
.addToData("password", "shadowgovernment")
.done();
- 列出指定 Namespace 下的所有
Secret
资源:
SecretList secretList = client.secrets().inNamespace("default").list();
- 列出所有 Namespace 下的所有
Secret
资源:
SecretList secretList = client.secrets().inAnyNamespace().list();
- 列出指定 Namespace 下包含指定标签的
Secret
资源:
SecretList secretList = client.secrets().inNamespace("default").withLabel("foo", "bar").list();
- 编辑
Secret
:
Secret secret1 = client.secrets().inNamespace(currentNamespace).withName("secret1").edit()
.withType("Opaque")
.done();
- 删除
Secret
:
Boolean isDeleted = client.secrets().inNamespace("default").withName("secret1").delete();
- 监听
Secret
:
client.secrets().inNamespace("default").watch(new Watcher<Secret>() {
@Override
public void eventReceived(Action action, Secret resource) {
// Do something depending upon action type
}
@Override
public void onClose(KubernetesClientException cause) {
}
});
Job
通过 client.batch().jobs()
可以实现对 Job 的操作。下面是一些常用方法:
- 通过 yaml 文件生成
Job
:
Job job = client.batch().jobs().load(new FileInputStream("sample-job.yml")).get();
- 根据名称获取
Job
:
Job job = client.batch().jobs().inNamespace("default").withName("pi").get();
- 创建
Job
:
final Job job = new JobBuilder()
.withApiVersion("batch/v1")
.withNewMetadata()
.withName("pi")
.withLabels(Collections.singletonMap("label1", "maximum-length-of-63-characters"))
.withAnnotations(Collections.singletonMap("annotation1", "some-very-long-annotation"))
.endMetadata()
.withNewSpec()
.withNewTemplate()
.withNewSpec()
.addNewContainer()
.withName("pi")
.withImage("perl")
.withArgs("perl", "-Mbignum=bpi", "-wle", "print bpi(2000)")
.endContainer()
.withRestartPolicy("Never")
.endSpec()
.endTemplate()
.endSpec()
.build();
client.batch().jobs().inNamespace("default").create(job);
- 创建或替换一个已存在的
Job
:
Job job = client.batch().jobs().inNamespace("default").createOrReplace(job);
- 通过 builders 创建或替换一个已存在的 `Job:
Job job = client.batch().jobs().inNamespace("default").createOrReplaceWithNew()
.withApiVersion("batch/v1")
.withNewMetadata()
.withName("pi")
.withLabels(Collections.singletonMap("label1", "maximum-length-of-63-characters"))
.withAnnotations(Collections.singletonMap("annotation1", "some-very-long-annotation"))
.endMetadata()
.withNewSpec()
.withNewTemplate()
.withNewSpec()
.addNewContainer()
.withName("pi")
.withImage("perl")
.withArgs("perl", "-Mbignum=bpi", "-wle", "print bpi(2000)")
.endContainer()
.withRestartPolicy("Never")
.endSpec()
.endTemplate()
.endSpec()
.done();
- List
Job
in some namespace:
JobList jobList = client.batch().jobs().inNamespace("default").list();
- List
Job
in any namespace:
JobList jobList = client.batch().jobs().inAnyNamespace().list();
- List
Job
resources in some namespace with some labels:
JobList jobList = client.batch().jobs().inNamespace("default").withLabel("foo", "bar").list();
- Delete
Job
:
Boolean isDeleted = client.batch().jobs().inNamespace("default").withName("pi").delete();
- Watch
Job
:
client.batch().jobs().inNamespace("default").watch(new Watcher<Job>() {
@Override
public void eventReceived(Action action, Job resource) {
// Do something depending upon action
}
@Override
public void onClose(KubernetesClientException cause) {
}
})
CronJob
CronJob
resource is available in Kubernetes Client api via client.batch().cronjobs()
. Here are some of the examples of its usages:
- Load
CronJob
from yaml:
CronJob cronJob = client.batch().cronjobs().load(new FileInputStream("cronjob.yml")).get();
- Get a
CronJob
from Kubernetes API server:
CronJob aCronJob = client.batch().cronjobs().inNamespace("default").withName("some-cj").get();
- Create
CronJob
:
CronJob cronJob1 = new CronJobBuilder()
.withApiVersion("batch/v1beta1")
.withNewMetadata()
.withName("hello")
.withLabels(Collections.singletonMap("foo", "bar"))
.endMetadata()
.withNewSpec()
.withSchedule("*/1 * * * *")
.withNewJobTemplate()
.withNewSpec()
.withNewTemplate()
.withNewSpec()
.addNewContainer()
.withName("hello")
.withImage("busybox")
.withArgs("/bin/sh", "-c", "date; echo Hello from Kubernetes")
.endContainer()
.withRestartPolicy("OnFailure")
.endSpec()
.endTemplate()
.endSpec()
.endJobTemplate()
.endSpec()
.build();
cronJob1 = client.batch().cronjobs().inNamespace("default").create(cronJob1);
- Create or Replace an existing
CronJob
:
CronJob cronJob = client.batch().cronjobs().inNamespace("default").createOrReplace(cronJob1);
- Create or Replace
CronJob
with builders:
CronJob cronJob = client.batch().cronjobs().inNamespace("default").createOrReplaceWithNew()
.withApiVersion("batch/v1beta1")
.withNewMetadata()
.withName("hello")
.withLabels(Collections.singletonMap("foo", "bar"))
.endMetadata()
.withNewSpec()
.withSchedule("*/1 * * * *")
.withNewJobTemplate()
.withNewSpec()
.withNewTemplate()
.withNewSpec()
.addNewContainer()
.withName("hello")
.withImage("busybox")
.withArgs("/bin/sh", "-c", "date; echo Hello from Kubernetes")
.endContainer()
.withRestartPolicy("OnFailure")
.endSpec()
.endTemplate()
.endSpec()
.endJobTemplate()
.endSpec()
.done();
- List some
CronJob
objects in some namespace:
CronJobList cronJobList = client.batch().cronjobs().inNamespace("default").list()
- List some
CronJob
objects in any namespace:
CronJobList cronJobList = client.batch().cronjobs().inAnyNamespace().list();
- List some
CronJob
objects in some namespace with some label:
CronJobList cronJobList = client.batch().cronjobs().inNamespace("default").withLabel("foo", "bar").list();
- Edit/Update
CronJob
:
CronJob cronJob1 = client.batch().cronjobs().inNamespace("default").withName(cronJob1.getMetadata().getName())
.edit()
.editSpec()
.withSchedule("*/1 * * * *")
.endSpec()
.done();
- Delete
CronJob
:
Boolean isDeleted = client.batch().cronjobs().inNamespace("default").withName("pi").delete();
Namespace
Namespace
is available in Kubernetes Client API via client.namespaces()
. Here are some of the common usages:
- Load
Namespace
from yaml:
Namespace namespace = client.namespaces().load(new FileInputStream("namespace-test.yml")).get();
- Get
Namespace
from Kubernetes API server:
Namespace namespace = client.namespaces().withName("namespace1").get();
- List
Namespace
objects:
NamespaceList namespaceList = client.namespaces().list();
- List
Namespace
objects with some labels:
NamespaceList namespaceList = client.namespaces().withLabel("key1", "value1").list();
- Delete
Namespace
objects:
Boolean isDeleted = client.namespaces().withName("ns1").delete();
ServiceAccount
ServiceAccount
resource is available in Kubernetes Client API via client.serviceAccounts()
. Here are some examples of it's usage:
- Load
ServiceAccount
from yaml:
ServiceAccount svcAccount = client.serviceAccounts().inNamespace("default")
.load(new FileInputStream("sa.yml")).get();
- Get
ServiceAccount
from Kubernetes API server:
ServiceAccount sa = client.serviceAccounts().inNamespace("default").withName("sa-ribbon").get();
- Create
ServiceAccount
:
ServiceAccount serviceAccount1 = new ServiceAccountBuilder()
.withNewMetadata().withName("serviceaccount1").endMetadata()
.withAutomountServiceAccountToken(false)
.build();
client.serviceAccounts().inNamespace("default").create(serviceAccount1);
- Create or Replace
ServiceAccount
:
ServiceAccount serviceAccount = client.serviceAccounts().inNamespace("default").createOrReplace(serviceAccount1);
- Create or Replace
ServiceAccount
with builders:
ServiceAccount serviceAccount = client.serviceAccounts().inNamespace("default").createOrReplaceWithNew()
.withNewMetadata().withName("serviceaccount1").endMetadata()
.withAutomountServiceAccountToken(false)
.done();
- List
ServiceAccount
in some specific namespace:
ServiceAccountList svcAccountList = client.serviceAccounts().inNamespace("default").list();
- List
ServiceAccount
in some namespace with labels:
ServiceAccountList saList = client.serviceAccounts().inNamespace("default").withLabel("foo", "bar").list();
- Update/Edit
ServiceAccount
:
ServiceAccount serviceAccount1 = client.serviceAccounts().inNamespace("default").withName("serviceaccount1").edit()
.addNewSecret().withName("default-token-uudp").endSecret()
.addNewImagePullSecret().withName("myregistrykey").endImagePullSecret()
.done();
- Delete
ServiceAccount
:
Boolean bDeleted = client.serviceAccounts().inNamespace("default").withName("serviceaccount1").delete();
Ingress
Ingress
resource is available in Kubernetes Client API via client.network().ingress()
. Here are some examples regarding its usage:
- Load
Ingress
from yaml:
Ingress ingress = client.network().ingress().load(new FileInputStream("ingress.yml")).get();
- Get
Ingress
from Kubernetes API server:
Ingress ingress = client.network().ingress().inNamespace("default").withName("ingress1").get();
- Create
Ingress
:
Ingress ingress = new IngressBuilder()
.withNewMetadata().withName("test-ingress").addToAnnotations("nginx.ingress.kubernetes.io/rewrite-target", "/").endMetadata()
.withNewSpec()
.addNewRule()
.withNewHttp()
.addNewPath()
.withPath("/testPath").withNewBackend().withServiceName("test").withServicePort(new IntOrString(80)).endBackend()
.endPath()
.endHttp()
.endRule()
.endSpec()
.build();
client.network().ingress().inNamespace("default").create(ingress);
- Create or Replace
Ingress
:
Ingress igx = client.network().ingress().inNamespace("default").createOrReplace(ingress);
- Create or Replace
Ingress
with Builders:
Ingress igx = client.network().ingress().inNamespace("default").createOrReplaceWithNew()
.withNewMetadata().withName("test-ingress").addToAnnotations("nginx.ingress.kubernetes.io/rewrite-target", "/").endMetadata()
.withNewSpec()
.addNewRule()
.withNewHttp()
.addNewPath()
.withPath("/testPath").withNewBackend().withServiceName("test").withServicePort(new IntOrString(80)).endBackend()
.endPath()
.endHttp()
.endRule()
.endSpec()
.done();
- List
Ingress
in some namespace:
IngressList ingressList = client.network().ingress().inNamespace("default").list();
- List
Ingress
in any namespace:
IngressList ingressList = client.network().ingress().inAnyNamespace().list();
- List
Ingress
with some label in any namespace:
IngressList ingressList = client.network().ingress().inNamespace("default").withLabel("foo", "bar").list();
- Delete
Ingress
:
Boolean isDeleted = client.network().ingress().inNamespace("default").withName("ingress1").delete();
StatefulSet
StatefulSet
resource is available in Kubernetes API via client.apps().statefulsets()
. Here are some examples of its common usages:
- Load
StatefulSet
from yaml:
StatefulSet aStatefulSet = client.apps().statefulSets()
.load(new FileInputStream("test-statefulset.yml")).get();
- Get a
StatefulSet
from Kubernetes API server:
StatefulSet ss1 = client.apps().statefulSets().inNamespace("default").withName("ss1").get();
- Create a
StatefulSet
:
StatefulSet ss1 = new StatefulSetBuilder()
.withNewMetadata().withName("ss1").endMetadata()
.withNewSpec()
.withReplicas(2)
.withNewSelector().withMatchLabels(Collections.singletonMap("app", "nginx")).endSelector()
.withNewTemplate()
.withNewMetadata()
.addToLabels("app", "nginx")
.endMetadata()
.withNewSpec()
.addNewContainer()
.withName("nginx")
.withImage("nginx")
.addNewPort()
.withContainerPort(80)
.withName("web")
.endPort()
.addNewVolumeMount()
.withName("www")
.withMountPath("/usr/share/nginx/html")
.endVolumeMount()
.endContainer()
.endSpec()
.endTemplate()
.addNewVolumeClaimTemplate()
.withNewMetadata()
.withName("www")
.endMetadata()
.withNewSpec()
.addToAccessModes("ReadWriteOnce")
.withNewResources()
.withRequests(Collections.singletonMap("storage", new Quantity("1Gi")))
.endResources()
.endSpec()
.endVolumeClaimTemplate()
.endSpec()
.build();
StatefulSet ss = client.apps().statefulSets().inNamespace("default").create(ss1);
- Create or Replace an existing
StatefulSet
:
StatefulSet ss = client.apps().statefulSets().inNamespace("default").createOrReplace(ss1);
- List
StatefulSet
in some particular namespace:
StatefulSetList statefulSetList = client.apps().statefulSets().inNamespace("default").list();
- List
StatefulSet
in any namespace:
StatefulSetList statefulSetList = client.apps().statefulSets().inAnyNamespace().list();
- List
StatefulSet
in some namespace with label:
StatefulSetList statefulSetList = client.apps().statefulSets().inNamespace("default").withLabel("foo", "bar").list();
- Delete
StatefulSet
:
Boolean bDeleted = client.apps().statefulSets().inNamespace("default").withName("ss1").delete();
- Scale
StatefulSet
:
client.apps().statefulSets().inNamespace("default").withName("ss1").scale(2);
- Watch
StatefulSet
:
client.apps().statefulSets().inNamespace("default").withName("ss1").watch(new Watcher<StatefulSet>() {
@Override
public void eventReceived(Action action, StatefulSet resource) {
// Do something on action type
}
@Override
public void onClose(KubernetesClientException cause) {
}
})
- Update Image in
StatefulSet
:
StatefulSet statefulSet = client.apps().statefulSets()
.inNamespace("default")
.withName("web")
.rolling()
.updateImage("nginx:1.19");
- Updated multiple containers in
StatefulSet
:
Map<String, String> containerToImageMap = new HashMap<>();
containerToImageMap("container1", "nginx:1.9");
containerToImageMap("container2", "busybox:latest");
Statefulset statefulSet = client.apps().statefulSets()
.inNamespace("default")
.withName("web")
.rolling()
.updateImage(params);
- Restart Rollout for
StatefulSet
:
StatefulSet ss = client.apps().statefulSets()
.inNamespace("default")
.withName("web")
.rolling()
.restart();
- Pause Rollout for
StatefulSet
:
StatefulSet ss = client.apps().statefulSets()
.inNamespace("default")
.withName("web")
.rolling()
.pause();
- Resume Rollout for
StatefulSet
:
StatefulSet ss = client.apps().statefulSets()
.inNamespace("default")
.withName("web")
.rolling()
.resume();
- Undo Rollout for
StatefulSet
:
StatefulSet ss = client.apps().statefulSets()
.inNamespace("default")
.withName("web")
.rolling()
.undo();
DaemonSet
DaemonSet
resource is available in Kubernetes Client API via client.apps().daemonSets()
. Here are some examples of its common usage:
- Load
DaemonSet
from yaml:
DaemonSet ds = client.apps().daemonSets().load(new FileInputStream("daemonset.yaml")).get();
- Get
DaemonSet
from Kubernetes API server:
DaemonSet ds = client.apps().daemonSets().inNamespace("default").withName("ds1").get();
- Create
DaemonSet
:
DaemonSet ds = new DaemonSetBuilder()
.withNewMetadata().withName("fluentd-elasticsearch").addToLabels("k8s-app", "fluentd-logging").endMetadata()
.withNewSpec()
.withNewSelector()
.addToMatchLabels("name", "fluentd-elasticsearch")
.endSelector()
.withNewTemplate()
.withNewSpec()
.addNewToleration().withKey("node-role.kubernetes.io/master").withEffect("NoSchedule").endToleration()
.addNewContainer()
.withName("fluentd-elasticsearch").withImage("quay.io/fluentd_elasticsearch/fluentd:v2.5.2")
.withNewResources()
.addToLimits(Collections.singletonMap("memory", new Quantity("200Mi")))
.addToRequests(Collections.singletonMap("cpu", new Quantity("100m")))
.endResources()
.addNewVolumeMount().withName("varlog").withMountPath("/var/log").endVolumeMount()
.endContainer()
.withTerminationGracePeriodSeconds(30l)
.addNewVolume()
.withName("varlog").withNewHostPath().withPath("/var/log").endHostPath()
.endVolume()
.endSpec()
.endTemplate()
.endSpec()
.build();
ds = client.apps().daemonSets().inNamespace("default").create(ds);
- Create or Replace existing
DaemonSet
:
DaemonSet ds = client.apps().daemonSets().inNamespace("default").createOrReplace(ds);
- List
DaemonSet
in some namespace:
DaemonSetList dsList = client.apps().daemonSets().inNamespace("default").list();
- List
DaemonSet
in any namespace:
DaemonSetList dsList = client.apps().daemonSets().inAnyNamespace().list();
- List
DaemonSet
with some label:
DaemonSetList dsList = client.apps().daemonSets().inNamespace("default").withLabel("foo", "bar").list();
- Delete
DaemonSet
:
Boolean isDeleted = client.apps().daemonSets().inNamespace("default").withName("ds1").delete();
- Watch
DaemonSet
:
client.apps().daemonSets().inNamespace("default").watch(new Watcher<DaemonSet>() {
@Override
public void eventReceived(Action action, DaemonSet resource) {
// Do something depending upon action type
}
@Override
public void onClose(KubernetesClientException cause) {
}
});
PersistentVolumeClaim
PersistentVolumeClaim
is available in Kubernetes Client API via client.persistentVolumeClaims()
. Here are some examples of it's common usage:
- Load a
PersistentVolumeClaim
from yaml:
PersistentVolumeClaim pvc = client.persistentVolumeClaims().load(new FileInputStream("pvc.yaml")).get();
- Get a
PersistentVolumeClaim
object from Kubernetes API server:
PersistentVolumeClaim pvc = client.persistentVolumeClaims().inNamespace("default").withName("test-pv-claim").get();
- Create
PersistentVolumeClaim
:
PersistentVolumeClaim persistentVolumeClaim = new PersistentVolumeClaimBuilder()
.withNewMetadata().withName("test-pv-claim").endMetadata()
.withNewSpec()
.withStorageClassName("my-local-storage")
.withAccessModes("ReadWriteOnce")
.withNewResources()
.addToRequests("storage", new Quantity("500Gi"))
.endResources()
.endSpec()
.build();
client.persistentVolumeClaims().inNamespace("default").create(persistentVolumeClaim);
- Create or Replace an existing
PersistentVolumeClaim
:
PersistentVolumeClaim pvc = client.persistentVolumeClaims().inNamespace("default").createOrReplace(pvcToCreate);
- Create or Replace an existing
PersistentVolumeClaim
with builders:
PersistentVolumeClaim pvc = client.persistentVolumeClaims().inNamespace("default").createOrReplaceWithNew()
.withNewMetadata().withName("test-pv-claim").endMetadata()
.withNewSpec()
.withStorageClassName("my-local-storage")
.withAccessModes("ReadWriteOnce")
.withNewResources()
.addToRequests("storage", new Quantity("500Gi"))
.endResources()
.endSpec()
.done();
- List
PersistentVolumeClaim
objects in a particular namespace:
PersistentVolumeClaimList pvcList = client.persistentVolumeClaims().inNamespace("default").list();
- List
PersistentVolumeClaim
objects in any namespace:
PersistentVolumeClaimList pvcList = client.persistentVolumeClaims().inAnyNamespace().list();
- List
PersistentVolumeClaim
objects in some namespace with some labels:
PersistentVolumeClaimList pvcList = client.persistentVolumeClaims().inNamespace("default").withLabel("foo", "bar").list();
- Delete
PersistentVolumeClaim
:
Boolean isDeleted = client.persistentVolumeClaims().inNamespace("default").withName("test-pv-claim").delete();
PersistentVolume
PersistentVolume
resource is available in Kubernetes Client API via client.persistentVolumes()
. Here are some of the examples of it's common usage:
- Load a
PersistentVolume
from yaml:
PersistentVolume pv = client.persistentVolumes().load(new FileInputStream("pv.yaml")).get();
- Get a
PersistentVolume
from Kubernetes API server:
PersistentVolume pv = client.persistentVolumes().withName("test-local-pv").get();
- Create
PersistentVolume
:
PersistentVolume pv = new PersistentVolumeBuilder()
.withNewMetadata().withName("test-local-pv").endMetadata()
.withNewSpec()
.addToCapacity(Collections.singletonMap("storage", new Quantity("500Gi")))
.withAccessModes("ReadWriteOnce")
.withPersistentVolumeReclaimPolicy("Retain")
.withStorageClassName("my-local-storage")
.withNewLocal()
.withPath("/mnt/disks/vol1")
.endLocal()
.withNewNodeAffinity()
.withNewRequired()
.addNewNodeSelectorTerm()
.withMatchExpressions(Arrays.asList(new NodeSelectorRequirementBuilder()
.withKey("kubernetes.io/hostname")
.withOperator("In")
.withValues("my-node")
.build()
))
.endNodeSelectorTerm()
.endRequired()
.endNodeAffinity()
.endSpec()
.build();
PersistentVolume pvCreated = client.persistentVolumes().create(pv)
- Create or Replace
PersistentVolume
:
PersistentVolume pv = client.persistentVolumes().createOrReplace(pvToCreate);
- List
PersistentVolume
:
PersistentVolumeList pvList = client.persistentVolumes().list();
- List
PersistentVolume
with some labels:
PersistentVolumeList pvList = client.persistentVolumes().withLabel("foo", "bar").list();
- Delete
PersistentVolume
:
Boolean isDeleted = client.persistentVolumes().withName("test-local-pv").delete();
NetworkPolicy
NetworkPolicy
is available in Kubernetes Client API via client.network().networkPolicies()
. Here are some examples of it's common usages:
- Load a
NetworkPolicy
from yaml:
NetworkPolicy loadedNetworkPolicy = client.network().networkPolicies()
.load(new FileInputStream("/test-networkpolicy.yml")).get();
- Get
NetworkPolicy
from Kubernetes API server:
NetworkPolicy getNetworkPolicy = client.network().networkPolicies()
.withName("networkpolicy").get();
- Create
NetworkPolicy
:
NetworkPolicy networkPolicy = new NetworkPolicyBuilder()
.withNewMetadata()
.withName("networkpolicy")
.addToLabels("foo","bar")
.endMetadata()
.withNewSpec()
.withNewPodSelector()
.addToMatchLabels("role","db")
.endPodSelector()
.addToIngress(0,
new NetworkPolicyIngressRuleBuilder()
.addToFrom(0, new NetworkPolicyPeerBuilder().withNewPodSelector()
.addToMatchLabels("role","frontend").endPodSelector()
.build()
).addToFrom(1, new NetworkPolicyPeerBuilder().withNewNamespaceSelector()
.addToMatchLabels("project","myproject").endNamespaceSelector()
.build()
)
.addToPorts(0,new NetworkPolicyPortBuilder().withPort(new IntOrString(6379))
.withProtocol("TCP").build())
.build()
)
.endSpec()
.build();
NetworkPolicy npCreated = client.network().networkPolicies().create(networkPolicy);
- Create or Replace some existing
NetworkPolicy
:
NetworkPolicy npCreated = client.network().networkPolicies().createOrReplace(networkPolicy);
- List
NetworkPolicy
:
NetworkPolicyList networkPolicyList = client.network().networkPolicies().list();
- List with labels
NetworkPolicy
:
NetworkPolicyList networkPolicyList = client.network().networkPolicies()
.withLabels(Collections.singletonMap("foo","bar")).list();
- Delete
NetworkPolicy
:
Boolean deleted = client.network().networkPolicies().withName("np-test").delete();
PodDisruptionBudget
PodDisruptionBudget
is available in Kubernetes Client API via client.policy().podDisruptionBudget()
. Here are some of the examples of its usage:
- Load
PodDisruptionBudget
from yaml:
PodDisruptionBudget pdb = client.policy().podDisruptionBudget().load(new FileInputStream("/test-pdb.yml")).get();
- Get
PodDisruptionBudget
from Kubernetes API server:
PodDisruptionBudget podDisruptionBudget = client.policy().podDisruptionBudget().inNamespace("default").withName("poddisruptionbudget1").get();
- Create
PodDisruptionBudget
:
PodDisruptionBudget podDisruptionBudget = new PodDisruptionBudgetBuilder()
.withNewMetadata().withName("zk-pkb").endMetadata()
.withNewSpec()
.withMaxUnavailable(new IntOrString("1%"))
.withNewSelector()
.withMatchLabels(Collections.singletonMap("app", "zookeeper"))
.endSelector()
.endSpec()
.build();
client.policy().podDisruptionBudget().inNamespace("default").create(podDisruptionBudget);
- Create or Replace
PodDisruptionBudget
:
PodDisruptionBudget pdb = client.policy().podDisruptionBudget().inNamespace("default").createOrReplace(podDisruptionBudgetObj);
- List
PodDisruptionBudget
in some namespace:
PodDisruptionBudgetList podDisruptionBudgetList = client.policy().podDisruptionBudget().inNamespace("default").list();
- List
PodDisruptionBudget
in any namespace:
PodDisruptionBudgetList pdbList = client.policy().podDisruptionBudget().inAnyNamespace().list();
- List
PodDisruptionBudget
with labels:
PodDisruptionBudgetList pdbList = client.policy().podDisruptionBudget().inNamespace("default").withLabel("foo", "bar").list();
- Delete
PodDisruptionBudget
:
Boolean deleted = client.policy().podDisruptionBudget().inNamespace("default").withName("poddisruptionbudget1").delete();
SelfSubjectAccessReview
- Create
SelfSubjectAccessReview
(equivalent ofkubectl auth can-i create deployments --namespace dev
):
try (KubernetesClient client = new DefaultKubernetesClient()) {
SelfSubjectAccessReview ssar = new SelfSubjectAccessReviewBuilder()
.withNewSpec()
.withNewResourceAttributes()
.withGroup("apps")
.withResource("deployments")
.withVerb("create")
.withNamespace("dev")
.endResourceAttributes()
.endSpec()
.build();
ssar = client.authorization().v1().selfSubjectAccessReview().create(ssar);
System.out.println("Allowed: "+ ssar.getStatus().getAllowed());
}
SubjectAccessReview
- Create
SubjectAccessReview
:
try (KubernetesClient client = new DefaultKubernetesClient()) {
SubjectAccessReview sar = new SubjectAccessReviewBuilder()
.withNewSpec()
.withNewResourceAttributes()
.withGroup("apps")
.withResource("deployments")
.withVerb("create")
.withNamespace("default")
.endResourceAttributes()
.withUser("kubeadmin")
.endSpec()
.build();
sar = client.authorization().v1().subjectAccessReview().create(sar);
System.out.println("Allowed: "+ sar.getStatus().getAllowed());
}
LocalSubjectAccessReview
- Create
LocalSubjectAccessReview
:
try (KubernetesClient client = new DefaultKubernetesClient()) {
LocalSubjectAccessReview lsar = new LocalSubjectAccessReviewBuilder()
.withNewMetadata().withNamespace("default").endMetadata()
.withNewSpec()
.withUser("foo")
.withNewResourceAttributes()
.withNamespace("default")
.withVerb("get")
.withGroup("apps")
.withResource("pods")
.endResourceAttributes()
.endSpec()
.build();
lsar = client.authorization().v1().localSubjectAccessReview().inNamespace("default").create(lsar);
System.out.println(lsar.getStatus().getAllowed());
}
SelfSubjectRulesReview
- Create
SelfSubjectRulesReview
:
try (KubernetesClient client = new DefaultKubernetesClient()) {
SelfSubjectRulesReview selfSubjectRulesReview = new SelfSubjectRulesReviewBuilder()
.withNewMetadata().withName("foo").endMetadata()
.withNewSpec()
.withNamespace("default")
.endSpec()
.build();
selfSubjectRulesReview = client.authorization().v1().selfSubjectRulesReview().create(selfSubjectRulesReview);
System.out.println(selfSubjectRulesReview.getStatus().getIncomplete());
System.out.println("non resource rules: " + selfSubjectRulesReview.getStatus().getNonResourceRules().size());
System.out.println("resource rules: " + selfSubjectRulesReview.getStatus().getResourceRules().size());
}
参考文档
Fabric8 Kubernetes Java Client Cheat Sheet
推荐阅读
-
使用管家的操作(II)
-
文件操作和 IO - II.文件系统操作
-
epoll简介及触发模式(accept、read、send)-epoll的简单介绍 epoll在LT和ET模式下的读写方式 一、epoll的接口非常简单,一共就三个函数:1. int epoll_create(int size);创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大。这个参数不同于select中的第一个参数,给出最大监听的fd+1的值。需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值,在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close关闭,否则可能导致fd被耗尽。2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);epoll的事件注册函数,它不同与select是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。第一个参数是epoll_create的返回值,第二个参数表示动作,用三个宏来表示:EPOLL_CTL_ADD:注册新的fd到epfd中;EPOLL_CTL_MOD:修改已经注册的fd的监听事件;EPOLL_CTL_DEL:从epfd中删除一个fd;第三个参数是需要监听的fd,第四个参数是告诉内核需要监听什么事,struct epoll_event结构如下:struct epoll_event { __uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */};events可以是以下几个宏的集合:EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭); EPOLLIN事件:EPOLLIN事件则只有当对端有数据写入时才会触发,所以触发一次后需要不断读取所有数据直到读完EAGAIN为止。否则剩下的数据只有在下次对端有写入时才能一起取出来了。现在明白为什么说epoll必须要求异步socket了吧?如果同步socket,而且要求读完所有数据,那么最终就会在堵死在阻塞里。 EPOLLOUT:表示对应的文件描述符可以写; EPOLLOUT事件:EPOLLOUT事件只有在连接时触发一次,表示可写,其他时候想要触发,那要先准备好下面条件:1.某次write,写满了发送缓冲区,返回错误码为EAGAIN。2.对端读取了一些数据,又重新可写了,此时会触发EPOLLOUT。简单地说:EPOLLOUT事件只有在不可写到可写的转变时刻,才会触发一次,所以叫边缘触发,这叫法没错的!其实,如果真的想强制触发一次,也是有办法的,直接调用epoll_ctl重新设置一下event就可以了,event跟原来的设置一模一样都行(但必须包含EPOLLOUT),关键是重新设置,就会马上触发一次EPOLLOUT事件。1. 缓冲区由满变空.2.同时注册EPOLLIN | EPOLLOUT事件,也会触发一次EPOLLOUT事件这个两个也会触发EPOLLOUT事件 EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);EPOLLERR:表示对应的文件描述符发生错误;EPOLLHUP:表示对应的文件描述符被挂断;EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);等待事件的产生,类似于select调用。参数events用来从内核得到事件的集合,maxevents告之内核这个events有多大,这个maxevents的值不能大于创建epoll_create时的size,参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。该函数返回需要处理的事件数目,如返回0表示已超时。-------------------------------------------------------------------------------------------- 从man手册中,得到ET和LT的具体描述如下EPOLL事件有两种模型:Edge Triggered (ET)Level Triggered (LT)假如有这样一个例子:1. 我们已经把一个用来从管道中读取数据的文件句柄(RFD)添加到epoll描述符2. 这个时候从管道的另一端被写入了2KB的数据3. 调用epoll_wait(2),并且它会返回RFD,说明它已经准备好读取操作4. 然后我们读取了1KB的数据5. 调用epoll_wait(2)......Edge Triggered 工作模式:如果我们在第1步将RFD添加到epoll描述符的时候使用了EPOLLET标志,那么在第5步调用epoll_wait(2)之后将有可能会挂起,因为剩余的数据还存在于文件的输入缓冲区内,而且数据发出端还在等待一个针对已经发出数据的反馈信息。只有在监视的文件句柄上发生了某个事件的时候 ET 工作模式才会汇报事件。因此在第5步的时候,调用者可能会放弃等待仍在存在于文件输入缓冲区内的剩余数据。在上面的例子中,会有一个事件产生在RFD句柄上,因为在第2步执行了一个写操作,然后,事件将会在第3步被销毁。因为第4步的读取操作没有读空文件输入缓冲区内的数据,因此我们在第5步调用 epoll_wait(2)完成后,是否挂起是不确定的。epoll工作在ET模式的时候,必须使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。最好以下面的方式调用ET模式的epoll接口,在后面会介绍避免可能的缺陷。 i 基于非阻塞文件句柄 ii 只有当read(2)或者write(2)返回EAGAIN时才需要挂起,等待。但这并不是说每次read时都需要循环读,直到读到产生一个EAGAIN才认为此次事件处理完成,当read返回的读到的数据长度小于请求的数据长度时,就可以确定此时缓冲中已没有数据了,也就可以认为此事读事件已处理完成。Level Triggered 工作模式相反的,以LT方式调用epoll接口的时候,它就相当于一个速度比较快的poll(2),并且无论后面的数据是否被使用,因此他们具有同样的职能。因为即使使用ET模式的epoll,在收到多个chunk的数据的时候仍然会产生多个事件。调用者可以设定EPOLLONESHOT标志,在 epoll_wait(2)收到事件后epoll会与事件关联的文件句柄从epoll描述符中禁止掉。因此当EPOLLONESHOT设定后,使用带有 EPOLL_CTL_MOD标志的epoll_ctl(2)处理文件句柄就成为调用者必须作的事情。然后详细解释ET, LT:LT(level triggered)是缺省的工作方式,并且同时支持block和no-block socket.在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型的代表.ET(edge-triggered)是高速工作方式,只支持no-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了(比如,你在发送,接收或者接收请求,或者发送接收的数据少于一定量时导致了一个EWOULDBLOCK 错误)。但是请注意,如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once),不过在TCP协议中,ET模式的加速效用仍需要更多的benchmark确认(这句话不理解)。在许多测试中我们会看到如果没有大量的idle -connection或者dead-connection,epoll的效率并不会比select/poll高很多,但是当我们遇到大量的idle- connection(例如WAN环境中存在大量的慢速连接),就会发现epoll的效率大大高于select/poll。(未测试)另外,当使用epoll的ET模型来工作时,当产生了一个EPOLLIN事件后,读数据的时候需要考虑的是当recv返回的大小如果等于请求的大小,那么很有可能是缓冲区还有数据未读完,也意味着该次事件还没有处理完,所以还需要再次读取: 这里只是说明思路(参考《UNIX网络编程》) while(rs) {buflen = recv(activeevents[i].data.fd, buf, sizeof(buf), 0);if(buflen < 0){// 由于是非阻塞的模式,所以当errno为EAGAIN时,表示当前缓冲区已无数据可读// 在这里就当作是该次事件已处理处.if(errno == EAGAIN)break; else return; }else if(buflen == 0) { // 这里表示对端的socket已正常关闭. } if(buflen == sizeof(buf) rs = 1; // 需要再次读取 else rs = 0; } 还有,假如发送端流量大于接收端的流量(意思是epoll所在的程序读比转发的socket要快),由于是非阻塞的socket,那么send函数虽然返回,但实际缓冲区的数据并未真正发给接收端,这样不断的读和发,当缓冲区满后会产生EAGAIN错误(参考man send),同时,不理会这次请求发送的数据.所以,需要封装socket_send的函数用来处理这种情况,该函数会尽量将数据写完再返回,返回-1表示出错。在socket_send内部,当写缓冲已满(send返回-1,且errno为EAGAIN),那么会等待后再重试.这种方式并不很完美,在理论上可能会长时间的阻塞在socket_send内部,但暂没有更好的办法. ssize_t socket_send(int sockfd, const char* buffer, size_t buflen) { ssize_t tmp; size_t total = buflen; const char *p = buffer; while(1) { tmp = send(sockfd, p, total, 0); if(tmp < 0) { // 当send收到信号时,可以继续写,但这里返回-1. if(errno == EINTR) return -1; // 当socket是非阻塞时,如返回此错误,表示写缓冲队列已满, // 在这里做延时后再重试. if(errno == EAGAIN) { usleep(1000); continue; } return -1; } if((size_t)tmp == total) return buflen; total -= tmp; p += tmp; } return tmp; } 二、epoll在LT和ET模式下的读写方式 在一个非阻塞的socket上调用read/write函数, 返回EAGAIN或者EWOULDBLOCK(注: EAGAIN就是EWOULDBLOCK) 从字面上看, 意思是: * EAGAIN: 再试一次 * EWOULDBLOCK: 如果这是一个阻塞socket, 操作将被block * perror输出: Resource temporarily unavailable 总结: 这个错误表示资源暂时不够, 可能read时, 读缓冲区没有数据, 或者, write时,写缓冲区满了 。 遇到这种情况, 如果是阻塞socket, read/write就要阻塞掉。 而如果是非阻塞socket, read/write立即返回-1, 同 时errno设置为EAGAIN. 所以, 对于阻塞socket, read/write返回-1代表网络出错了. 但对于非阻塞socket, read/write返回-1不一定网络真的出错了. 可能是Resource temporarily unavailable. 这时你应该再试, 直到Resource available. 综上, 对于non-blocking的socket, 正确的读写操作为: 读: 忽略掉errno = EAGAIN的错误, 下次继续读 写: 忽略掉errno = EAGAIN的错误, 下次继续写 对于select和epoll的LT模式, 这种读写方式是没有问题的. 但对于epoll的ET模式, 这种方式还有漏洞. epoll的两种模式 LT 和 ET
-
Istio II 入门 - Istio 实践操作
-
Lua5.4 源代码分析:II.字符串数据结构和操作算法
-
OpenCV | 基本图形绘制操作 - II.绘制文本
-
[操作系统] 存储模型 (II):虚拟存储技术和替换算法
-
操作系统(II) - 操作系统内存管理(下)
-
云计算时代的操作系统 Kubernetes 的容器技术支柱
-
Kubernetes_21_查询所有命名空间下的所有资源(kubectl 查询操作)