Susun Docker + Konsul + Booting Musim Semi + FeignClient

Artikel ini menunjukkan contoh cara meningkatkan lingkungan pengembangan lokal menggunakan Docker Compose, Consul, Make for the Spring Boot (dan tidak hanya), menggunakan, misalnya, PostgreSQL dan Browserless.


Rencana:


  1. Mengkonfigurasi Layanan di Docker Compose
  2. Pendaftaran layanan di Consul'e dan menambahkan variabel ke repositori Consul'a
  3. Buat Makefile
  4. Konfigurasi postgreSQL
  5. Menggunakan FeignClient
  6. Kesimpulan

Aplikasi ini sama sekali tidak berguna: mengikuti tautan ke halaman, ia mengembalikan tautan ke gambar terbesar dari halaman ini. Gambar akan diambil oleh Browserless, dan dalam PostgreSQL kasus ini akan disimpan.


Tautan ke proyek: https://bitbucket.org/maximka777/consul-docker-spring-cloud/src/master/ .


1. Menyiapkan layanan di Docker Compose


Hal pertama yang harus dilakukan adalah membuat file konfigurasi docker-compose.yml untuk kontainer buruh pelabuhan:


 touch docker-compose.yml 

File ini berisi versi komposisi buruh pelabuhan:


 version: '3.4' 

Konfigurasi jaringan:


 networks: lan: 

Dan konfigurasi layanan yang diperlukan, dalam hal ini Consul, Browserless, dan 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 - kata sandi ke basis data pengguna secara default postgres , POSTGRES_DB - secara otomatis membuat basis data dalam wadah.


Untuk memulai layanan, Anda perlu menjalankan perintah:


 docker-compose up 

Kami sedang menunggu akhir memuat gambar wadah dan meluncurkan wadah. Untuk menghentikan kontainer berjalan, gunakan perintah docker-compose down . Setelah memulai semua kontainer, Anda dapat pergi ke alamat di browser localhost:8500 - klien web Konsul harus terbuka (Gbr. 1).


Gambar 1


Gambar 1


2. Pendaftaran layanan di Konsul'e dan menambahkan variabel ke penyimpanan Konsul'a


Anda dapat mendaftarkan layanan di Konsul dengan mengirimkan beberapa permintaan pasca ke alamat localhost:8500/v1/agent/service/register , misalnya, menggunakan curl.


Masukkan semua panggilan curl ke skrip bash.


 #!/bin/bash curl -s -XPUT -d"{ \"Name\": \"postgres\", \"ID\": \"postgres\", \"Tags\": [ \"postgres\" ], \"Address\": \"localhost\", \"Port\": 5432, \"Check\": { \"Name\": \"PostgreSQL TCP on port 5432\", \"ID\": \"postgres\", \"Interval\": \"10s\", \"TCP\": \"postgres:5432\", \"Timeout\": \"1s\", \"Status\": \"passing\" } }" localhost:8500/v1/agent/service/register curl -s -XPUT -d"{ \"Name\": \"browserless\", \"ID\": \"browserless\", \"Tags\": [ \"browserless\" ], \"Address\": \"localhost\", \"Port\": 3000, \"Check\": { \"Name\": \"Browserless TCP on port 3000\", \"ID\": \"browserless\", \"Interval\": \"10s\", \"TCP\": \"browserless:3000\", \"Timeout\": \"1s\", \"Status\": \"passing\" } }" localhost:8500/v1/agent/service/register curl -s -XPUT -d"{ \"Name\": \"example.app\", \"ID\": \"example.app\", \"Tags\": [ \"example.app\" ], \"Address\": \"localhost\", \"Port\": 8080, \"Check\": { \"Name\": \"example.app HTTP on port 8080\", \"ID\": \"example.app\", \"Interval\": \"10s\", \"HTTP\": \"example.app:8080/actuator/health\", \"Timeout\": \"1s\", \"Status\": \"passing\" } }" localhost:8500/v1/agent/service/register 

chmod +x register-services.sh - untuk membuat file dapat dijalankan.


Setelah script dieksekusi, PostgreSQSL dan Browserless kami akan muncul dalam daftar layanan terdaftar di Consule'e (Gbr. 2).


Gambar 2


Gambar 2


Angka tersebut menunjukkan bahwa pemeriksaan PostgreSQL gagal dengan kesalahan - (itu tidak akan mempengaruhi esensi) .


Tambahkan konfigurasi ke penyimpanan kunci / nilai Konsul. Buat variabel test.property di direktori example.app :


 curl --request PUT --data TEST \ localhost:8500/v1/kv/example.app/test.property 

Jika ada banyak variabel, lebih baik menggunakan skrip bash.


3. Membuat Makefile


Untuk mempermudah peluncuran semua ini, tulis 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 

Peringatan: Makefile menggunakan jenis lekukan khusus!


Perintah make up akan memulai seluruh lingkungan.


4. Konfigurasi postgreSQL


Selanjutnya, proyek Spring Boot dasar (Maven) dibuat menggunakan penginisialisasi aplikasi Spring Boot https://start.spring.io/ .


Ketergantungan berikut telah ditambahkan ke 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> 

Dari nama-nama paket jelas mengapa mereka diperlukan.
Mari kita menulis konfigurasi untuk DataSource. Di file bootstrap.properties , letakkan konfigurasi:


 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 

Dalam 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: '*' 

Dan kelas konfigurasi itu sendiri:


 @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")); } } 

Metode getPostgresInstance() mengambil instance layanan pertama dengan tag postgres terdaftar di Konsul. Metode dataSource() adalah kacang dari DataSource.


Selanjutnya, kami mendeklarasikan repositori dengan operasi dasar pada entitas Image , yang menyimpan alamat halaman dan alamat gambar:


 @Repository public interface ImageRepository extends JpaRepository<Image, Long> { } 

5. Menggunakan FeignClient


Selanjutnya, kita akan memasukkan skrip JS ke sumber, yang akan mengeluarkan gambar terbesar dari halaman.


 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' }; }; 

Tentukan antarmuka BlowserlessClient:


 @FeignClient("browserless") //   browserless      public interface BrowserlessClient { @PostMapping("/function") ImageInfo findLargestImage(LargestImageRequest request); //       Browserless'     class ImageInfo { private String url; public String getUrl() { return url; } } //  ,    Browserless  ,    class LargestImageRequest { private String code; private BrowserlessContext context; public LargestImageRequest(String code, BrowserlessContext context) { this.code = code; this.context = context; } public String getCode() { return code; } public BrowserlessContext getContext() { return context; } } //        class BrowserlessContext { private String url; public BrowserlessContext(String url) { this.url = url; } public String getUrl() { return url; } } } 

Metode layanan meminta gambar dan menyimpan dalam database:


 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); } 

Pengontrol fungsionalitas:


 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); } } 

Di sini bidang testProperty ditarik dari penyimpanan kunci / nilai testProperty .


6. Akhir


Itu saja!


Saya harap saya dapat menunjukkan kemungkinan konfigurasi alat yang disajikan dan artikel ini akan bermanfaat bagi seseorang.


Tidak banyak penjelasan dalam artikel ini, karena saya percaya dalam hal ini lebih mudah untuk memahami kode.


Tautan yang bermanfaat:
1) https://docs.docker.com/compose/overview/ - Dokumentasi Penulis Docker
2) https://www.consul.io/intro/index.html - pengantar Konsul
3) http://matt.might.net/articles/intro-to-make/ - pengantar untuk dibuat
4) https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html - dokumentasi tentang Feign

Source: https://habr.com/ru/post/id429472/


All Articles