فریم ورک اور SDK کے بغیر ازگر میں Kubernetes آپریٹر

فریم ورک اور SDK کے بغیر ازگر میں Kubernetes آپریٹر

پروگرامنگ زبانوں پر فی الحال Go کی اجارہ داری ہے لوگ Kubernetes کے لیے بیانات لکھنے کا انتخاب کرتے ہیں۔ اس کی معروضی وجوہات ہیں، جیسے:

  1. گو میں آپریٹرز کی ترقی کے لیے ایک طاقتور فریم ورک ہے - آپریٹر SDK.
  2. گیم تبدیل کرنے والی ایپلی کیشنز جیسے Docker اور Kubernetes Go میں لکھے گئے ہیں۔ اپنے آپریٹر کو Go میں لکھنے کا مطلب ہے ایکو سسٹم کے ساتھ وہی زبان بولنا۔
  3. گو ایپلی کیشنز کی اعلی کارکردگی اور باکس سے باہر کنکرنسی کے ساتھ کام کرنے کے لیے آسان ٹولز۔

NB: ویسے، گو میں اپنا بیان کیسے لکھیں، ہم پہلے ہی بیان کیا گیا ہے۔ غیر ملکی مصنفین کے ہمارے ترجمے میں سے ایک میں۔

لیکن کیا ہوگا اگر آپ کو وقت کی کمی یا آسان الفاظ میں حوصلہ افزائی کی وجہ سے گو سیکھنے سے روکا جائے؟ مضمون اس بات کی ایک مثال فراہم کرتا ہے کہ آپ کس طرح مقبول ترین زبانوں میں سے ایک کا استعمال کرتے ہوئے ایک اچھا بیان لکھ سکتے ہیں جسے تقریباً ہر DevOps انجینئر جانتا ہے۔ ازگر.

ملو: کاپیئر - کاپی آپریٹر!

مثال کے طور پر، ایک سادہ سا بیان تیار کرنے پر غور کریں جو ConfigMap کو کاپی کرنے کے لیے ڈیزائن کیا گیا ہو یا تو جب کوئی نیا نام کی جگہ ظاہر ہو یا جب دو اداروں میں سے ایک تبدیل ہو: ConfigMap اور Secret۔ عملی نقطہ نظر سے، آپریٹر ایپلیکیشن کنفیگریشنز کی بلک اپڈیٹنگ (کنفیگ میپ کو اپ ڈیٹ کرکے) یا خفیہ ڈیٹا کو اپ ڈیٹ کرنے کے لیے کارآمد ثابت ہوسکتا ہے - مثال کے طور پر، ڈوکر رجسٹری کے ساتھ کام کرنے کے لیے کیز (جب نام کی جگہ میں سیکریٹ شامل کرتے ہیں)۔

اس طرح، ایک اچھا آپریٹر کیا ہونا چاہئے:

  1. آپریٹر کے ساتھ تعامل کا استعمال کرتے ہوئے کیا جاتا ہے حسب ضرورت وسائل کی تعریفیں (اس کے بعد CRD کہا جاتا ہے)۔
  2. آپریٹر کو ترتیب دیا جا سکتا ہے۔ ایسا کرنے کے لیے، ہم کمانڈ لائن فلیگ اور ماحولیاتی متغیرات استعمال کریں گے۔
  3. ڈوکر کنٹینر اور ہیلم چارٹ کی تعمیر کو ڈیزائن کیا گیا ہے تاکہ صارف آسانی سے (لفظی طور پر ایک کمانڈ کے ساتھ) آپریٹر کو اپنے Kubernetes کلسٹر میں انسٹال کر سکیں۔

CRD

آپریٹر کے لیے یہ جاننے کے لیے کہ کن وسائل کو تلاش کرنا ہے اور کہاں دیکھنا ہے، ہمیں اس کے لیے ایک اصول طے کرنے کی ضرورت ہے۔ ہر اصول کو ایک واحد CRD آبجیکٹ کے طور پر پیش کیا جائے گا۔ اس CRD میں کون سے فیلڈز ہونے چاہئیں؟

  1. وسائل کی قسم، جسے ہم تلاش کریں گے (ConfigMap یا Secret)۔
  2. نام کی جگہوں کی فہرست، جس میں وسائل واقع ہونے چاہئیں۔
  3. منتخب کنندہجس کے ذریعے ہم نام کی جگہ میں وسائل تلاش کریں گے۔

