
كيف يستخدم Dailymotion Kubernetes: نشر التطبيق
بدأنا في Dailymotion باستخدام Kubernetes في الإنتاج منذ 3 سنوات. ولكن نشر التطبيقات على مجموعات متعددة لا يزال من دواعي سروري ، لذلك حاولنا في السنوات القليلة الماضية تحسين أدواتنا وسير العمل لدينا.
من أين بدأت؟
نوضح هنا كيف ننشر تطبيقاتنا على العديد من مجموعات Kubernetes حول العالم.
لنشر كائنات Kubernetes متعددة في وقت واحد ، نستخدم Helm ، ويتم تخزين جميع مخططاتنا في مستودع بوابة واحد. لنشر مكدس التطبيق الكامل من العديد من الخدمات ، نستخدم ما يسمى المخطط المعمم. في جوهره ، هذا مخطط يُعلن عن التبعيات ويسمح لك بتهيئة واجهة برمجة التطبيقات وخدماتها بواسطة أمر واحد.
لقد كتبنا أيضًا نصًا بيثونًا صغيرًا أعلى هيلم للقيام بالتحققات وإنشاء المخططات وإضافة الأسرار ونشر التطبيقات. يتم تنفيذ كل هذه المهام على النظام الأساسي المركزي CI باستخدام صورة عامل ميناء.
دعنا نصل الى هذه النقطة.
المذكرة. عندما تقرأ هذا ، تم بالفعل الإعلان عن أول مرشح لإصدار Helm 3. تحتوي النسخة الرئيسية على مجموعة كاملة من التحسينات المصممة لحل بعض المشكلات التي واجهناها في الماضي.
تطوير الرسم البياني سير العمل
بالنسبة للتطبيقات ، نستخدم التفرع ، وقررنا تطبيق نفس النهج على الرسوم البيانية.
- يتم استخدام فرع التطوير لإنشاء مخططات سيتم اختبارها على مجموعات التطوير.
- عند نقل طلب التجميع إلى الرئيسي ، يتم إيداعه في التدريج.
- أخيرًا ، نقوم بإنشاء طلب تجميع لدفع التغييرات إلى فرع prod وتطبيقها في الإنتاج.
كل بيئة لها مستودعها الخاص الذي يخزن مخططاتنا ، ونحن نستخدم Chartmuseum مع واجهات برمجة التطبيقات المفيدة للغاية. وبالتالي ، فإننا نضمن العزلة الصارمة بين البيئات والتحقق من الرسوم البيانية في ظروف حقيقية قبل استخدامها في الإنتاج.

مستودعات التخطيط في بيئات مختلفة
تجدر الإشارة إلى أنه عندما يرسل المطورون فرع dev ، يتم إرسال نسخة من مخططهم تلقائيًا إلى dev Chartmuseum. وبالتالي ، يستخدم جميع المطورين نفس مستودع التخزين ، وتحتاج إلى الإشارة بعناية إلى إصدار المخطط الخاص بك حتى لا تستخدم تغييرات شخص آخر عن طريق الخطأ.
علاوة على ذلك ، يقوم برنامج Python الصغير الخاص بنا بفحص كائنات Kubernetes مقابل مواصفات Kubernetes OpenAPI باستخدام Kubeval قبل نشرها على Chartmusem.
سير العمل في تطوير المخطط العام

- إعداد مهمة خط أنابيب وفقا لمواصفات gazr.io لمراقبة الجودة (الوبر ، اختبار وحدة).
- إرسال صورة عامل ميناء باستخدام أدوات Python التي تنشر تطبيقاتنا.
- إعداد البيئة باسم الفرع.
- تحقق yaml Kubernetes الملفات مع Kubeval.
- قم تلقائيًا بزيادة إصدار المخطط والمخططات الأصل (المخططات التي تعتمد على المخطط الجاري تغييره).
- تقديم مخطط إلى Chartmuseum يطابق بيئته
إدارة الفرق العنقودية
اتحاد الكتلة
كان هناك وقت استخدمنا فيه Kubernetes Cluster Federation ، حيث يمكنك إعلان كائنات Kubernetes من نقطة نهاية API واحدة. ولكن كانت هناك مشاكل. على سبيل المثال ، لا يمكن إنشاء بعض كائنات Kubernetes عند نقطة نهاية الاتحاد ، لذلك كان من الصعب الحفاظ على الكائنات المدمجة والكائنات الأخرى للمجموعات الفردية.
لحل المشكلة ، بدأنا في إدارة المجموعات بشكل مستقل ، الأمر الذي سهّل العملية إلى حد كبير (استخدمنا الإصدار الأول من الاتحاد ، وفي الثانية ، يمكن أن يتغير شيء).
الآن يتم توزيع منصتنا في 6 مناطق - 3 محليًا و 3 في السحابة.

