Deploying a Microservice Stack Using Docker
Deploying a Java EE microservice with the whole stack might seem like a complicated process, but it's simply a matter of a few Docker commands.
Join the DZone community and get the full member experience.
Join For FreeThis blog will show how Docker simplifies the creation and shutting down of a microservice.
All code used in this blog can be found here.
Microservice Definition Using Compose
Docker 1.13 introduced a v3 of Docker Compose. The changes in the syntax are minimal but the key difference is the addition of the deploy attribute. This attribute allows to specify replicas, rolling update, and restart policy for the container.
Our microservice will start a WildFly application server with a Java EE application pre-deployed. This application will talk to a Couchbase database to CRUD application data.
Here is the Compose definition:
version: '3'
services:
web:
image: arungupta/couchbase-javaee:travel
environment:
- COUCHBASE_URI=db
ports:
- 8080:8080
- 9990:9990
depends_on:
- db
db:
image: arungupta/couchbase:travel
ports:
- 8091:8091
- 8092:8092
- 8093:8093
- 11210:11210
In this Compose file:
Two services in this Compose are defined by the name db and web attributes.
Image name for each service is defined using image attribute.
The arungupta/couchbase:travel image starts Couchbase server, configures it using the Couchbase REST API, and loads travel-sample bucket with ~32k JSON documents.
The arungupta/couchbase-javaee:travel image starts WildFly and deploys application WAR file built from here. Clone that project if you want to build your own image.
The envrionment attribute defines environment variables accessible by the application deployed in WildFly. COUCHBASE_URI refers to the database service. This is used in the application code.
Port forwarding is achieved using ports attribute.
The depends_on attribute in the Compose definition file ensures the container startup order. However, application-level startup needs to be ensured by the applications running inside the container. In our case, WildFly starts up rather quickly but takes a few seconds for the database to start up. This means the Java EE application deployed in WildFly is not able to communicate with the database. This outlines a best practice when building microservices applications. You must code defensively and ensure in your application initialization that the microservices you depend on have started, without assuming startup order. This is shown in the database initialization code here. It performs the following checks:
Bucket exists.
Query service of Couchbase is up and running.
Sample bucket is fully loaded.
This application can be started using docker-compose up -d command on a single host. Or a cluster of Docker engines in swarm-mode using docker stack deploy command.
Set Up Docker Swarm-Mode
Initialize Swarm mode using the following command.
docker swarm init
This starts a Swarm Manager. By default, manager nodes are also workers but can be configured to be manager-only.
Find some information about this one-node cluster using the command docker info command:
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 17
Server Version: 1.13.0
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Swarm: active
NodeID: 92mydh0e09ba5hx3wtmcmvktz
Is Manager: true
ClusterID: v68ikyaff7rdxpaw1j0c9i60s
Managers: 1
Nodes: 1
Orchestration:
Task History Retention Limit: 5
Raft:
Snapshot Interval: 10000
Number of Old Snapshots to Retain: 0
Heartbeat Tick: 1
Election Tick: 3
Dispatcher:
Heartbeat Period: 5 seconds
CA Configuration:
Expiry Duration: 3 months
Node Address: 192.168.65.2
Manager Addresses:
192.168.65.2:2377
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 03e5862ec0d8d3b3f750e19fca3ee367e13c090e
runc version: 2f7393a47307a16f8cee44a37b262e8b81021e3e
init version: 949e6fa
Security Options:
seccomp
Profile: default
Kernel Version: 4.9.5-moby
Operating System: Alpine Linux v3.5
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 1.952 GiB
Name: moby
ID: SGCM:KDRD:G3M7:PZHN:J4RL:VFFR:G2SR:EKD5:JV4J:RL3X:LF7T:XF6V
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): true
File Descriptors: 31
Goroutines: 124
System Time: 2017-01-27T08:25:58.032295342Z
EventsListeners: 1
No Proxy: *.local, 169.254/16
Username: arungupta
Registry: https://index.docker.io/v1/
Experimental: true
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
This cluster has one node, which is a manager.
Alternatively, a multi-host cluster can be easily setup using Docker for AWS.
Deploy Microservice
The microservice can be started as:
docker stack deploy --compose-file=docker-compose.yml webapp
This shows the output:
Creating network webapp_default
Creating service webapp_web
Creating service webapp_db
WildFly and Couchbase services are started on this node. Each service has a single container. If the Swarm mode is enabled on multiple nodes, then the containers will be distributed across multiple nodes.
A new overlay network is created. This allows multiple containers on different hosts to communicate with each other.
Verify that the WildFly and Couchbase services are running using docker service ls:
ID NAME MODE REPLICAS IMAGE
a9pkiziw3vgw webapp_db replicated 1/1 arungupta/couchbase:travel
hr5s6ue54kwj webapp_web replicated 1/1 arungupta/couchbase-javaee:travel
Logs for the service can be seen using docker service logs -f webapp_web:
webapp_web.1.wby0b04t7bap@moby | =========================================================================
webapp_web.1.wby0b04t7bap@moby |
webapp_web.1.wby0b04t7bap@moby | JBoss Bootstrap Environment
webapp_web.1.wby0b04t7bap@moby |
webapp_web.1.wby0b04t7bap@moby | JBOSS_HOME: /opt/jboss/wildfly
webapp_web.1.wby0b04t7bap@moby |
webapp_web.1.wby0b04t7bap@moby | JAVA: /usr/lib/jvm/java/bin/java
webapp_web.1.wby0b04t7bap@moby |
webapp_web.1.wby0b04t7bap@moby | JAVA_OPTS: -server -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true
webapp_web.1.wby0b04t7bap@moby |
webapp_web.1.wby0b04t7bap@moby | =========================================================================
. . .
webapp_web.1.wby0b04t7bap@moby | 23:14:15,811 INFO [org.jboss.as.server] (ServerService Thread Pool -- 34) WFLYSRV0010: Deployed "airlines.war" (runtime-name : "airlines.war")
webapp_web.1.wby0b04t7bap@moby | 23:14:16,076 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/management
webapp_web.1.wby0b04t7bap@moby | 23:14:16,077 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://127.0.0.1:9990
webapp_web.1.wby0b04t7bap@moby | 23:14:16,077 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 10.1.0.Final (WildFly Core 2.2.0.Final) started in 98623ms - Started 443 of 691 services (404 services are lazy, passive or on-demand)
Make sure to wait for the last log statement to show.
Access Microservice
Get 10 airlines from the microservice with the following code.
curl -v http://localhost:8080/airlines/resources/airline
This shows the results as:
* Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET /airlines/resources/airline HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Connection: keep-alive
< X-Powered-By: Undertow/1
< Server: WildFly/10
< Content-Type: application/octet-stream
< Content-Length: 1402
< Date: Fri, 03 Feb 2017 17:02:45 GMT
<
* Connection #0 to host localhost left intact
[{"travel-sample":{"country":"United States","iata":"Q5","callsign":"MILE-AIR","name":"40-Mile Air","icao":"MLA","id":10,"type":"airline"}}, {"travel-sample":{"country":"United States","iata":"TQ","callsign":"TXW","name":"Texas Wings","icao":"TXW","id":10123,"type":"airline"}}, {"travel-sample":{"country":"United States","iata":"A1","callsign":"atifly","name":"Atifly","icao":"A1F","id":10226,"type":"airline"}}, {"travel-sample":{"country":"United Kingdom","iata":null,"callsign":null,"name":"Jc royal.britannica","icao":"JRB","id":10642,"type":"airline"}}, {"travel-sample":{"country":"United States","iata":"ZQ","callsign":"LOCAIR","name":"Locair","icao":"LOC","id":10748,"type":"airline"}}, {"travel-sample":{"country":"United States","iata":"K5","callsign":"SASQUATCH","name":"SeaPort Airlines","icao":"SQH","id":10765,"type":"airline"}}, {"travel-sample":{"country":"United States","iata":"KO","callsign":"ACE AIR","name":"Alaska Central Express","icao":"AER","id":109,"type":"airline"}}, {"travel-sample":{"country":"United Kingdom","iata":"5W","callsign":"FLYSTAR","name":"Astraeus","icao":"AEU","id":112,"type":"airline"}}, {"travel-sample":{"country":"France","iata":"UU","callsign":"REUNION","name":"Air Austral","icao":"REU","id":1191,"type":"airline"}}, {"travel-sample":{"country":"France","iata":"A5","callsign":"AIRLINAIR","name":"Airlinair","icao":"RLA","id":1203,"type":"airline"}}]
Docker for Java Developers workshop is a self-paced hands-on lab and allows you to get started with Docker easily.
Get a single resource:
curl -v http://localhost:8080/airlines/resources/airline/137
Create a new resource:
curl -v -H "Content-Type: application/json" -X POST -d '{"country":"France","iata":"A5","callsign":"AIRLINAIR","name":"Airlinair","icao":"RLA","type":"airline"}' http://localhost:8080/airlines/resources/airline
Update a resource:
curl -v -H "Content-Type: application/json" -X PUT -d '{"country":"France","iata":"A5","callsign":"AIRLINAIR","name":"Airlin Air","icao":"RLA","type":"airline","id": "19810"}' http://localhost:8080/airlines/resources/airline/19810
Delete a resource:
curl -v -X DELETE http://localhost:8080/airlines/resources/airline/19810
Detailed output from each of these commands is here!
Delete Microservice
The microservice can be removed using the command docker stack rm webapp:
Removing service webapp_web
Removing service webapp_db
Removing network webapp_default
Want to get started with Couchbase? Look at Couchbase Starter Kits.
Published at DZone with permission of Arun Gupta, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments