2017-01-24 by Axel Fontaine
While CloudCaptain makes it dead easy to run your JVM applications (Spring Boot, JHipster, Grails, Dropwizard, Tomcat, TomEE or executable jar) on AWS, sometimes those applications also depend on other native Linux x64 binaries and libs. Typically these would be native applications for audio, video or image processing, but they could be anything.
Until now this meant writing some custom code to manually extract those binaries to the filesystem, giving them execute permissions and so on. Not exactly complicated. But certainly more complicated than things could and should be.
No more. Today we are introducing dead easy built-in support for shipping native Linux x64 binaries with your JVM apps.
Simply place your binaries under a special native/bin
directory and CloudCaptain
will automatically add them to the PATH
at runtime in your instances.
If those binaries also depend on additional shared libraries beyond the C library, place the .so files of your libraries
under native/lib
and CloudCaptain
will automatically add them to the LD_LIBRARY_PATH
at runtime in your instances.
And that's all!
For this post, we're going to build a remote version of the Linux cowsay
utility using Spring Boot.
First let's start by taking the sources of this simple c port of cowsay:
#include <stdio.h> int main(int argc, char **argv) { int i; if (argc == 1) printf("< moOh >\n"); for (i = 1; i < argc; i++) if (i == 1) printf("/ %s \\\n", argv[i]); else if (i == argc - 1) printf("\\ %s /\n", argv[i]); else printf("| %s |\n", argv[i]); printf(" \\ ^__^\n"); printf(" (oo)\\_______\n"); printf(" (__)\\ )\\/\\\n"); printf(" ||----w |\n"); printf(" || ||\n"); return (0); }
and compiling them into a native Linux x64 binary:
$ gcc -Wall -g cowsay.c -o cowsay.elf64
Now let's create a simple Spring Boot app to expose this:
$ curl 'https://start.spring.io/starter.zip?type=maven-project&bootVersion=1.4.3.RELEASE&baseDir=remote-cowsay&groupId=com.boxfuse.demo&artifactId=remote-cowsay&version=1.0&name=remote-cowsay&description=Remote+cowsay&packageName=com.boxfuse.demo&packaging=jar&javaVersion=1.8&language=java&autocomplete=&generate-project=&style=web' -o remote-cowsay.zip && unzip remote-cowsay.zip
Next add our freshly compiled cowsay.elf64
Linux x64 binary to our project under the src/main/resources/native/bin
directory to ensure it will be added to the PATH
at runtime:
remote-cowsay
src
main
java
com
boxfuse
demo
RemoteCowsayApplication.java
native
bin
cowsay.elf64
test
.mvn
.gitignore
mvnw
mvnw.cmd
pom.xml
And finally let's add a controller to our RemoteCowsayApplication
class:
package com.boxfuse.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.util.FileCopyUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; @SpringBootApplication @RestController public class RemoteCowsayApplication { @RequestMapping(path = "/") public String cowsay(@RequestParam(value = "t", defaultValue = "Moo") String text) throws IOException { return FileCopyUtils.copyToString(new InputStreamReader( // No need to specify absolute path as binary is available on $PATH new ProcessBuilder("cowsay.elf64", text).start().getInputStream(), StandardCharsets.UTF_8)); } public static void main(String[] args) { SpringApplication.run(RemoteCowsayApplication.class, args); } }
Now it is time to package our jar:
$ mvnw package
And let CloudCaptain create an image and launch an instance on VirtualBox:
$ boxfuse run
Creating remote-cowsay ...
Mapping remotecowsay-dev-axelfontaine.boxfuse.io to 127.0.0.1 ...
Successfully created app remote-cowsay (type: single-instance, db: none, logs: cloudwatch-logs)
Fusing Image for remote-cowsay-1.0.jar (Spring Boot) ...
Image fused in 00:03.320s (58621 K) -> axelfontaine/remote-cowsay:1.0
Launching Instance of axelfontaine/remote-cowsay:1.0 on VirtualBox ...
Forwarding http port localhost:8080 -> vb-f3f3a0a4:8080
Instance launched in 00:04.597s -> vb-f3f3a0a4
Waiting for payload to start on vb-f3f3a0a4:8080 (expecting HTTP 200 at / within 300s) ...
Successfully started payload in 00:12.134s -> https://127.0.0.1:8080
Last but not least, let's see it in action!
$ curl https://localhost:8080?t=Moooooohh
/ Moooooohh \
\ ^__^
(oo)\_______
(__)\ )\/\
||----w |
|| ||
And there you have it! Our native Linux x64 binary was automatically added to the PATH
with the correct
execute permissions. And all we needed to do to invoke it was a simple one-liner.
The CloudCaptain built-in support for shipping native Linux x64 binaries with your JVM apps is available today at no charge to all customers. Enjoy!
So if you haven't already, sign up for your CloudCaptain account now (simply log in with your GitHub id, it's free), start deploying your application effortlessly to AWS today and enjoy the dead easy integration for shipping native binaries.