Publish Docker Images to Google Cloud Registry using Jenkins and Fabric8 Maven Plugin

Athul RAVINDRAN
5 min readNov 1, 2019

--

Recently I have been trying to do some side projects developing an ecosystem of micro services applications using Spring Boot 2 and Netflix OSS. I found GCP (Google Cloud Platform) pretty cool and less expensive to run my applications, as GCP offers a $300 credit.

I started to explore GCP’s Kubernetes Engine for deployments but before that I needed to publish docker images to a registry. GCP offers Google Container Registry (GCR) for publishing docker images. At first it was easy to manually run docker commands to publish images to GCR.

docker build -t gcr.io/projectName/imageName:version -f Dockerfile .docker push  gcr.io/projectName/imageName:version

After I started to expand my application and ended up creating 11 micro-services, executing 22 commands every time is a cumbersome process.

I have a very good experience working on Agile development and using Jenkins for every part of automation is a day to day practice at my work.

I had already installed Jenkins on GCP’s Compute Engine VM using Bitnami distribution and I began to create dependent job that builds and pushes images after my build job that runs unit test and integration test passes.

There are two ways to automate publishing images to GCR.

  1. Using the following Jenkins plugins: Docker build step, Google Container Registry Auth, Google O Auth Credentials.

2. Using Fabric8 Maven Plugin and Maven Profile

I found some examples in the internet for option 1 and I came up with option 2 and decided to give it a try. I liked option 2 because most of the control is kept within the source code. If you decided to use another tool for CI other than Jenkins, you can easily run the job without having to reinvent the wheel. Also executing the core part of the job thru a maven profile lets you to get the job done on your local machine as well. Simply run the maven goal and thats it !!

Enough of stories, let’s start working !!

Pre-requisites:

  1. Jenkins with maven plugin, git plugin, docker plugin installed.
  2. GCP account and a project already set up.
  3. GCP service account (let’s look at this next) with admin permission to GCR storage bucket.
  4. JSON key file of your service account for authentication purposes. (https://support.google.com/cloud/answer/6158849#serviceaccounts)

Creating a GCP service account and granting permission to GCR

Click here to read my other story to create GCP service account and granting access to GCR and generating JSON key.

Creating Jenkins Credential Using GCP service account JSON key.

To create a credential of type “Secret Text”, you will need Plain Credential Plugin installed on you Jenkins.

Go to Jenkins Global Credentials and Add Credentials.

Choose Secret Text from the drop down, give it an ID and paste the contents of downloaded JSON file from GCP into the secret text box and Click OK to create a credential.

Now that we have a service account created in GCP and granted access to GCR and also set up as a credential in Jenkins, the next step is to configure our project with Fabric8 maven plugin.

Fabric8 Maven Plugin:

<plugin>
<groupId>io.fabric8</groupId>
<artifactId>fabric8-maven-plugin</artifactId>
<version>4.2.0</version>
</plugin>

Fabric8 Maven Plugin (aka F8) has features to build and push images to various registries. It also has features to even deploy containers. See documentation.

Let’s add the above plugin to our project PluginsManagement Section in project pom.xml.

Create a Fabric8 Maven profile

<profile>
<id>gcr</id>
<activation>
<activeByDefault>false</activeByDefault>
<property>
<name>registry</name>
<value>gcr</value>
</property>
<file>
<exists>deploy</exists>
</file>
</activation>
<build>
<plugins>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>fabric8-maven-plugin</artifactId>
<configuration>
<mode>kubernetes</mode>
<forcePull>true</forcePull>
<images>
<image>
<name>gcr.io/test-project/${project.artifactId}</name>
<build>
<tags>
<tag>v2</tag>
</tags>
<dockerFile>${project.basedir}/deploy/Dockerfile</dockerFile>
<contextDir>${project.basedir}</contextDir>
</build>
</image>
</images>
</configuration>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>resource</goal>
<goal>build</goal>
<goal>push</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>

Decoding the above profile settings:

Profile has an id “gcr” and profile is NOT activated by default. This profile can be invoked either by using profile id “gcr” or using system property in maven command “-Dregistry=gcr”.

Profile also executes only if a file/folder called “deploy” exists in the project. I have all my docker deployment files in a “deploy” folder directly under the project main folder.

Under the images section, I have my image name configured as “gcr.io/test-project/${project.artifactId}”. My project is a multi module maven project and this profile is configured in the parent pom. When I build the entire project, all of the modules (child) will trigger this plugin resolving the module name as “project.artifactId” and thus creating separate images.

eg: “gcr.io/test-project/moduleA”, gcr.io/test-project/moduleB”

Similarly dockerFile section is configured as “${project.basedir}/deploy/Dockerfile” . The property project.basedir will also resolve to the module name as it gets built.

Execution of this plugin is triggered only during the install phase. You could configure to run it during any phase in maven life cycle but I chose install coz it makes sense.

During this execution, fabric8’s resource, build and push goals are invoked and thus image gets pushed to registry which is gcr.io in this case.

                <execution>
<phase>install</phase>
<goals>
<goal>resource</goal>
<goal>build</goal>
<goal>push</goal>
</goals>
</execution>

Now we have 3 pieces, a service account with storage bucket access, a jenkins credential and a maven profile. The last and final piece of that wires all these 3 pieces together is a Jenkins Job that will invoke the above created profile and use the service account credential.

Finally — Jenkins Job

Go ahead and create a “Maven Project” Jenkins job and put all the required information like github repo url etc., Following are the configurations for getting the job done.,

  1. Bindings: In the Bindings section, click Add and choose “Secret Text” from the dropdown.

Give a variable name , I call it “SECRET” and choose the credential “GCP_SECRET” from the drop down.

2. Authentication — Execute Shell script

The job needs to authenticate with GCP to allow it to push images to the bucket. Choose Execute shell from Add pre-build step in Jenkins. Enter the following command.

docker login -u _json_key -p "${SECRET}" https://gcr.io

3. Maven Goal

As we have defined our profile to trigger execution during install phase and System property registry=gcr, the following maven goal will do the trick !!

mvn clean install -Dregistry=gcr

Save and run your jenkins job. Your job should build successfully.

To verify the result, go to GCP console and navigate to “Container Registry” using the side bar menu. You should see your published image(s).

Good Luck !!!

--

--