X Tutup
Skip to content

Latest commit

 

History

History
248 lines (194 loc) · 7.69 KB

File metadata and controls

248 lines (194 loc) · 7.69 KB

#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.

What is Java 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.

(Optional) Setting a Global Client-Config

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.

Manifest of Supported Commands

Kubectl get

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();

Kubectl create

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

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

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();

Kubectl apply

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

// kubectl scale -n default rs foo --replicas=2
V1ReplicaSet scaledRs = Kubectl.scale(V1ReplicaSet.class)
                .namespace("default")
                .name("foo")
                .replicas(2)
                .execute();

Kubectl drain

// kubectl drain node1
V1Node drainedNode = Kubectl.drain()
                .name("node1")
                .execute();

Kubectl cordon/uncordon

// kubectl cordon node1
V1Node cordondNode = Kubectl.cordon()
                .name("node1")
                .execute();
// kubectl uncordon node1
V1Node uncordondNode = Kubectl.uncordon()
                .name("node1")
                .execute();

Kubectl taint

// 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/annotate

// 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

// kubectl api-resources
Set<Discovery.APIResource> apiResourceSet = Kubectl.apiResources()
                .execute()

Kubectl exec

// 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

// kubectl logs -n default foo -c test-container
InputStream logStream = Kubectl.log()
                .namespace("default")
                .name("foo")
                .container("test-container")
                .execute();

Kubectl top

// kubectl top node
List<Pair<V1Node, NodeMetrics>> metrics = Kubectl.top(V1Node.class, NodeMetrics.class)
                .metric("cpu")
                .execute();

Advanced Tips

API Discovery for custom models

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
X Tutup