Kubernetes Container Orchestration through Java APIs

10 minute read

Overview

In this article we will look at how to drive Kubernetes using Java APIs. More general information about Kubernetes and containers can be found here. Kubernetes itself offers a RESTful API but of course most prefer to use a client that is already handling low-level HTTP protocol operations.

Kubernetes_API_Architecture It turns out Fabric8 is providing an integration and management platform above kubernetes and docker. In addition to integrating container orchestration through Kubernetes, Fabric8 also integrates with OpenShift v3 and Jube. OpenShift v3 exposes Kubernetes extensions such as app templates and builds. These Kubernetes extensions allow the container to be bundled with the application code and thus greatly increase application deployment cycles. Jube is a pure Java implementation of Kubernetes to provide containers to non-Linux world. In this article we will just focus on Kubernetes using the Fabric8 Java API.

Setup

The easiest way to get access to the Fabric8 Kubernetes Java API is through maven. Both Kubernetes and Fabric8 are changing fast so make sure you update and stay current with versions. The below dependency can be added to your pom.xml file.

[code language="xml"]

<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-api</artifactId>
<version>2.0.37</version>
</dependency>

[/code]

After updating the pom.xml you can run maven to add the new dependency to the local maven repository.

mvn clean compile

Connection

In order to communicate with Kubernetes through the Fabric8 Java API a connection must be established. The Kubernetes API support HTTPS through TLS certificates but in this example we are just using HTTP and no authentication. The ConnectionExample class requires only IP and Port in order to return a kube connection object. By default unless specified the Kubernetes API will be read-only. In oder to get access to the read-write API the following environment parameters must be exported:

export KUBERNETES_SERVICE_HOST=192.168.2.14
export KUBERNETES_SERVICE_PORT=8080

[code language="java"]
package examples;

import io.fabric8.kubernetes.api.KubernetesClient;
import io.fabric8.kubernetes.api.KubernetesFactory;

public class ConnectionExample {
private String ip;
private String port;

public ConnectionExample(String ip, String port) {
this.ip= ip;
this.port = port;
}

public KubernetesClient getConnection() {
final String URI = "http://" + ip+ ":" + port;
final KubernetesClient kubernetes = new KubernetesClient(new KubernetesFactory(URI));

return kubernetes;
}
}

[/code]

Once we have a Kubernetes connection object we can manage pods, replication controllers and services. We can perform typical RESTFul operations such as get, post, update and delete.

Pods

A pod is the most granular unit of management in Kubernetes and contains one or more containers that share the same resources. The main operations that can be performed are listing, creating and deleting pods.

Listing Pods

[code language="java"]
public List<KubePodModel> getKubePods() {
List<KubePodModel> kubePodList = new ArrayList<KubePodModel>();

for (Pod pod : kubernetes.getPods().getItems()) {
KubePodModel model = new KubePodModel();

model.setId(pod.getId());
model.setApiVersion(pod.getApiVersion());
model.setCreationTime(pod.getCreationTimestamp());
model.setNamespace(pod.getNamespace());
model.setPodHostName(pod.getCurrentState().getHost());
model.setPodIp(pod.getCurrentState().getPodIP());
model.setStatus(pod.getCurrentState().getStatus());

kubePodList.add(podModel);

}

return kubePodModelList;
}
[/code]

Creating Pods

[code language="java"]

public void createKubePod(String id, String namespace, List<String> containerPorts, String image, Map<String, String> labels) {

Pod pod = new Pod();
pod.setId(id);

pod.setLabels(labels);
PodState desiredState = new PodState();
ContainerManifest manifest = new ContainerManifest();

Container manifestContainer = new Container();
manifestContainer.setName(podId);
manifestContainer.setImage(image);

List<Port> ports = new ArrayList<Port>();
for (String containerInputPort : containerPorts) {
CharSequence inputStr = containerInputPort;
String patternStr = "(\\S+):(\\S+)";
Pattern pattern = Pattern.compile(patternStr);
Matcher matcher = pattern.matcher(inputStr);
boolean matchFound = matcher.find();

if (matchFound) {
int contanierPort = Integer.valueOf(matcher.group(1));
String containerProto = matcher.group(2);

Port port = new Port();
port.setContainerPort(contanierPort);
port.setProtocol(containerProto);
ports.add(port);
}
}

manifestForContainer.setPorts(ports);

List<Container> containers = new ArrayList<>();
containers.add(manifestForContainer);
manifest.setContainers(containers);

desiredState.setManifest(manifest);
pod.setDesiredState(desiredState);

kubernetes.createPod(pod, namespace);
}

[/code]

Deleting Pods

[code language="java"]

public void deleteKubePod(String id, String namespace) {
kubernetes.deletePod(id, namespace);
}

[/code]

Replication Controllers