توزيع الموزعة
قيم هيلم العالمية
4 قيم هيلم العالمية تسمح لك بتحديد الاختلافات بين المجموعات. لجميع مخططاتنا ، هناك حد أدنى من الإعدادات الافتراضية.
global: cloud: True env: staging region: us-central1 clusterName: staging-us-central1
القيم العالمية
تساعد هذه القيم في تحديد سياق تطبيقاتنا وتستخدم في مهام مختلفة: المراقبة ، التتبع ، التسجيل ، إجراء مكالمات خارجية ، التحجيم ، إلخ.
- "سحابة": لدينا منصة مختلطة Kubernetes. على سبيل المثال ، يتم نشر واجهة برمجة التطبيقات (API) الخاصة بنا في مناطق GCP وفي مراكز البيانات الخاصة بنا.
- "Env": قد تختلف بعض القيم للبيئات غير العاملة. على سبيل المثال ، تعريفات الموارد وتكوينات autoscale.
- "المنطقة": تساعد هذه المعلومات في تحديد موقع الكتلة ويمكن استخدامها لتحديد أقرب نقاط النهاية للخدمات الخارجية.
- "ClusterName": إذا وعندما نريد تحديد قيمة الكتلة الفردية.
هنا مثال ملموس:
{{/* Returns Horizontal Pod Autoscaler replicas for GraphQL*/}} {{- define "graphql.hpaReplicas" -}} {{- if eq .Values.global.env "prod" }} {{- if eq .Values.global.region "europe-west1" }} minReplicas: 40 {{- else }} minReplicas: 150 {{- end }} maxReplicas: 1400 {{- else }} minReplicas: 4 maxReplicas: 20 {{- end }} {{- end -}}
مثال هيلم القالب
يتم تعريف هذا المنطق في قالب المساعد حتى لا تسد Kubernetes YAML.
إعلان التطبيق
تعتمد أدوات النشر الخاصة بنا على العديد من ملفات YAML. فيما يلي مثال عن كيفية إعلاننا عن الخدمة وطوبولوجيا تحجيمها (عدد النسخ المتماثلة) في نظام المجموعة.
releases: - foo.world foo.world: # Release name services: # List of dailymotion's apps/projects foobar: chart_name: foo-foobar repo: git@github.com:dailymotion/foobar contexts: prod-europe-west1: deployments: - name: foo-bar-baz replicas: 18 - name: another-deployment replicas: 3
تعريف الخدمة
هذا رسم تخطيطي لجميع الخطوات التي تحدد سير عمل النشر لدينا. الخطوة الأخيرة تنشر التطبيق على مجموعات عمل متعددة في وقت واحد.

