Este art铆culo muestra un ejemplo de c贸mo elevar el entorno de desarrollo local usando Docker Compose, Consul, Make para la aplicaci贸n Spring Boot (y no solo), usando, por ejemplo, PostgreSQL y Browserless.
Plan:
- Configuraci贸n de servicios en Docker Compose
- Registro de servicios en Consul'e y adici贸n de variables al repositorio de Consul'a
- Crear Makefile
- Configuraci贸n de PostgreSQL
- Usando FeignClient
- Conclusi贸n
La aplicaci贸n es absolutamente in煤til: despu茅s de un enlace a una p谩gina, devuelve un enlace a la imagen m谩s grande de esta p谩gina. Browserless recuperar谩 la imagen, y en PostgreSQL este caso se guardar谩.
Enlace al proyecto: https://bitbucket.org/maximka777/consul-docker-spring-cloud/src/master/ .
1. Configuraci贸n de servicios en Docker Compose
Lo primero que debe hacer es crear un archivo de configuraci贸n docker-compose.yml
para contenedores docker:
touch docker-compose.yml
Este archivo contiene la versi贸n de docker-compose:
version: '3.4'
Configuraci贸n de red:
networks: lan:
Y la configuraci贸n de los servicios necesarios, en este caso Consul, Browserless y PostgreSQL:
services: consul: image: consul:1.1.0 hostname: localhost networks: - lan ports: - 8500:8500 postgres: image: postgres:11.0 hostname: localhost networks: - lan ports: - 5432:5432 environment: POSTGRES_PASSWORD: password POSTGRES_DB: example_app browserless: image: browserless/chrome hostname: localhost networks: - lan ports: - 3000:3000
POSTGRES_PASSWORD
: contrase帽a de la base de datos de usuario por defecto postgres
, POSTGRES_DB
: base de datos creada autom谩ticamente en el contenedor.
Para iniciar los servicios, necesita ejecutar el comando:
docker-compose up
Estamos esperando el final de cargar im谩genes de contenedores y lanzar contenedores. Para detener la ejecuci贸n de contenedores, use el docker-compose down
. Despu茅s de iniciar todos los contenedores, puede ir a la direcci贸n en el navegador localhost:8500
: el cliente web Consul deber铆a abrirse (Fig. 1).

Figura 1
2. Registro de servicios en Consul'e y agregar variables al almacenamiento de Consul'a
Puede registrar servicios en Consul enviando varias solicitudes posteriores a la direcci贸n de localhost:8500/v1/agent/service/register
, por ejemplo, usando curl.
Ponga todas las llamadas curl en el script bash.
chmod +x register-services.sh
- para hacer que el archivo sea ejecutable.
Despu茅s de ejecutar el script, nuestro PostgreSQSL y Browserless aparecer谩n en la lista de servicios registrados en Consule'e (Fig. 2).

