ڪبرنيٽس آپريٽر پٿون ۾ فريم ورڪ ۽ SDK کان سواءِ

ڪبرنيٽس آپريٽر پٿون ۾ فريم ورڪ ۽ SDK کان سواءِ

Go في الحال پروگرامنگ ٻولين تي هڪ هٽي آهي ماڻهو ڪبرنيٽس لاءِ بيان لکڻ لاءِ چونڊيندا آهن. ان جا مقصدي سبب آهن، جهڙوڪ:

  1. گو ۾ آپريٽرز کي ترقي ڪرڻ لاءِ هڪ طاقتور فريم ورڪ آهي - آپريٽر SDK.
  2. راند بدلائڻ واريون ايپليڪيشنون جهڙوڪ Docker ۽ Kubernetes گو ۾ لکيل آهن. توهان جي آپريٽر کي Go ۾ لکڻ جو مطلب آهي ايڪو سسٽم سان ساڳي ٻولي ڳالهائڻ.
  3. گو ايپليڪيشنن جي اعلي ڪارڪردگي ۽ دٻي کان ٻاهر ڪم ڪرڻ لاء سادي اوزار.

NB: رستي جي ذريعي، توهان جي پنهنجي بيان کي ڪيئن لکڻ لاء Go، we اڳ ۾ ئي بيان ڪيو ويو آهي اسان جي ترجمي مان هڪ ۾ پرڏيهي ليکڪن طرفان.

پر ڇا جيڪڏهن توهان کي وقت جي کوٽ جي ڪري سکڻ کان روڪيو وڃي يا، آسانيء سان، حوصلہ افزائي؟ آرٽيڪل هڪ مثال پيش ڪري ٿو ته توهان هڪ تمام مشهور ٻولين مان هڪ استعمال ڪندي سٺو بيان ڪيئن لکي سگهو ٿا جيڪا تقريبن هر DevOps انجنيئر ڄاڻي ٿو - Python.

ملو: ڪاپيئر - ڪاپي آپريٽر!

مثال طور، هڪ سادي بيان ٺاهڻ تي غور ڪريو جيڪو ConfigMap کي نقل ڪرڻ لاءِ ٺاهيو ويو آهي يا ته جڏهن نئين نالي جي جاءِ ظاهر ٿئي يا جڏهن ٻن ادارن مان هڪ تبديل ٿئي: ConfigMap ۽ راز. عملي نقطي نظر کان، آپريٽر ايپليڪيشن ترتيبن جي وڏي تعداد ۾ تازه ڪاري ڪرڻ (ConfigMap کي اپڊيٽ ڪرڻ) يا ڳجهي ڊيٽا کي اپڊيٽ ڪرڻ لاءِ ڪارائتو ٿي سگهي ٿو - مثال طور، Docker رجسٽري سان ڪم ڪرڻ لاءِ ڪنجيون (جڏهن نالي جي جاءِ تي راز شامل ڪندي).

۽ ائين، ڇا هڪ سٺو آپريٽر هجڻ گهرجي:

  1. آپريٽر سان رابطي جو استعمال ڪيو ويندو آهي حسب ضرورت وسيلن جي وصف (هتان کان پوء CRD طور حوالو ڏنو ويو).
  2. آپريٽر ترتيب ڏئي سگهجي ٿو. هن کي ڪرڻ لاء، اسان استعمال ڪنداسين ڪمانڊ لائين پرچم ۽ ماحولياتي متغير.
  3. ڊاڪر ڪنٽينر جي تعمير ۽ هيلم چارٽ ٺهيل آهي ته جيئن صارف آساني سان (لفظي طور هڪ حڪم سان) آپريٽر کي پنهنجي ڪبرنيٽس ڪلستر ۾ انسٽال ڪري سگهن.

CRD

آپريٽر کي ڄاڻڻ لاءِ ڪھڙا وسيلا ڳولڻ ۽ ڪٿي ڏسڻ لاءِ، اسان کي ان لاءِ ضابطو مقرر ڪرڻ گھرجي. هر قاعدي کي هڪ واحد CRD اعتراض طور پيش ڪيو ويندو. ھن CRD کي ڪھڙا شعبا ھجن؟

  1. وسيلن جو قسم، جنهن کي اسين ڳولينداسين (ConfigMap يا راز).
  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 سرور ڏانهن درخواستون نه لکنداسين. هن کي ڪرڻ لاء، اسان هڪ تيار ڪيل پٿون لائبريري استعمال ڪنداسين 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']}

عظيم: اسان آپريٽر لاءِ هڪ قاعدو حاصل ڪرڻ ۾ ڪامياب ٿياسين. ۽ سڀ کان اهم، اسان اهو ڪيو جيڪو ڪبرنيٽس رستو سڏيو ويندو آهي.

ماحولياتي متغير يا پرچم؟ اسان سڀ ڪجهه وٺون ٿا!

اچو ته مکيه آپريٽر جي ترتيب ڏانهن وڃو. ايپليڪيشنن کي ترتيب ڏيڻ لاء ٻه بنيادي طريقا آهن:

  1. ڪمانڊ لائن جا اختيار استعمال ڪريو؛
  2. ماحولياتي متغير استعمال ڪريو.

ڪمانڊ لائن جا اختيار توهان کي سيٽنگون پڙهڻ جي اجازت ڏين ٿا وڌيڪ لچڪدار، ڊيٽا جي قسم جي حمايت ۽ تصديق سان. Python جي معياري لائبريري ۾ هڪ ماڊل آهي 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()

ٻئي طرف، ڪبرنيٽس ۾ ماحولياتي متغير استعمال ڪندي، توهان آساني سان ڪنٽينر اندر پوڊ بابت سروس معلومات منتقل ڪري سگهو ٿا. مثال طور، اسان نالي جي جڳھ بابت معلومات حاصل ڪري سگھون ٿا جنھن ۾ پوڊ ھيٺ ڏنل تعمير سان ھلندو آھي.

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)

مکيه منطق تيار آهي! ھاڻي اسان کي ھي سڀ ھڪڙي پيٿون پيڪيج ۾ پيڪ ڪرڻ جي ضرورت آھي. اسان فائل تيار ڪريون ٿا 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: kubernetes ڪلائنٽ Python لاءِ پنهنجي ورزننگ آهي. ڪلائنٽ ورزن ۽ Kubernetes ورزن جي وچ ۾ مطابقت بابت وڌيڪ معلومات ملي سگهي ٿي مطابقت جي ماپ.

هاڻي اسان جو منصوبو هن طرح نظر اچي ٿو:

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

ڊاڪر ۽ هيلم

Dockerfile ناقابل يقين حد تائين سادو ٿيندو: بنيادي پيٿون-الپائن تصوير وٺو ۽ اسان جو پيڪيج انسٽال ڪريو. اچو ته بهتر وقت تائين ان جي اصلاح کي ملتوي ڪريون:

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، اسان پائٿون ۾ ڪبرنيٽس لاءِ پنهنجو آپريٽر ٺاهي سگهندا هئاسين. يقينن، اهو اڃا تائين وڌڻ جي گنجائش آهي: مستقبل ۾ اهو ڪيترن ئي قاعدن تي عمل ڪرڻ جي قابل هوندو، ڪيترن ئي موضوعن ۾ ڪم ڪرڻ، آزاديء سان پنهنجي CRDs ۾ تبديلين جي نگراني ڪندو ...

توهان کي ڪوڊ تي هڪ ويجهي نظر ڏيڻ لاء، اسان ان کي داخل ڪيو آهي عوامي مخزن. جيڪڏھن توھان چاھيو ٿا وڌيڪ سنگين آپريٽرز جا مثال جيڪي پائٿون استعمال ڪندي لاڳو ڪيا ويا آھن، توھان پنھنجو ڌيان ٻن آپريٽرن ڏانھن موڙي سگھو ٿا mongodb (первый и ٻيو).

PS ۽ جيڪڏهن توهان ڪبرنيٽس جي واقعن کي منهن ڏيڻ ۾ تمام سست آهيو يا توهان صرف بش استعمال ڪرڻ جا عادي آهيو، اسان جي ساٿين فارم ۾ تيار ڪيل حل تيار ڪيو آهي. شيل آپريٽر (اسان اعلان ڪيو اپريل ۾).

پي پي ايس

اسان جي بلاگ تي پڻ پڙهو:

جو ذريعو: www.habr.com

تبصرو شامل ڪريو