Persisting a Key Value in etcd using jetcd for Java

The logo may be the copyright of the CoreOS
etcd is a distributed key-value store which can be used for storing configuration information needed by the applications like database urls, driver etc. This is essential when we have applications running in a cluster that need to share information.
For example, in microservices architecture, we can have multiple instances of an application running across different machines. So when a new instance spawns up it is essential to that the new instance should have the configuration information it needed.
For example, if the instance connects to a database, it needs to know how to connect to the database (the configuration) which must be stored somewhere and is accessible across the cluster, no matter in which machine the instance spawns up.
This means that you cannot have configuration information residing in just a single machine! Because if the machine fails, or is down, new instances simply cannot work because the lack the configuration information needed for them to start because the machine is down.
This is the beauty of distributed architecture, where the information is distributed across several machines.
etcd is from CoreOS, a lightweight OS designed for Containers, it is often termed as Container Linux.
jetcd is a Java library for etcd.
You can perform operations like get, put, watch on etcd using etcdctl (etcdctl is a binary or a command line tool which can be used to store the values). But, now, you can also do the same using a Java program instead of using etcdctl.

Set up the etcd in a docker container

Go to the releases section of the etcd page, and follow the instructions under the Docker heading.
It will have commands, just simply paste those commands in the terminal of the host where docker is installed. A sample below looks like this: (Remember to go to the page and copy the code for the latest release)!

rm -rf /tmp/etcd-data.tmp && mkdir -p /tmp/etcd-data.tmp && \

  docker rmi gcr.io/etcd-development/etcd:v3.3.10 || true && \

  docker run \

  -p 2379:2379 \

  -p 2380:2380 \

  --mount type=bind,source=/tmp/etcd-data.tmp,destination=/etcd-data \

  --name etcd-gcr-v3.3.10 \

  gcr.io/etcd-development/etcd:v3.3.10 \

  /usr/local/bin/etcd \

  --name s1 \

  --data-dir /etcd-data \

  --listen-client-urls http://0.0.0.0:2379 \

  --advertise-client-urls http://0.0.0.0:2379 \

  --listen-peer-urls http://0.0.0.0:2380 \

  --initial-advertise-peer-urls http://0.0.0.0:2380 \

  --initial-cluster s1=http://0.0.0.0:2380 \

  --initial-cluster-token tkn \

  --initial-cluster-state new

docker exec etcd-gcr-v3.3.10 /bin/sh -c "/usr/local/bin/etcd --version"
docker exec etcd-gcr-v3.3.10 /bin/sh -c "ETCDCTL_API=3 /usr/local/bin/etcdctl version"
docker exec etcd-gcr-v3.3.10 /bin/sh -c "ETCDCTL_API=3 /usr/local/bin/etcdctl endpoint health"
docker exec etcd-gcr-v3.3.10 /bin/sh -c "ETCDCTL_API=3 /usr/local/bin/etcdctl put foo bar"
docker exec etcd-gcr-v3.3.10 /bin/sh -c "ETCDCTL_API=3 /usr/local/bin/etcdctl get foo"

pom.xml


 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.test</groupId>
    <artifactId>etcdtest</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
         <!-- https://mvnrepository.com/artifact/com.coreos/jetcd-core -->
        <dependency>
            <groupId>com.coreos</groupId>
            <artifactId>jetcd-core</artifactId>
            <version>0.0.2</version>
        </dependency>   

    </dependencies>

</project>

Java program


import com.coreos.jetcd.Client;
import com.coreos.jetcd.KV;
import com.coreos.jetcd.data.ByteSequence;
import com.coreos.jetcd.data.KeyValue;
import com.coreos.jetcd.kv.GetResponse;


import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class Demo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        Client client = Client.builder().endpoints("http://10.x.x.x:2379").build();
        ByteSequence key = ByteSequence.fromString("foo");
        ByteSequence value = ByteSequence.fromString("test_value");

        // put the key-value
        KV kvClient=client.getKVClient();

        kvClient.put(key,value).get();

        // get the CompletableFuture
        CompletableFuture<GetResponse> getFuture = kvClient.get(key);

        // get the value from CompletableFuture
        GetResponse response = getFuture.get();

        for(KeyValue kv:response.getKvs())
        {
            System.out.println(kv.getKey()+" == "+kv.getValue());
        }

        System.out.println(response);

    }
}

Check if the value is inserted using etcdctl


docker exec etcd-gcr-v3.3.10 /bin/sh -c "ETCDCTL_API=3 /usr/local/bin/etcdctl get foo"
Note: The jetcd uses the API 3. So, if you simply run the command, etcdctl without setting the API version, you may not get it.

docker exec etcd-gcr-v3.3.10 /bin/sh -c "/usr/local/bin/etcdctl get foo"
The above will not do, also,

docker exec etcd-gcr-v3.3.10 /bin/sh -c "/usr/local/bin/etcdctl set /bar test"
and checking the value from jetcd for /bar will not get the value. Since, the default API is set to be 2 and not to 3.

No comments: