Cloud Native 7 min read

Using the Kubernetes Java Client: CSR, SharedInformers, ListOptions, DeleteOptions, WatchOptions, LogOptions and Resource Operations

This article explains how to use the Kubernetes Java client to create, approve, and deny CertificateSigningRequests, work with SharedInformers, list and delete resources with ListOptions and DeleteOptions, watch resources, retrieve logs, serialize objects to YAML, and run Pods, providing practical code examples and best‑practice recommendations.

FunTester
FunTester
FunTester
Using the Kubernetes Java Client: CSR, SharedInformers, ListOptions, DeleteOptions, WatchOptions, LogOptions and Resource Operations

CertificateSigningRequest (CSR) is an object in Kubernetes used to request a certificate from the cluster's Certificate Authority (CA), typically for nodes or users.

The Kubernetes Java client provides support for CertificateSigningRequest , allowing you to create, approve, or deny CSRs.

Creating a CertificateSigningRequest:

try (KubernetesClient client = new KubernetesClientBuilder().build()) {
    CertificateSigningRequest csr = new CertificateSigningRequestBuilder()
            .withNewMetadata().withName("test-k8s-csr").endMetadata()
            .withNewSpec()
            .addNewGroup("system:authenticated")
            .withRequest("LS VE9PQotL BSRVFVRVNULS0tLS0K")
            .addNewUsage("FunTesterclient auth")
            .endSpec()
            .build();

    client.certificates().v1().certificateSigningRequests().resource(csr).create();
}

Approving a CertificateSigningRequest:

CertificateSigningRequestCondition csrCondition = new CertificateSigningRequestConditionBuilder()
        .withType("Approved")
        .withStatus("True")
        .withReason("Approved ViaRESTApi")
        .withMessage("Approved by REST API /approval endpoint.")
        .build();
client.certificates().v1().certificateSigningRequests().withName("test-k8s-csr").approve(csrCondition);

Denying a CertificateSigningRequest:

CertificateSigningRequestCondition csrCondition = new CertificateSigningRequestConditionBuilder()
        .withType("Denied")
        .withStatus("True")
        .withReason("Denied ViaRESTApi")
        .withMessage("Denied by REST API /approval endpoint.")
        .build();
client.certificates().v1().certificateSigningRequests().withName("test-k8s-csr").deny(csrCondition);

SharedInformers are a mechanism in the client‑go library for efficiently watching and caching resource changes, reducing pressure on the API server and improving performance.

The Kubernetes client offers SharedInformer support for resource watching.

Getting a SharedInformerFactory:

SharedInformerFactory sharedInformerFactory = client.informers();

Creating a SharedIndexInformer for Pods:

SharedIndexInformer
podInformer = sharedInformerFactory.sharedIndexInformerFor(Pod.class, 30 * 1000L);
podInformer.addEventHandler(new ResourceEventHandler
() {
    @Override
    public void onAdd(Pod pod) {
        logger.info("{} pod added", pod.getMetadata().getName());
    }

    @Override
    public void onUpdate(Pod oldPod, Pod newPod) {
        logger.info("{} pod updated", oldPod.getMetadata().getName());
    }

    @Override
    public void onDelete(Pod pod, boolean deletedFinalStateUnknown) {
        logger.info("{} pod deleted", pod.getMetadata().getName());
    }
});

Starting and Stopping All Registered Informers:

sharedInformerFactory.startAllRegisteredInformers();
sharedInformerFactory.stopAllRegisteredInformers();

Creating a Namespace‑Scoped SharedIndexInformer:

SharedIndexInformer
podInformer = client.pods().inNamespace("default").inform(new ResourceEventHandler<>() {
    @Override
    public void onAdd(Pod pod) {
        logger.info("Pod " + pod.getMetadata().getName() + " got added");
    }
    @Override
    public void onUpdate(Pod oldPod, Pod newPod) {
        logger.info("Pod " + oldPod.getMetadata().getName() + " got updated");
    }
    @Override
    public void onDelete(Pod pod, boolean deletedFinalStateUnknown) {
        logger.info("Pod " + pod.getMetadata().getName() + " got deleted");
    }
}, 30 * 1000L);

Listing Resources with ListOptions (pagination, label selector, etc.):

PodList podList = client.pods().inNamespace("FunTester").list(new ListOptionsBuilder().withLimit(5L).build());
// Continue pagination
podList = client.pods().inNamespace("FunTester").list(new ListOptionsBuilder()
        .withLimit(5L)
        .withContinue(podList.getMetadata().getContinue())
        .build());

// List by label
PodList podList = client.pods().inNamespace("FunTester").withLabel("foo", "bar").list();

Deleting Resources with DeleteOptions:

// Delete with cascading
client.apps().deployments().inNamespace("default").withName("nginx-deploy").cascading(true).delete();

// Delete with grace period and propagation policy
client.apps().deployments().inNamespace("FunTester").withName("mydeployment")
        .withPropagationPolicy(DeletionPropagation.FOREGROUND)
        .withGracePeriod(10)
        .delete();

Watching Resources with ListOptions:

client.pods().watch(new ListOptionsBuilder().withTimeoutSeconds(30L).build(), new Watcher<>() {
    @Override
    public void eventReceived(Action action, Pod resource) { }
    @Override
    public void onClose(WatcherException cause) { }
});

Retrieving Pod Logs (container selection, tail lines):

// Get full log of a specific container
String log = client.pods().inNamespace("FunTester").withName("foo").inContainer("container1").getLog();

// Get last 10 lines of the log
String tailLog = client.pods().inNamespace("FunTester").withName("foo").tailingLines(10).getLog();

Serializing Resources to YAML:

Pod myPod;
String myPodAsYaml = Serialization.asYaml(myPod);

Running a Pod by Providing Image and Name:

try (KubernetesClient client = new KubernetesClientBuilder().build()) {
    client.run().inNamespace("default")
            .withName("FunTester")
            .withImage("FunTester/FunTester:3.12.9")
            .done();
}

Server‑Side Apply for Custom Resources (e.g., DeploymentConfig):

// Create or update
DeploymentConfig dc = client.deploymentConfigs().inNamespace("FunTester").resource(dcToCreate).serverSideApply();

// Force update, ignoring conflicts
DeploymentConfig dc = client.deploymentConfigs().inNamespace("FunTester").resource(dcToCreate).forceConflicts().serverSideApply();

By using these APIs and following the best‑practice recommendations—such as proper resource cleanup with try‑with‑resources, robust error handling, pagination for large lists, preferring SharedInformer over direct Watch, configuring appropriate RBAC, and externalizing configuration—developers can build efficient, reliable Kubernetes management applications that meet enterprise‑grade requirements.

JavaoperationsKubernetesClientCSRSharedInformer
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.