Cet article montre comment augmenter l'environnement de développement local à l'aide de Docker Compose, Consul, Make pour l'application Spring Boot (et pas seulement), en utilisant, par exemple, PostgreSQL et Browserless.
Plan:
- Configuration des services dans Docker Compose
- Enregistrement des services dans Consul'e et ajout de variables au référentiel Consul'a
- Créer un Makefile
- Configuration de PostgreSQL
- Utilisation de FeignClient
- Conclusion
L'application est absolument inutile: en suivant un lien vers une page, elle renvoie un lien vers la plus grande image de cette page. L'image sera récupérée par Browserless, et dans PostgreSQL ce cas sera enregistré.
Lien vers le projet: https://bitbucket.org/maximka777/consul-docker-spring-cloud/src/master/ .
1. Configuration des services dans Docker Compose
La première chose à faire est de créer un fichier de configuration docker-compose.yml
pour les conteneurs docker:
touch docker-compose.yml
Ce fichier contient la version de docker-compose:
version: '3.4'
Configuration du réseau:
networks: lan:
Et la configuration des services nécessaires, dans ce cas Consul, Browserless et 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
- mot de passe de la base de données utilisateur par défaut postgres
, POSTGRES_DB
- base de données créée automatiquement dans le conteneur.
Pour démarrer les services dont vous avez besoin pour exécuter la commande:
docker-compose up
Nous attendons la fin du chargement des images de conteneurs et du lancement des conteneurs. Pour arrêter l'exécution des conteneurs, utilisez la commande docker-compose down
. Après avoir démarré tous les conteneurs, vous pouvez vous rendre à l'adresse dans le navigateur localhost:8500
- le client Web Consul devrait s'ouvrir (Fig. 1).

Figure 1
2. Enregistrement des services dans Consul'e et ajout de variables au stockage de Consul'a
Vous pouvez enregistrer des services dans Consul en envoyant plusieurs post-requêtes à l'adresse de l' localhost:8500/v1/agent/service/register
, par exemple, en utilisant curl.
Mettez tous les appels curl dans le script bash.
chmod +x register-services.sh
- pour rendre le fichier exécutable.
Une fois le script exécuté, nos PostgreSQSL et Browserless apparaîtront dans la liste des services enregistrés dans Consule'e (Fig. 2).

Figure 2
La figure montre que la vérification PostgreSQL échoue avec une erreur - (cela n'affectera pas l'essence) .
Ajoutez la configuration au stockage de clé / valeur de Consul. Créez la variable test.property
dans le répertoire example.app
:
curl --request PUT --data TEST \ localhost:8500/v1/kv/example.app/test.property
S'il y a beaucoup de variables, il est préférable d'utiliser un script bash.
3. Création d'un Makefile
Pour simplifier le lancement de tout cela, écrivez 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
Attention: Makefile
utilise un type d'indentation spécial!
La commande make up
démarrera tout l'environnement.
4. Configuration PostgreSQL
Ensuite, un projet Spring Boot de base (Maven) a été généré à l'aide de l'initialiseur de l'application Spring Boot https://start.spring.io/ .
Les dépendances suivantes ont été ajoutées à 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>
D'après les noms des packages, il est clair pourquoi ils sont nécessaires.
Écrivons la configuration du DataSource. Dans le fichier bootstrap.properties
, supprimez les configurations:
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
Dans 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: '*'
Et la classe de configuration elle-même:
@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")); } }
La méthode getPostgresInstance()
prend la première instance de service avec la balise postgres
enregistrée dans Consul. La méthode dataSource()
est le bean du DataSource.
Ensuite, nous déclarons un référentiel avec des opérations de base sur l'entité Image
, qui stocke l'adresse de la page et l'adresse de l'image:
@Repository public interface ImageRepository extends JpaRepository<Image, Long> { }
5. Utilisation de FeignClient
Ensuite, nous déposerons un script JS dans les ressources, ce qui extraira la plus grande image de la page.
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' }; };
Définissez l'interface BlowserlessClient:
@FeignClient("browserless")
Méthode de service demandant une image et stockée dans la base de données:
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); }
Contrôleur de fonctionnalité:
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); } }
Ici, le champ testProperty
extrait du magasin de clés / valeurs de testProperty
.
6. La fin
Voilà!
J'espère avoir pu montrer une configuration possible des outils présentés et cet article sera utile à quelqu'un.
Il n'y a pas beaucoup d'explications dans cet article, car je pense que dans ce cas, il est plus facile de comprendre le code.
Liens utiles:
1) https://docs.docker.com/compose/overview/ - Documentation Docker Compose
2) https://www.consul.io/intro/index.html - introduction à Consul
3) http://matt.might.net/articles/intro-to-make/ - introduction à faire
4) https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html - documentation sur Feign