آئیے CRD کی وضاحت کریں:

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: copyrator.flant.com
spec:
  group: flant.com
  versions:
  - name: v1
    served: true
    storage: true
  scope: Namespaced
  names:
    plural: copyrators
    singular: copyrator
    kind: CopyratorRule
    shortNames:
    - copyr
  validation:
    openAPIV3Schema:
      type: object
      properties:
        ruleType:
          type: string
        namespaces:
          type: array
          items:
            type: string
        selector:
          type: string

اور ہم اسے فوراً بنا لیں گے۔ سادہ اصول - نام کے ساتھ نام کی جگہ میں تلاش کرنے کے لیے default تمام ConfigMap جیسے لیبل کے ساتھ copyrator: "true":

apiVersion: flant.com/v1
kind: CopyratorRule
metadata:
  name: main-rule
  labels:
    module: copyrator
ruleType: configmap
selector:
  copyrator: "true"
namespace: default

تیار! اب ہمیں کسی نہ کسی طرح اپنے اصول کے بارے میں معلومات حاصل کرنے کی ضرورت ہے۔ مجھے فوراً ایک ریزرویشن کرنے دو کہ ہم خود کلسٹر API سرور کو درخواستیں نہیں لکھیں گے۔ ایسا کرنے کے لیے، ہم ایک ریڈی میڈ Python لائبریری استعمال کریں گے۔ kubernetes-کلائنٹ:

import kubernetes
from contextlib import suppress


CRD_GROUP = 'flant.com'
CRD_VERSION = 'v1'
CRD_PLURAL = 'copyrators'


def load_crd(namespace, name):
    client = kubernetes.client.ApiClient()
    custom_api = kubernetes.client.CustomObjectsApi(client)

    with suppress(kubernetes.client.api_client.ApiException):
        crd = custom_api.get_namespaced_custom_object(
            CRD_GROUP,
            CRD_VERSION,
            namespace,
            CRD_PLURAL,
            name,
        )
    return {x: crd[x] for x in ('ruleType', 'selector', 'namespace')}

اس کوڈ کو چلانے کے نتیجے میں، ہمیں درج ذیل ملتا ہے:

{'ruleType': 'configmap', 'selector': {'copyrator': 'true'}, 'namespace': ['default']}

بہت اچھا: ہم آپریٹر کے لیے ایک اصول حاصل کرنے میں کامیاب ہو گئے۔ اور سب سے اہم بات یہ ہے کہ ہم نے وہی کیا جسے Kubernetes طریقہ کہا جاتا ہے۔

ماحولیاتی متغیرات یا جھنڈے؟ ہم سب کچھ لیتے ہیں!

آئیے مین آپریٹر کنفیگریشن کی طرف چلتے ہیں۔ ایپلی کیشنز کو ترتیب دینے کے لیے دو بنیادی طریقے ہیں:

  1. کمانڈ لائن کے اختیارات استعمال کریں؛
  2. ماحولیاتی متغیرات کا استعمال کریں۔

کمانڈ لائن کے اختیارات آپ کو ڈیٹا کی قسم کی حمایت اور توثیق کے ساتھ ترتیبات کو زیادہ لچکدار طریقے سے پڑھنے کی اجازت دیتے ہیں۔ ازگر کی معیاری لائبریری میں ایک ماڈیول ہے۔ argparser، جسے ہم استعمال کریں گے۔ اس کی صلاحیتوں کی تفصیلات اور مثالیں موجود ہیں۔ سرکاری دستاویزات.

