Rook or not Rook - هذا هو السؤال



في وقت سابق من هذا الشهر ، 3 مايو ، تم الإعلان عن إصدار رئيسي من "نظام إدارة مستودعات البيانات الموزعة في Kubernetes" - Rook 1.0.0 . منذ أكثر من عام ، نشرنا بالفعل نظرة عامة على Rook. ثم طُلب منا التحدث عن تجربة استخدامه في الممارسة - والآن ، وفي الوقت المناسب لمثل هذا المعلم الهام في تاريخ المشروع ، يسرنا أن نشارك انطباعاتنا المتراكمة.

باختصار ، Rook عبارة عن مجموعة من مشغلي Kubernetes التي تتحكم بالكامل في نشر حلول التخزين وإدارتها واستردادها تلقائيًا مثل Ceph و EdgeFS و Minio و Cassandra و CockroachDB.

في الوقت الحالي ، فإن أكثر الحلول تطوراً ( والوحيد في مرحلة مستقرة ) هو المشغل الصخري .

ملاحظة : من بين التغييرات المهمة في إصدار Rook 1.0.0 المتعلقة بدعم Ceph ، يمكن الإشارة إلى Ceph Nautilus والقدرة على استخدام NFS لدلو CephFS أو RGW. من بين أمور أخرى ، يبرز "نضج" دعم EdgeFS إلى مستوى الإصدار التجريبي.

لذلك ، في هذه المقالة نحن:

  • أجب عن السؤال حول المزايا التي نراها في استخدام Rook لنشر Ceph في مجموعة Kubernetes ؛
  • تبادل الخبرات وانطباعات استخدام Rook في الإنتاج ؛
  • سنخبرك لماذا نقول "نعم!" لـ Rook وخططنا له.

لنبدأ بالمفاهيم والنظرية العامة.

"لدي ميزة في رخ واحد!" (لاعب شطرنج غير معروف)




إحدى المزايا الرئيسية لـ Rook هي أن التفاعل مع مستودعات البيانات يتم من خلال آليات Kubernetes. هذا يعني أنك لم تعد بحاجة لنسخ الأوامر لتكوين Ceph من النشرة إلى وحدة التحكم.

- هل تريد النشر في مجموعة CephFS؟ فقط اكتب ملف yaml!
- ماذا؟ هل تريد نشر ملف تخزين عناصر باستخدام S3 API؟ فقط اكتب ملف yaml الثاني!

يتم إنشاء الغراب من قبل جميع قواعد مشغل نموذجي. يحدث التفاعل معها بمساعدة CRD (تعريفات الموارد المخصصة) ، حيث نصف خصائص كيانات Ceph التي نحتاجها (نظرًا لأن هذا هو التطبيق الثابت الوحيد ، ستتحدث المقالة افتراضيًا عن Ceph ، ما لم ينص صراحة على خلاف ذلك) . وفقًا للمعايير المحددة ، سيقوم المشغل تلقائيًا بتنفيذ الأوامر اللازمة للإعداد.

دعنا ننظر إلى التفاصيل باستخدام مثال إنشاء كائن تخزين ، أو بالأحرى CephObjectStoreUser .

 apiVersion: ceph.rook.io/v1 kind: CephObjectStore metadata: name: {{ .Values.s3.crdName }} namespace: kube-rook spec: metadataPool: failureDomain: host replicated: size: 3 dataPool: failureDomain: host erasureCoded: dataChunks: 2 codingChunks: 1 gateway: type: s3 sslCertificateRef: port: 80 securePort: instances: 1 allNodes: false --- apiVersion: ceph.rook.io/v1 kind: CephObjectStoreUser metadata: name: {{ .Values.s3.crdName }} namespace: kube-rook spec: store: {{ .Values.s3.crdName }} displayName: {{ .Values.s3.username }} 

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

يعود مخطط العمل العام إلى حقيقة أننا من خلال ملف YAML نقوم "بترتيب" الموارد ، والتي ينفذ المشغل بها الأوامر اللازمة ويعيدنا إلى السر "غير الحقيقي" ، الذي يمكننا من خلاله مواصلة العمل (انظر أدناه) . ومن المتغيرات المشار إليها أعلاه ، سيتم إنشاء الأمر واسم السر.

أي نوع من الفريق هو هذا؟ عند إنشاء مستخدم لتخزين الكائنات ، ستقوم عبارة Rook داخل الحافظة بما يلي:

 radosgw-admin user create --uid="rook-user" --display-name="{{ .Values.s3.username }}" 

ستكون نتيجة هذا الأمر بنية JSON:

 { "user_id": "rook-user", "display_name": "{{ .Values.s3.username }}", "keys": [ { "user": "rook-user", "access_key": "NRWGT19TWMYOB1YDBV1Y", "secret_key": "gr1VEGIV7rxcP3xvXDFCo4UDwwl2YoNrmtRlIAty" } ], ... } 

