{"id":73864,"date":"2018-02-27T11:17:20","date_gmt":"2018-02-27T09:17:20","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/?p=73864"},"modified":"2023-12-11T10:33:36","modified_gmt":"2023-12-11T08:33:36","slug":"docker-java-developers-continuous-integration-docker","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html","title":{"rendered":"Docker for Java Developers: Continuous Integration on Docker"},"content":{"rendered":"<p><em>This article is part of our Academy Course titled <a href=\"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-tutorial-java-developers.html\">Docker Tutorial for Java Developers<\/a>.<\/p>\n<p>In this course, we provide a series of tutorials so that you can develop your own Docker based applications. We cover a wide range of topics, from Docker over command line, to development, testing, deployment and continuous integration. With our straightforward tutorials, you will be able to get your own projects up and running in minimum time. Check it out <a href=\"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-tutorial-java-developers.html\">here<\/a>!<\/em><\/p>\n<div class=\"toc\">\n<h3>Table Of Contents<\/h3>\n<dl>\n<dt><a href=\"#introduction\">1. Introduction<\/a><\/dt>\n<dt><a href=\"#why\">2. Why Jenkins?<\/a><\/dt>\n<dt><a href=\"#pipeline\">3. Pipeline as a code<\/a><\/dt>\n<dt><a href=\"#jenkins\">4. Jenkins on Docker<\/a><\/dt>\n<dt><a href=\"#docker\">5. Docker in Jenkins<\/a><\/dt>\n<dt><a href=\"#conclusions\">6. Conclusions<\/a><\/dt>\n<\/dl>\n<\/div>\n<h2><a name=\"introduction\"><\/a>1. Introduction<\/h2>\n<p>Along this tutorial we have seen how <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> penetrated into every aspect of the typical <a href=\"https:\/\/www.java.com\/en\/\">Java<\/a> application lifecycle: build, development, testing and deployment. In this part we are going to focus on the one of the increasingly important topics of continuous integration.<\/p>\n<p>Although the market of the continuous integration (and continuous delivery) solutions is overcrowded, for better or worse, there is one product which stands still for years and is very close to the heart of every <a href=\"https:\/\/www.java.com\/en\/\">Java<\/a> developer out there. Yes, your guess is right, it is <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a>, the leading open source automation server.<\/p>\n<h2><a name=\"why\"><\/a>2. Why Jenkins?<\/h2>\n<p>For many, the relationship with <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> falls into hate or love category. Leaving the history behind, the second generation of <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> platform, namely <code>2.x<\/code> release branch, hit the ecosystem like a tornado and literally became a game changer.<\/p>\n<p>To make a point, here are the key features of <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> which are distinguishing it from many other competing solutions:<\/p>\n<ul>\n<li>Built-in support for delivery pipelines (also known as &#8220;pipeline as a code&#8221;)<\/li>\n<li>Improved UI and usability<\/li>\n<li>Very easy to install and configure<\/li>\n<li>Exceptional extensibility and very rich plugins ecosystem<\/li>\n<li>Distributed deployment<\/li>\n<li>Automation<\/li>\n<\/ul>\n<p>To illustrate most of them in action, we are going to put what we have learned about <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> so far at work and build our own <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> image. Not only that, we would integrate it with <a href=\"https:\/\/git-scm.com\/\">Git<\/a> (using tremendously popular <a href=\"https:\/\/github.com\/\">Github<\/a> hosting), configure the tooling, create multibranch pipeline for our <a href=\"https:\/\/projects.spring.io\/spring-boot\/\">Spring Boot<\/a> application we have <a href=\"https:\/\/www.javacodegeeks.com\/2017\/11\/docker-java-developers-build-docker.html\">developed previously<\/a>. And, last but not least, we are going to do all that in a completely automated fashion. If it sounds exciting, let us get started.<\/p>\n<h2><a name=\"pipeline\"><\/a>3. Pipeline as a code<\/h2>\n<p>One of the recent trends in the industry is to treat your continuous delivery pipelines as a code, storing them in the source control system and versioning if necessarily. If you are looking to introduce something like that into your projects, <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> is a perfect match, no doubts.<\/p>\n<p>There are multiple favors of pipeline configurations which <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> supports out of the box. The one we are going to use in this part of the tutorial is to keep the pipeline definition, <a href=\"https:\/\/jenkins.io\/doc\/book\/pipeline\/jenkinsfile\/\">Jenkinsfile<\/a>, along with your project, in the root of the repository tree.<\/p>\n<p>As you <a href=\"https:\/\/www.javacodegeeks.com\/2017\/11\/docker-java-developers-build-docker.html\">may remember<\/a>, our <a href=\"https:\/\/projects.spring.io\/spring-boot\/\">Spring Boot<\/a> application requires <a href=\"https:\/\/www.java.com\/en\/\">Java<\/a> and is using <a href=\"https:\/\/gradle.org\/\">Gradle<\/a> for dependency management. Keeping that in mind, here is an example we could come up with as a simple pipeline to build such a project in <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a>.<\/p>\n<pre class=\"brush:bash\">pipeline {\n  agent any\n\n  options {\n    disableConcurrentBuilds()\n    buildDiscarder(logRotator(numToKeepStr:'5'))\n  }\n\n  triggers {\n    pollSCM('H\/15 * * * *')\n  }\n\n  tools {\n    jdk \"jdk-8u162\"\n  }\n\n  environment {\n    JAVA_HOME=\"${jdk}\"\n  }\n\n  stages {\n    stage('Cleanup before build') {\n      steps {\n        cleanWs()\n      }\n    }\n\n    stage('Checkout from Github') {\n      steps {\n        checkout scm\n      }\n    }\n\n    stage('Build') {\n      steps {\n        script {\n          def rtGradle = Artifactory.newGradleBuild()\n          rtGradle.tool = \"Gradle 4.3.0\"\n          rtGradle.run buildFile: 'build.gradle', tasks: 'clean build'\n        }\n      }\n    }\n  }\n\n  post {\n    always {\n      archiveArtifacts artifacts: 'build\/libs\/*.jar', fingerprint: true\n    }\n  }\n}<\/pre>\n<p>I hope you would agree, it is surprisingly very clean and expressive. The only thing we need to do is co-locate this definition with the project in question.<\/p>\n<p>If you would like to see our <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> deployment in action, at this time it would be good to create a new <a href=\"https:\/\/github.com\/\">Github<\/a> (or <a href=\"https:\/\/bitbucket.org\/\u200e\">Bitbucket<\/a>, <a href=\"https:\/\/bitbucket.org\/\u200e\">Gitlab<\/a>, \u2026) repository with <a href=\"https:\/\/projects.spring.io\/spring-boot\/\">Spring Boot<\/a> application inside.<\/p>\n<h2><a name=\"jenkins\"><\/a>4. Jenkins and Docker<\/h2>\n<p>To our luck, <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> maintains the official <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> images <a href=\"https:\/\/hub.docker.com\/r\/jenkins\/jenkins\/\">repository<\/a>, so it becomes very easy to integrate and extend it for your needs. As of now, the latest long-term support version of <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> is <code>2.89.4<\/code> and this is what we are going to use in this part of the tutorial.<\/p>\n<p>What is interesting, <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> also has a comprehensive <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> support (as part of the pipeline declarations and the job definitions) and we are going to look at it as well.<\/p>\n<p>With the <a href=\"https:\/\/hub.docker.com\/r\/jenkins\/jenkins\/\">official images<\/a> available out of the box, it is simple to build your own image by extending one of those, for example.<\/p>\n<pre class=\"brush:bash\">FROM jenkins\/jenkins:lts\n<\/pre>\n<p>Good start but it would be great to preinstall some plugins which we think would be useful to us. It is straightforward to do with the <code>install-plugins.sh<\/code> script already provided.<\/p>\n<pre class=\"brush:bash\">RUN \/usr\/local\/bin\/install-plugins.sh docker-plugin docker-slaves workflow-scm-step workflow-cps  pipeline-model-definition docker-workflow cloudbees-folder timestamper workflow-aggregator git gradle pipeline-maven artifactory maven-plugin ssh-slaves build-timeout pipeline-stage-view  antisamy-markup-formatter mailer matrix-auth junit findbugs maven-invoker-plugin pipeline-build-step credentials ws-cleanup email-ext ldap pam-auth subversion blueocean credentials-binding\n<\/pre>\n<p>There are quite a lot of the plugins listed here, to be honest, but this is just a tiny piece of what is available. The <a href=\"https:\/\/plugins.jenkins.io\/\">plugins ecosystem<\/a> around <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> is just astonishing. At this point we would need to generate a key pair to use with <a href=\"https:\/\/github.com\/\">Github<\/a> (or <a href=\"https:\/\/bitbucket.org\/\u200e\">Bitbucket<\/a>, <a href=\"https:\/\/bitbucket.org\/\u200e\">Gitlab<\/a>, \u2026) repository.<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<pre class=\"brush:bash\">ssh-keygen -t rsa -C jenkins@javacodegeeks.com<\/pre>\n<p>And copy this key pair to our image:<\/p>\n<pre class=\"brush:xml\">COPY github\/id_rsa \/var\/jenkins_home\/.ssh\/\nCOPY github\/id_rsa.pub \/var\/jenkins_home\/.ssh\/\n<\/pre>\n<p>Moving on, we would certainly aim to run <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> using secure protocol, <a href=\"https:\/\/en.wikipedia.org\/wiki\/HTTPS\">HTTPS<\/a>, so we would have to generate a self-signed certificate along with the private key.<\/p>\n<pre class=\"brush:xml\">openssl req  -x509  -sha256  -newkey rsa:2048  -keyout jenkins.key  -out jenkins.crt  -days 1024  -nodes\nopenssl rsa -in jenkins.key -out jenkins.rsa\n<\/pre>\n<p>Let us add the generated files to the image as well:<\/p>\n<pre class=\"brush:xml\">COPY jenkins\/jenkins.crt \/var\/lib\/jenkins\/cert\nCOPY jenkins\/jenkins.rsa \/var\/lib\/jenkins\/pk\n<\/pre>\n<p>Awesome, we are pretty much done with the environment part. Let us finalize it with a couple of environment variables.<\/p>\n<pre class=\"brush:xml\">ENV JENKINS_SLAVE_AGENT_PORT 50001\nENV JAVA_OPTS -Djenkins.install.runSetupWizard=false\nENV JENKINS_OPTS --httpPort=-1 --httpsPort=8083 --httpsCertificate=\/var\/lib\/jenkins\/cert --httpsPrivateKey=\/var\/lib\/jenkins\/pk\n<\/pre>\n<p>To keep things simple, it would be great to pre-configure the administrative account so we could login right away with known to us credentials.<\/p>\n<pre class=\"brush:bash\">ENV JENKINS_USER admin\nENV JENKINS_PASS ef8a7543087c4b999cbecdd57696f557\n<\/pre>\n<p>Also, it would be good to know the URL to connect to Git-compatible repository and fetch the project we are going to build.<\/p>\n<pre class=\"brush:bash\">ENV GIT_URL \"&lt;Git URL to repo&gt;\"\n<\/pre>\n<p>Next come the important ones but not very obvious. We would need the username and password in order to be able to download the official <a href=\"http:\/\/www.oracle.com\/technetwork\/java\/javase\/overview\/index.html\">Oracle JDK<\/a> distribution (as we all remember, the licensing agreement should be accepted before doing that).<\/p>\n<pre class=\"brush:bash\">ENV ORACLE_JDK_USER \"&lt;username&gt;\"\nENV ORACLE_JDK_PASSWORD \"&lt;password&gt;\"\n<\/pre>\n<p>If we just build the image at this stage and run the container out of it, we would end up with a fully functional <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> instance but without any tooling, security or jobs configured. As our goal is full automation, we are going to use <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> scripting (based on <a href=\"http:\/\/groovy-lang.org\/\">Groovy<\/a>) capabilities to accomplish that.<\/p>\n<p>The uncomplicated example of the script would be a good starting point to understand the core idea behind <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> automation, here is the <code>init.groovy<\/code> one.<\/p>\n<pre class=\"brush:groovy\">def instance = Jenkins.getInstance()\ninstance.setNumExecutors(5)\ninstance.setSlaveAgentPort([55001])\n<\/pre>\n<p>It does not look scary at all. Progressively adding more meat, let us take a look on the next script which configures security setting to access <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a>\u00a0 instance, <code>security.groovy<\/code>.<\/p>\n<pre class=\"brush:groovy\">\/\/ Get system environment\ndef env = System.getenv()\ndef instance = Jenkins.getInstance()\ninstance.setSecurityRealm(new HudsonPrivateSecurityRealm(false))\ninstance.setAuthorizationStrategy(new GlobalMatrixAuthorizationStrategy())\n\ndef user = instance.getSecurityRealm().createAccount(env.JENKINS_USER, env.JENKINS_PASS)\nuser.save()\n\ninstance.getAuthorizationStrategy().add(Jenkins.ADMINISTER, env.JENKINS_USER)\ninstance.save()\n<\/pre>\n<p>You can also spot how we use the <code>JENKINS_USER<\/code> and <code>JENKINS_PASS<\/code> environment variables from the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/\">Dockerfile<\/a> definition above. Moving forward, the next thing we are going to do is to store the private key (which we have copied to the image before) to access the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Version_control\">SCM<\/a> of our choice, scripted in the <code>credentials.groovy<\/code>.<\/p>\n<pre class=\"brush:groovy\">def instance = Jenkins.getInstance()\nString keyfile = \"\/var\/jenkins_home\/.ssh\/id_rsa\"\ndef domain = Domain.global()\ndef store = instance.getExtensionList('com.cloudbees.plugins.credentials.SystemCredentialsProvider')[0].getStore()\n\ndef credentials = new BasicSSHUserPrivateKey(\n     CredentialsScope.GLOBAL,\n     \"22d9d94b-2794-4d0c-8576-accf87764d0f\",\n     \"jenkins\",\n     new BasicSSHUserPrivateKey.FileOnMasterPrivateKeySource(keyfile),\n     \"\",\n     \"\"\n)\n\nstore.addCredentials(domain, credentials)\n<\/pre>\n<p>As we have decided to focus on <a href=\"https:\/\/projects.spring.io\/spring-boot\/\">Spring Boot<\/a> application, and already come up with a <a href=\"https:\/\/jenkins.io\/doc\/book\/pipeline\/jenkinsfile\/\">Jenkinsfile<\/a> for that, it would be good to preinstall <a href=\"http:\/\/www.oracle.com\/technetwork\/java\/javase\/overview\/index.html\">Oracle JDK 8<\/a> (latest version is <code>8u162<\/code>) and <a href=\"https:\/\/gradle.org\/\">Gradle<\/a> tooling (the version we use is <code>4.3.0<\/code>, although not latest but let us stick to it). The <code>jdk.groovy<\/code> snippet is taking care of <a href=\"http:\/\/www.oracle.com\/technetwork\/java\/javase\/overview\/index.html\">Oracle JDK<\/a> configuration.<\/p>\n<pre class=\"brush:groovy\">def env = System.getenv()\ndef instance = Jenkins.getInstance()\ndef descriptor = instance.getDescriptor(\"hudson.model.JDK\")\ndef installations = []\ndef installer = new JDKInstaller(\"jdk-8u162-oth-JPR\", true)\ndef installerProps = new InstallSourceProperty([installer])\ndef installation = new JDK(\"jdk-8u162\", \"\", [installerProps])\ninstallations.push(installation)\n\ndescriptor.setInstallations(installations.toArray(new JDK[0]))\ndescriptor.save()\n\ndef jdkInstaller = instance.getDescriptor(\"hudson.tools.JDKInstaller\")\njdkInstaller.doPostCredential(env.ORACLE_JDK_USER, env.ORACLE_JDK_PASSWORD)\n<\/pre>\n<p>Please notice the mandatory step to configure username and password to download the <a href=\"http:\/\/www.oracle.com\/technetwork\/java\/javase\/overview\/index.html\">JDK<\/a> (using <code>ORACLE_JDK_USER<\/code> and <code>ORACLE_JDK_PASSWORD<\/code> environment variables). On the other side, <code>gradle.groovy<\/code> is looking much simpler.<\/p>\n<pre class=\"brush:groovy\">def instance = Jenkins.getInstance()\ndef gradle = new GradleInstallation(\"Gradle 4.3.0\", \"\", [new InstallSourceProperty([new GradleInstaller(\"4.3.0\")])])\ndef descriptor = instance.getDescriptorByType(GradleInstallation.DescriptorImpl)\ndescriptor.setInstallations(gradle)\ndescriptor.save()\n<\/pre>\n<p>Terrific so far, but the most interesting script is left in the end. It is the pipeline configuration stored in the <code>pipeline.groovy<\/code>.<\/p>\n<pre class=\"brush:groovy\">def env = System.getenv()\ndef instance = Jenkins.getInstance()\n\ndef project = instance.createProject(WorkflowMultiBranchProject, 'spring-boot-webapp-pipeline')\nGitSCMSource gitSCMSource = new GitSCMSource(null, env.GIT_URL, \"22d9d94b-2794-4d0c-8576-accf87764d0f\", \"*\", \"\", false)\nproject.getSourcesList().add(new BranchSource(gitSCMSource))\n<\/pre>\n<p>Please notice how we reference the credentials preconfigured in the <code>credentials.groovy<\/code> by using the unique identifier, <code>22d9d94b-2794-4d0c-8576-accf87764d0f<\/code>.\u00a0The URL to <a href=\"https:\/\/git-scm.com\/\">Git<\/a> repository comes from the environment variable <code>GIT_URL<\/code>.<\/p>\n<p>And as the last step, let us copy all the scripts to our image to give <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> a chance to execute them during the initialization phase.<\/p>\n<pre class=\"brush:bash\">COPY scripts\/init.groovy \/usr\/share\/jenkins\/ref\/init.groovy.d\/init.groovy\nCOPY scripts\/credentials.groovy \/usr\/share\/jenkins\/ref\/init.groovy.d\/credentials.groovy\nCOPY scripts\/pipeline.groovy \/usr\/share\/jenkins\/ref\/init.groovy.d\/pipeline.groovy\nCOPY scripts\/security.groovy \/usr\/share\/jenkins\/ref\/init.groovy.d\/security.groovy\nCOPY scripts\/jdk.groovy \/usr\/share\/jenkins\/ref\/init.groovy.d\/jdk.groovy\nCOPY scripts\/gradle.groovy \/usr\/share\/jenkins\/ref\/init.groovy.d\/gradle.groovy\n<\/pre>\n<p>Awesome, the only thing which we have to do manually (but one time only) is to authorize <code>github\/id_rsa.pub<\/code> key to have read-only access to your <a href=\"https:\/\/github.com\/\">Github<\/a> (or <a href=\"https:\/\/bitbucket.org\/\u200e\">Bitbucket<\/a>, <a href=\"https:\/\/bitbucket.org\/\u200e\">Gitlab<\/a>, \u2026) repository. When it is done, we could go ahead and build the image:<\/p>\n<pre class=\"brush:bash\">docker build . --tag jenkins:jcg<\/pre>\n<p>And run our <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> container right away.<\/p>\n<pre class=\"brush:bash\">docker run --rm -p 8083:8083 -p 50001:50001 -v \/var\/run\/docker.sock:\/var\/run\/docker.sock --privileged jenkins:jcg\n<\/pre>\n<p>[ulp id=&#8217;MD25RnPuC2vrVItl&#8217;]<br \/>\n&nbsp;<br \/>\nOnce the container is started, we could navigate to <a href=\"https:\/\/localhost:8083\">https:\/\/localhost:8083<\/a> and use the username <code>admin<\/code> and password <code>ef8a7543087c4b999cbecdd57696f557<\/code> to login, scan the pipeline, wait for the build and check out our <code>spring-boot-webapp-pipeline<\/code> job status.<\/p>\n<p><figure id=\"attachment_74032\" aria-describedby=\"caption-attachment-74032\" style=\"width: 860px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/pipeline-jcg.png\"><img decoding=\"async\" class=\"wp-image-74032 size-full\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/pipeline-jcg.png\" alt=\"\" width=\"860\" height=\"179\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/pipeline-jcg.png 860w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/pipeline-jcg-300x62.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/pipeline-jcg-768x160.png 768w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><figcaption id=\"caption-attachment-74032\" class=\"wp-caption-text\">Pipeline job<\/figcaption><\/figure><\/p>\n<p>All is looking green, as any healthy project should be looking all the time. It would be nice to make sure that our tooling has been configured properly.<\/p>\n<p><figure id=\"attachment_74033\" aria-describedby=\"caption-attachment-74033\" style=\"width: 860px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/jdk-jcg.png\"><img decoding=\"async\" class=\"wp-image-74033 size-full\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/jdk-jcg.png\" alt=\"\" width=\"860\" height=\"327\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/jdk-jcg.png 860w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/jdk-jcg-300x114.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/jdk-jcg-768x292.png 768w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><figcaption id=\"caption-attachment-74033\" class=\"wp-caption-text\">JDK tooling<\/figcaption><\/figure><br \/>\n<figure id=\"attachment_74034\" aria-describedby=\"caption-attachment-74034\" style=\"width: 860px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/gradle-jcg.png\"><img decoding=\"async\" class=\"wp-image-74034 size-full\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/gradle-jcg.png\" alt=\"\" width=\"860\" height=\"304\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/gradle-jcg.png 860w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/gradle-jcg-300x106.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/gradle-jcg-768x271.png 768w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><figcaption id=\"caption-attachment-74034\" class=\"wp-caption-text\">Gradle tooling<\/figcaption><\/figure><\/p>\n<p>Also, it will not hurt to verify that out pipeline is configured with correct repository and is pointing to the right credentials to use.<\/p>\n<p><figure id=\"attachment_74035\" aria-describedby=\"caption-attachment-74035\" style=\"width: 860px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/branch-source-jcg.png\"><img decoding=\"async\" class=\"wp-image-74035 size-full\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/branch-source-jcg.png\" alt=\"\" width=\"860\" height=\"410\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/branch-source-jcg.png 860w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/branch-source-jcg-300x143.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/branch-source-jcg-768x366.png 768w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><figcaption id=\"caption-attachment-74035\" class=\"wp-caption-text\">Git branch source<\/figcaption><\/figure><\/p>\n<p>The best confirmation that things have been set in place properly is to check that pipeline and all its stages have been executed successfully.<\/p>\n<p><figure id=\"attachment_74036\" aria-describedby=\"caption-attachment-74036\" style=\"width: 860px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/build-jcg.png\"><img decoding=\"async\" class=\"wp-image-74036 size-full\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/build-jcg.png\" alt=\"\" width=\"860\" height=\"226\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/build-jcg.png 860w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/build-jcg-300x79.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/build-jcg-768x202.png 768w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><figcaption id=\"caption-attachment-74036\" class=\"wp-caption-text\">Build stages<\/figcaption><\/figure><\/p>\n<p>In case you are looking for modern and fancier web UI, <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> is offering such kind of user experience with <a href=\"https:\/\/jenkins.io\/doc\/book\/blueocean\/\">Blue Ocean<\/a>, designed from the ground up for <a href=\"https:\/\/jenkins.io\/doc\/book\/pipeline\/\">Jenkins Pipeline<\/a>.<\/p>\n<p><figure id=\"attachment_74037\" aria-describedby=\"caption-attachment-74037\" style=\"width: 860px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/blueocean-jcg.png\"><img decoding=\"async\" class=\"wp-image-74037 size-full\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/blueocean-jcg.png\" alt=\"\" width=\"860\" height=\"339\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/blueocean-jcg.png 860w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/blueocean-jcg-300x118.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/blueocean-jcg-768x303.png 768w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><figcaption id=\"caption-attachment-74037\" class=\"wp-caption-text\">Blue Ocean<\/figcaption><\/figure><\/p>\n<p>We could have declared success at this point, but to be fair, the need to install tooling and whatnot complicates the automation process. Any chance we could make it simpler? Yes, for sure, and the key player here is once again <a href=\"https:\/\/www.docker.com\/\">Docker<\/a>.<\/p>\n<h2><a name=\"docker\"><\/a>5. Docker in Jenkins<\/h2>\n<p>As we mentioned already, <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> has an outstanding <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> support fulfilled by fair number of plugins with <a href=\"https:\/\/plugins.jenkins.io\/docker-plugin\">Docker plugin<\/a> and <a href=\"https:\/\/plugins.jenkins.io\/docker-workflow\">Docker Pipeline plugin<\/a> being the keys ones. What it means practically is that your pipeline (or other kind of job) may spin up containers to run the build (and any other tasks or stage) on them.<\/p>\n<p>The best way to illustrate the difference is to modify our <a href=\"https:\/\/jenkins.io\/doc\/book\/pipeline\/jenkinsfile\/\">Jenkinsfile<\/a> from the previous section to use <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> agent instead of predefined tooling.<\/p>\n<pre class=\"brush:bash\">pipeline {\n  agent {\n    docker {\n      image 'gradle:4.3.0-jdk8-alpine'\n    }\n  }\n\n  options {\n    disableConcurrentBuilds()\n    buildDiscarder(logRotator(numToKeepStr:'5'))\n  }\n\n  triggers {\n    pollSCM('H\/15 * * * *')\n  }\n\n  stages {\n    stage('Cleanup before build') {\n      steps {\n        cleanWs()\n      }\n    }\n\n    stage('Checkout from Github') {\n      steps {\n        checkout scm\n      }\n    }\n\n    stage('Build') {\n      steps {\n        sh 'gradle build'\n      }\n    }\n  }\n\n  post {\n    always {\n      archiveArtifacts artifacts: 'build\/libs\/*.jar', fingerprint: true\n    }\n  }\n}\n<\/pre>\n<p>This pipeline looks more compact. We get rid of quite a few definitions (and practically could get rid of some initialization scripts as well). When we commit this new <a href=\"https:\/\/jenkins.io\/doc\/book\/pipeline\/jenkinsfile\/\">Jenkinsfile<\/a> to our existing repository (overriding the current one) we should observe a bit different set of stages but the build is still green.<\/p>\n<p><figure id=\"attachment_74038\" aria-describedby=\"caption-attachment-74038\" style=\"width: 860px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/build-docker-jcg.png\"><img decoding=\"async\" class=\"wp-image-74038 size-full\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/build-docker-jcg.png\" alt=\"\" width=\"860\" height=\"215\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/build-docker-jcg.png 860w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/build-docker-jcg-300x75.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/build-docker-jcg-768x192.png 768w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><figcaption id=\"caption-attachment-74038\" class=\"wp-caption-text\">Build stages with Docker<\/figcaption><\/figure><\/p>\n<p>This is just one example of <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> integration with <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a>, there are tons of different ways you could leverage <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> \u00a0to push the limits of your continuous integration (and delivery) processes to perfection.<\/p>\n<p>There is one more thing to mention here before we wrap up the discussion. Because we are running <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> in <a href=\"https:\/\/www.docker.com\/\">Docker<\/a>, and <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a> itself executes job\/stage steps in <a href=\"https:\/\/www.docker.com\/\">Docker<\/a>, such model of containers usage is known as <code>Docker-in-Docker<\/code> (or shortly <code>DinD<\/code>). There are quite a few things to be aware of when you are running <code>DinD<\/code> environments, brilliantly summarized by <a href=\"https:\/\/jpetazzo.github.io\/2015\/09\/03\/do-not-use-docker-in-docker-for-ci\/\">J\u00e9r\u00f4me Petazzoni in the blog post<\/a>. Please check it out if you are seriously considering this model.<\/p>\n<h2><a name=\"conclusions\"><\/a>6. Conclusions<\/h2>\n<p>In this very last part of the tutorial we have looked at quite a practical application of <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> by deploying and configuring continuous integration platform (based on <a href=\"https:\/\/jenkins.io\/\">Jenkins<\/a>) in a fully automated fashion. We created a build pipelines for one of the applications we <a href=\"https:\/\/www.javacodegeeks.com\/2017\/11\/docker-java-developers-build-docker.html\">have developed previously<\/a> and demonstrated the use case of running <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> inside live <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> containers.<\/p>\n<p>With that, our tutorial comes to the end. It was a long but hopefully useful journey, where we have learned something practical and helpful. The conclusion of this whole series could be nicely summarized by restating that <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> is terrific piece of technology which is capable to push us to the new horizons.<\/p>\n<p>The complete scripts and project sources are available for download:<\/p>\n<ul>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/multibranch-pipeline.zip\">Spring Boot web application with Jenkinsfile<\/a><\/li>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/multibranch-pipeline-docker.zip\">Jenkinsfile with Docker agent<\/a><\/li>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/02\/jenkins.zip\">Jenkins Docker image and scripts<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>This article is part of our Academy Course titled Docker Tutorial for Java Developers. In this course, we provide a series of tutorials so that you can develop your own Docker based applications. We cover a wide range of topics, from Docker over command line, to development, testing, deployment and continuous integration. With our straightforward &hellip;<\/p>\n","protected":false},"author":141,"featured_media":24013,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[14],"tags":[936],"class_list":["post-73864","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","tag-docker"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Docker for Java Developers: Continuous Integration on Docker - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"This article is part of our Academy Course titled Docker Tutorial for Java Developers. In this course, we provide a series of tutorials so that you can\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Docker for Java Developers: Continuous Integration on Docker - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"This article is part of our Academy Course titled Docker Tutorial for Java Developers. In this course, we provide a series of tutorials so that you can\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2018-02-27T09:17:20+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-12-11T08:33:36+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/04\/docker-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Andrey Redko\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andrey Redko\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/02\\\/docker-java-developers-continuous-integration-docker.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/02\\\/docker-java-developers-continuous-integration-docker.html\"},\"author\":{\"name\":\"Andrey Redko\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/771a6504862edc45322776832cbce413\"},\"headline\":\"Docker for Java Developers: Continuous Integration on Docker\",\"datePublished\":\"2018-02-27T09:17:20+00:00\",\"dateModified\":\"2023-12-11T08:33:36+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/02\\\/docker-java-developers-continuous-integration-docker.html\"},\"wordCount\":1901,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/02\\\/docker-java-developers-continuous-integration-docker.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2014\\\/04\\\/docker-logo.jpg\",\"keywords\":[\"Docker\"],\"articleSection\":[\"DevOps\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/02\\\/docker-java-developers-continuous-integration-docker.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/02\\\/docker-java-developers-continuous-integration-docker.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/02\\\/docker-java-developers-continuous-integration-docker.html\",\"name\":\"Docker for Java Developers: Continuous Integration on Docker - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/02\\\/docker-java-developers-continuous-integration-docker.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/02\\\/docker-java-developers-continuous-integration-docker.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2014\\\/04\\\/docker-logo.jpg\",\"datePublished\":\"2018-02-27T09:17:20+00:00\",\"dateModified\":\"2023-12-11T08:33:36+00:00\",\"description\":\"This article is part of our Academy Course titled Docker Tutorial for Java Developers. In this course, we provide a series of tutorials so that you can\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/02\\\/docker-java-developers-continuous-integration-docker.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/02\\\/docker-java-developers-continuous-integration-docker.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/02\\\/docker-java-developers-continuous-integration-docker.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2014\\\/04\\\/docker-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2014\\\/04\\\/docker-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/02\\\/docker-java-developers-continuous-integration-docker.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"DevOps\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/devops\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Docker for Java Developers: Continuous Integration on Docker\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/771a6504862edc45322776832cbce413\",\"name\":\"Andrey Redko\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g\",\"caption\":\"Andrey Redko\"},\"description\":\"Andriy is a well-grounded software developer with more then 12 years of practical experience using Java\\\/EE, C#\\\/.NET, C++, Groovy, Ruby, functional programming (Scala), databases (MySQL, PostgreSQL, Oracle) and NoSQL solutions (MongoDB, Redis).\",\"sameAs\":[\"http:\\\/\\\/aredko.blogspot.com\\\/\",\"http:\\\/\\\/ca.linkedin.com\\\/in\\\/aredko\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/andrey-redko\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Docker for Java Developers: Continuous Integration on Docker - Java Code Geeks","description":"This article is part of our Academy Course titled Docker Tutorial for Java Developers. In this course, we provide a series of tutorials so that you can","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html","og_locale":"en_US","og_type":"article","og_title":"Docker for Java Developers: Continuous Integration on Docker - Java Code Geeks","og_description":"This article is part of our Academy Course titled Docker Tutorial for Java Developers. In this course, we provide a series of tutorials so that you can","og_url":"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2018-02-27T09:17:20+00:00","article_modified_time":"2023-12-11T08:33:36+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/04\/docker-logo.jpg","type":"image\/jpeg"}],"author":"Andrey Redko","twitter_card":"summary_large_image","twitter_creator":"@javacodegeeks","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Andrey Redko","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html"},"author":{"name":"Andrey Redko","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/771a6504862edc45322776832cbce413"},"headline":"Docker for Java Developers: Continuous Integration on Docker","datePublished":"2018-02-27T09:17:20+00:00","dateModified":"2023-12-11T08:33:36+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html"},"wordCount":1901,"commentCount":0,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/04\/docker-logo.jpg","keywords":["Docker"],"articleSection":["DevOps"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html","url":"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html","name":"Docker for Java Developers: Continuous Integration on Docker - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/04\/docker-logo.jpg","datePublished":"2018-02-27T09:17:20+00:00","dateModified":"2023-12-11T08:33:36+00:00","description":"This article is part of our Academy Course titled Docker Tutorial for Java Developers. In this course, we provide a series of tutorials so that you can","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/04\/docker-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/04\/docker-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/2018\/02\/docker-java-developers-continuous-integration-docker.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"DevOps","item":"https:\/\/www.javacodegeeks.com\/category\/devops"},{"@type":"ListItem","position":3,"name":"Docker for Java Developers: Continuous Integration on Docker"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/771a6504862edc45322776832cbce413","name":"Andrey Redko","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/16419ce8394173028eddaeb992859862bab50cfcf74589fa9bb9a3dd8bb27518?s=96&d=mm&r=g","caption":"Andrey Redko"},"description":"Andriy is a well-grounded software developer with more then 12 years of practical experience using Java\/EE, C#\/.NET, C++, Groovy, Ruby, functional programming (Scala), databases (MySQL, PostgreSQL, Oracle) and NoSQL solutions (MongoDB, Redis).","sameAs":["http:\/\/aredko.blogspot.com\/","http:\/\/ca.linkedin.com\/in\/aredko"],"url":"https:\/\/www.javacodegeeks.com\/author\/andrey-redko"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/73864","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/141"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=73864"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/73864\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/24013"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=73864"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=73864"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=73864"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}