Showing posts with label Docker Registry. Show all posts
Showing posts with label Docker Registry. Show all posts

Monday, 3 October 2016

Integrated Continuous Integration (CI) Solution With Jenkins, Maven, docker-maven-plugin, Private Docker Registry


In previous blog, I shared how to run Jenkins + Maven in Docker container here and we could already automate the Maven-based build automatically in our Jenkins CI server, which is great to kick off for the CI process.

But, while reviewing what we're going to achieve as below diagram, we realize that having a Spring Boot-powered jar file is not what we want, we want to have a Docker image built and registered into our private Docker Registry so that we're fully ready for the coming Continuous Deployment!

Integrated Jenkins + Maven + docker-maven-plugin

So let's focus on the highlighted part on above diagram to build an integrated Jenkins + Maven + docker-maven-plugin solution, by using Docker container technology also!

Build Up Our Private Docker Registry

Docker has provided a great Docker image for building up our private Docker Registry, here.
Let's do it by simply running through below commands:
$ sudo mkdir /data/registry
$ sudo chown -R devops:docker /data/registry
$ whoami
devops
$ pwd
/home/devops
$ vim docker-compose.yml
-------------------------------
# Private Docker Registry
docker-registry:
  image: registry
  volumes:
    - /data/registry:/var/lib/registry
  ports:
    - "5000:5000"
-------------------------------

It's almost done, let's spin it up:
$ docker-compose up

And try it out:
$ curl http://127.0.0.1:5000/
"\"docker-registry server\""

Well, our private Docker Registry works but wait…the Docker client can’t push image to it yet.
We need to make some changes at Docker's configuration before pushing images:
$ sudo vim /etc/default/docker
---------------------------
DOCKER_OPTS="--insecure-registry 192.168.56.118:5000"
---------------------------

And then restart the Docker daemon:
$ sudo service docker restart

Now our private Docker Registry is ready to rock.

But how to verify whether our Docker Registry is really working as what we expected?
It must be: 1) Ready for publishing; and 2) Ready for searching.

The idea is to use our greatest public available "hello-world" image which is lightweight enough to try, 960B!

$ docker pull hello-world
$ docker images
...
hello-world    latest                     690ed74de00f        11 months ago       960 B

$ docker tag 690ed74de00f 192.168.56.118:5000/hello-world
$ docker images
...
192.168.56.118:5000/hello-world    latest  690ed74de00f        11 months ago       960 B
hello-world                        latest  690ed74de00f        11 months ago       960 B

$ docker push 192.168.56.118:5000/hello-world
The push refers to a repository [192.168.56.118:5000/hello-world]
5f70bf18a086: Image successfully pushed
b652ec3a27e7: Image succewr12334567ssfully pushed
Pushing tag for rev [690ed74de00f] on {http://192.168.56.118:5000/v1/repositories/hello-world/tags/latest}

$ curl http://192.168.56.118:5000/v1/search?q=hello
{"num_results": 1, "query": "hello", "results": 
 [
  {"description": "", "name": "library/hello-world"}
 ]
}

Sure enough, our private Docker Registry is fully ready!

Okay, so far we already have a private Docker Registry, already can do a basic Maven build in Jenkins. What should we do next?

Enable the docker-maven-plugin

It's time to enable our glue, the docker-maven-plugin, in our project.
The purposes of using this plugin are to:

  1. Automate the Docker image build process on top of our typical build which the output might be jar, war. Now, we want to have a Docker image equipped with our application as the deliverable!
  2. Publish our built Docker image to our private Docker Registry where is the starting point of our Continuous Deployment!
<Frankly speaking, there were many issues encountered along my experiment like here but to make long story short, I'll go directly to the points>


Firstly, please refer to my previous blog "Some Practices to Run Maven + Jenkins In Docker Container" here for the basic setup of the environment.
Below successful experiment would be on top of this environment.

Explicitly Specify Docker Host in /etc/default/docker

Edit the /etc/default/docker as below:
#DOCKER_OPTS="--insecure-registry 192.168.56.118:5000"
DOCKER_OPTS="--insecure-registry 192.168.56.118:5000 -H tcp://0.0.0.0:4243 -H unix:///var/run/docker.sock"

And restart the Docker daemon is required, of course:
$ sudo service docker restart

Enable the docker-maven-plugin In pom.xml

There are many Docker Maven plugins available and I simply choose spotify's one, here.
The configuration of the plugin in pom.xml is as below:
<!-- Docker image building plugin -->
<plugin>
 <groupId>com.spotify</groupId>
 <artifactId>docker-maven-plugin</artifactId>
 <version>0.4.13</version>
 <executions>
  <execution>
   <phase>package</phase>
   <goals>
    <goal>build</goal>
   </goals>
  </execution>
 </executions>
 <configuration>
  <dockerHost>${docker.host}</dockerHost>
  
  <baseImage>frolvlad/alpine-oraclejdk8:slim</baseImage>
  <imageName>${docker.registry}/devops/${project.artifactId}</imageName>
  <entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]</entryPoint>
  
  <resources>
     <resource>
    <targetPath>/</targetPath>
    <directory>${project.build.directory}</directory>
    <include>${project.build.finalName}.jar</include>
     </resource>
  </resources>
  
  <forceTags>true</forceTags>
  <imageTags>
     <imageTag>${project.version}</imageTag>
  </imageTags>
 </configuration>
</plugin>
Note: For complete pom.xml file, please refer to my GitHub repository, here.

The Jenkins Job

Below screenshots are the major configuration parts of the Jenkins Job.

Source Code Management


Build Triggers


Maven Goals


Console Output

Here I also posted a typical Console Output of the Jenkins Job for reference as a Gist here.

Have A Check On What We Have

Firstly we can check whether our local repository has the cached image:
$ docker images
REPOSITORY                                             TAG                        IMAGE ID            CREATED             SIZE
...
192.168.56.118:5000/devops/springboot-jersey-swagger   1.0.0-SNAPSHOT             203fde08df84        44 minutes ago      191.9 MB
...

Great, then have a check whether this image has been registered into our private Docker Registry:
$ curl http://192.168.56.118:5000/v1/search?q=springboot-jersey-swagger
{"num_results": 1, "query": "springboot-jersey-swagger", "results": 
 [
  {"description": "", "name": "devops/springboot-jersey-swagger"}
 ]
}

Yeah! We made it!

Try Our Docker Image Out Also

To go deeper, we can also take a look on whether our application works or not:
docker run -d -p 8000:8000 192.168.56.118:5000/devops/springboot-jersey-swagger

Open the browser and key in: http://192.168.56.118:8000


Hooray, it works perfectly!

Conclusion

From this experiment we have learned that:
  1. By using a customized Docker container, we can put Jenkins, Maven and docker-maven-plugin together to automate our project build process and the deliverable can be our desired Docker image;
  2. The Docker image can be pushed automatically to our private Docker Registry within the pipeline which will enable us to make the Continuous Deployment happen soon.

So the CI part is done and let's look forward to our CD part soon!
Enjoy your CI experiments also!