Los contenedores, los microservicios y NoSQL proporcionan un trío impresionante para crear aplicaciones modernas. Estas aplicaciones deben ser ágiles, satisfacer las demandas de los clientes en constante evolución, ser omnipresentes y funcionar en plataformas móviles, web e IoT.
Este blog explicará una sencilla pila de microservicios utilizando Enjambre WildFly, Dockery Couchbase. El código completo y las instrucciones de este blog están documentados en: github.com/arun-gupta/wildfly-swarm-couchbase.
Entendamos primero los componentes clave de esta pila.
Enjambre WildFly permite empaquetar y ejecutar aplicaciones JavaEE empaquetándolas con lo justo del tiempo de ejecución del servidor para java -jar su aplicación. Con el descubrimiento de servicios integrado, inicio de sesión único con Keycloak, supervisión mediante Hawkulary muchas más características, WildFly Swarm proporciona todos los componentes necesarios para desarrollar su microservicio.
Docker para Mac proporciona soporte nativo para ejecutar contenedores Docker en Mac OSX. Se basa en Hipervisor.framework en OSX. El motor Docker se ejecuta en una distribución Linux Alpine sobre un xhyve Máquina Virtual, e incluso la VM es gestionada por Docker. No hay necesidad de Docker Machine o VirtualBox, y se integra con el modelo sandbox de seguridad de OSX. DockerCon 2016 eliminó la restricción de beta privada de Docker para Mac, por lo que ya está disponible para todo el mundo. 
NoSQL ofrece la agilidad y flexibilidad de las bases de datos sin esquema. Esto permite que la aplicación evolucione de forma independiente y rápida sin pasar por engorrosas migraciones de bases de datos. Couchbase ofrece un verdadero escalado horizontal con arquitectura homogéneaa diferencia de la arquitectura maestro/esclavo no escalable. También ofrece auto-sharding, Lenguaje de consulta tipo SQL para JSON (N1QL), base de datos móvil y sincronización con el servidor backend, y mucho más. La aplicación de ejemplo completa en este blog está en: github.com/arun-gupta/wildfly-swarm-couchbase.
Aplicación WildFly Swarm
Veamos el punto final REST de Java EE:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package com.couchbase.wildfly.swarm; . . . @Path("airline") public class AirlineResource { @Inject Database database; @GET public String getAll() { N1qlQuery query = N1qlQuery.simple("SELECT * FROM `travel-sample` LIMIT 10"); N1qlQueryResult result = database.getBucket().query(query); return result.allRows().toString(); } . . . } |
Utiliza la anotación JAX-RS estándar para convertir un POJO en un endpoint REST. API Java de Couchbase proporcionan una API fluida y utilizan la sentencia N1QL para consultar los documentos y devolver los resultados. La sentencia N1QL devuelve los 10 primeros elementos del resultado de la consulta. Aprenda más sobre la sintaxis N1QL en este tutorial interactivo. La abstracción de la base de datos se define como:
|
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 |
package com.couchbase.wildfly.swarm; . . . @Singleton @Startup public class Database { CouchbaseCluster cluster; Bucket bucket; public CouchbaseCluster getCluster() { if (null == cluster) { String couchbaseURI = System.getenv("COUCHBASE_URI"); if (null == couchbaseURI) { System.err.println("WARING: No COUCHBASE_URI specified, defaulting to localhost"); couchbaseURI = "localhost:8093"; } System.out.println("Couchbase endpoint: " + System.getenv("COUCHBASE_URI")); cluster = CouchbaseCluster.create(couchbaseURI); } return cluster; } public Bucket getBucket() { if (null == bucket) { bucket = getCluster().openBucket("travel-sample"); } return bucket; } } |
Se trata de un EJB singleton que se inicializa por anticipado. Utiliza SDK Java de Couchbase para conectarse a Couchbase. El punto final de la base de datos se puede especificar utilizando el parámetro COUCHBASE_URI variable de entorno. El siguiente paso es pom.xml para configurar WildFly Swarm y Cliente Java de Couchbase:
|
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 |
org.wildfly.swarm bom ${version.wildfly-swarm} pom import javax javaee-web-api 7.0 provided org.wildfly.swarm jaxrs-cdi org.wildfly.swarm ejb com.couchbase.client java-client 2.2.5 |
Utiliza la "lista de materiales" de WildFly Swarm para extraer todas las dependencias. Sólo las dependencias específicas necesarias para la compilación se especifican en . A continuación, se empaquetan en el "fat jar". El plugin Maven de WildFly Swarm se utiliza para empaquetar y ejecutar la aplicación:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
org.wildfly.swarm wildfly-swarm-plugin ${version.wildfly-swarm} package ${COUCHBASE_URI} |
COUCHBASE_URI se utiliza para leer el host donde se ejecuta el servidor de base de datos Couchbase.
Ejecutar Couchbase Server
Ejecute el servidor Couchbase utilizando Docker para Mac:
|
1 |
docker run -d --name db -p 8091-8093:8091-8093 -p 11210:11210 arungupta/couchbase |
En arungupta/couchbase se basa en el imagen estándar de Couchbase y utiliza API REST de Couchbase para configurar el servidor. Espere un par de minutos a que el bucket de muestra se rellene con los documentos JSON. Ejecute la aplicación Herramienta CLI de Couchbase cbq crear un índice primario en el bucket de muestra:
|
1 |
docker run -it --link db:db arungupta/couchbase cbq -u Administrator -p password -engine https://db:8093 -s "create primary index `travel-sample-primary-index` on `travel-sample`;" |
Esto mostrará la salida como:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Connected to : https://db:8093/. Type Ctrl-D or QUIT to exit. Path to history file for the shell : /root/.cbq_history { "requestID": "d0b2e4dd-b702-49e2-971c-a4c640ddb498", "signature": null, "results": [ ], "status": "success", "metrics": { "elapsedTime": "3.154540272s", "executionTime": "3.154493281s", "resultCount": 0, "resultSize": 0 } } |
Esta salida muestra que el resultado de la creación del índice fue exitoso. Una de las ventajas de ejecutar Docker para Mac es que todos los contenedores son accesibles en localhost. Es decir Consola web de Couchbase puede consultarse en localhost:8091. 
Esta pantalla asegura que Couchbase está configurado correctamente.
Ejecutar el microservicio WildFly Swarm
Empaqueta y ejecuta el microservicio autónomo como:
|
1 |
mvn wildfly-swarm:run |
Si Couchbase se está ejecutando en un host diferente, entonces el comando cambiará a:
|
1 |
mvn -DCOUCHBASE_URI= wildfly-swarm:run |
Muestra la salida como:
|
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 |
[INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building nosql-microservices 1.0-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] . . . 2016-06-27 22:21:47,170 WARN [org.jboss.as.dependency.private] (MSC service thread 1-6) WFLYSRV0018: Deployment "deployment.nosql-microservices.war" is using a private module ("org.jboss.jts:main") which may be changed or removed in future versions without notice. 2016-06-27 22:21:47,203 INFO [org.jboss.weld.deployer] (MSC service thread 1-1) WFLYWELD0003: Processing weld deployment nosql-microservices.war 2016-06-27 22:21:47,542 INFO [org.hibernate.validator.internal.util.Version] (MSC service thread 1-1) HV000001: Hibernate Validator 5.2.3.Final 2016-06-27 22:21:47,600 INFO [org.jboss.as.ejb3.deployment] (MSC service thread 1-1) WFLYEJB0473: JNDI bindings for session bean named 'Database' in deployment unit 'deployment "nosql-microservices.war"' are as follows: java:global/nosql-microservices/Database!com.couchbase.wildfly.swarm.Database java:app/nosql-microservices/Database!com.couchbase.wildfly.swarm.Database java:module/Database!com.couchbase.wildfly.swarm.Database java:global/nosql-microservices/Database java:app/nosql-microservices/Database java:module/Database 2016-06-27 22:21:47,731 INFO [org.jboss.weld.deployer] (MSC service thread 1-3) WFLYWELD0006: Starting Services for CDI deployment: nosql-microservices.war 2016-06-27 22:21:47,758 INFO [org.jboss.weld.Version] (MSC service thread 1-3) WELD-000900: 2.3.2 (Final) 2016-06-27 22:21:47,780 INFO [org.wildfly.extension.undertow] (MSC service thread 1-1) WFLYUT0018: Host default-host starting 2016-06-27 22:21:47,788 INFO [org.jboss.weld.deployer] (MSC service thread 1-8) WFLYWELD0009: Starting weld service for deployment nosql-microservices.war 2016-06-27 22:21:48,180 INFO [stdout] (ServerService Thread Pool -- 10) Couchbase endpoint: 2016-06-27 22:21:48,275 INFO [com.couchbase.client.core.CouchbaseCore] (ServerService Thread Pool -- 10) CouchbaseEnvironment: {sslEnabled=false, sslKeystoreFile='null', sslKeystorePassword='null', queryEnabled=false, queryPort=8093, bootstrapHttpEnabled=true, bootstrapCarrierEnabled=true, bootstrapHttpDirectPort=8091, bootstrapHttpSslPort=18091, bootstrapCarrierDirectPort=11210, bootstrapCarrierSslPort=11207, ioPoolSize=8, computationPoolSize=8, responseBufferSize=16384, requestBufferSize=16384, kvServiceEndpoints=1, viewServiceEndpoints=1, queryServiceEndpoints=1, searchServiceEndpoints=1, ioPool=NioEventLoopGroup, coreScheduler=CoreScheduler, eventBus=DefaultEventBus, packageNameAndVersion=couchbase-jvm-core/1.2.5 (git: 1.2.5), dcpEnabled=false, retryStrategy=BestEffort, maxRequestLifetime=75000, retryDelay=ExponentialDelay{growBy 1.0 MICROSECONDS, powers of 2; lower=100, upper=100000}, reconnectDelay=ExponentialDelay{growBy 1.0 MILLISECONDS, powers of 2; lower=32, upper=4096}, observeIntervalDelay=ExponentialDelay{growBy 1.0 MICROSECONDS, powers of 2; lower=10, upper=100000}, keepAliveInterval=30000, autoreleaseAfter=2000, bufferPoolingEnabled=true, tcpNodelayEnabled=true, mutationTokensEnabled=false, socketConnectTimeout=1000, dcpConnectionBufferSize=20971520, dcpConnectionBufferAckThreshold=0.2, queryTimeout=75000, viewTimeout=75000, kvTimeout=2500, connectTimeout=5000, disconnectTimeout=25000, dnsSrvEnabled=false} 2016-06-27 22:21:48,829 INFO [com.couchbase.client.core.node.Node] (cb-io-1-1) Connected to Node localhost 2016-06-27 22:21:49,035 INFO [com.couchbase.client.core.config.ConfigurationProvider] (cb-computations-1) Opened bucket travel-sample 2016-06-27 22:21:49,415 INFO [org.jboss.resteasy.resteasy_jaxrs.i18n] (ServerService Thread Pool -- 10) RESTEASY002225: Deploying javax.ws.rs.core.Application: class com.couchbase.wildfly.swarm.MyApplication 2016-06-27 22:21:49,438 INFO [org.wildfly.extension.undertow] (ServerService Thread Pool -- 10) WFLYUT0021: Registered web context: / 2016-06-27 22:21:49,457 INFO [org.jboss.as.server] (main) WFLYSRV0010: Deployed "nosql-microservices.war" (runtime-name : "nosql-microservices.war") |
Ahora se puede acceder a la aplicación como:
|
1 |
curl https://localhost:8080/webresources/airline |
Y una salida formateada tiene este aspecto:
|
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 |
[ { "travel-sample": { "country": "United States", "iata": "Q5", "callsign": "MILE-AIR", "name": "40-Mile Air", "icao": "MLA", "id": 10, "type": "airline" } }, . . . { "travel-sample": { "country": "France", "iata": "A5", "callsign": "AIRLINAIR", "name": "Airlinair", "icao": "RLA", "id": 1203, "type": "airline" } } ] |
Así que has construido un microservicio simple usando WildFly Swarm accediendo a una base de datos Couchbase ejecutándose como un contenedor Docker. Ahora, idealmente este servicio WildFly Swarm debería ser empaquetado como una imagen Docker y luego esa imagen Docker serviría como el servicio. Un perfil de Maven con el nombre docker ya se ha añadido a pom.xml pero número #3 está haciendo fracasar ese escenario.
