{"id":70418,"date":"2017-11-14T07:00:16","date_gmt":"2017-11-14T05:00:16","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/?p=70418"},"modified":"2023-12-11T10:27:59","modified_gmt":"2023-12-11T08:27:59","slug":"docker-java-developers-build-docker","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2017\/11\/docker-java-developers-build-docker.html","title":{"rendered":"Docker for Java Developers: Build 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=\"#glass\">2. Under the Magnifying Glass<\/a><\/dt>\n<dt><a href=\"#gradle\">3. Gradle and Docker<\/a><\/dt>\n<dt><a href=\"#gradledocker\">4. Gradle on Docker<\/a><\/dt>\n<dt><a href=\"#maven\">5. Maven and Docker<\/a><\/dt>\n<dt><a href=\"#mavendocker\">6. Maven on Docker<\/a><\/dt>\n<dt><a href=\"#conclusions\">7. Conclusions<\/a><\/dt>\n<dt><a href=\"#next\">8. What\u2019s next<\/a><\/dt>\n<\/dl>\n<\/div>\n<h2><a name=\"introduction\"><\/a>1. Introduction<\/h2>\n<p>Over the first few parts of the tutorial we went through basics of the <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> and the multitude of the ways to interface with it. It is time to apply the knowledge we have acquired to real-world Java projects, starting the discussion from the topic of how <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> affects the well-established build processes and practices.<\/p>\n<p>Fairly speaking, the goal of this section is two-fold. First, we will take a look at how the existing build tools, namely the <a href=\"https:\/\/maven.apache.org\/\">Apache Maven<\/a> and <a href=\"https:\/\/gradle.org\/\">Gradle<\/a>, are helping to package Java applications as <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> containers. Secondly, we will push this idea even further and learn how we could use <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> to entirely encapsulate the build pipeline of our Java applications and produce the final <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> images at the end.<\/p>\n<h2><a name=\"glass\"><\/a>2. Under the Magnifying Glass<\/h2>\n<p>To experiment with, we are going to design two simple (but nonetheless meaningful) Java web applications which would implement and expose the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Representational_state_transfer\">REST(ful) APIs<\/a> for tasks management.<\/p>\n<p>The first application is going to be developed on top of <a href=\"https:\/\/projects.spring.io\/spring-boot\/\">Spring Boot<\/a> and <a href=\"https:\/\/docs.spring.io\/spring\/docs\/current\/spring-framework-reference\/web-reactive.html\">Spring Webflux<\/a>, using <a href=\"https:\/\/gradle.org\/\">Gradle<\/a> as build and dependency management tool. In terms of versions, we will be using <a href=\"https:\/\/projects.spring.io\/spring-boot\/\">Spring Boot<\/a> latest milestone <code>2.0.0.M6<\/code>, <a href=\"https:\/\/docs.spring.io\/spring\/docs\/current\/spring-framework-reference\/web-reactive.html\">Spring Webflux<\/a> latest release <code>5.0.1<\/code> and <a href=\"https:\/\/gradle.org\/\">Gradle<\/a> latest release <code>4.3<\/code>.<\/p>\n<p>The second application, while functionally equivalent to the first one, will be developed on top of another popular Java framework, <a href=\"http:\/\/www.dropwizard.io\/\">Dropwizard<\/a>, this time using <a href=\"https:\/\/maven.apache.org\/\">Apache Maven<\/a> for build and dependency management. In terms of versions, we are going to bring <a href=\"http:\/\/www.dropwizard.io\/\">Dropwizard<\/a> latest release <code>1.2.0<\/code> and <a href=\"https:\/\/maven.apache.org\/\">Apache Maven<\/a> latest release <code>3.5.2<\/code>.<\/p>\n<p>As we mentioned, both applications would implement and expose the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Representational_state_transfer\">REST(ful) APIs<\/a> for tasks management, essentially wrapping the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Create,_read,_update_and_delete\">CRUD<\/a> (create, read, update and delete) operations.<\/p>\n<pre class=\"brush:bash\">    GET     \/tasks\n    POST    \/tasks\n    DELETE  \/tasks\/{id}\n    GET     \/tasks\/{id}\n<\/pre>\n<p>The task itself is modeled as a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Java_Persistence_API\">persistent entity<\/a> which is going to be managed by <a href=\"http:\/\/hibernate.org\/\">Hibernate ORM<\/a> and stored in the <a href=\"https:\/\/dev.mysql.com\/doc\/connector-j\/8.0\/en\/\">MySQL<\/a> relation database.<\/p>\n<pre class=\"brush:java\">@Entity \n@Table(name = \"tasks\")\npublic class Task {\n    @Id\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n    @Column(name = \"id\")\n    private Integer id;\n    \n    @Column(name = \"title\", nullable = false, length = 255)\n    private String title;\n    \n    @Column(name = \"description\", nullable = true, columnDefinition = \"TEXT\")\n    private String description;\n    \n    \/\/ Getters and setters are omitted\n    ...\n}\n<\/pre>\n<p>At this point, the similarities between both applications end and each of them is going to follow its own idiomatic way of development.<\/p>\n<h2><a name=\"gradle\"><\/a>3. Gradle and Docker<\/h2>\n<p>So the ground is set, let us begin the journey by exploring what it takes to integrate <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> into typical <a href=\"https:\/\/gradle.org\/\">Gradle<\/a> build. For this subsection you would need to have <a href=\"https:\/\/gradle.org\/\">Gradle<\/a> <code>4.3<\/code> installed on your development machine. If you don\u2019t have it yet, please follow the <a href=\"https:\/\/gradle.org\/install\/\">installation instructions<\/a> by choosing any suggested method you prefer.<\/p>\n<p>In order to package a typical <a href=\"https:\/\/projects.spring.io\/spring-boot\/\">Spring Boot<\/a> application as a <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> image using <a href=\"https:\/\/gradle.org\/\">Gradle<\/a>\u00a0we just need to include two additional plugins in <code>build.gradle<\/code> file:<\/p>\n<ul>\n<li><a href=\"https:\/\/spring.io\/blog\/2017\/04\/05\/spring-boot-s-new-gradle-plugin\">Spring Boot Gradle<\/a> plugin<\/li>\n<li><a href=\"https:\/\/github.com\/palantir\/gradle-docker\">Palantir Docker Gradle<\/a> plugin (but there are quite a <a href=\"https:\/\/plugins.gradle.org\/search?term=docker\">few alternative options available<\/a>)<\/li>\n<\/ul>\n<p>The build pipeline would basically rely on <a href=\"https:\/\/spring.io\/blog\/2017\/04\/05\/spring-boot-s-new-gradle-plugin\">Spring Boot Gradle<\/a> plugin to produce an <a href=\"https:\/\/stackoverflow.com\/questions\/11947037\/what-is-an-uber-jar\">uber-jar<\/a> (the term often used to describe the technique of generating a single runnable application JAR archive) which will be later used by <a href=\"https:\/\/github.com\/palantir\/gradle-docker\">Palantir Docker Gradle<\/a> to assemble the <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> image. Here is how the build definition, <code>build.gradle<\/code> file, looks like.<\/p>\n<pre class=\"brush:groovy\">buildscript {\n    repositories {\n        maven { url 'https:\/\/repo.spring.io\/libs-milestone' }\n    }\n  \n    dependencies {\n        classpath \"org.springframework.boot:spring-boot-gradle-plugin:2.0.0.M6\"\n    }\n}\n\nplugins {\n    id 'com.palantir.docker' version '0.13.0'\n}\n\napply plugin: \"org.springframework.boot\"\napply plugin: 'java'\napply plugin: 'eclipse'\napply plugin: 'application'\n\nsourceCompatibility = 1.8\ntargetCompatibility = 1.8\n\ndependencies {\n    compile(\"org.flywaydb:flyway-core:4.2.0\")\n    compile(\"org.springframework.boot:spring-boot-starter-webflux:2.0.0.M6\")\n    compile(\"org.springframework.boot:spring-boot-starter-data-jpa:2.0.0.M6\")\n    compile(\"org.springframework.boot:spring-boot-starter-actuator:2.0.0.M6\")\n    compile(\"mysql:mysql-connector-java:8.0.7-dmr\")\n}\n\nrepositories {\n    maven {\n        mavenCentral()\n        url 'https:\/\/repo.spring.io\/libs-milestone'\n    }\n}\n\nspringBoot {\n    mainClassName = \"com.javacodegeeks.spring.AppStarter\"\n}\n\njar {\n    mainClassName = \"com.javacodegeeks.spring.AppStarter\"\n    baseName = 'spring-boot-webapp '\n    version = project.version\n}\n\nbootJar {\n    baseName = 'spring-boot-webapp '\n    version = project.version\n}\n\ndocker {\n    name \"jcg\/spring-boot-webapp:$project.version\"\n    tags 'latest'\n    dependsOn build\n    files bootJar\n    dockerfile file('src\/main\/docker\/Dockerfile')\n    buildArgs([BUILD_VERSION: project.version])\n}\n<\/pre>\n<p>That is actually pretty straightforward, all the meat is essentially inside the <code>docker<\/code> section of the <code>build.gradle<\/code> file. You may also notice that we are using our own <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/\">Dockerfile<\/a>, <code>src\/main\/docker\/Dockerfile<\/code>, to supply the instructions to <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> on how to build the image.<\/p>\n<pre class=\"brush:bash\">FROM openjdk:8-jdk-alpine\nARG BUILD_VERSION\n\nENV DB_HOST localhost\nENV DB_PORT 3306\n\nADD spring-boot-webapp-${BUILD_VERSION}.jar spring-boot-webapp.jar\n\nEXPOSE 19900\n\nENTRYPOINT exec java $JAVA_OPTS -Ddb.host=$DB_HOST -Ddb.port=$DB_PORT -jar \/spring-boot-webapp.jar\n<\/pre>\n<p>Indeed, as simple as it could get. Please notice how we use <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/#arg\">ARG<\/a> instruction (and <code>buildArgs<\/code> setting in <code>build.gradle<\/code> file) to pass the arguments to the image. In this case, we are passing the version of the project in order to locate the final build artifacts. Another interesting detail to look at is the usage of <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/#env\">ENV<\/a> instructions to wire the <a href=\"https:\/\/dev.mysql.com\/doc\/connector-j\/8.0\/en\/\">MySQL<\/a> instance host and port to connect to. And, as you may guess already, the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/#expose\">EXPOSE<\/a> instruction informs <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> that the container listens on the port <code>19900<\/code> at runtime.<\/p>\n<p>Awesome, so what is next? Well, we just need to trigger our <a href=\"https:\/\/gradle.org\/\">Gradle<\/a> build, like that:<\/p>\n<pre class=\"brush:bash\">&gt; gradle clean docker dockerTag\n...\nBUILD SUCCESSFUL in 12s\n15 actionable tasks: 14 executed, 1 up-to-date\n<\/pre>\n<p>The <code>dockerTag<\/code> task is not really necessary but due to this <a href=\"https:\/\/github.com\/palantir\/gradle-docker\/issues\/149\">issue<\/a> reported against <a href=\"https:\/\/github.com\/palantir\/gradle-docker\">Palantir Docker Gradle<\/a> plugin we should explicitly invoke it in order to have our image tagged properly. Let us check if we have our image available locally.<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\">&gt; docker image ls\nREPOSITORY               TAG            IMAGE ID      CREATED             SIZE\njcg\/spring-boot-webapp   0.0.1-SNAPSHOT 65057c7ae9ba  21 seconds ago      133MB\njcg\/spring-boot-webapp   latest         65057c7ae9ba  21 seconds ago      133MB\n...\n<\/pre>\n<p>Nice, the new image is there, right from the oven. We could run it immediately, using <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/cli\/\">docker<\/a> command line tool, but first we need to have the <a href=\"https:\/\/dev.mysql.com\/doc\/connector-j\/8.0\/en\/\">MySQL<\/a> container available somewhere. Luckily, we did it so many times already that it will not puzzle us.<\/p>\n<pre class=\"brush:bash\">docker run --rm -d \\\n  --name mysql \\\n  -e MYSQL_ROOT_PASSWORD='p$ssw0rd' \\\n  -e MYSQL_DATABASE=my_app_db \\\n  -e MYSQL_ROOT_HOST=% \\\n  mysql:8.0.2\n<\/pre>\n<p>Now we are ready to run our application as a <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> container. There are multiple ways we could use to reference the <a href=\"https:\/\/dev.mysql.com\/doc\/connector-j\/8.0\/en\/\">MySQL<\/a> container, with <a href=\"https:\/\/docs.docker.com\/engine\/userguide\/networking\/work-with-networks\/#connect-containers\">user-defined networking<\/a> being the preferred option. For the simple cases like ours we may just refer to it by assigning to <code>DB_HOST<\/code> environment variable the IP address of the running <a href=\"https:\/\/dev.mysql.com\/doc\/connector-j\/8.0\/en\/\">MySQL<\/a> container, for example:<\/p>\n<pre class=\"brush:bash\">docker run -d --rm \\\n  --name spring-boot-webapp \\\n  -p 19900:19900 \\\n  -e DB_HOST=`docker inspect --format '{{ .NetworkSettings.IPAddress }}' mysql` \\\n  jcg\/spring-boot-webapp:0.0.1-SNAPSHOT\n<\/pre>\n<p>By mapping the port <code>19900<\/code> from the container to the host, we could talk to our application by accessing its <a href=\"https:\/\/en.wikipedia.org\/wiki\/Representational_state_transfer\">REST(ful) APIs<\/a> from <a href=\"https:\/\/curl.haxx.se\/\">curl<\/a> using the <code>localhost<\/code> as the host name. Let us do that right away.<\/p>\n<pre class=\"brush:bash\">$ curl -X POST http:\/\/localhost:19900\/tasks \\\n   -d '[{\"title\": \"Task #1\", \"description\": \"Sample Task\"}]' \\\n   -H \"Content-Type: application\/json\"\n\n[\n  {\n    \"id\":1,\n    \"title\":\"Task #1\",\n    \"description\":\"Sample Task\"\n  }\n]\n<\/pre>\n<pre class=\"brush:bash\">$ curl http:\/\/localhost:19900\/tasks\n\n[\n  {\n    \"id\":1,\n    \"title\":\"Task #1\",\n    \"description\":\"Sample Task\"\n  }\n]\n<\/pre>\n<pre class=\"brush:bash\">$ curl http:\/\/localhost:19900\/tasks\/1\n\n{\n  \"id\":1,\n  \"title\":\"Task #1\",\n  \"description\":\"Sample Task\"\n}\n<\/pre>\n<p>There are many moving parts under the hood like, for example, automatic database migrations using <a href=\"https:\/\/flywaydb.org\/\">Flyway<\/a> and out of the box health checks support using <a href=\"https:\/\/docs.spring.io\/spring-boot\/docs\/2.0.0.M5\/reference\/html\/production-ready-endpoints.html\">Spring Boot Actuator<\/a>. Some of them are going to pop up in the upcoming sections of the tutorial but look how simple and natural it is to build and package your <a href=\"https:\/\/projects.spring.io\/spring-boot\/\">Spring Boot<\/a> applications as <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> images using <a href=\"https:\/\/gradle.org\/\">Gradle<\/a>.<\/p>\n<h2><a name=\"gradledocker\"><\/a>4. Gradle on Docker<\/h2>\n<p>It turns out that building <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> images with <a href=\"https:\/\/gradle.org\/\">Gradle<\/a> is not painful at all. But still, the prerequisite to have <a href=\"https:\/\/gradle.org\/\">Gradle<\/a> installed on the target system, along with JDK\/JRE, requires some preliminary work to be done. It may not be an issue let say for development, as it is very likely you would have all of that (and many more) installed anyway.<\/p>\n<p>In the case of cloud deployments or CI\/CD pipelines, this could be an issue though, incurring additional costs in terms of work or\/and maintenance. Could we somehow find a way to get rid of such overhead and rely on <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> entirely? Yes, in fact we can, by adopting <a href=\"https:\/\/docs.docker.com\/engine\/userguide\/eng-image\/multistage-build\/\">multi-stage builds<\/a>, one of the recent additions to the <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> feature set.<\/p>\n<p>If you are wondering how it may help us, here is the idea. Essentially, we are going to follow the regular procedure to build the image from the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/\">Dockerfile<\/a>. But the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/\">Dockerfile<\/a> would actually contain two image definitions. The first one (based on the one of the <a href=\"https:\/\/hub.docker.com\/_\/gradle\/\">official Gradle images<\/a>) instructs the <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> to run the <a href=\"https:\/\/gradle.org\/\">Gradle<\/a> build of our <a href=\"https:\/\/projects.spring.io\/spring-boot\/\">Spring Boot<\/a> application. The second one would pick the binaries produced by the first image and create the final <a href=\"https:\/\/www.docker.com\/\">Docker<\/a>\u00a0 image with our <a href=\"https:\/\/projects.spring.io\/spring-boot\/\">Spring Boot<\/a> application sealed inside (much like we have done before).<\/p>\n<p>It might be better to see it once than trying to explain it. The <code>Dockerfile.build<\/code> file below illustrates this idea in action, using <a href=\"https:\/\/docs.docker.com\/engine\/userguide\/eng-image\/multistage-build\/\">multi-stage build<\/a> instructions.<\/p>\n<pre class=\"brush:bash\">FROM gradle:4.3.0-jdk8-alpine\n\nADD src src\nADD build.gradle .\nADD gradle.properties .\n\nRUN gradle build\n\nFROM openjdk:8-jdk-alpine\nARG BUILD_VERSION\n\nENV DB_HOST localhost\nENV DB_PORT 3306\n\nCOPY --from=0 \/home\/gradle\/build\/libs\/spring-boot-webapp-${BUILD_VERSION}.jar spring-boot-webapp.jar\n\nEXPOSE 19900\n\nENTRYPOINT exec java $JAVA_OPTS -Ddb.host=$DB_HOST -Ddb.port=$DB_PORT -jar \/spring-boot-webapp.jar\n<\/pre>\n<p>The first part of the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/\">Dockerfile<\/a> definition describes the image based on\u00a0 <code>gradle:4.3.0-jdk8-alpine<\/code>. Because our project is quite small, we just copy all the sources inside the image and run <code>gradle build<\/code> command (this command will be executed by <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> while the image is being built). The result of the build would be the <a href=\"https:\/\/stackoverflow.com\/questions\/11947037\/what-is-an-uber-jar\">uber-jar<\/a> which we feed into another image definition, this time based on <code>openjdk:8-jdk-alpine<\/code>.\u00a0This would constitute our final image, which we could produce using <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/cli\/\">docker<\/a> command line tool.<\/p>\n<pre class=\"brush:bash\">docker image build \\\n  --build-arg BUILD_VERSION=0.0.1-SNAPSHOT \\\n  -f Dockerfile.build \\\n  -t jcg\/spring-boot-webapp:latest \\\n  -t jcg\/spring-boot-webapp:0.0.1-SNAPSHOT .\n<\/pre>\n<p>Upon command competition, we should see our newly baked image in the list of the available <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> images.<\/p>\n<pre class=\"brush:bash\">$ docker image ls\nREPOSITORY               TAG            IMAGE ID       CREATED           SIZE\njcg\/spring-boot-webapp   0.0.1-SNAPSHOT  02abf724da64  10 seconds ago    133MB\njcg\/spring-boot-webapp   latest          02abf724da64  10 seconds ago    133MB\n...\n<\/pre>\n<p>There is lot of potential behind <a href=\"https:\/\/docs.docker.com\/engine\/userguide\/eng-image\/multistage-build\/\">multi-stage builds<\/a>, but even for such a simple application as ours they have proven to be worth the attention.<br \/>\n[ulp id=&#8217;MD25RnPuC2vrVItl&#8217;]<br \/>\n&nbsp;<\/p>\n<h2><a name=\"maven\"><\/a>5. Maven and Docker<\/h2>\n<p>Let us switch gears a bit and look at how <a href=\"https:\/\/maven.apache.org\/\">Apache Maven<\/a> rides the build management for <a href=\"http:\/\/www.dropwizard.io\/\">Dropwizard<\/a> applications. For this subsection you would need to have <a href=\"https:\/\/maven.apache.org\/\">Apache Maven<\/a> <code>3.2.5<\/code> installed on your development machine (however if you already have <a href=\"https:\/\/maven.apache.org\/\">Apache Maven<\/a> <code>3.2.1<\/code> or higher, you may just stick to it).<\/p>\n<p>The steps we have to follow are mostly identical to what we have discussed for <a href=\"https:\/\/gradle.org\/\">Gradle<\/a> builds, the changes are essentially only in the plugins to use:<\/p>\n<ul>\n<li><a href=\"https:\/\/maven.apache.org\/plugins\/maven-shade-plugin\/\">Maven Shade<\/a> plugin<\/li>\n<li><a href=\"https:\/\/github.com\/spotify\/docker-maven-plugin\">Spotify Docker Maven<\/a> plugin<\/li>\n<\/ul>\n<p>The <a href=\"https:\/\/maven.apache.org\/plugins\/maven-shade-plugin\/\">Maven Shade<\/a> plugin produces an <a href=\"https:\/\/stackoverflow.com\/questions\/11947037\/what-is-an-uber-jar\">uber-jar<\/a> which will be later used by <a href=\"https:\/\/github.com\/spotify\/docker-maven-plugin\">Spotify Docker Maven<\/a> plugin to build <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> image. Without any fuss, let us take a look at the <code>pom.xml<\/code> file.<\/p>\n<pre class=\"brush:xml\">     \n&lt;project \n  xmlns=http:\/\/maven.apache.org\/POM\/4.0.0\n  xmlns:xsi=http:\/\/www.w3.org\/2001\/XMLSchema-instance\n  xsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0\n                      http:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd\"&gt;\n  &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;\n\n  &lt;groupId&gt;com.javacodegeeks&lt;\/groupId&gt;\n  &lt;artifactId&gt;dropwizard-webapp&lt;\/artifactId&gt;\n  &lt;version&gt;0.0.1-SNAPSHOT&lt;\/version&gt;\n  &lt;packaging&gt;jar&lt;\/packaging&gt;\n\n  &lt;properties&gt;\n      &lt;project.build.sourceEncoding&gt;UTF-8&lt;\/project.build.sourceEncoding&gt;\n  &lt;\/properties&gt;\n\n  &lt;dependencyManagement&gt;\n    &lt;dependencies&gt;\n      &lt;dependency&gt;\n        &lt;groupId&gt;io.dropwizard&lt;\/groupId&gt;\n        &lt;artifactId&gt;dropwizard-bom&lt;\/artifactId&gt;\n        &lt;version&gt;1.2.0&lt;\/version&gt;\n        &lt;type&gt;pom&lt;\/type&gt;\n        &lt;scope&gt;import&lt;\/scope&gt;\n      &lt;\/dependency&gt;\n    &lt;\/dependencies&gt;\n  &lt;\/dependencyManagement&gt;\n\n  &lt;dependencies&gt;\n    &lt;dependency&gt;\n      &lt;groupId&gt;io.dropwizard&lt;\/groupId&gt;\n      &lt;artifactId&gt;dropwizard-core&lt;\/artifactId&gt;\n    &lt;\/dependency&gt;\n\n    &lt;dependency&gt;\n      &lt;groupId&gt;io.dropwizard&lt;\/groupId&gt;\n      &lt;artifactId&gt;dropwizard-hibernate&lt;\/artifactId&gt;\n    &lt;\/dependency&gt;\n        \n    &lt;dependency&gt;\n      &lt;groupId&gt;mysql&lt;\/groupId&gt;\n      &lt;artifactId&gt;mysql-connector-java&lt;\/artifactId&gt;\n      &lt;version&gt;8.0.7-dmr&lt;\/version&gt;\n    &lt;\/dependency&gt;\n\n    &lt;dependency&gt;\n      &lt;groupId&gt;io.dropwizard.modules&lt;\/groupId&gt;\n      &lt;artifactId&gt;dropwizard-flyway&lt;\/artifactId&gt;\n      &lt;version&gt;1.2.0-1&lt;\/version&gt;\n    &lt;\/dependency&gt;\n        \n    &lt;dependency&gt;\n      &lt;groupId&gt;com.google.guava&lt;\/groupId&gt;\n      &lt;artifactId&gt;guava&lt;\/artifactId&gt;\n    &lt;\/dependency&gt;\n    \n    &lt;dependency&gt;\n      &lt;groupId&gt;junit&lt;\/groupId&gt;\n      &lt;artifactId&gt;junit&lt;\/artifactId&gt;\n      &lt;scope&gt;test&lt;\/scope&gt;\n    &lt;\/dependency&gt;\n  &lt;\/dependencies&gt;\n\n  &lt;build&gt;\n    &lt;plugins&gt;\n      &lt;plugin&gt;\n        &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;\n        &lt;artifactId&gt;maven-compiler-plugin&lt;\/artifactId&gt;\n        &lt;version&gt;3.1&lt;\/version&gt;\n        &lt;configuration&gt;\n          &lt;source&gt;1.8&lt;\/source&gt;\n          &lt;target&gt;1.8&lt;\/target&gt;\n        &lt;\/configuration&gt;\n      &lt;\/plugin&gt;\n      &lt;plugin&gt;\n        &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;\n        &lt;artifactId&gt;maven-jar-plugin&lt;\/artifactId&gt;\n        &lt;version&gt;3.0.2&lt;\/version&gt;\n        &lt;configuration&gt;\n          &lt;archive&gt;\n            &lt;manifest&gt;\n              &lt;mainClass&gt;com.javacodegeeks.docker.AllApiApp&lt;\/mainClass&gt;\n            &lt;\/manifest&gt;\n          &lt;\/archive&gt;\n        &lt;\/configuration&gt;\n      &lt;\/plugin&gt;\n      &lt;plugin&gt;\n        &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;\n        &lt;artifactId&gt;maven-shade-plugin&lt;\/artifactId&gt;\n        &lt;version&gt;3.1.0&lt;\/version&gt;\n        &lt;configuration&gt;\n          &lt;filters&gt;\n            &lt;filter&gt;\n              &lt;artifact&gt;*:*&lt;\/artifact&gt;\n              &lt;excludes&gt;\n                &lt;exclude&gt;META-INF\/*.SF&lt;\/exclude&gt;\n                &lt;exclude&gt;META-INF\/*.DSA&lt;\/exclude&gt;\n                &lt;exclude&gt;META-INF\/*.RSA&lt;\/exclude&gt;\n              &lt;\/excludes&gt;\n            &lt;\/filter&gt;\n          &lt;\/filters&gt;\n        &lt;\/configuration&gt;\n        &lt;executions&gt;\n          &lt;execution&gt;\n            &lt;phase&gt;package&lt;\/phase&gt;\n            &lt;goals&gt;\n              &lt;goal&gt;shade&lt;\/goal&gt;\n            &lt;\/goals&gt;\n            &lt;configuration&gt;\n              &lt;transformers&gt;\n                &lt;transformer \nimplementation=\"org.apache.maven.plugins.shade.resource.ServicesResourceTransformer\"\/&gt;\n                &lt;transformer implementation=\"org.apache.maven.plugins.shade.resource.ManifestResourceTransformer\"&gt;                                  \n                  &lt;mainClass&gt;com.javacodegeeks.dw.AppStarter&lt;\/mainClass&gt;\n                &lt;\/transformer&gt;\n              &lt;\/transformers&gt;\n            &lt;\/configuration&gt;\n          &lt;\/execution&gt;\n        &lt;\/executions&gt;\n      &lt;\/plugin&gt;\n      &lt;plugin&gt;\n        &lt;groupId&gt;com.spotify&lt;\/groupId&gt;\n        &lt;artifactId&gt;docker-maven-plugin&lt;\/artifactId&gt;\n        &lt;version&gt;1.0.0&lt;\/version&gt;\n        &lt;configuration&gt;\n          &lt;imageName&gt;jcg\/dropwizard-webapp:${project.version}&lt;\/imageName&gt;\n          &lt;dockerDirectory&gt;src\/main\/docker&lt;\/dockerDirectory&gt;\n          &lt;resources&gt;\n            &lt;resource&gt;\n              &lt;targetPath&gt;\/&lt;\/targetPath&gt;\n              &lt;directory&gt;${project.build.directory}&lt;\/directory&gt;\n              &lt;include&gt;${project.build.finalName}.jar&lt;\/include&gt;\n            &lt;\/resource&gt;\n            &lt;resource&gt;\n              &lt;targetPath&gt;\/&lt;\/targetPath&gt;\n              &lt;directory&gt;${project.basedir}&lt;\/directory&gt;\n              &lt;include&gt;application.yml&lt;\/include&gt;\n            &lt;\/resource&gt;\n          &lt;\/resources&gt;\n          &lt;buildArgs&gt;\n            &lt;BUILD_VERSION&gt;${project.version}&lt;\/BUILD_VERSION&gt;\n          &lt;\/buildArgs&gt;\n          &lt;imageTags&gt;\n            &lt;tag&gt;latest&lt;\/tag&gt;\n          &lt;\/imageTags&gt;\n        &lt;\/configuration&gt;\n      &lt;\/plugin&gt;\n    &lt;\/plugins&gt;\n  &lt;\/build&gt;\n&lt;\/project&gt;\n<\/pre>\n<p>To be fair, it looks considerably more verbose than <a href=\"https:\/\/gradle.org\/\">Gradle<\/a> build, but if we imagine for a second that all <a href=\"https:\/\/en.wikipedia.org\/wiki\/XML\">XML<\/a> tags are gone, we would end up with mostly identical definition, at least in case of <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> plugins. The <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/\">Dockerfile<\/a> is a bit different though:<\/p>\n<pre class=\"brush:bash\">FROM openjdk:8-jdk-alpine\nARG BUILD_VERSION\n\nENV DB_HOST localhost\nENV DB_PORT 3306\n\nADD dropwizard-webapp-${BUILD_VERSION}.jar dropwizard-webapp.jar\nADD application.yml application.yml \nADD docker-entrypoint.sh docker-entrypoint.sh\nRUN chmod a+x \/docker-entrypoint.sh\n\nEXPOSE 19900 19901\n\nENTRYPOINT [\"\/docker-entrypoint.sh\"]\n<\/pre>\n<p>Due to the specifics of <a href=\"http:\/\/www.dropwizard.io\/\">Dropwizard<\/a> application, we have to bundle the configuration file, in our case <code>application.yml<\/code>, along with application. Instead of exposing just one port <code>19900<\/code>, we have to expose another one, <code>19901<\/code>, for administrative tasks. Last but not least, we provide the script to the <a href=\"https:\/\/docs.docker.com\/engine\/reference\/builder\/#entrypoint\">ENTRYPOINT<\/a> \u00a0instruction, the <code>docker-entrypoint.sh<\/code>.<\/p>\n<pre class=\"brush:bash\">#!\/bin\/sh\n\nset -e\njava $JAVA_OPTS -DDB_HOST=$DB_HOST -DDB_PORT=$DB_PORT -jar \/dropwizard-webapp.jar db migrate application.yml\n\nif [ ! $? -ne 0 ]; then\n  exec java $JAVA_OPTS -DDB_HOST=$DB_HOST -DDB_PORT=$DB_PORT -jar \/dropwizard-webapp.jar server application.yml\t\nfi\n\nexec \"$@\"\n<\/pre>\n<p>The reason for adding a bit of complexity here is because by default the <a href=\"https:\/\/github.com\/dropwizard\/dropwizard-flyway\">Dropwizard Flyway<\/a> addon bundle does not perform automatic database schema migrations. We could workaround that but the cleanest way is to run <code>db migrate<\/code> command before starting the <a href=\"http:\/\/www.dropwizard.io\/\">Dropwizard<\/a> application. This is exactly what we do inside the shell script above. Now, it is time to trigger the build!<\/p>\n<pre class=\"brush:bash\">&gt;  mvn clean package docker:build\n\n...\n\nSuccessfully tagged jcg\/dropwizard-webapp:0.0.1-SNAPSHOT\n[INFO] Built jcg\/dropwizard-webapp:0.0.1-SNAPSHOT\n[INFO] Tagging jcg\/dropwizard-webapp:0.0.1-SNAPSHOT with latest\n[INFO] ---------------------------------------------------------\n[INFO] BUILD SUCCESS\n[INFO] ---------------------------------------------------------\n\n...\n<\/pre>\n<p>Let us see if we have our image available locally this time.<\/p>\n<pre class=\"brush:bash\">&gt; docker image ls\nREPOSITORY               TAG            IMAGE ID      CREATED             SIZE\njcg\/dropwizard-webapp    0.0.1-SNAPSHOT fa9c310683b1  20 seconds ago      128MB\njcg\/dropwizard-webapp    latest         fa9c310683b1  20 seconds ago      128MB\n...\n<\/pre>\n<p>Excellent, assuming the <a href=\"https:\/\/dev.mysql.com\/doc\/connector-j\/8.0\/en\/\">MySQL<\/a> container is up and running (this part does not change at all, we could use the same command from the <a href=\"#gradle\">previous section<\/a>), we could just run our <a href=\"http:\/\/www.dropwizard.io\/\">Dropwizard<\/a> application container.<\/p>\n<pre class=\"brush:bash\">docker run -d --rm \\\n  --name dropwizard-webapp \\\n  -p 19900:19900 \\\n  -p 19901:19901 \\\n  -e DB_HOST=`docker inspect --format '{{ .NetworkSettings.IPAddress }}' mysql` \\\n  jcg\/dropwizard-webapp:0.0.1-SNAPSHOT\n<\/pre>\n<p>We also map the ports <code>19900<\/code> and <code>19901<\/code> from the container to the host so we could use <code>localhost<\/code> as the host name in <a href=\"https:\/\/curl.haxx.se\/\">curl<\/a>.<\/p>\n<pre class=\"brush:bash\">$ curl -X POST http:\/\/localhost:19900\/tasks \\\n   -d '[{\"title\": \"Task #1\", \"description\": \"Sample Task\"}]' \\\n   -H \"Content-Type: application\/json\"\n\n[\n  {\n    \"id\":1,\n    \"title\":\"Task #1\",\n    \"description\":\"Sample Task\"\n  }\n]\n<\/pre>\n<pre class=\"brush:bash\">$ curl http:\/\/localhost:19900\/tasks\n\n[\n  {\n    \"id\":1,\n    \"title\":\"Task #1\",\n    \"description\":\"Sample Task\"\n  }\n]\n<\/pre>\n<pre class=\"brush:bash\">$ curl http:\/\/localhost:19900\/tasks\/1\n\n{\n  \"id\":1,\n  \"title\":\"Task #1\",\n  \"description\":\"Sample Task\"\n}\n<\/pre>\n<p>Please take a note that with host port mappings we could run either <code>jcg\/dropwizard-webapp:0.0.1-SNAPSHOT<\/code> container or <code>jcg\/spring-boot-webapp:0.0.1-SNAPSHOT<\/code> container, but not both at the same time, due to the inevitable port conflicts. We just use the same port for convenience but it in most cases you will be using dynamic port bindings and will not see this issue happening.<\/p>\n<h2><a name=\"mavendocker\"><\/a>6. Maven on Docker<\/h2>\n<p>The same technique of using <a href=\"https:\/\/docs.docker.com\/engine\/userguide\/eng-image\/multistage-build\/\">multi-stage builds<\/a> is equally applicable for the projects which use <a href=\"https:\/\/maven.apache.org\/\">Apache Maven<\/a> for build and dependency management (to our luck, there are <a href=\"https:\/\/hub.docker.com\/r\/library\/maven\/\">official Apache Maven images<\/a> published on <a href=\"https:\/\/hub.docker.com\/r\/library\/maven\/\">Docker Hub<\/a>).<\/p>\n<pre class=\"brush:bash\">FROM maven:3.5.2-jdk-8-alpine\n\nADD src src\nADD pom.xml .\n\nRUN mvn package\n\nFROM openjdk:8-jdk-alpine\nARG BUILD_VERSION\n\nENV DB_HOST localhost\nENV DB_PORT 3306\n\nCOPY --from=0 \/target\/dropwizard-webapp-${BUILD_VERSION}.jar dropwizard-webapp.jar\nADD application.yml application.yml \nADD src\/main\/docker\/docker-entrypoint.sh docker-entrypoint.sh\nRUN chmod a+x \/docker-entrypoint.sh\n\nEXPOSE 19900 19901\n\nENTRYPOINT [\"\/docker-entrypoint.sh\"]\n<\/pre>\n<p>Not much to add here once we cracked how the <a href=\"https:\/\/docs.docker.com\/engine\/userguide\/eng-image\/multistage-build\/\">multi-stage builds<\/a> work, so let us build the final image using <a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/cli\/\">docker<\/a> command line tool.<\/p>\n<pre class=\"brush:bash\">docker image build \\\n  --build-arg BUILD_VERSION=0.0.1-SNAPSHOT \\\n  -f Dockerfile.build \\\n  -t jcg\/dropwizard-webapp:latest \\\n  -t jcg\/dropwizard-webapp:0.0.1-SNAPSHOT .\n<\/pre>\n<p>And make sure the image appears in the list of the available <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> images.<\/p>\n<pre class=\"brush:bash\">&gt; docker image ls\nREPOSITORY             TAG             IMAGE ID       CREATED          SIZE\njcg\/dropwizard-webapp  0.0.1-SNAPSHOT  5b006fcc9a1d   26 seconds ago   128MB\njcg\/dropwizard-webapp  latest          5b006fcc9a1d   26 seconds ago   128MB\n...\n<\/pre>\n<p>It is pretty awesome, to be honest. Before finishing up the discussion about <a href=\"https:\/\/docs.docker.com\/engine\/userguide\/eng-image\/multistage-build\/\">multi-stage builds<\/a>, let us touch upon the use case you may certainly run into: checking out the project from the source control system. The examples we have seen so far assume the project is available locally, but we could clone it from the remote repository as part of the <a href=\"https:\/\/docs.docker.com\/engine\/userguide\/eng-image\/multistage-build\/\">multi-stage builds<\/a> definition as well.<\/p>\n<h2><a name=\"conclusions\"><\/a>7. Conclusions<\/h2>\n<p>In this section of the tutorial we have seen a couple of examples on how the popular build and dependency management tools, namely <a href=\"https:\/\/maven.apache.org\/\">Apache Maven<\/a> and <a href=\"https:\/\/gradle.org\/\">Gradle<\/a>, support the packaging of the Java applications as <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> images. We have also spent some time discussing the <a href=\"https:\/\/docs.docker.com\/engine\/userguide\/eng-image\/multistage-build\/\">multi-stage builds<\/a> and the opportunities they open for implementing portable, zero-dependency (literally!) build pipelines.<\/p>\n<h2><a name=\"next\"><\/a>8. What\u2019s next<\/h2>\n<p>In the next section of the tutorial we are going to look at how <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> could simplify the development processes and practices, particularly around dealing with data stores and external (or even internal) services.<\/p>\n<p>The complete project sources are <a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2017\/11\/Section-4.zip\">available for download<\/a>.<\/p>\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-70418","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: Build 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\/2017\/11\/docker-java-developers-build-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: Build 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\/2017\/11\/docker-java-developers-build-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=\"2017-11-14T05:00:16+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-12-11T08:27:59+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=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/11\\\/docker-java-developers-build-docker.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/11\\\/docker-java-developers-build-docker.html\"},\"author\":{\"name\":\"Andrey Redko\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/771a6504862edc45322776832cbce413\"},\"headline\":\"Docker for Java Developers: Build on Docker\",\"datePublished\":\"2017-11-14T05:00:16+00:00\",\"dateModified\":\"2023-12-11T08:27:59+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/11\\\/docker-java-developers-build-docker.html\"},\"wordCount\":1989,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/11\\\/docker-java-developers-build-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\\\/2017\\\/11\\\/docker-java-developers-build-docker.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/11\\\/docker-java-developers-build-docker.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/11\\\/docker-java-developers-build-docker.html\",\"name\":\"Docker for Java Developers: Build on Docker - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/11\\\/docker-java-developers-build-docker.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/11\\\/docker-java-developers-build-docker.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2014\\\/04\\\/docker-logo.jpg\",\"datePublished\":\"2017-11-14T05:00:16+00:00\",\"dateModified\":\"2023-12-11T08:27:59+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\\\/2017\\\/11\\\/docker-java-developers-build-docker.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/11\\\/docker-java-developers-build-docker.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/11\\\/docker-java-developers-build-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\\\/2017\\\/11\\\/docker-java-developers-build-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: Build 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: Build 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\/2017\/11\/docker-java-developers-build-docker.html","og_locale":"en_US","og_type":"article","og_title":"Docker for Java Developers: Build 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\/2017\/11\/docker-java-developers-build-docker.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2017-11-14T05:00:16+00:00","article_modified_time":"2023-12-11T08:27:59+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":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2017\/11\/docker-java-developers-build-docker.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/11\/docker-java-developers-build-docker.html"},"author":{"name":"Andrey Redko","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/771a6504862edc45322776832cbce413"},"headline":"Docker for Java Developers: Build on Docker","datePublished":"2017-11-14T05:00:16+00:00","dateModified":"2023-12-11T08:27:59+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/11\/docker-java-developers-build-docker.html"},"wordCount":1989,"commentCount":2,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/11\/docker-java-developers-build-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\/2017\/11\/docker-java-developers-build-docker.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2017\/11\/docker-java-developers-build-docker.html","url":"https:\/\/www.javacodegeeks.com\/2017\/11\/docker-java-developers-build-docker.html","name":"Docker for Java Developers: Build on Docker - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/11\/docker-java-developers-build-docker.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/11\/docker-java-developers-build-docker.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2014\/04\/docker-logo.jpg","datePublished":"2017-11-14T05:00:16+00:00","dateModified":"2023-12-11T08:27:59+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\/2017\/11\/docker-java-developers-build-docker.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2017\/11\/docker-java-developers-build-docker.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2017\/11\/docker-java-developers-build-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\/2017\/11\/docker-java-developers-build-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: Build 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\/70418","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=70418"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/70418\/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=70418"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=70418"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=70418"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}