ہمارے معاملے کے لیے، ریڈنگ کمانڈ لائن جھنڈوں کو ترتیب دینے کی مثال اس طرح نظر آئے گی:

   parser = ArgumentParser(
        description='Copyrator - copy operator.',
        prog='copyrator'
    )
    parser.add_argument(
        '--namespace',
        type=str,
        default=getenv('NAMESPACE', 'default'),
        help='Operator Namespace'
    )
    parser.add_argument(
        '--rule-name',
        type=str,
        default=getenv('RULE_NAME', 'main-rule'),
        help='CRD Name'
    )
    args = parser.parse_args()

دوسری طرف، Kubernetes میں ماحولیاتی متغیرات کا استعمال کرتے ہوئے، آپ آسانی سے کنٹینر کے اندر پوڈ کے بارے میں سروس کی معلومات کو منتقل کر سکتے ہیں۔ مثال کے طور پر، ہم نام کی جگہ کے بارے میں معلومات حاصل کر سکتے ہیں جس میں پوڈ درج ذیل تعمیر کے ساتھ چل رہا ہے:

env:
- name: NAMESPACE
  valueFrom:
     fieldRef:
         fieldPath: metadata.namespace 

آپریٹر منطق

یہ سمجھنے کے لیے کہ ConfigMap اور Secret کے ساتھ کام کرنے کے طریقوں کو کیسے الگ کیا جائے، ہم خصوصی نقشے استعمال کریں گے۔ تب ہم سمجھ سکتے ہیں کہ ہمیں آبجیکٹ کو ٹریک کرنے اور بنانے کے لیے کن طریقوں کی ضرورت ہے:

LIST_TYPES_MAP = {
    'configmap': 'list_namespaced_config_map',
    'secret': 'list_namespaced_secret',
}

CREATE_TYPES_MAP = {
    'configmap': 'create_namespaced_config_map',
    'secret': 'create_namespaced_secret',
}

اگلا، آپ کو API سرور سے واقعات موصول کرنے کی ضرورت ہے۔ آئیے اسے مندرجہ ذیل طور پر لاگو کریں:

def handle(specs):
    kubernetes.config.load_incluster_config()
    v1 = kubernetes.client.CoreV1Api()

    # Получаем метод для слежения за объектами
    method = getattr(v1, LIST_TYPES_MAP[specs['ruleType']])
    func = partial(method, specs['namespace'])

    w = kubernetes.watch.Watch()
    for event in w.stream(func, _request_timeout=60):
        handle_event(v1, specs, event)

ایونٹ حاصل کرنے کے بعد، ہم اس پر کارروائی کرنے کی بنیادی منطق کی طرف بڑھتے ہیں:

# Типы событий, на которые будем реагировать
ALLOWED_EVENT_TYPES = {'ADDED', 'UPDATED'}


def handle_event(v1, specs, event):
    if event['type'] not in ALLOWED_EVENT_TYPES:
        return

    object_ = event['object']
    labels = object_['metadata'].get('labels', {})

    # Ищем совпадения по selector'у
    for key, value in specs['selector'].items():
        if labels.get(key) != value:
            return
    # Получаем активные namespace'ы
    namespaces = map(
        lambda x: x.metadata.name,
        filter(
            lambda x: x.status.phase == 'Active',
            v1.list_namespace().items
        )
    )
    for namespace in namespaces:
        # Очищаем метаданные, устанавливаем namespace
        object_['metadata'] = {
            'labels': object_['metadata']['labels'],
            'namespace': namespace,
            'name': object_['metadata']['name'],
        }
        # Вызываем метод создания/обновления объекта
        methodcaller(
            CREATE_TYPES_MAP[specs['ruleType']],
            namespace,
            object_
        )(v1)

اہم منطق تیار ہے! اب ہمیں یہ سب ایک Python پیکیج میں پیک کرنے کی ضرورت ہے۔ ہم فائل تیار کرتے ہیں۔ setup.py، وہاں پروجیکٹ کے بارے میں میٹا معلومات لکھیں:

from sys import version_info

from setuptools import find_packages, setup

if version_info[:2] < (3, 5):
    raise RuntimeError(
        'Unsupported python version %s.' % '.'.join(version_info)
    )


