په پایتون کې د کوبرنیټس آپریټر پرته له چوکاټونو او SDK څخه

په پایتون کې د کوبرنیټس آپریټر پرته له چوکاټونو او SDK څخه

Go اوس مهال د برنامه کولو ژبو انحصار لري خلک د Kubernetes لپاره بیانات لیکل غوره کوي. د دې لپاره معقول دلایل شتون لري، لکه:

  1. په Go کې د آپریټرانو پراختیا لپاره یو پیاوړی چوکاټ شتون لري - آپریټر SDK.
  2. د لوبې بدلولو غوښتنلیکونه لکه Docker او Kubernetes په Go کې لیکل شوي. په Go کې د خپل آپریټر لیکل پدې معنی دي چې د اکوسیستم سره ورته ژبه خبرې کول.
  3. د ګو غوښتنلیکونو لوړ فعالیت او د بکس څخه بهر همغږي سره کار کولو لپاره ساده وسیلې.

NB: په لاره کې، څنګه په Go کې خپل بیان ولیکئ، موږ دمخه تشریح شوی زموږ په یوه ژباړه کې د بهرنیو لیکوالانو لخوا.

مګر که تاسو د وخت نشتوالي یا په ساده ډول د هڅونې له امله د زده کړې مخه ونیسئ؟ مقاله یو مثال وړاندې کوي چې تاسو څنګه کولی شئ د یوې خورا مشهورې ژبې په کارولو سره ښه بیان ولیکئ چې نږدې هر DevOps انجینر پوهیږي - Python.

ملاقات: کاپير - کاپي آپریټر!

د مثال په توګه، د یو ساده بیان رامینځته کول په پام کې ونیسئ چې د ConfigMap د کاپي کولو لپاره ډیزاین شوي یا کله چې د نوي نوم ځای څرګند شي یا کله چې د دوو ادارو څخه یو بدل شي: ConfigMap او Secret. د عملي لید څخه ، آپریټر کولی شي د غوښتنلیک تنظیماتو لوی تازه کولو (د ConfigMap تازه کولو سره) یا د پټ ډیټا تازه کولو لپاره ګټور وي - د مثال په توګه ، د ډاکر راجسټری سره کار کولو کیلي (کله چې د نوم ځای ته راز اضافه کول).

او همداسې، کوم ښه چلوونکی باید ولري:

  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 سرور ته غوښتنې ونه لیکو. د دې کولو لپاره، موږ به د تیار شوي 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']}

عالي: موږ وکولی شو د آپریټر لپاره قاعده ترلاسه کړو. او تر ټولو مهم، موږ هغه څه وکړل چې د کوبرنیټس لاره بلل کیږي.

د چاپیریال تغیرات یا بیرغونه؟ موږ هرڅه اخلو!

راځئ چې د اصلي آپریټر ترتیب ته لاړ شو. د غوښتنلیکونو تنظیم کولو لپاره دوه اساسي لارې شتون لري:

  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()

له بلې خوا، په 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 # Оформление пакета

ډاکر او هیلم

د ډاکرفایل به خورا په زړه پوري ساده وي: د بیس پایتون - الپین عکس واخلئ او زموږ کڅوړه نصب کړئ. راځئ چې د هغې اصلاح تر غوره وخت پورې وځنډوو:

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 په کارولو سره پلي شوي د نورو جدي آپریټرانو مثالونه غواړئ ، نو تاسو کولی شئ د مونګوډب ځای پرځای کولو لپاره دوه آپریټرانو ته پاملرنه وکړئ (первый и دوهم).

PS او که تاسو د کوبرنیټس پیښو سره معامله کولو کې ډیر سست یاست یا تاسو د باش کارولو سره ډیر عادی یاست ، زموږ همکارانو په فورمه کې چمتو شوی حل چمتو کړی. شیل چلونکی (موږ اعلان شو دا په اپریل کې).

پی پی ایس

زموږ په بلاګ کې هم ولولئ:

سرچینه: www.habr.com

Add a comment