Keys هي ما ستحتاجه التطبيقات المستقبلية للوصول إلى تخزين الكائنات من خلال S3 API. يرجى من مشغل rook-ceph-object-user-{{ $.Values.s3.crdName }}-{{ $.Values.s3.username }} في مساحة الاسم الخاصة به في شكل سر يحمل اسم rook-ceph-object-user-{{ $.Values.s3.crdName }}-{{ $.Values.s3.username }} .

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

 {{- range $bucket := $.Values.s3.bucketNames }} apiVersion: batch/v1 kind: Job metadata: name: create-{{ $bucket }}-bucket-job annotations: "helm.sh/hook": post-install "helm.sh/hook-weight": "2" spec: template: metadata: name: create-{{ $bucket }}-bucket-job spec: restartPolicy: Never initContainers: - name: waitdns image: alpine:3.6 command: ["/bin/sh", "-c", "while ! getent ahostsv4 rook-ceph-rgw-{{ $.Values.s3.crdName }}; do sleep 1; done" ] - name: config image: rook/ceph:v1.0.0 command: ["/bin/sh", "-c"] args: ["s3cmd --configure --access_key=$(ACCESS-KEY) --secret_key=$(SECRET-KEY) -s --no-ssl --dump-config | tee /config/.s3cfg"] volumeMounts: - name: config mountPath: /config env: - name: ACCESS-KEY valueFrom: secretKeyRef: name: rook-ceph-object-user-{{ $.Values.s3.crdName }}-{{ $.Values.s3.username }} key: AccessKey - name: SECRET-KEY valueFrom: secretKeyRef: name: rook-ceph-object-user-{{ $.Values.s3.crdName }}-{{ $.Values.s3.username }} key: SecretKey containers: - name: create-bucket image: rook/ceph:v1.0.0 command: - "s3cmd" - "mb" - "--host=rook-ceph-rgw-{{ $.Values.s3.crdName }}" - "--host-bucket= " - "s3://{{ $bucket }}" ports: - name: s3-no-sll containerPort: 80 volumeMounts: - name: config mountPath: /root volumes: - name: config emptyDir: {} --- {{- end }} 

تم تنفيذ جميع الأنشطة المدرجة في هذه الوظيفة دون تجاوز Kubernetes. يتم طي الهياكل الموصوفة في ملفات YAML في مستودع Git وإعادة استخدامها بشكل متكرر. في هذا ، نشهد إضافة كبيرة لمهندسي DevOps وعملية CI / CD ككل.

مع الغراب ورادوس الفرح


باستخدام مجموعة من Ceph + RBD يفرض قيودًا معينة على وحدات تخزين متزايدة على السنفات.

على وجه الخصوص ، يجب أن يكون لمساحة الاسم سرًا للوصول إلى Ceph حتى تعمل التطبيقات ذات الحالة. لا بأس إذا كان لديك 2-3 بيئات في مساحات الأسماء الخاصة بك: يمكنك الانتقال ونسخ السر يدويًا. ولكن ماذا لو أن كل ميزة مطور تنشئ بيئة منفصلة بمساحة الاسم الخاصة بها؟

لقد حللنا هذه المشكلة بمساعدة مشغل shell الذي قام بنسخ الأسرار تلقائيًا إلى مساحة الاسم الجديدة (تم توضيح مثال على مثل هذا الخطاف في هذه المقالة ).

 #! /bin/bash if [[ $1 == “--config” ]]; then cat <<EOF {"onKubernetesEvent":[ {"name": "OnNewNamespace", "kind": "namespace", "event": ["add"] } ]} EOF else NAMESPACE=$(kubectl get namespace -o json | jq '.items | max_by( .metadata.creationTimestamp ) | .metadata.name') kubectl -n ${CEPH_SECRET_NAMESPACE} get secret ${CEPH_SECRET_NAME} -o json | jq ".metadata.namespace=\"${NAMESPACE}\"" | kubectl apply -f - fi 

ومع ذلك ، عند استخدام Rook ، هذه المشكلة ببساطة غير موجودة. تتم عملية التثبيت باستخدام برامج التشغيل الخاصة بك استنادًا إلى Flexvolume أو CSI (لا تزال في مرحلة تجريبية) وبالتالي لا تتطلب أسرارًا.

يعمل Rook تلقائيًا على حل العديد من المشكلات ، مما يشجعنا على استخدامه في مشاريع جديدة.

حصار الرخ


نكمل الجزء العملي بنشر Rook و Ceph لإمكانية إجراء تجاربنا الخاصة. من أجل اقتحام هذا البرج المشدود كان الأمر أسهل ، فقد أعد المطورون حزمة Helm. لنقم بتنزيلها:

 $ helm fetch rook-master/rook-ceph --untar --version 1.0.0 

