اكتشاف الخدمات والإعداد والبوّابة

الإعداد المركزي

18 دقيقة الدرس 4 من 12

الإعداد المركزي

في التطبيق الأحادي (Monolith) تدير ملف application.properties واحدًا. انشر عشر خدمات مصغّرة عبر ثلاث بيئات وستجد نفسك فجأة أمام ثلاثين ملف إعداد تحتاج إلى تناسق مستمر. غيّر عنوان URL مشتركًا لقاعدة البيانات وستضطر إلى تحديث كل خدمة وإعادة بناء كل منها ونشرها من جديد. تحل Spring Cloud Config هذه المشكلة بتقديم خادم إعداد مخصص يعمل مصدرًا وحيدًا للحقيقة لجميع الإعدادات، إذ يخدم الخصائص لكل خدمة مصغّرة عبر HTTP عند بدء التشغيل — وبشكل اختياري في وقت التشغيل دون إعادة تشغيل.

كيف تعمل Spring Cloud Config

يتكوّن المعمار من جزأين رئيسيين:

  • Config Server — تطبيق Spring Boot مستقل يقرأ الإعداد من مخزن خلفي (عادةً مستودع Git) ويعرضه عبر واجهة REST.
  • Config Client — أي خدمة مصغّرة تحتوي تبعية spring-cloud-starter-config. يتصل بـ Config Server أثناء بدء التشغيل، ويُنزّل خصائصه، ثم يدمجها في Environment قبل إنشاء أي Bean.
لماذا Git كخلفية؟ تخزين الإعداد في Git يمنحك سجل الإصدارات وسير عمل فرع لكل بيئة ومراجعات طلبات السحب لتغييرات الإعداد ومسار التدقيق — وكل ذلك مجانًا. يمكن لـ Config Server أيضًا القراءة من نظام الملفات المحلي وVault وJDBC وخلفيات أخرى، لكن Git هو الافتراضي في الإنتاج.

إعداد Config Server

أنشئ مشروع Spring Boot جديدًا وأضف تبعية الخادم:

<!-- pom.xml --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency>

فعّل الخادم بتوضيع تعليق توضيحي واحد على الفئة الرئيسية:

package com.example.configserver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer; @SpringBootApplication @EnableConfigServer public class ConfigServerApplication { public static void main(String[] args) { SpringApplication.run(ConfigServerApplication.class, args); } }

اضبط مصدر قراءة الخصائص في ملف application.yml الخاص به:

server: port: 8888 spring: cloud: config: server: git: uri: https://github.com/your-org/service-configs default-label: main # فرع Git المستخدم search-paths: '{application}' # البحث في مجلد فرعي باسم الخدمة clone-on-start: true # فشل سريع إذا كان المستودع غير متاح

يخدم الخادم الإعداد الآن عبر نمط URL التالي: /{application}/{profile}/{label}. مثلًا، يُعيد GET /order-service/production/main الخصائص المدمجة لتطبيق order-service في بروفايل production على الفرع main.

تنظيم مستودع الإعداد

يبدو هيكل مستودع Git النموذجي للإعداد كالتالي:

service-configs/ application.yml # مشترك بين جميع الخدمات application-production.yml # تجاوزات مشتركة للإنتاج order-service/ application.yml # إعدادات order-service الافتراضية application-production.yml inventory-service/ application.yml application-production.yml

تدمج Spring Cloud Config هذه الملفات وفق أولوية واضحة (الأكثر تحديدًا يفوز):

  1. خاص بالخدمة + البروفايل (مثل order-service/application-production.yml)
  2. خاص بالخدمة الافتراضي (مثل order-service/application.yml)
  3. المشترك + البروفايل (مثل application-production.yml)
  4. المشترك الافتراضي (application.yml)
ضع القيم المشتركة حقًا في المستوى الأعلى. أسماء فئات تشغيل قاعدة البيانات والمهلات المشتركة وعلامات الميزات المشتركة تنتمي إلى ملف application.yml في الجذر. أما عناوين URL الخاصة بالخدمة وبيانات الاعتماد فتنتمي إلى ملفات الخدمات الفردية. هذا يُبقي إعدادات كل خدمة صغيرة ومركّزة.

إعداد Config Client

في كل خدمة مصغّرة، أضف تبعية Config Client:

<!-- pom.xml الخاص بالخدمة المصغّرة --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency>

أضف إعداد Bootstrap الأدنى. في Spring Boot 3 / Spring Cloud 2022+ معالجة bootstrap معطّلة افتراضيًا؛ يمكن إعادة تفعيلها بتبعية spring-cloud-starter-bootstrap، أو — وهو النهج الحديث المفضّل — ضع إحداثيات Config Server مباشرةً في application.yml:

# order-service/src/main/resources/application.yml spring: application: name: order-service # يُستخدم بواسطة Config Server لإيجاد ملفاتك config: import: "configserver:http://localhost:8888" cloud: config: profile: ${SPRING_PROFILES_ACTIVE:development} fail-fast: true # توقف عند بدء التشغيل إذا لم يكن Config Server متاحًا retry: max-attempts: 6 initial-interval: 1000 # ثانية واحدة بين كل محاولة

عند بدء تشغيل التطبيق، تعالج Spring Boot إدخال spring.config.import قبل إنشاء أي Bean، وتجلب الخصائص البعيدة، وتحقنها في سياق التطبيق تمامًا كأنها ملفات .yml محلية.

تأمين Config Server

يمكن أن يعرض Config Server كلمات مرور قواعد البيانات ومفاتيح API وأسرارًا أخرى. احمه بشكل صحيح:

  • HTTP Basic / OAuth2: أضف spring-boot-starter-security إلى Config Server واضبط بيانات الاعتماد. يُمرّرها العملاء في خصائص spring.cloud.config.username وspring.cloud.config.password (مخزّنة في مدير أسرار محلي، ليس في المستودع).
  • التشفير المتماثل: يدعم Config Server تشفير القيم بمفتاح مشترك. خزّن القيمة المشفّرة في Git بصيغة {cipher}AQA... — يفكّ الخادم تشفيرها قبل التقديم. عيّن ENCRYPT_KEY كمتغير بيئي على مضيف الخادم، وليس في ملفات الإعداد أبدًا.
  • التشفير غير المتماثل: استخدم زوج مفاتيح RSA مخزّنًا في JKS keystore لأمان أعلى. يحتفظ الخادم بالمفتاح الخاص؛ يحتوي مستودع Git على النص المشفّر فقط.
# تشفير قيمة باستخدام نقطة نهاية Config Server المدمجة: # POST http://config-server:8888/encrypt # Body: s3cr3t-db-password # # Response: AQBxyz123... # # خزّنها في Git بصيغة: spring: datasource: password: '{cipher}AQBxyz123...'
لا تخزّن أسرارًا بنص عادي في مستودع Git للإعداد أبدًا. يمكن لأي شخص يملك صلاحية قراءة المستودع — الآن أو في تاريخ الـ commit — استخراجها. شفّر كل سر قبل الإيداع. غيّر فورًا أي مفتاح أُودع بنص عادي في أي وقت مضى.

طوبولوجيا الشبكة في مجموعة حقيقية

في الإنتاج يعمل Config Server نفسه كخدمة مسجّلة في Eureka (تناولناها في الدرس الثاني). يكتشفه العملاء بمعرّف الخدمة بدلًا من عنوان URL مُرمَّز:

spring: cloud: config: discovery: enabled: true service-id: config-server # معرّف خدمة Eureka

يُزيل هذا آخر عنوان URL مُرمَّز من عملاءك. يصبح تسلسل بدء التشغيل: اتصل بـ Eureka ← اكتشف Config Server ← اجلب الإعداد ← أكمل بدء التشغيل. المقايضة هي أن Eureka يجب أن يكون متاحًا قبل أن تبدأ أي خدمة أخرى؛ لهذا السبب يُنشر Eureka عادةً بنسخ متعددة وعنوان ثابت ومعروف.

الخلاصة

تستبدل Spring Cloud Config فوضى ملفات application.yml لكل خدمة بخادم وحيد مدعوم بـ Git يخدم إعدادًا ذا إصدار وواعيًا بالبيئة وخاصًا بالبروفايل لكل خدمة مصغّرة. يتصل العملاء عند بدء التشغيل عبر spring.config.import، يدمج الخادم الخصائص وفق الأولوية، ويمكن تشفير القيم الحساسة في حالة السكون. في الدرس القادم ستتعلّم كيفية دفع الإعداد المحدَّث إلى الخدمات الجارية دون إعادة تشغيلها.