I wrote a simple Java program that I wanted to run every 15 minutes. I decided to wrap everything into a Docker image so that I would get the logging, restart capability, and portability goodness that one gets for free when running a Docker container. It’s not a difficult thing to do, but it took me longer than it should since I made some incorrect assumptions.
Since I wanted the image to be small, I went with an “Alpine” version of the openjdk image. My first incorrect assumption was that I could use cron and crontab like I do on Ubuntu or Red Hat systems–but Alpine doesn’t come with cron. However, it’s actually easier than messing with crontab–I just had to put my script into the /etc/periodic/15min directory.
Once I had the script in place, I tried to run the container, but eventually discovered the the small Alpine image does not have the daemon enabled when the container starts up. This was solved by running crond in the foreground. Here’s a Dockerfile showing the important bits:
ROM openjdk:alpine MAINTAINER Nathan Bak <dockerhub@yellowslicker.com> # Create directory to store jars and copy jars there RUN mkdir /jars COPY jars/*.jar /jars/ # Copy bin directory of project to root directory COPY bin/ / # Copy runJavaApp script into correct location and modify permissions COPY runJavaApp /etc/periodic/15min/ RUN chmod 755 /etc/periodic/15min/runJavaApp # When the container starts, run crond in foreground and direct the output to stderr CMD ["crond", "-f", "-d", "8"]
Here is the runJavaApp script:
#!/bin/sh java -cp /:/jars/commons-codec-1.9.jar:/jars/commons-logging-1.2.jar:/jars/fluent-hc-4.5.2.jar:/jars/httpclient-4.5.2.jar:/jars/httpclient-cache-4.5.2.jar:/jars/httpclient-win-4.5.2.jar:/jars/httpcore-4.4.4.jar:/jars/httpmime-4.5.2.jar:/jars/jna-4.1.0.jar:/jars/jna-platform-4.1.0.jar com.yellowslicker.sample.Client
The “gotchas” I ran into with the script include:
- The script must begin with #!/bin/sh (out of habit I tried #!/bin/bash, but Alpine doesn’t come with bash)
- Each jar must be listed explicitly (I tried using /:/jars/*.jar for my path, but it didn’t work)
There are a lot of ways to schedule things, but this method was simple (once I figured it out) and I think it is robust. In my case, it also fits well into the Docker microservice environment I’m running.