خطوات نشر جنكينز
ماذا عن الأسرار؟
فيما يتعلق بالأمان ، فإننا نتتبع جميع الأسرار من أماكن مختلفة ونخزنها في مستودع Vault الفريد في باريس.
تقوم أدوات النشر الخاصة بنا باستخراج قيم الأسرار من Vault ، وعندما يحين وقت النشر ، قم بإدراجها في Helm.
للقيام بذلك ، حددنا التعيين بين الأسرار في Vault والأسرار التي تحتاج إليها تطبيقاتنا:
secrets: - secret_id: "stack1-app1-password" contexts: - name: "default" vaultPath: "/kv/dev/stack1/app1/test" vaultKey: "password" - name: "cluster1" vaultPath: "/kv/dev/stack1/app1/test" vaultKey: "password"
- لقد حددنا القواعد العامة التي يجب اتباعها عند كتابة الأسرار إلى Vault.
- إذا كان السر يشير إلى سياق أو مجموعة محددة ، فأنت بحاجة إلى إضافة إدخال محدد. (هنا ، يحتوي سياق cluster1 على قيمته الخاصة بكلمة المرور السرية المكدس-app1).
- خلاف ذلك ، يتم استخدام القيمة الافتراضية .
- لكل عنصر في هذه القائمة ، يتم إدراج زوج قيمة المفتاح في سر Kubernetes . لذلك ، فإن النمط السري في مخططاتنا بسيط للغاية.
apiVersion: v1 data: {{- range $key,$value := .Values.secrets }} {{ $key }}: {{ $value | b64enc | quote }} {{ end }} kind: Secret metadata: name: "{{ .Chart.Name }}" labels: chartVersion: "{{ .Chart.Version }}" tillerVersion: "{{ .Capabilities.TillerVersion.SemVer }}" type: Opaque
المشاكل والقيود
العمل مع مستودعات متعددة
نحن الآن نشارك في تطوير المخططات والتطبيقات. وهذا يعني أن المطورين يجب أن يعملوا في مستودعين git: أحدهما للتطبيق ، والثاني لتحديد نشره في Kubernetes. 2 من مستودعات git عبارة عن سير عمل ، ومن السهل على المبتدئ أن يتشوش.
إدارة المخططات الملخصة أمر مزعج
كما قلنا سابقًا ، تعتبر المخططات العامة ملائمة جدًا لتحديد التبعيات ونشر التطبيقات المتعددة بسرعة. لكننا نستخدم --reuse-values
لتجنب تمرير كل القيم في كل مرة ننشر فيها التطبيق المتضمن في هذا المخطط المعمم.
في سير عمل التسليم المستمر ، لدينا فقط قيمتان تتغيران بانتظام: عدد النسخ المتماثلة وعلامة الصورة (الإصدار). يتم تغيير القيم الأخرى الأكثر ثباتًا يدويًا ، وهذا معقد إلى حد ما. علاوة على ذلك ، يمكن أن يؤدي خطأ في نشر مخطط عام إلى إخفاقات خطيرة ، كما رأينا من تجربتنا الخاصة.
تحديث ملفات التكوين متعددة
عندما يضيف مطور تطبيقًا جديدًا ، يتعين عليه تغيير عدة ملفات: الإعلان عن التطبيق ، وقائمة من الأسرار ، وإضافة التطبيق اعتمادًا على ما إذا كان موجودًا على المخطط المعمم.
أذونات Jenkins ممتدة جدًا في Vault
الآن لدينا AppRole واحد يقرأ كل الأسرار من Vault.
عملية الاستعادة ليست آلية
للتراجع ، تحتاج إلى تشغيل الأمر على عدة مجموعات ، وهذا محفوف بالأخطاء. نقوم بتنفيذ هذه العملية يدويًا للتأكد من تحديد معرف الإصدار الصحيح.
نحن نتجه نحو GitOps
هدفنا
نريد أن نعيد المخطط إلى مستودع التطبيق الذي ينشره.
سير العمل سيكون هو نفسه من أجل التنمية. على سبيل المثال ، عندما يتم إرسال فرع إلى المعالج ، سيبدأ النشر تلقائيًا. سيكون الاختلاف الرئيسي بين هذا النهج وسير العمل الحالي هو أن كل شيء سيتم إدارته في بوابة (التطبيق نفسه وطريقة نشره في Kubernetes).
هناك العديد من المزايا:
- أكثر وضوحا بكثير للمطور. من الأسهل تعلم كيفية تطبيق التغييرات على المخطط المحلي.
- يمكن تحديد تعريف نشر الخدمة في مكان رمز الخدمة.
- إدارة إزالة المخططات المعممة . سيكون للخدمة إصدار هيلم الخاص بها. سيتيح لك ذلك إدارة دورة حياة التطبيق (التراجع ، الترقية) على أصغر مستوى ، حتى لا تؤثر على الخدمات الأخرى.
- فوائد git لإدارة الرسوم البيانية هي: التراجع عن التغييرات ، ومراجعة الحسابات ، وما إلى ذلك. إذا كنت بحاجة إلى التراجع عن التغيير في الرسم البياني ، فيمكنك القيام بذلك باستخدام git. يبدأ النشر تلقائيًا.
- قد تفكر في تحسين سير عملك في التطوير باستخدام أدوات مثل Skaffold ، والتي يمكن للمطورين من خلالها اختبار التغييرات في سياق يشبه الإنتاج.
الهجرة على مرحلتين
يستخدم مطورونا سير العمل هذا منذ عامين ، لذلك نحتاج إلى ترحيل غير مؤلم. لذلك ، قررنا إضافة مرحلة وسيطة في الطريق إلى الهدف.
الخطوة الأولى بسيطة:
- نحافظ على بنية مماثلة لتكوين نشر التطبيق ، ولكن في نفس الكائن المسمى DailymotionRelease.
apiVersion: "v1" kind: "DailymotionRelease" metadata: name: "app1.ns1" environment: "dev" branch: "mybranch" spec: slack_channel: "#admin" chart_name: "app1" scaling: - context: "dev-us-central1-0" replicas: - name: "hermes" count: 2 - context: "dev-europe-west1-0" replicas: - name: "app1-deploy" count: 2 secrets: - secret_id: "app1" contexts: - name: "default" vaultPath: "/kv/dev/ns1/app1/test" vaultKey: "password" - name: "dev-europe-west1-0" vaultPath: "/kv/dev/ns1/app1/test" vaultKey: "password"
- إصدار واحد لكل تطبيق (بدون مخططات معممة).
- الرسوم البيانية في مستودع تطبيق بوابة.
تحدثنا مع جميع المطورين ، لذلك بدأت عملية الترحيل بالفعل. لا يزال يتم التحكم في المرحلة الأولى باستخدام منصة CI. قريباً سأكتب منشورًا آخر عن المرحلة الثانية: كيف تحولنا إلى سير عمل GitOps مع Flux . سوف أخبركم كيف أنشأنا جميعًا والصعوبات التي واجهناها (عدة مستودعات ، أسرار ، إلخ). اتبع الأخبار.
هنا ، حاولنا وصف تقدمنا في سير عمل نشر التطبيق خلال السنوات الأخيرة ، مما أدى إلى أفكار حول طريقة GitOps. لم نصل إلى الهدف وسنبلغ عن النتائج ، لكننا الآن مقتنعون بأننا فعلنا ذلك بشكل صحيح عندما قررنا تبسيط كل شيء وجعله أقرب إلى عادات المطورين.