Figura 2
La figura muestra que la comprobaci贸n de PostgreSQL falla con un error (no afectar谩 la esencia) .
Agregue la configuraci贸n al almacenamiento de clave / valor de Consul. Cree la variable test.property
en el directorio example.app
:
curl --request PUT --data TEST \ localhost:8500/v1/kv/example.app/test.property
Si hay muchas variables, es mejor usar un script bash.
3. Crear un Makefile
Para simplificar el lanzamiento de todo esto, escriba Makefile`:
docker_up: @docker-compose up -d consul_up: @./register-services.sh && \ ./register-variables.sh compile: @cd example.app && mvn package run: @cd example.app && java -jar target/example.app-1.0-SNAPSHOT.jar up: docker_up consul_up compile run down: @docker-compose down
Advertencia: 隆 Makefile
utiliza un tipo especial de sangr铆a!
El comando de make up
iniciar谩 todo el entorno.
4. Configuraci贸n de PostgreSQL
A continuaci贸n, se gener贸 un proyecto Spring Boot b谩sico (Maven) utilizando el inicializador de la aplicaci贸n Spring Boot https://start.spring.io/ .
Se han agregado las siguientes dependencias a pom.xml
:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-config</artifactId> <version>2.0.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> <version>2.0.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency>
Por los nombres de los paquetes est谩 claro por qu茅 son necesarios.
Escribamos la configuraci贸n para el DataSource. En el archivo bootstrap.properties
, suelte las configuraciones:
spring.cloud.consul.host=localhost spring.cloud.consul.port=8500 spring.cloud.consul.config.enabled=true spring.cloud.consul.config.prefix= spring.cloud.consul.config.defaultContext=example.app spring.cloud.consul.discovery.register=false spring.cloud.service-registry.auto-registration.enabled=false spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect spring.jpa.show-sql=false spring.jpa.hibernate.ddl-auto=create
En application.yml
:
example.app: db: name: 'example_app' feign: client: config: default: connectTimeout: 20000 readTimeout: 20000 loggerLevel: basic management: endpoint: health: show-details: always endpoints: web.exposure: include: '*'
Y la clase de configuraci贸n en s铆:
@Configuration public class PersistenceConfiguration { @Value("${example.app.db.name}") private String databaseName; @Autowired private DiscoveryClient discoveryClient; @Bean @Primary public DataSource dataSource() { var postgresInstance = getPostgresInstance(); return DataSourceBuilder .create() .username("postgres") .password("password") .url(format("jdbc:postgresql://%s:%s/%s", postgresInstance.getHost(), postgresInstance.getPort(), databaseName)) .driverClassName("org.postgresql.Driver") .build(); } private ServiceInstance getPostgresInstance() { return discoveryClient.getInstances("postgres") .stream() .findFirst() .orElseThrow(() -> new IllegalStateException("Unable to discover a Postgres instance")); } }
El m茅todo getPostgresInstance()
toma la primera instancia de servicio con la etiqueta postgres
registrada en Consul. El m茅todo dataSource()
es el bean de DataSource.
A continuaci贸n, declaramos un repositorio con operaciones b谩sicas en la entidad Image
, que almacena la direcci贸n de la p谩gina y la direcci贸n de la imagen:
@Repository public interface ImageRepository extends JpaRepository<Image, Long> { }
5. Usando FeignClient
A continuaci贸n, colocaremos un script JS en los recursos, que extraer谩 la imagen m谩s grande de la p谩gina.
module.exports = async ({page, context}) => { const {url} = context; await page.goto(url); await page.evaluate(_ => { window.scrollBy(0, window.innerHeight); }); const data = await page._client.send('Page.getResourceTree') .then(tree => { return Array.from(tree.frameTree.resources) .filter(resource => resource.type === 'Image' && resource.url && resource.url.indexOf('.svg') == -1) .sort((a, b) => b.contentSize - a.contentSize)[0]; }); return { data, type: 'json' }; };
Defina la interfaz de BlowserlessClient:
@FeignClient("browserless")
M茅todo de servicio solicitando una imagen y almacenando en la base de datos:
public Image findLargestImage(String url) { var browserlessContext = new BrowserlessContext(url); var largestImageRequest = new LargestImageRequest(getLargestImageScript, browserlessContext); var imageInfo = browserlessClient.findLargestImage(largestImageRequest); var image = new Image(); image.setSourceUrl(url); image.setImageUrl(imageInfo.getUrl()); return imageRepository.save(image); }
Controlador de funcionalidad:
public class MainController { private static Logger log = LoggerFactory.getLogger(MainController.class); @Autowired private ImageService imageService; @Value("${test.property}") private String testProperty; @GetMapping("/largest-image") public ResponseEntity<Image> getTitle(@RequestParam("url") String url) { return ResponseEntity.ok(imageService.findLargestImage(url)); } @GetMapping("/property") public ResponseEntity<String> getProperty() { return ResponseEntity.ok(testProperty); } }
Aqu铆 el campo testProperty
extrae del almac茅n de claves / valores de testProperty
.
6. El fin
Eso es todo!
Espero haber podido mostrar una posible configuraci贸n de las herramientas presentadas y este art铆culo ser谩 煤til para alguien.
No hay muchas explicaciones en este art铆culo, ya que creo que en este caso es m谩s f谩cil entender el c贸digo.
Enlaces utiles:
1) https://docs.docker.com/compose/overview/ - Documentaci贸n de Docker Compose
2) https://www.consul.io/intro/index.html - introducci贸n al c贸nsul
3) http://matt.might.net/articles/intro-to-make/ - introducci贸n para hacer
4) https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html - documentaci贸n sobre Feign