GitOps مع ArgoCD وFlux

نمط التطبيق الجذر ومجموعات التطبيقات في ArgoCD

18 دقيقة الدرس 5 من 30

نمط التطبيق الجذر ومجموعات التطبيقات في ArgoCD

يعمل مورد Application الواحد في ArgoCD بشكل جيد لخدمة واحدة. أما فريق المنصة الحقيقي فيدير مئات الخدمات عبر عشرات الكلاسترات. إنشاء ملف YAML لكل خدمة صغيرة يدويًا — ثم تكراره لبيئة التجهيز والإنتاج وكل منطقة جغرافية — لا يمكن توسيعه. يحل ArgoCD هذا بنمطين متكاملين: App-of-Apps (التطبيق الجذر) وApplicationSets (مجموعات التطبيقات).

نمط التطبيق الجذر (App-of-Apps)

الفكرة بسيطة: تشير تطبيق جذر في ArgoCD إلى مسار في Git يحتوي على مانيفستات Application أخرى لـ ArgoCD. حين يزامن ArgoCD الجذر، يكتشف التطبيقات الفرعية وينشئها. كل فرع هو مورد Application كامل يشير إلى مصدر Git الخاص به وله سياسة مزامنة مستقلة.

App-of-Apps reconciliation flow Git Repo apps/root/ Root App ArgoCD Application sync Child: api Application Child: frontend Application Child: worker Application creates Cluster prod-us-east Cluster prod-us-east Cluster prod-us-east
التطبيق الجذر يزامن مانيفستات التطبيقات الفرعية من Git؛ كل تطبيق فرعي يدير حِمله الخاص على الكلاستر المستهدف.

يبدو مانيفست التطبيق الجذر البسيط كالتالي:

# apps/root/api.yaml (هذا الملف يعيش داخل مستودع gitops) apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: api namespace: argocd finalizers: - resources-finalizer.argocd.argoproj.io # حذف موارد الكلاستر عند حذف التطبيق spec: project: default source: repoURL: https://github.com/acme/gitops targetRevision: HEAD path: envs/prod/api destination: server: https://kubernetes.default.svc namespace: api syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespace=true
الـ finalizer المسمى resources-finalizer.argocd.argoproj.io أمر حاسم. بدونه، يؤدي حذف كائن Application في ArgoCD إلى تخلي الكلاستر عن جميع الموارد (Deployments، Services، PVCs) دون حذفها. أضفه دائمًا على كل تطبيق فرعي.

يُنشأ التطبيق الجذر مرة واحدة فقط — عادةً عبر kubectl apply أو مخطط تثبيت ArgoCD. بعد ذلك، يعني إضافة خدمة جديدة مجرد إيداع ملف YAML جديد في مجلد apps/root/؛ يكتشفه ArgoCD تلقائيًا عند المزامنة التالية.

ApplicationSets: التوسع المدفوع بالمولدات

يعمل نمط التطبيق الجذر جيدًا، لكنه لا يزال يتطلب كتابة ملف YAML واحد لكل خدمة ولكل بيئة. تذهب ApplicationSets (مستقرة، جزء من نواة ArgoCD منذ الإصدار 2.3) أبعد من ذلك: مورد ApplicationSet واحد يستخدم مولدات لإنتاج عدد كبير من كائنات Application من قالب واحد. لا نسخ ولصق، ولا ملفات يدوية لكل كلاستر.

أهم المولدات:

  • List — قائمة مدمجة من أزواج المفتاح والقيمة؛ أبسط مولد للمجموعات الصغيرة والثابتة.
  • Git — يكتشف التطبيقات تلقائيًا بمسح مجلدات أو ملفات Git؛ مثالي للـ monorepo.
  • Matrix — الجداء الديكارتي لمولدَين؛ مثلًا: الخدمات × البيئات.
  • Cluster — يكرر على الكلاسترات المسجلة في ArgoCD؛ للنشر على كل كلاستر تلقائيًا.
  • SCM Provider — يمسح جميع المستودعات في مؤسسة GitHub؛ مناسب للتطبيق على مستوى المنصة.
  • Pull Request — ينشئ تطبيقًا مؤقتًا لكل PR مفتوح؛ يتيح بيئات المعاينة.

مولد المصفوفة (Matrix): الخدمات × البيئات

هذا هو العمود الفقري في الإنتاج. المولد الخارجي يُعطي البيئات، والداخلي يُعطي الخدمات؛ يُصدر ArgoCD تطبيقًا واحدًا لكل زوج:

apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: microservices namespace: argocd spec: goTemplate: true # يُفعّل صياغة Go template في كتلة الـ template goTemplateOptions: ["missingkey=error"] generators: - matrix: generators: - list: elements: - env: staging cluster: https://k8s-staging.acme.internal valuesFile: values-staging.yaml - env: production cluster: https://k8s-prod-us-east.acme.internal valuesFile: values-prod.yaml - git: repoURL: https://github.com/acme/gitops revision: HEAD directories: - path: services/* # يكتشف services/api, services/frontend, إلخ template: metadata: name: "{{.path.basenameNormalized}}-{{.env}}" labels: app.kubernetes.io/managed-by: argocd env: "{{.env}}" spec: project: default source: repoURL: https://github.com/acme/gitops targetRevision: HEAD path: "services/{{.path.basename}}" helm: valueFiles: - "../../envs/{{.env}}/{{.valuesFile}}" destination: server: "{{.cluster}}" namespace: "{{.path.basename}}" syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespace=true - ServerSideApply=true
فعّل goTemplate: true مع goTemplateOptions: ["missingkey=error"] على كل ApplicationSet. صياغة fasttemplate القديمة {{env}} تُعيد سلسلة فارغة بصمت للمتغيرات غير المعرّفة، مما يخفي أخطاء الإعداد. قوالب Go تفشل بصوت عالٍ عند المفاتيح المفقودة، وهذا تمامًا ما تريده في الإنتاج.

