DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
11 Monitoring and Observability Tools for 2023
Learn more
  1. DZone
  2. Software Design and Architecture
  3. Cloud Architecture
  4. Using Docker to Deploy a Containerized Java Web App

Using Docker to Deploy a Containerized Java Web App

Docker can be used to create a familiar environment for devs to work on. Using a simple API, you can build a Docker image and deploy it to suit your needs.

Nic Raboy user avatar by
Nic Raboy
·
May. 03, 17 · Tutorial
Like (12)
Save
Tweet
Share
31.76K Views

Join the DZone community and get the full member experience.

Join For Free

not too long ago i wrote about containerizing a node.js restful api and couchbase server to demonstrate how easy it is to deploy web applications in a quick and reliable fashion. in that guide, we created a simple api, built a docker image from it, deployed it as a container, and deployed couchbase as a container. however, i understand that not everyone is familiar with node.js.

here we’re going to build a simple java restful api using spring boot, create a docker image from it, and deploy it as a container with couchbase . this will create a familiar environment for java developers.

this tutorial requires that you have a docker installed and configured on your machine. with docker, we’ll be creating custom docker images and deploying them as containers.

create a custom docker image for couchbase server

let’s start with creating a custom docker image for couchbase server. while an official couchbase image exists, it isn’t automatically provisioned when deployed. our custom image will automatically provision itself upon deployment as a container.

somewhere on your computer create a directory with a dockerfile file and configure.sh file in it. the dockerfile file will be the blueprint for our image and the configure.sh file will be the provisioning script that is run when the container is deployed.

open the configure.sh file and include the following:

set -m

/entrypoint.sh couchbase-server &

sleep 15

curl -v -x post http://127.0.0.1:8091/pools/default -d memoryquota=512 -d indexmemoryquota=512

curl -v http://127.0.0.1:8091/node/controller/setupservices -d services=kv%2cn1ql%2cindex

curl -v http://127.0.0.1:8091/settings/web -d port=8091 -d username=$couchbase_administrator_username -d password=$couchbase_administrator_password

curl -i -u $couchbase_administrator_username:$couchbase_administrator_password -x post http://127.0.0.1:8091/settings/indexes -d 'storagemode=memory_optimized'

curl -v -u $couchbase_administrator_username:$couchbase_administrator_password -x post http://127.0.0.1:8091/pools/default/buckets -d name=$couchbase_bucket -d buckettype=couchbase -d ramquotamb=128 -d authtype=sasl -d saslpassword=$couchbase_bucket_password

sleep 15

curl -v http://127.0.0.1:8093/query/service -d "statement=create primary index on `$couchbase_bucket`"

fg 1


couchbase can be configured through http after being deployed. our configuration script will specify instance resources, administrative credentials, a bucket, and a primary index. you’ll notice that a variety of variables are used such as $couchbase_administrative_username and $couchbase_bucket . these can be passed in at runtime preventing us from having to hard-code sensitive information.

more information on provisioning a couchbase container via http can be seen in a previous article that i wrote on the topic.

with the provisioning script complete, we have to finish the dockerfile file. open it and include the following:

from couchbase

copy configure.sh /opt/couchbase

cmd ["/opt/couchbase/configure.sh"]


the custom docker image will use the official docker image as the base, copy our provisioning script during the build process, and execute it at runtime.

to build the custom image for couchbase, execute the following:

docker build -t couchbase-custom /path/to/directory/with/dockerfile


in the above command, couchbase-custom is the image name and it is built from the path that contains the dockerfile file.

developing a spring boot restful api with java

before we can containerize our java application we have to build it. because we are using spring boot, we need to download a starter project. this can easily be done from the spring initializr website.

for this project, i’m using com.couchbase as my group and docker as my artifact . i also prefer gradle, so i’m using that instead of maven.

extract the downloaded project, and open the project’s src/main/resources/application.properties file. in this file include the following:

couchbase_host=couchbase
couchbase_bucket=default
couchbase_bucket_password=


in the above snippet, we are assuming our host instance is called couchbase and it has a passwordless bucket called default . if you were testing locally, the host would probably be localhost instead. in any case, all these properties are going to be defined at container runtime through environment variables.

now open the project’s src/main/java/com/couchbase/dockerapplication.java file. here we’re going to load our properties and define our endpoints. open this file and include the following java code:

package com.couchbase;

import com.couchbase.client.java.bucket;
import com.couchbase.client.java.cluster;
import com.couchbase.client.java.couchbasecluster;
import com.couchbase.client.java.query.*;
import com.couchbase.client.java.query.consistency.scanconsistency;
import com.couchbase.client.java.document.json.jsonobject;
import com.couchbase.client.java.document.jsondocument;
import org.springframework.beans.factory.annotation.value;
import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.*;
import org.springframework.context.annotation.*;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import javax.servlet.*;
import javax.servlet.http.httpservletresponse;
import java.util.*;
import java.util.concurrent.timeunit;

@springbootapplication
@restcontroller
@requestmapping("/")
public class dockerapplication {

