This Docker image is intended to standardize the way we run project releases where Apache Maven is in use. It forms a clean, known build environment in which there is no pre-existing Maven state (local repository) and where only the basics necessary for a Maven release are present.
This image should be available via:
$ docker pull docker.io/commonjava/maven-release
If you make changes to the environment, you'll need to rebuild it. Maybe the easiest way to do this is:
$ ./scripts/build-image.sh
This script simply builds the Dockerfile from the current directory ($PWD) using the tag docker.io/commonjava/maven-release
.
NOTE: You'll need to run the build-image.sh
script from the root of this git repository, where the Dockerfile is located.
To run a release with this Docker image, you'll need to satisfy some prerequisites in terms of configuration. These congfiguration files are not stored in the image because they're private to you. This git repository contains a convenience script for launching a Docker container to run your release, but it assumes you have all of your configuration assembled in a directory within the git working directory called private/
. Follow the instructions below to setup these configurations.
You need to have a GPG configuration directory that you can provide via volume mount to the Docker container. To set this up, you need to install GPG, then generate a default key for signing build output. You can find more information about this at: Working with PGP Signatures - Sonatype.
Once you have a directory called $HOME/.gnupg, you can copy this whole directory to <maven-release-git-workdir>/private/gnupg
.
You'll need a Maven settings.xml
capable of authenticating to the Sonatype OSS staging server, and potentially, to Docker. It will also have to know about the GPG key / passphrase you setup above. Since we really don't want to leave passwords available in plaintext in your settings.xml
, it's a good idea to encrypt the passwords before adding them. To do that, its helpful if you have Maven installed. If you don't, install it now.
Next, copy the <maven-release-git-workdir>/private.template/m2
directory to $HOME/.m2
. If you have a $HOME/.m2
already, move it out of the way temporarily. Follow the instructions at Maven - Password Encryption to setup your master key and then encrypt passphrases for all of the necessary fields in the $HOME/.m2/settings.xml
you just copied. There will be 3-4 passwords / passphrases you need to encrypt here.
Once that's complete, copy your $HOME/.m2
to <maven-release-git-workdir>/private/m2
and, if appropriate, restore your original $HOME/.m2
directory.
Since a standard Maven release involves creation of a Git tag (not to mention pushing various commits), you need to give Git some basic information about who you are. You can copy the <maven-release-git-workdir>/private.template/gitconf
directory into <maven-release-git-workdir>/private/gitconf
and then just edit the file to fill in real values for the placeholders.
Again, since the Maven release will tag and push commits to GitHub, it's important that you have a SSH public key registered on GitHub (see your account settings, under SSH Keys on the left-hand side). Then, you have to provide the corresponding private key to this Docker container so it can push content on your behalf. You can simply copy the correct id_rsa
file to <maven-release-git-workdir>/private/ssh
.
Once you assemble all of these configurations, you may need to correct the selinux context on the private/
sub-directories:
$ chcon -Rt svirt_sandbox_file_t <maven-release-git-workdir>/private/*
The final pieces you have to know before you run your release are:
- Your GitHub URL (Use the
git@github.com:Commonjava/foo.git
/ SSH URL so you can use your SSH key) - The Git branch from which you wish to run the release (OPTIONAL; defaults to
master
)
When you have all this assembled, you can run the release with:
$ ./scripts/start-release.sh <GIT-URL> [<GIT-BRANCH>] [<MAVEN_OPTIONS>]
NOTE: If you want to provide extra Maven options to this script, you'll need to add the branch to the call, even if the branch is master
.
If you peek at the scripts/start-release.sh
script, you'll see that we don't use the Docker --rm
option to the run command. This is intentional. If the build fails for a mysterious reason, keeping the container will allow you to copy the contents from the /home/maven/
directory and possibly figure out what went wrong.
The consequence of this is that, if you don't clean up your Docker system yourself, you'll begin to accumulate old maven-release containers. This causes quite a lot of clutter, and can fill up your hard drive over time. To clean, you can use:
$ for c in $(docker ps -a | grep 'commonjava/maven-release' | grep Exited | awk '{print $1}'); do docker rm $c; done
Some Maven builds we have in Commonjava require building Docker images and running Docker containers in order to do integration tests. When you have a project like this, you'll need to make special preparations for the Docker environment in which you intend to run releases.
If you're going to use Docker containers during your release, your Docker daemon must listen on a TCP port. To enable this, edit your /etc/sysconfig/docker
file as follows:
OPTIONS='--selinux-enabled --log-driver=journald -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock'
Then, restart your Docker daemon using something like:
$ systemctl restart docker
Docker containers can't talk to each other when they use the default docker0
network bridge. They can't even see each other. So, if your release (running in a container) needs to start other containers and then communicate with them, you'll need to create a separate Docker network for that. Since you're going to be interacting with the outside world (pulling down Maven plugins, publishing build output, etc.), this network will have to be a bridge network. By default (and for historical reasons), the <maven-release-git-workdir>/scripts/start-release.sh
script assumes this network will be called ci-network
and use the IP address range 172.18.0.0/24
, which means the DOCKER_HOST environment variable passed into the release container will be tcp://172.18.0.1:2375
.
You can create this ci-network
bridge using the following command:
$ docker network create -d bridge ci-network
Docker and firewalld have a fraught relationship. For most Docker use cases, they work together well enough. However, when you have a Docker container that requires access to the Docker daemon (to build or run containers), firewalld will do its best to block your access.
To accomplish this, the scripts/start-release.sh
script will call the scripts/trust-docker-net.sh
script, which adds the docker interface given in $DOCKER_NET
as a trusted interface via firewalld and restarts that interface to put the changes into effect.