Monday, October 22, 2018

Running Apache Geode in a Docker Container


Apache Geode is a distributed, in-memory database with strong data consistency. It's also the basis for a powerful commercial implementation that runs in Cloud Foundry.
"Pivotal Cloud Cache (PCC) is a specialized implementation of Pivotal GemFire, Pivotal’s commercial caching product based on Apache Geode." This quote comes from a good article covering the balancing act between Availability and Consistency of this technology.
In any of it's three variations, it can provide a strong foundation for a 12 Factor application that needs a persistence layer (Geode also supports read-through, write-through and overflow techniques).

Start Geode in a Docker container

To get started playing around with Geode, it's easy to spin up a Docker container. There is one gotcha, that I'll describe a workaround for. Ideally, someone more Docker savvy can let me know a better method to access Geode from the host OS.

docker run -p 8080:8080 -p 10334:10334 -p 40404:40404 -p 1099:1099 -p 7070:7070 -it apachegeode/geode

Start a Locator and a Server

Once the container starts, you'll have an interactive shell active from which you can start Geode services. The "gee-fish" prompt is a shortened name for the GemFire Shell.

gfsh > start locator 
Note the hostname it starts on. It will be output from the previous command in a format like: "d26f1ea42d39[10334]".

gfsh > start server

Setup a Geode Region

Next, create a region that will host your application data.

gfsh > create region --name=hello-world-region --type=REPLICATE


Access the Geode from a Windows OS Host

To reach the Geode services controller from outside of the container, I had to implement a small networking hack.  Edit your Windows "C:\Windows\System32\drivers\etc\hosts" file to give the address "127.0.0.1" an alias matching the locator host address noted above.

For the location host shown above, the hosts entry would look like this:

127.0.0.1       localhost   d26f1ea42d39

Running a Simple Java Client

I created a simple GitHub repo containing a Java client application to verify that the container is up and accepting data flow to the defined region: https://github.com/thecodebeneath/geodeclient

To run the simple Spring Boot client that writes some data to Geode, run the Maven command:

> mvn spring-boot:run

Query the Geode region for data by running this command from the container prompt:

gfsh > query --query='select * from /hello-world-region'

Summary

I hope this is a helpful bootstrap to get up and running with a Geode instance.

If you know of a way to avoid the Windows hosts file edit, please let me know - I'm always ready to learn something new!

Wednesday, October 17, 2018

Pushing a Java Project To Cloud Foundry

Pushing a self-contained Java artifact to Pivotal Cloud Foundry is very straightforward. However, I found the instructions to push an existing legacy application this is not self-contained sparse and not as clear as they could be. This blog post detail what I found out and how to do it.
As a code reference, you can look at this Java project and scripts in my GitHub repository here: https://github.com/thecodebeneath/cfpushdir
The project in this repo can be built with Maven and pushed to Cloud Foundry two ways:

1. Standard CF push pointing to a jar file

This is the easiest method and mirrors a simple uber-jar that the Java buildpack can easily upload, detect and start.

> cf push -f manifest-from-jarpath.yml

Where the manifest file looks like this:

---
applications:
- name: carservice-from-jarpath
  path: target/release/lib/carService-1.0-SNAPSHOT-shaded.jar
  buildpacks:
  - java_buildpack
  memory: 1G
  instances: 1
  random-route: true

2. CF push a directory of files that contain the jar

This is the method that caused me a lot of trouble trying to figure out. The key is understanding that the Java buildpack can handle three separate push styles: 1) jar/war, 2) zip file or 3) nested directories. The last two styles end up both being handled by the "distzip" capability of the Java buildback. This requires an explicit set of named directories, in addition to any that you might also need for your application. The two required directories are "bin" and "lib", as documented here: Dist Zip Container.
  • The "bin" directory must contain your start script
  • The "lib" directory must contain your main Java artifact
> cf push -f manifest-from-dirpath.yml

Where the manifest file looks like this:

---
applications:
- name: carservice-from-dirpath
  path: target/release
  command: "$PWD/bin/startCommand"
  buildpacks:
  - java_buildpack
  memory: 1G
  instances: 1
  random-route: true

The target/release directory on your development machine contains the "bin" and "lib" directories, and the startCommand script in the "bin" directory has a command that references the jar as a relative path inside of "lib": 

> $HOME/.java-buildpack/open_jdk_jre/bin/java -jar lib/carService-1.0-SNAPSHOT-shaded.jar 'manifest-from-dirpath'


Summary

I hope my instructions and git project help someone else avoid the time and confusion I had while trying to figure out this solution.