There is plenty of material on microservices, just google it! I gave a presentation on refactoring monolith to microservices at Devoxx Belgium a couple of years back and it has good reviews:
This blog will show how Docker simplifies creation and shutting down of a microservice.
All code used in this blog is at github.com/arun-gupta/couchbase-javaee.
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 addition of deploy attribute. This attribute allows to specify replicas, rolling update and restart policy for the container.
Our microservice will start a WldFly 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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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
andweb
attributes - Image name for each service defined using
image
attribute - The
arungupta/couchbase:travel
image starts Couchbase server, configures it using Couchbase REST API, and loadstravel-sample
bucket with ~32k JSON documents. - The
arungupta/couchbase-javaee:travel
image starts WildFly and deploys application WAR file built from https://github.com/arun-gupta/couchbase-javaee. Clone that project if you want to build your own image. 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 as shown at https://github.com/arun-gupta/couchbase-javaee/blob/master/src/main/java/org/couchbase/sample/javaee/Database.java.- Port forwarding is achieved using
ports
attribute -
depends_on
attribute in Compose definition file ensures the container start up order. But application-level start up needs to be ensured by the applications running inside 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 micro services applications: you must code defensively and ensure in your application initialization that the micro services you depend on have started, without assuming startup order. This is shown in the database initialization code at https://github.com/arun-gupta/couchbase-javaee/blob/master/src/main/java/org/couchbase/sample/javaee/Database.java. 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.
Setup Docker Swarm-mode
Initialize Swarm mode using the following command:
1
2
3
|
docker swarm init
|
This starts a Swarm Manager. By default, manager node are also worker but can be configured to be manager-only.
Find some information about this one-node cluster using the command docker info
command:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
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 1 node, and that is manager.
Alternatively, a multi-host cluster can be easily setup using Docker for AWS.
Deploy Microservice
The microservice can be started as:
1
2
3
|
docker stack deploy --compose-file=docker-compose.yml webapp
|
This shows the output:
1
2
3
4
5
|
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
:
1
2
3
4
5
|
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
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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)
|
Access Microservice
Get 10 airlines from the microservice:
1
2
3
|
curl -v http://localhost:8080/airlines/resources/airline
|
This shows the results as:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
* 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:
1
2
3
|
curl -v http://localhost:8080/airlines/resources/airline/137
|
Create a new resource:
1
2
3
|
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:
1
2
3
|
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:
1
2
3
|
curl -v -X DELETE http://localhost:8080/airlines/resources/airline/19810
|
Detailed output from each of these commands is at github.com/arun-gupta/couchbase-javaee.
Delete Microservice
The microservice can be removed using the command docker stack rm webapp
:
1
2
3
4
5
|
Removing service webapp_web
Removing service webapp_db
Removing network webapp_default
|
Want to get started with Couchbase? Look at Couchbase Starter Kits.
Want to learn more about running Couchbase in containers?
- Couchbase on Containers
- Couchbase Forums
- Couchbase Developer Portal
- @couchhasedev and @couchbase
Source: https://blog.couchbase.com/2017/february/microservice-using-docker-stack-deploy-wildfly-javaee-couchbase