Jenkins in a Docker container

After having our Sonatype Nexus repository running in a Docker container (see my previous post), the next part of our infrastructure I wanted to move into a Docker container was our Jenkins build server.

The most difficult part of this, was to get the Android SDK installed inside the Docker image. After downloading the compressed SDK you have to run the android installer from the tools folder. This installer downloads the requested Android versions and asks for accepting the different license agreements – which is a problem because the building the docker images is non interactive. After a lot of trial and error, I found the Android SDK Installer project on github which provides the necessary scripts.

Here is my resulting Dockerfile using the Android SDK Installer:

The steps in this Dockerfile are

  • installing required libs for the Android SDK via apt
  • downloading the latest Jenkins WAR file
  • using the Android SDK Installer to install the required parts for building our Android apps
  • defining the ANDROID_HOME environment variable
  • defining an entrypoint using the war file for starting Jenkins
  • exposing port 8080 for accessing Jenkins
  • defining a volume for persisting the Jenkins work directory

With the image generated by this Dockerfile it is now possible to start up a Jenkins build wherever I want. To make the running Jenkins docker container available via Apache on Port 80 I use the following reverse proxy config:

The jenkinsPort is defined in an apache config file as 8080.

I am using a data volume for persisting the /jenkins folder as explained in my last post under “Data volumes”.

Because Jenkins allows to install everything else that is required afterwards via the web UI (JDKs, Maven, Gradle, Plugins, …) this basic image is enough. Another great improvement in Jenkins is the ability to configure credentials, like SSH keys and username/password combinations, via the web UI. This way it is not required to stored the secret stuff inside the Docker image anymore.

Again, like for the nexus repository in my last post, it is very nice to update Jenkins to the newest version by just executing docker stop, docker build and docker run.

For our Xcode builds we use the Jenkins config that is executed via SSH access to a Mac mini server. Nothing Jenkins specific had to be installed on the Mac mini, Java, Xcode and a SSH access was enough.

Signing Android APK files under JDK7

We are using maven to build our Android applications in Jenkins for testing and for publishing them to the Play Store. Recently I started to have problems with the Play Store saying that the APK files were not signed or not aligned so I upgraded the Android Maven plugin and adapted the pom.xml files. Finally I was able to submit the signed and aligned APK files again to the Play Store – everything fine again, at least I thought so.

An hour later I got the first mail from a user telling me that he hat troubles installing the update of the app from the Play Store. The error message said something about the certificate so I tried it myself and got the message

INSTALL_PARSE_FAILED_NO_CERTIFICATES

when trying to install the app on my device. I was confused because the app was signed, it contained the certificate information in the META-INF directory and the MANIFEST file and the Play Store validated it as signed.

Some research brought up this article about Android’s Problem with JDK7 and I remembered that I recently installed JDK7 on my MacBook. It turns out that there is a difference in JDK7 regarding signature algorithms and ant has a problem with it too. So to get APK files that are signed correct I had to configure the signature and digest algorithm the maven-jarsigner-plugin uses as described here:

<arguments>
  <argument>-sigalg</argument><argument>MD5withRSA</argument>
  <argument>-digestalg</argument><argument>SHA1</argument>
</arguments>

Conclusion: Always test APK files after signing!