مولد Git: الاكتشاف التلقائي في الـ Monorepo

حين يتبع الـ monorepo اتفاقية مثل services/<name>/kustomization.yaml، يكتشف مولد ملف Git الخدمات الجديدة تلقائيًا — لا تغيير في ApplicationSet مطلوب حين يضيف المطور مجلدًا جديدًا:

apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: platform-services namespace: argocd spec: generators: - git: repoURL: https://github.com/acme/platform revision: HEAD files: - path: "services/**/app-config.json" # يكتشف أي app-config.json تحت services/ template: metadata: name: "{{path.basenameNormalized}}" spec: project: platform source: repoURL: https://github.com/acme/platform targetRevision: HEAD path: "{{path}}" destination: server: https://kubernetes.default.svc namespace: "{{path.basename}}" syncPolicy: automated: prune: true selfHeal: true

سياسة المزامنة والحماية من الحذف في ApplicationSets

تُدخل ApplicationSets خطرًا مهمًا: خطأ في إعداد المولد — كخطأ مطبعي في نمط glob لمجلد ما — يمكن أن يُنتج صفر نتائج، مما يدفع ArgoCD إلى حذف جميع التطبيقات الفرعية وتنظيف كل مورد في الكلاستر. احمِ من هذا بسياسة preserveResourcesOnDeletion:

spec: syncPolicy: preserveResourcesOnDeletion: true # لا تحذف موارد الكلاستر إذا حُذفت ApplicationSet # يمكن إضافة: ignoreApplicationDifferences: - jsonPointers: - /spec/source/targetRevision # السماح بالتجاوزات اليدوية دون إثارة فارق
لا تُشغّل ApplicationSets مع prune: true على التطبيقات الفرعية دون ضبط preserveResourcesOnDeletion: true على ApplicationSet نفسها. أدى تحديث مولد خاطئ إلى مسح بيئة إنتاج كاملة في شركة fintech كبرى عام 2023 لأن نمط glob للمجلد أعاد صفر نتائج — فقام ArgoCD بتنظيف جميع التطبيقات، مما أدى إلى تنظيف جميع الأحمال.

عزل المشاريع (Projects)

على النطاق الواسع ستكون لديك فرق متعددة. تُطبّق المشاريع في ArgoCD حدود RBAC: أي مستودعات مصدر يمكن للفريق استخدامها، وأي كلاسترات ومساحات أسماء يمكنه النشر فيها، وأي أنواع موارد يمكنه إنشاؤها. يجب أن تستهدف ApplicationSets دائمًا مشروع الفريق بدلًا من default:

# تعريف المشروع مرة واحدة apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: payments-team namespace: argocd spec: description: "خدمات المدفوعات — يملكها فريق payments-eng" sourceRepos: - "https://github.com/acme/payments-*" destinations: - server: "https://k8s-prod-us-east.acme.internal" namespace: "payments-*" clusterResourceWhitelist: - group: "" kind: Namespace namespaceResourceBlacklist: - group: "" kind: ResourceQuota # فريق المنصة يمتلك الحصص، لا فِرق التطبيقات roles: - name: deployer policies: - p, proj:payments-team:deployer, applications, sync, payments-team/*, allow groups: - acme:payments-eng

أفضل الممارسات التشغيلية

  • ApplicationSet واحدة لكل فريق، لا لكل خدمة. عدد أقل من الكائنات للتفكير فيها؛ المولدات تتولى التوسع.
  • استخدم ServerSideApply=true في syncOptions حين تُدير وحدات تحكم متعددة الكائن ذاته (مثل HPA + ArgoCD). يُزيل تعارضات مدير الحقول.
  • اختبر المولدات محليًا باستخدام argocd appset generate ./my-appset.yaml قبل التطبيق — شاهد ما سيُنشأ من تطبيقات دون لمس الكلاستر.
  • حدّ المزامنة المتزامنة بـ --application-set-concurrent-reconciliations=20 على applicationset-controller؛ ApplicationSet بدون حد تدير 500 تطبيق يمكن أن ترفع حمل خادم API عند المزامنة.
  • أضف تسميات للتطبيقات الفرعية (env، team، region) لتتمكن من التصفية في واجهة ArgoCD وكتابة سياسات RBAC مستهدفة.
يمنحك نمط التطبيق الجذر مانيفستات Application صريحة وقابلة للتدقيق في Git — سهلة المراجعة في طلبات السحب. تمنحك ApplicationSets أتمتة مدفوعة بالمولدات بدون YAML لكل تطبيق. تستخدم منصات الشركات الكبرى كليهما: ApplicationSets للأحمال المتجانسة (جميع الخدمات الصغيرة)، ونمط التطبيق الجذر لإقلاع البنية التحتية غير المتجانسة (cert-manager، ingress، مكدس المراقبة) حيث يحتاج كل تطبيق إلى إعداد فريد لا يناسب القالب.

ES
Edrees Salih
منذ ساعة

We are still cooking the magic in the way!