#Kubectl Equivalence in Java
TL;DR: Used to kubectl? Now our Kubernetes Java client library has released a set of helpful client utilities which has a similar input argument interface as the kubectl binary. Especially the developers who're already familiar with kubectl commands, after reading this document, you will know how to build programs that interact with Kubernetes as easily as kubectl.
The Java Kubectl is not only a more user-friendly wrapper for our direct HTTP Kubernetes client,
but also contains the implementation of commonly-used kubectl advanced commands. All these kubectl
equivalences are accessible as a group of static helper functions under io.kubernetes.client.extended.kubectl.Kubectl
class. You can import them by adding the following dependency to your project:
<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java-extended</artifactId>
<version>${latest project version}</version>
</dependency>Now you're all set, invoke the kubectl commands as Java static functions wherever you like in your project.
Kubectl static helpers don't know its client-config (or kubeconfig if the name makes more sense to you) unless you set it when your application starts. You can either specify the client-config upon invoking kubectl helpers or simply set a global config at the start of your application:
Configuration.setDefaultApiClient(ClientBuilder.defaultClient());This will create a client on either a client, or a container in Kubernetes.
You can either query a single resource or list multiple resources using the Kubectl#get helper depending
on whether you're passing name() in the flow. Here are few illustrative examples for querying pod
resources:
// kubectl get -n default pod foo
V1Pod pod = Kubectl.get(V1Pod.class)
.namespace("default")
.name("foo")
.execute();
// kubectl get -n default pod
List<V1Pod> pods = Kubectl.get(V1Pod.class)
.namespace("default")
.execute();
// kubectl get pod --all-namespaces
List<V1Pod> pods = Kubectl.get(V1Pod.class)
.execute();Currently the Kubectl#create helper only accepts a desired instance of resource object, you need to do the
deserialization of a resource object or manually craft an instance of the resource.
// kubectl create -f <file>
V1Pod creatingPod = /* load it from file or else */;
V1Pod createdPod = Kubectl.create(V1Pod.class)
.resource(creatingPod)
.execute();Kubectl#delete works the same as kubectl delete command.
// kubectl delete -n default pod foo
V1Pod deletedPod = Kubectl.delete(V1Pod.class)
.namespace("default")
.name("foo")
.execute();Kubectl#patch works the same as kubectl patch command.
// kubectl patch --type='strategic' --patch="{\"metadata\":{\"labels\":{\"foo\":\"bar\"}}"
V1Pod patchedPod = Kubectl.patch(V1Pod.class)
.patchType(V1Patch.PATCH_FORMAT_STRATEGIC_MERGE_PATCH)
.patchContent(new V1Patch("{\"metadata\":{\"labels\":{\"foo\":\"bar\"}}"))
.execute();Note that for now only server-side apply is supported, so your apiserver version is required to
be greater than or equal to 1.18.0. Kubectl#apply works the same as kubectl apply --server-side=true.
// kubectl apply --server-side=true --field-manager=java-kubectl --force-conflict=true -f <file>
V1Pod applyingPod = /* load it from file or else */;
V1Pod appliedPod = Kubectl.apply(V1Pod.class)
.fieldManager("java-kubectl")
.forceConflict(true)
.resource(applyingPod)
.execute();// kubectl scale -n default rs foo --replicas=2
V1ReplicaSet scaledRs = Kubectl.scale(V1ReplicaSet.class)
.namespace("default")
.name("foo")
.replicas(2)
.execute();// kubectl drain node1
V1Node drainedNode = Kubectl.drain()
.name("node1")
.execute();// kubectl cordon node1
V1Node cordondNode = Kubectl.cordon()
.name("node1")
.execute();
// kubectl uncordon node1
V1Node uncordondNode = Kubectl.uncordon()
.name("node1")
.execute();// kubectl taint nodes foo dedicated:NoSchedule
V1Node taintedNode = Kubectl.taint()
.addTaint("dedicated", "NoSchedule")
.execute()
// kubectl taint nodes foo dedicated=special-user:NoSchedule
V1Node taintedNode = Kubectl.taint()
.addTaint("dedicated", "special-user", "NoSchedule")
.execute()
// kubectl taint nodes foo dedicated:NoSchedule-
V1Node taintedNode = Kubectl.taint()
.removeTaint("dedicated", "NoSchedule")
.execute()// kubectl label -n default pod foo key1=value1 key2=value2
V1Pod labelledPod = Kubectl.label(V1Pod)
.addLabel("key1", "value1")
.addLabel("key2", "value2")
.namespace("default")
.name("foo")
.execute();
// kubectl annotate -n default pod foo key1=value1 key2=value2
V1Pod annotatedPod = Kubectl.annotate(V1Pod)
.addLabel("key1", "value1")
.addLabel("key2", "value2")
.namespace("default")
.name("foo")
.execute();// kubectl api-resources
Set<Discovery.APIResource> apiResourceSet = Kubectl.apiResources()
.execute()// kubectl exec -n default foo -c test-container echo test
int retCode = Kubectl.exec()
.namespace("default")
.name("foo")
.container("test-container")
.command(new String[]{"echo","test"})
.execute();// kubectl logs -n default foo -c test-container
InputStream logStream = Kubectl.log()
.namespace("default")
.name("foo")
.container("test-container")
.execute();// kubectl top node
List<Pair<V1Node, NodeMetrics>> metrics = Kubectl.top(V1Node.class, NodeMetrics.class)
.metric("cpu")
.execute();Kubernetes allows you to extend new kubernetes API types by either CustomResourceDefinition
or APIServerAggregation,
and api-discovery is basically a process of discovering new kubernetes resources types from the client-side.
The java client is managing all the api-discovery information at io.kubernetes.client.util.ModelMapper.
In order to make the java client know the connection between new kubernetes api and custom Java models, you're
supposed to manually set up the mappings for them by:
ModelMapper.addModelMap(
"example.io", // api-group
"v1", // api-version
"Foo", // kind name -- camel-case'd singular resource name.
"foos", // resource name -- lowercase plural resource name
true, // is namespace-scoped
Foo.class); // java model class