Spring Boot and Docker

Summary

My toy angular/rest/spring project, HIIT (high intensity interval training), was something I wanted to package inside a docker container that could run on any machine, regardless of the presence of a JVM (especially Java8). I decided to try out the maven targets for packaging in a docker image – the result was VERY easy to do.

Background

Docker is something I’ve been slow to warm to. Historically my argument against it is that it was a quick-and-dirty solution (and I felt dirtier than it has to be) vs. standard package management like rpm/deb files. However, as I’ve played with Docker more seriously and thought about the troubles it digs people out of I’ve changed my tune. Pros that docker brings include not worrying about the dependencies that make your app run (i.e. the jvm) and being able to allow parameters/shared volumes to run multiple containers side-by-side with nearly zero overhead. When comparing this to standard package management this just isn’t possible.

My friend Blake also said something to me that really resonated, he said think of a docker image as your application’s “executable”. This instantly clicked with me. An executable is something that can be adjusted with command-line switches and is fully self contained (let’s not get too pedantic about dynamic libraries). It’s can be run many times and the switches give it a different ‘profile’. Once I started thinking about Docker images this way, it made me want to do more with Docker since it gives so much flexibility AND given its immutable nature (i.e. an image can never be changed, it is frozen in time just as git freezes a repo in time at each commit) Docker allows multiple instances to be running quite easily and unaware of each other.

How To

The Spring Blogs given a good Docker tutorial, all I did was apply the tutorial to my app.

First

First I made sure docker was installed on my machine (Ubuntu 15.10). This was as simple as running apt-get

sudo apt-get install docker

Second

After docker was installed I proceeded to add details to my pom.xml. You can see my branch here where I have the Dockerfile and changes in the pom.xml. There’s some other noise with my update of Spring Boot in the same branch, but generally speaking the interesting changes are

Dockerfile

FROM java:8
VOLUME /tmp
ADD com.basilio.hiit-0.0.1-SNAPSHOT.jar hiit.jar
RUN bash -c 'touch /hiit.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom", "-Dspring.profiles.active=hsqldb","-jar","/hiit.jar"]

pom.xml

..
<properties>
  <docker.image.prefix>jimbasilio</docker.image.prefix>
</properties>
..
<!-- Package as a docker image -->
<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>0.2.3</version>
    <configuration>
        <imageName>${docker.image.prefix}/${project.artifactId}</imageName>
        <dockerDirectory>src/main/docker</dockerDirectory>
        <resources>
            <resource>
                <targetPath>/</targetPath>
                <directory>${project.build.directory}</directory>
                <include>${project.build.finalName}.jar</include>
            </resource>
        </resources>
    </configuration>
</plugin>

The Dockerfile grabs the java:8 docker image from the docker repo, creates a shared volume in /tmp (where tomcat will write to), ensures the jarfile has a fresh datestamp on a docker rebuild, and declares the entrypoint to run (which means what switches I want the docker “exe” to automatically use). You can see I wanted to run in the -Dspring.profiles.active=hsqldb profile but I could have also passed parameters into docker to set the active profile.

Third

Now when I issue the docker image build via maven

[jim@galago~/projects/HIIT (master)]$ mvn package docker:build

you can see the docker image being built. From here I can see my image and then run my image and start my container

[jim@galago~/projects/HIIT (master)]$ sudo docker images
REPOSITORY                    TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
jimbasilio/com.basilio.hiit   latest              c3360feee95d        2 minutes ago       714.1 MB
java                          8                   d4849089125b        3 weeks ago         642 MB
[jim@galago~/projects/HIIT (master)]$ sudo docker run -p 8080:8080 jimbasilio/com.basilio.hiit
....loads of spring boot stuff printed to stdout to let you know what's going on

Now, point your browser to http://localhost:8080 you’ll see the hiit app (in all its skeleton glory) show up. Also, notice the console out messages being emitted from the docker container that’s being executed.

I can also run another container on port 8081 and it will happily startup

[jim@galago~/projects/HIIT (master)]$ sudo docker run -p 8081:8080 jimbasilio/com.basilio.hiit

Now point your browser to http://localhost:8081, you’ll see console message from hits to that port. The cool thing is the Spring Boot application has no idea it’s serving on port 8081, because it’s really bound to the docker container’s port 8080. At this point I could go more advanced and put a load balancer in front of both port 8080 and 8081 and optimally flood my CPUs (although realistically on 1 machine java will already do this quite happily by threaded connections through Tomcat).

Bottom Line

Docker is something that takes some getting used to. Thinking about the final Docker image as an ‘executable’ AND also an immutable (and comprised of) series of inner containers with each building on the previous immutable image helps things (at least it will help things once they start to click).

Being able to spin-up your ‘exe’ wherever you are (think dumb cloud box), not having to worry about what the host system has installed, and the very low overhead that containers have gives you one more tool in the toolbox to manage your application.

More examples of Docker usage are a maven docker image so you don’t have to worry about your CI builds (i.e. Jenkins) having maven installed. You can simply  have Jenkins start the maven docker container, share a volume with your sourcecode, compile/run tests, then the stdout is checked for success.

Docker is an endless thought experiment which really opens a lot of doors for creative (and reproducible) solutions.

Good luck and ENJOY!

Add better git support to your bash shell