    @value("${couchbase_host}")
    private string hostname;

    @value("${couchbase_bucket}")
    private string bucket;

    @value("${couchbase_bucket_password}")
    private string password;

    public @bean
    cluster cluster() {
        return couchbasecluster.create(hostname);
    }

    public @bean
    bucket bucket() {
        return cluster().openbucket(bucket, password);
    }

    @requestmapping(value="/", method= requestmethod.get)
    public string root() {
        return "try visiting the `/get` or `/save` endpoints";
    }


    @requestmapping(value="/get", method= requestmethod.get)
    public object get() {
        string query = "select `" + bucket().name() + "`.* from `" + bucket().name() + "`";
        return bucket().async().query(n1qlquery.simple(query, n1qlparams.build().consistency(scanconsistency.request_plus)))
                .flatmap(asyncn1qlqueryresult::rows)
                .map(result -> result.value().tomap())
                .tolist()
                .timeout(10, timeunit.seconds)
                .toblocking()
                .single();
    }

    @requestmapping(value="/save", method=requestmethod.post)
    public object save(@requestbody string json) {
        jsonobject jsondata = jsonobject.fromjson(json);
        jsondocument document = jsondocument.create(uuid.randomuuid().tostring(), jsondata);
        bucket().insert(document);
        return new responseentity<string>(json, httpstatus.ok);
    }

public static void main(string[] args) {
springapplication.run(dockerapplication.class, args);
}
}


not too much is happening in the above. much of it is boilerplate code and import statements. because the goal of this article isn’t in regards to using java with couchbase, i won’t explain each part of the code. instead know that it has three endpoints, one of which will get all documents in the bucket and one of which will save new documents to couchbase.

if you’re using gradle like i am, you need to change the build.gradle file. it needs to have a task created and dependencies added. your build.gradle file should look something like this:

buildscript {
    ext {
        springbootversion = '1.5.2.release'
    }
    repositories {
        mavencentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springbootversion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

version = '0.0.1-snapshot'
sourcecompatibility = 1.8

repositories {
    mavencentral()
}


dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework:spring-tx')
    compile('org.springframework.security:spring-security-core')
    compile('com.couchbase.client:java-client')
    testcompile('org.springframework.boot:spring-boot-starter-test')
}

task(run, dependson: 'classes', type: javaexec) {
    main = 'com.couchbase.dockerapplication'
    classpath = sourcesets.main.runtimeclasspath
}


to build the application, execute the following:

gradle build -x test


now you’ll have a jar file to be used in our docker image.

build a custom docker image for the spring boot application

building a custom image will require that we have a dockerfile file in place. at the base of your java project, add a dockerfile file and include the following:

from openjdk:8

copy ./build/libs/java-project-0.0.1-snapshot.jar spring-boot.jar

cmd java -jar spring-boot.jar


in the above snippet, we’re using the official openjdk image as our base and we’re copying our jar into the image at build time. at deployment, the jar is executed.

to build this image, execute the following:

docker build -t spring-boot-custom /path/to/directory/with/dockerfile


the above command should look familiar. we’re creating a spring-boot-custom image using the blueprint found in the directory of our dockerfile file.

for more information on creating custom docker images, you can visit a previous article i wrote called, build a custom docker image for your containerized web application .

deploying the couchbase and the spring boot images as containers

there are a few options when it comes to deploying our images. we can use a compose file or deploy them as vanilla containers. i find compose to be a cleaner approach so we’ll use that.

somewhere on your computer create a docker-compose.yml file and include the following:

version: '2'

services:
    couchbase:
        image: couchbase-custom
        ports:
            - 8091:8091
            - 8092:8092
            - 8093:8093
        environment:
            - couchbase_administrator_username=administrator
            - couchbase_administrator_password=password
            - couchbase_bucket=default
            - couchbase_bucket_password=

    spring-boot:
        image: spring-boot-custom
        ports:
            - 8080:8080
        environment:
            - couchbase_host=couchbase
            - couchbase_bucket=default
            - couchbase_bucket_password=
        restart: always


in the above file, we are defining the custom images that we built and we are doing port mapping to the host machine. what is particularly interesting is the environment options. these match the variables that we have in our application.properties and configure.sh files.

to deploy our containers with compose, execute the following:

docker-compose run -d --service-ports --name couchbase couchbase
docker-compose run -d --service-ports --name spring-boot spring-boot


something to note about the above commands. couchbase does not deploy instantly. you’ll need to wait until it is completely launched before you deploy the java application. after both applications are launched, check them out by navigating to the java application in your web browser.

conclusion

you just saw how to create custom docker images for a spring boot application and couchbase server. after deploying each as containers, they will be able to communicate to each other, which is incredibly convenient for maintenance.

Docker (software) Java (programming language) Spring Framework Web application app

Published at DZone with permission of Nic Raboy, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How To Build an Effective CI/CD Pipeline
  • Using GPT-3 in Our Applications
  • Little's Law and Lots of Kubernetes
  • 10 Easy Steps To Start Using Git and GitHub

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: