كيف قمت بنقل مشروع هوايتي إلى k8s

صورة

في هذه المقالة ، أود أن أتحدث عن مشروع هوايتي المتمثل في البحث وتصنيف الإعلانات لاستئجار شقق من الشبكة الاجتماعية فكونتاكتي وتجربة نقلها إلى K8s.


جدول المحتويات


  • قليلا عن المشروع
  • تقديم k8s
  • التحضير لهذه الخطوة
  • تطوير التكوين K8s
  • نشر الكتلة K8s

قليلا عن المشروع


IMG



في مارس 2017 ، أطلقت خدمة لتحليل وتصنيف الإعلانات لاستئجار شقق من الشبكة الاجتماعية فكونتاكتي.


هنا يمكنك قراءة المزيد من التفاصيل حول كيف حاولت تصنيف الإعلانات بطرق مختلفة واستقرت في نهاية المطاف على المحلل اللغوي المعجم Yandex Tomita Parser .


هنا يمكنك أن تقرأ عن بنية المشروع في بداية وجوده وما هي التقنيات المستخدمة ولماذا.


استغرق تطوير الإصدار الأول من الخدمة حوالي عام. لنشر كل مكون من مكونات الخدمة ، كتبت البرامج النصية في Ansible . من وقت لآخر ، لم تعمل الخدمة بسبب أخطاء في الكود المعاد تصميمه أو التكوين غير الصحيح للمكونات.


حوالي يونيو 2019 ، تم اكتشاف خطأ في رمز المحلل اللغوي بسبب عدم جمع إعلانات جديدة. بدلاً من تصحيح آخر ، تقرر تعطيله مؤقتًا.


كان سبب استعادة الخدمة هو دراسة k8s.


تقديم k8s


k8s عبارة عن برنامج مفتوح المصدر لأتمتة نشر التطبيقات ذات الحاوية وتوسيع نطاقها وإدارتها.


يتم وصف البنية التحتية للخدمة بأكملها بواسطة ملفات التكوين بتنسيق yaml (في معظم الأحيان).


لن أتحدث عن البنية الداخلية ل k8s ، ولكن فقط إعطاء بعض المعلومات حول بعض مكوناته.


مكونات K8s


  • قرنة هي أصغر وحدة. قد تحتوي على عدة حاويات سيتم إطلاقها على نفس العقدة.
    حاويات داخل قرنة:
    • لديك شبكة مشتركة ويمكن الوصول إلى بعضها البعض من خلال 127.0.0.1:$containerPort؛
    • ليس لديك نظام ملفات مشترك ، لذلك لا يمكنك كتابة الملفات مباشرة من حاوية إلى أخرى.
  • نشر - يراقب عمل قرنة. يمكنه رفع العدد المطلوب من مثيلات Pod ، وإعادة تشغيلها إذا سقطت ، وتنفيذ عملية نشر Pods جديدة.
  • PersistentVolumeClaim - مستودع البيانات. بشكل افتراضي ، يعمل مع نظام ملفات العقدة المحلي. لذلك ، إذا كنت تريد أن يكون لقردين مختلفين على عقد مختلفة نظام ملفات مشترك ، فعليك استخدام نظام ملفات شبكة مثل Ceph .
  • خدمة - الوكلاء طلبات من وإلى قرنة.
    أنواع الخدمات:
    • LoadBalancer - للتفاعل مع شبكة خارجية مع موازنة التحميل بين عدة قرون ؛
    • NodePort (منافذ 30000-32767 فقط) - للتفاعل مع شبكة خارجية دون موازنة التحميل ؛
    • ClusterIp - للتفاعل في الشبكة المحلية للكتلة ؛
    • ExternalName - للتفاعل بين Pod والخدمات الخارجية.
  • ConfigMap - تخزين التكوينات.
    من أجل k8s لإعادة تشغيل Pod مع التكوينات الجديدة عندما يتغير ConfigMap ، يجب عليك الإشارة إلى الإصدار باسم ConfigMap الخاص بك وتغييره في كل مرة يتغير ConfigMap.
    الشيء نفسه ينطبق على السرية.

مثال التكوين مع ConfigMap
containers: - name: collect-consumer image: mrsuh/rent-collector:1.3.1 envFrom: - configMapRef: name: collector-configmap-1.1.0 - secretRef: name: collector-secrets-1.0.0 

  • سر - تخزين التكوينات السرية (كلمات المرور ، المفاتيح ، الرموز).
  • التصنيف - أزواج المفتاح / القيمة المعينة لمكونات k8s ، على سبيل المثال ، Pod.
    في بداية التعارف مع k8s ، قد لا يكون من الواضح تمامًا كيفية استخدام الملصقات. فيما يلي التكوين الذي يشرح المبادئ الأساسية للعمل مع الملصقات:

مثال التكوين مع التسميات
 apiVersion: apps/v1 kind: Deployment #  Deployment metadata: name: deployment-name #  Deployment labels: app: deployment-label-app # Label Deployment spec: selector: matchLabels: app: pod-label-app # Label,   Deployment    Pods   template: metadata: name: pod-name labels: app: pod-label-app # Label Pod spec: containers: - name: container-name image: mrsuh/rent-parser:1.0.0 ports: - containerPort: 9080 --- apiVersion: v1 kind: Service #  Service metadata: name: service-name #  Service labels: app: service-label-app # Label Service spec: selector: #  Service   matchLabels,  Deployment,      Labels app: pod-label-app # Label,   Service ,   Pod    ports: - protocol: TCP port: 9080 type: NodePort 

التحضير لهذه الخطوة


وظيفة التشذيب


لجعل الخدمة أكثر استقرارًا ويمكن التنبؤ بها ، اضطررت إلى إزالة جميع المكونات الإضافية التي عملت بشكل سيء وإعادة كتابة المكونات الرئيسية قليلاً.
لذلك ، قررت رفض:


  • تحليل التعليمات البرمجية لمواقع أخرى غير VK ؛
  • طلب مكون الوكيل ؛
  • مكون إخطارات الإعلانات الجديدة في فكونتاكتي و Telegram.

مكونات الخدمة


بعد كل التغييرات ، بدأت الخدمة من الداخل تبدو كما يلي:
مخطط


  • عرض - البحث وعرض الإعلانات على الموقع (NodeJS) ؛
  • المحلل اللغوي - مصنف الإعلانات (Go) ؛
  • جامع - جمع الإعلانات ومعالجتها وحذفها (PHP):
    • cron-Explore - فريق وحدة تحكم يبحث عن مجموعات في فكونتاكتي لتأجير المساكن ؛
    • cron-collect - أمر وحدة التحكم ينتقل إلى المجموعات التي يتم تجميعها عن طريق استكشاف cron وجمع الإعلانات بنفسها ؛
    • cron-delete - أمر وحدة تحكم يحذف الإعلانات منتهية الصلاحية ؛
    • تحليل المستهلك - معالج قائمة الانتظار ، الذي يتلقى وظائف من جمع cron. يصنف الإعلانات باستخدام مكون المحلل اللغوي.
    • المستهلك - جمع - معالج قائمة الانتظار الذي يحصل على وظائف من تحليل المستهلك. يقوم بتصفية الإعلانات السيئة والمكررة.

بناء صور عامل الميناء


من أجل إدارة المكونات ومراقبتها بأسلوب واحد ، قررت:


  • وضع تكوين المكون في متغيرات env ،
  • كتابة السجلات في stdout.

لا يوجد شيء محدد في الصور نفسها.


تطوير التكوين K8s


لذلك حصلت على المكونات في صور Docker ، وبدأت في تطوير تكوين k8s.


يتم تمييز جميع المكونات التي تعمل كأنها شياطين في النشر. يجب أن يكون كل برنامج خفي قابلاً للوصول داخل المجموعة ، بحيث يكون لدى الجميع خدمة. جميع المهام التي يجب القيام بها تعمل بشكل دوري في CronJob.


يتم تخزين جميع الإحصائيات (الصور ، js ، css) في حاوية العرض ، ويجب على حاوية Nginx توزيعها. كل من الحاويات في قرنة واحدة. لم يتم تخبط نظام الملفات في Pod ، ولكن في بداية Pod يمكنك نسخ جميع الإحصائيات إلى مجلد blankDir الشائع في كلتا الحاويتين. ستتم مشاركة هذا المجلد في حاويات مختلفة ، ولكن داخل مجلد واحد فقط.


مثال التكوين مع blankDir
 apiVersion: apps/v1 kind: Deployment metadata: name: view spec: selector: matchLabels: app: view replicas: 1 template: metadata: labels: app: view spec: volumes: - name: view-static emptyDir: {} containers: - name: nginx image: mrsuh/rent-nginx:1.0.0 - name: view image: mrsuh/rent-view:1.1.0 volumeMounts: - name: view-static mountPath: /var/www/html lifecycle: postStart: exec: command: ["/bin/sh", "-c", "cp -r /app/web/. /var/www/html"] 

يتم استخدام المكون جامع في النشر و CronJob.


كل هذه المكونات تصل إلى VKontakte API ويجب أن تخزن الرمز المميز للوصول المشترك في مكان ما.
لهذا ، استخدمت PersistentVolumeClaim ، والتي قمت بتوصيلها بكل قرنة. ستتم مشاركة هذا المجلد مع Pods مختلفة ، ولكن داخل عقدة واحدة فقط.


مثال التكوين مع PersistentVolumeClaim
 apiVersion: apps/v1 kind: Deployment metadata: name: collector spec: selector: matchLabels: app: collector replicas: 1 template: metadata: labels: app: collector spec: volumes: - name: collector-persistent-storage persistentVolumeClaim: claimName: collector-pv-claim containers: - name: collect-consumer image: mrsuh/rent-collector:1.3.1 volumeMounts: - name: collector-persistent-storage mountPath: /tokenStorage command: ["php"] args: ["bin/console", "app:consume", "--channel=collect"] - name: parse-consumer image: mrsuh/rent-collector:1.3.1 volumeMounts: - name: collector-persistent-storage mountPath: /tokenStorage command: ["php"] args: ["bin/console", "app:consume", "--channel=parse"] 

يستخدم PersistentVolumeClaim أيضًا لتخزين بيانات قاعدة البيانات. نتيجة لذلك ، حصلنا على مثل هذا المخطط (يتم جمع القرون من مكون واحد في كتل):


مخطط


نشر الكتلة K8s


للبدء ، قمت بنشر الكتلة محليًا باستخدام Minikube .
بالطبع ، كانت هناك بعض الأخطاء ، لذا ساعدني الفريق كثيرًا.


 kubectl logs -f pod-name kubectl describe pod pod-name 

بعد أن تعلمت كيفية نشر كتلة في Minikube ، لم يكن من الصعب علي نشرها في DigitalOcean.


في الختام ، أستطيع أن أقول أن الخدمة كانت مستقرة لمدة شهرين. التكوين الكامل يمكن العثور عليها هنا .

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


All Articles