rook-ceph/values.yaml العثور على العديد من الإعدادات المختلفة في ملف rook-ceph/values.yaml . الأهم من ذلك ، تحديد التسامح لوكلاء والبحث. لماذا يمكنك استخدام آلية الطلاء / التسامح ، لقد وصفنا بالتفصيل في هذه المقالة .

باختصار ، لا نريد تحديد موقع القرون التي تحتوي على تطبيق العميل على نفس العقد التي توجد بها أقراص تخزين البيانات. السبب بسيط: بهذه الطريقة لن يؤثر عمل وكلاء Rook على التطبيق نفسه.

لذلك ، افتح الملف rook-ceph/values.yaml المفضل وأضف الكتلة التالية إلى النهاية:

 discover: toleration: NoExecute tolerationKey: node-role/storage agent: toleration: NoExecute tolerationKey: node-role/storage mountSecurityMode: Any 

لكل عقدة مخصصة لتخزين البيانات ، أضف المادة المناسبة:

 $ kubectl taint node ${NODE_NAME} node-role/storage="":NoExecute 

ثم قم بتثبيت مخطط Helm باستخدام الأمر:

 $ helm install --namespace ${ROOK_NAMESPACE} ./rook-ceph 

أنت الآن بحاجة إلى إنشاء كتلة والإشارة إلى موقع OSD :

 apiVersion: ceph.rook.io/v1 kind: CephCluster metadata: clusterName: "ceph" finalizers: - cephcluster.ceph.rook.io generation: 1 name: rook-ceph spec: cephVersion: image: ceph/ceph:v13 dashboard: enabled: true dataDirHostPath: /var/lib/rook/osd mon: allowMultiplePerNode: false count: 3 network: hostNetwork: true rbdMirroring: workers: 1 placement: all: tolerations: - key: node-role/storage operator: Exists storage: useAllNodes: false useAllDevices: false config: osdsPerDevice: "1" storeType: filestore resources: limits: memory: "1024Mi" requests: memory: "1024Mi" nodes: - name: host-1 directories: - path: "/mnt/osd" - name: host-2 directories: - path: "/mnt/osd" - name: host-3 directories: - path: "/mnt/osd" 

التحقق من حالة HEALTH_OK - من المتوقع أن ترى HEALTH_OK :

 $ kubectl -n ${ROOK_NAMESPACE} exec $(kubectl -n ${ROOK_NAMESPACE} get pod -l app=rook-ceph-operator -o name -o jsonpath='{.items[0].metadata.name}') -- ceph -s 

في الوقت نفسه ، تحقق من عدم وصول القرون مع تطبيق العميل إلى العقد المحجوزة لـ Ceph:

 $ kubectl -n ${APPLICATION_NAMESPACE} get pods -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName 

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

الصخور والسنانير: هل الغراب كافية لكل شيء؟


كما ترون ، فإن تطوير Rook على قدم وساق. ولكن لا تزال هناك مشاكل لا تسمح لنا بالتخلي عن التكوين اليدوي لـ Ceph تمامًا:

  • لا يمكن لبرنامج تشغيل Rook تصدير مقاييس حول استخدام الكتل المركبة ، مما يحرمنا من المراقبة.
  • لا يعرف Flexvolume و CSI كيفية تغيير حجم وحدات التخزين (على عكس نفس RBD) ، لذلك يفقد Rook أداة مفيدة (وضرورية في بعض الأحيان!).
  • الرخ لا يزال غير مرن مثل Ceph العادية. إذا كنا نرغب في تكوين مجموعة البيانات الوصفية لـ CephFS ليتم تخزينها على SSD ، والبيانات نفسها على HDD ، فسنحتاج إلى تسجيل مجموعات الأجهزة الفردية يدويًا في خرائط CRUSH.
  • على الرغم من أن مشغل rook-ceph يعتبر ثابتًا ، إلا أنه في الوقت الحالي توجد بعض المشكلات عند تحديث Ceph من الإصدار 13 إلى 14.

النتائج


"الآن أصبحت Rook مغلقة عن العالم الخارجي عن طريق البيادق ، لكننا نعتقد أنها ستلعب ذات يوم دورًا مهمًا في الحفلة!" (اخترع اقتباس على وجه التحديد لهذا المقال)

لقد حقق مشروع Rook ربحًا بلا شك - نعتقد أنه [بكل إيجابيات وسلبيات] فهو بالتأكيد يستحق اهتمامك.

تكمن خططنا الإضافية في جعل rook-ceph وحدة نمطية للمشغل الإضافي ، والتي ستستخدمها في مجموعات Kubernetes العديدة لدينا بشكل أبسط وأكثر ملاءمة.

PS


اقرأ أيضًا في مدونتنا:

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


All Articles