A replication controller is a pod that has N replicas. The replication controller ensures the number of pod replicas defined also exists. The replication controller will automatically manage pod deployments.The main operations that can be performed are listing, creating and deleting replication controllers.

Listing Replication Controllers

[code language="java"]

public List<ControllerModel> getKubeReplicationControllers() {
List<ControllerModel> controllerList = new ArrayList<ReplicationControllerModel>();
for (ReplicationController controller : kubernetes.getReplicationControllers().getItems()) {
ControllerModel model = new ControllerModel();

model.setId(controller.getId());
model.setApiVersion(controller.getApiVersion());
model.setCreationTime(controller.getCreationTimestamp());
model.setReplicas(controller.getCurrentState().getReplicas());

controllerList.add(model);
}

return controllerList;
}

[/code]

Creating Replication Controllers

[code language="java"]

public void createKubeReplicationController(String id, String namespace, int replicas, Map<String, String> controllerLabels,
Map<String, String> selectorLabels, String podId, String image, List<String> containerPorts, Map<String, String> podLabels, String manifestId) {
ReplicationController controller = new ReplicationController();
controller.setId(id);
controller.setNamespace(namespace);
controller.setLabels(controllerLabels);

PodState podState = new PodState();
ReplicationControllerState repState = new ReplicationControllerState();
repState.setReplicas(replicas);
repState.setReplicaSelector(selectorLabels);

PodTemplate podTmpl = new PodTemplate();
podTmpl.setLabels(podLabels);

ContainerManifest manifest = new ContainerManifest();
manifest.setId(manifestId);
Container manifestContainer = new Container();
manifestContainer.setName(podId);
manifestContainer.setImage(image);

List<Port> ports = new ArrayList<Port>();
for (String containerInputPort : containerPorts) {
CharSequence inputStr = containerInputPort;
String patternStr = "(\\S+):(\\S+)";
Pattern pattern = Pattern.compile(patternStr);
Matcher matcher = pattern.matcher(inputStr);
boolean matchFound = matcher.find();

if (matchFound) {
int contanierPort = Integer.valueOf(matcher.group(1));
String containerProtocol = matcher.group(2);

Port port = new Port();
port.setContainerPort(contanierPort);
port.setProtocol(containerProtocol);
ports.add(port);
}
}

manifestContainer.setPorts(ports);

List<Container> containers = new ArrayList<>();
containers.add(manifestContainer);
manifest.setContainers(containers);

podState.setManifest(manifest);
podTmpl.setDesiredState(podState);
repState.setPodTemplate(podTmpl);

controller.setDesiredState(repState);

kubernetes.createReplicationController(controller, namespace);

}

[/code]

Deleting Replication Controllers

[code language="java"]

public void deleteReplicationController(String id, String namespace) {
kubernetes.deleteReplicationController(id, namespace);
}

[/code]

Services

A service exposes an application running in a pod externally using the Kubernetes proxy. It essentially maps public IPs / Ports on Kubernetes Minions (nodes) to internal container IPs / Ports. The main operations that can be performed are listing, creating and deleting services.

Listing Services

[code language="java"]

public List<ServiceModel> getKubeServices() {
List<ServiceModel> serviceList = new ArrayList<ServiceModel>();
for (Service service : kubernetes.getServices().getItems()) {
ServiceModel model = new ServiceModel();

model.setId(service.getId());
model.setApiVersion(service.getApiVersion());
model.setCreationTime(service.getCreationTimestamp());
model.setIp(service.getPortalIP());
model.setPort(service.getPort());
model.setProtocol(service.getProtocol());

serviceList.add(serviceModel);
}

return serviceList;
}

[/code]

Creating Services

[code language="java"]

public void createKubeService(String id, String namespace, int containerPort, int port, List<String> publicIps,
Map<String, String> labels, Map<String, String> selectors) {
Service service = new Service();

IntOrString containerPortObj = new IntOrString();
containerPortPojo.setIntVal(containerPort);

service.setId(id);
service.setContainerPort(containerPortObj);
service.setPort(port);
service.setPublicIPs(publicIps);
service.setLabels(labels);
service.setSelector(selectors);

kubernetes.createService(service, namespace);
}

[/code]

Deleting Services

[code language="java"]

public void deleteService(String id, String namespace) {
kubernetes.deleteService(id, namespace);
}

[/code]

Summary

Kubernetes and Linux containers are rapidly developing and emerging technologies. We have seen how to easily orchestrate containers in a Kubernetes environment using the Fabric8 Java APIs. Container orchestration is about performing operations on various Kubernetes components such as pods, replication controllers and services. Using the APIs you can easily build Kubernetes functionality into any Java applications. I hope you found this article useful. If you have examples of orchestrating Kubernetes or containers through APIs please share!

Happy Containerizing!

(c) 2015 Keith Tenzer