फ्रेमवर्क और एसडीके के बिना पायथन में कुबेरनेट्स ऑपरेटर

फ्रेमवर्क और एसडीके के बिना पायथन में कुबेरनेट्स ऑपरेटर

गो का वर्तमान में उन प्रोग्रामिंग भाषाओं पर एकाधिकार है जिन्हें लोग कुबेरनेट्स के लिए स्टेटमेंट लिखने के लिए चुनते हैं। इसके वस्तुनिष्ठ कारण हैं, जैसे:

  1. गो में ऑपरेटरों को विकसित करने के लिए एक शक्तिशाली ढांचा है - ऑपरेटर एसडीके.
  2. डॉकर और कुबेरनेट्स जैसे गेम-चेंजिंग एप्लिकेशन गो में लिखे गए हैं। अपने ऑपरेटर को गो में लिखने का अर्थ है पारिस्थितिकी तंत्र के साथ एक ही भाषा बोलना।
  3. गो एप्लिकेशन का उच्च प्रदर्शन और बॉक्स से बाहर समवर्ती के साथ काम करने के लिए सरल उपकरण।

NB: वैसे, गो में अपना स्टेटमेंट कैसे लिखें, हम पहले ही वर्णित है विदेशी लेखकों द्वारा हमारे एक अनुवाद में।

लेकिन क्या होगा यदि आपको समय की कमी या सीधे शब्दों में कहें तो प्रेरणा के कारण सीखने से रोका जाता है? लेख एक उदाहरण प्रदान करता है कि आप सबसे लोकप्रिय भाषाओं में से एक का उपयोग करके एक अच्छा कथन कैसे लिख सकते हैं जिसे लगभग हर DevOps इंजीनियर जानता है - अजगर.

मिलें: कॉपियर - कॉपी ऑपरेटर!

उदाहरण के तौर पर, कॉन्फिग मैप को कॉपी करने के लिए डिज़ाइन किए गए एक सरल कथन को विकसित करने पर विचार करें, जब कोई नया नेमस्पेस प्रकट होता है या जब दो संस्थाओं में से एक बदलता है: कॉन्फिग मैप और सीक्रेट। व्यावहारिक दृष्टिकोण से, ऑपरेटर एप्लिकेशन कॉन्फ़िगरेशन को बड़े पैमाने पर अपडेट करने (कॉन्फिग मैप को अपडेट करके) या गुप्त डेटा को अपडेट करने के लिए उपयोगी हो सकता है - उदाहरण के लिए, डॉकर रजिस्ट्री के साथ काम करने के लिए कुंजी (नेमस्पेस में सीक्रेट जोड़ते समय)।

इस प्रकार, एक अच्छे ऑपरेटर में क्या होना चाहिए:

  1. ऑपरेटर के साथ बातचीत का उपयोग करके किया जाता है कस्टम संसाधन परिभाषाएँ (इसके बाद सीआरडी के रूप में संदर्भित)।
  2. ऑपरेटर को कॉन्फ़िगर किया जा सकता है. ऐसा करने के लिए, हम कमांड लाइन फ़्लैग और पर्यावरण चर का उपयोग करेंगे।
  3. डॉकर कंटेनर और हेल्म चार्ट का निर्माण इस तरह से डिज़ाइन किया गया है कि उपयोगकर्ता आसानी से (शाब्दिक रूप से एक कमांड के साथ) ऑपरेटर को अपने कुबेरनेट्स क्लस्टर में स्थापित कर सकते हैं।

CRD

ऑपरेटर को यह जानने के लिए कि कौन से संसाधन देखने हैं और कहाँ देखना है, हमें उसके लिए एक नियम निर्धारित करने की आवश्यकता है। प्रत्येक नियम को एकल सीआरडी ऑब्जेक्ट के रूप में दर्शाया जाएगा। इस सीआरडी में कौन से फ़ील्ड होने चाहिए?

  1. संसाधन प्रकार, जिसे हम (ConfigMap या Secret) खोजेंगे।
  2. नामस्थानों की सूची, जिसमें संसाधन स्थित होने चाहिए।
  3. चयनकर्ता, जिसके द्वारा हम नेमस्पेस में संसाधनों की खोज करेंगे।

आइए सीआरडी का वर्णन करें:

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 जैसे लेबल वाले सभी कॉन्फ़िगमैप copyrator: "true":

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

तैयार! अब हमें किसी तरह अपने नियम के बारे में जानकारी हासिल करनी है. मैं तुरंत एक आरक्षण कर दूं कि हम स्वयं क्लस्टर एपीआई सर्वर के लिए अनुरोध नहीं लिखेंगे। ऐसा करने के लिए, हम एक तैयार पायथन लाइब्रेरी का उपयोग करेंगे 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. पर्यावरण चर का उपयोग करें.

कमांड लाइन विकल्प आपको डेटा प्रकार समर्थन और सत्यापन के साथ सेटिंग्स को अधिक लचीले ढंग से पढ़ने की अनुमति देते हैं। पायथन की मानक लाइब्रेरी में एक मॉड्यूल है 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 

संचालक तर्क

कॉन्फिग मैप और सीक्रेट के साथ काम करने के तरीकों को अलग करने के तरीके को समझने के लिए, हम विशेष मानचित्रों का उपयोग करेंगे। तब हम समझ सकते हैं कि ऑब्जेक्ट को ट्रैक करने और बनाने के लिए हमें किन तरीकों की आवश्यकता है:

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

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

इसके बाद, आपको एपीआई सर्वर से ईवेंट प्राप्त करने की आवश्यकता है। आइए इसे इस प्रकार कार्यान्वित करें:

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: पायथन के लिए कुबेरनेट्स क्लाइंट का अपना संस्करण है। क्लाइंट संस्करणों और कुबेरनेट्स संस्करणों के बीच संगतता के बारे में अधिक जानकारी यहां पाई जा सकती है संगतता मैट्रिक्स.

अब हमारा प्रोजेक्ट इस तरह दिखता है:

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 }}

संपूर्ण

इस तरह, बिना किसी डर, तिरस्कार या गो सीखने के, हम पायथन में कुबेरनेट्स के लिए अपना खुद का ऑपरेटर बनाने में सक्षम हुए। बेशक, इसमें अभी भी बढ़ने की गुंजाइश है: भविष्य में यह कई नियमों को संसाधित करने, कई थ्रेड्स में काम करने, स्वतंत्र रूप से अपने सीआरडी में बदलावों की निगरानी करने में सक्षम होगा...

आपको कोड को करीब से देखने के लिए, हमने इसे डाला है सार्वजनिक भंडार. यदि आप पायथन का उपयोग करके कार्यान्वित अधिक गंभीर ऑपरेटरों के उदाहरण चाहते हैं, तो आप अपना ध्यान मोंगोडब को तैनात करने के लिए दो ऑपरेटरों पर केंद्रित कर सकते हैं (первый и दूसरा).

पुनश्च और यदि आप कुबेरनेट्स घटनाओं से निपटने के लिए बहुत आलसी हैं या आप बैश का उपयोग करने के अधिक आदी हैं, तो हमारे सहयोगियों ने फॉर्म में एक तैयार समाधान तैयार किया है शेल-ऑपरेटर (हम की घोषणा की यह अप्रैल में)

पीपीएस

हमारे ब्लॉग पर भी पढ़ें:

स्रोत: www.habr.com

एक टिप्पणी जोड़ें