Add this to your ~/.bash_rc

if [ -f /usr/lib/git-core/git-sh-prompt ]
then
  source /usr/lib/git-core/git-sh-prompt
  export PS1='[\u@\h\w$(__git_ps1 " (%s)")]\$ '
fi

Then watch your shell go from this

[jim@galago~/projects/HIIT]$

to this

[jim@galago~/projects/HIIT (add-docker)]$

Notice the branch name (add-docker) in the prompt?

You’ll also have command completion for git commands (i.e. git a<tab><tab> will show)

[jim@galago~/projects/HIIT (add-docker)]$ git a
add        am         annotate   apply      archive

And you’ll have command completion for the branches et al (i.e. git checkout <tab><tab> will show)

 

[jim@galago~/projects/HIIT (add-docker)]$ git checkout 
add-docker          HEAD                ORIG_HEAD           origin/HEAD         reactify 
FETCH_HEAD          master              origin/add-docker   origin/master

Enjoy!

Back to the future – Dell XPS 9350 (4.4-rc7 kernel)

My previous post on this topic talked about a mechanism for installing a custom 4.3 kernel that has the broadcom wireless drivers built in. I found a cleaner way to run a 4.4rc7 kernel from ubuntu that supports wifi, has no audio sizzle/static, and seems to run everything wonderfully.

It’s as simple as the following steps (as detailed on this blog)

cd /tmp
wget kernel.ubuntu.com/~kernel-ppa/mainline/v4.4-rc7-wily/linux-headers-4.4.0-040400rc7_4.4.0-040400rc7.201512272230_all.deb kernel.ubuntu.com/~kernel-ppa/mainline/v4.4-rc7-wily/linux-headers-4.4.0-040400rc7-generic_4.4.0-040400rc7.201512272230_amd64.deb kernel.ubuntu.com/~kernel-ppa/mainline/v4.4-rc7-wily/linux-image-4.4.0-040400rc7-generic_4.4.0-040400rc7.201512272230_amd64.deb
sudo dpkg -i linux-headers-4.4*.deb linux-image-4.4*.deb

Once you are done the above, reboot and select the 4.4 kernel (it may go to this by default). For me, everything “just worked”.

Also, whatever you do, don’t forget to install libinput’s X touchpad driver – it’s superior to the synaptic driver in every way.

Can’t wait until an official release from Dell and/or ubuntu 16.04 – until this I’m happy as a clam on this laptop. It’s a dream form factor, battery life, and power combination (assuming you aren’t intending on running games).

Back to the future – Dell XPS 9350 (4.3 kernel – old)

The Present

So my first post on this blog was about the Dell XPS 9333 compared to the System76 Galago UltraPro – I bought the System76 and don’t regret it at all. It’s a beast. The GPU is VERY strong (not as good as a discrete GPU but much better than the normal laptop level embedded GPU), the CPU is a MONSTER quad-core beast. The downside is battery life – it stinks. 3 hrs max .. if you are working it hard much less.

The Future

So with Dell’s new XPS 13 Skylake 9350 AND with a $100 rebate from MS I had to buy-in again. It’s just too nice of a footprint/screen/battery life to pass up. I love my Galago, but I love battery life when I don’t need the horsepower.

The Problem

Only problem is I didn’t want to run windows on it. MS was kind enough to give me $100 discount through a Christmas 2015 promotion, but I’m a linux guy and windows just isn’t as good for me. Problem is Dell’s Sputnik program doesn’t have everything worked out yet since Skylake is still fairly new and the drivers are only now in the 4.4 kernels which, as of this writing, are still in release candidate phase.

But never fear, here’s what I did to get it running!
NOTE: You’ll need a machine that DOES have internet access to do the below steps to copy the file to a thumb drive or other medium to transfer

  1. Put Ubuntu 15.10 on a thumb drive (get it here)
  2. Follow these steps on this wiki to download a custom 4.3 kernel
      1. If you don’t want to go to that link, download the custom 4.3 kernel by clicking this
      2. Go to terminal and change to directory you downloaded the file
      3. Enter the following
    tar jxf xps13_9350_kernel.tar.bz2
    sudo chown root:root brcmfmac4350-pcie.bin BCM-0a5c-6412.hcd
    sudo mv -t /lib/firmware/brcm/ BCM-0a5c-6412.hcd brcmfmac4350-pcie.bin
    sudo dpkg -i linux-headers-4.3.0-wifitest-custom_4.3.0-wifitest-custom-10.00.Custom_amd64.deb linux-image-4.3.0-wifitest-custom_4.3.0-wifitest-custom-10.00.Custom_amd64.deb
    
  3. Reboot and enjoy (NOTE: there is an issue with this 4.3 kernel where there is some static that comes from the speaker, this is more noticeable with headphones plugged in.)

I have had great luck with the above. I’m quite positive that I’ll have better luck with an official kernel and especially 4.4, but until then I’m not taking any kernel updates but do take all the other updates that ubuntu pushes.

Alternative

An alternative is to just buy an intel wifi device (http://www.amazon.com/gp/product/B00GUNZUG0) and be done with it. 🙂

Also…

No matter what you do above (custom kernel or new wifi device) make sure you update from the X synaptic driver to the libinput X driver – it’s MUCH better.

Use these steps on a previous post.