_NAME = 'copyrator'
setup(
    name=_NAME,
    version='0.0.1',
    packages=find_packages(),
    classifiers=[
        'Development Status :: 3 - Alpha',
        'Programming Language :: Python',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.5',
        'Programming Language :: Python :: 3.6',
        'Programming Language :: Python :: 3.7',
    ],
    author='Flant',
    author_email='[email protected]',
    include_package_data=True,
    install_requires=[
        'kubernetes==9.0.0',
    ],
    entry_points={
        'console_scripts': [
            '{0} = {0}.cli:main'.format(_NAME),
        ]
    }
)

NB: Python کے لیے kubernetes کلائنٹ کا اپنا ورژن ہے۔ کلائنٹ ورژن اور Kubernetes ورژن کے درمیان مطابقت کے بارے میں مزید معلومات میں مل سکتی ہے۔ مطابقت کے میٹرکس.

اب ہمارا پروجیکٹ اس طرح لگتا ہے:

copyrator
├── copyrator
│   ├── cli.py # Логика работы с командной строкой
│   ├── constant.py # Константы, которые мы приводили выше
│   ├── load_crd.py # Логика загрузки CRD
│   └── operator.py # Основная логика работы оператора
└── setup.py # Оформление пакета

ڈوکر اور ہیلم

Dockerfile ناقابل یقین حد تک آسان ہو گا: بیس python-alpine امیج لیں اور ہمارا پیکج انسٹال کریں۔ آئیے اس کی اصلاح کو بہتر وقت تک ملتوی کرتے ہیں:

FROM python:3.7.3-alpine3.9

ADD . /app

RUN pip3 install /app

ENTRYPOINT ["copyrator"]

آپریٹر کے لیے تعیناتی بھی بہت آسان ہے:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Chart.Name }}
spec:
  selector:
    matchLabels:
      name: {{ .Chart.Name }}
  template:
    metadata:
      labels:
        name: {{ .Chart.Name }}
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: privaterepo.yourcompany.com/copyrator:latest
        imagePullPolicy: Always
        args: ["--rule-type", "main-rule"]
        env:
        - name: NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
      serviceAccountName: {{ .Chart.Name }}-acc

آخر میں، آپ کو ضروری حقوق کے ساتھ آپریٹر کے لیے ایک مناسب کردار بنانے کی ضرورت ہے:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: {{ .Chart.Name }}-acc

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: {{ .Chart.Name }}
rules:
  - apiGroups: [""]
    resources: ["namespaces"]
    verbs: ["get", "watch", "list"]
  - apiGroups: [""]
    resources: ["secrets", "configmaps"]
    verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: {{ .Chart.Name }}
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: {{ .Chart.Name }}
subjects:
- kind: ServiceAccount
  name: {{ .Chart.Name }}

کل

اس طرح، بغیر کسی خوف، ملامت، یا Go سیکھنے کے، ہم Python میں Kubernetes کے لیے اپنا آپریٹر بنانے کے قابل ہو گئے۔ بلاشبہ، اس میں اب بھی بڑھنے کی گنجائش ہے: مستقبل میں یہ متعدد اصولوں پر عمل کرنے، متعدد تھریڈز میں کام کرنے، آزادانہ طور پر اپنے CRDs میں ہونے والی تبدیلیوں کی نگرانی کر سکے گا...

آپ کو کوڈ کو قریب سے دیکھنے کے لیے، ہم نے اسے ڈال دیا ہے۔ عوامی ذخیرہ. اگر آپ Python کا استعمال کرتے ہوئے مزید سنجیدہ آپریٹرز کی مثالیں نافذ کرنا چاہتے ہیں، تو آپ mongodb (первый и دوسری).

PS اور اگر آپ Kubernetes کے واقعات سے نمٹنے میں بہت سست ہیں یا آپ Bash استعمال کرنے کے زیادہ عادی ہیں، تو ہمارے ساتھیوں نے فارم میں ایک تیار حل تیار کیا ہے۔ شیل آپریٹر (ہم اعلان کیا یہ اپریل میں)۔

پی پی ایس

ہمارے بلاگ پر بھی پڑھیں:

ماخذ: www.habr.com

نیا تبصرہ شامل کریں