फ्रेमवर्क आणि SDK शिवाय पायथनमधील Kubernetes ऑपरेटर

फ्रेमवर्क आणि SDK शिवाय पायथनमधील Kubernetes ऑपरेटर

गो ची सध्या प्रोग्रामिंग भाषांवर मक्तेदारी आहे जे लोक कुबरनेटसाठी विधाने लिहिण्यासाठी निवडतात. याची वस्तुनिष्ठ कारणे आहेत, जसे की:

  1. Go मध्ये ऑपरेटर विकसित करण्यासाठी एक शक्तिशाली फ्रेमवर्क आहे - ऑपरेटर SDK.
  2. Docker आणि Kubernetes सारखे गेम बदलणारे ऍप्लिकेशन Go मध्ये लिहिलेले आहेत. तुमचा ऑपरेटर Go मध्ये लिहिणे म्हणजे इकोसिस्टमसह समान भाषा बोलणे.
  3. गो ऍप्लिकेशन्सची उच्च कार्यक्षमता आणि बॉक्सच्या बाहेर एकरूपतेसह कार्य करण्यासाठी साधी साधने.

NB: तसे, गो मध्ये आपले स्वतःचे विधान कसे लिहायचे, आम्ही आधीच वर्णन केले आहे परदेशी लेखकांनी केलेल्या आमच्या अनुवादांपैकी एकात.

पण जर तुम्हाला वेळेअभावी किंवा सोप्या भाषेत सांगायचे तर प्रेरणेने गो शिकण्यापासून रोखले जात असेल तर? जवळजवळ प्रत्येक DevOps अभियंत्याला माहित असलेल्या सर्वात लोकप्रिय भाषांपैकी एक वापरून तुम्ही चांगले विधान कसे लिहू शकता याचे एक उदाहरण लेखात दिले आहे - python ला.

भेटा: कॉपीर - कॉपी ऑपरेटर!

उदाहरण म्हणून, नवीन नेमस्पेस दिसल्यावर किंवा जेव्हा दोन घटकांपैकी एक बदलते तेव्हा कॉन्फिगमॅप कॉपी करण्यासाठी डिझाइन केलेले एक साधे विधान विकसित करण्याचा विचार करा: कॉन्फिगमॅप आणि सिक्रेट. व्यावहारिक दृष्टिकोनातून, ऑपरेटर ऍप्लिकेशन कॉन्फिगरेशनच्या मोठ्या प्रमाणात अद्यतनित करण्यासाठी (कॉन्फिगमॅप अद्यतनित करून) किंवा गुप्त डेटा अद्यतनित करण्यासाठी उपयुक्त ठरू शकतो - उदाहरणार्थ, डॉकर रेजिस्ट्रीसह कार्य करण्यासाठी की (नेमस्पेसमध्ये सिक्रेट जोडताना).

त्यामुळे एक चांगला ऑपरेटर काय असावा:

  1. वापरून ऑपरेटरशी संवाद साधला जातो सानुकूल संसाधन व्याख्या (यापुढे CRD म्हणून संदर्भित).
  2. ऑपरेटर कॉन्फिगर केले जाऊ शकते. हे करण्यासाठी, आम्ही कमांड लाइन फ्लॅग आणि पर्यावरण व्हेरिएबल्स वापरू.
  3. डॉकर कंटेनर आणि हेल्म चार्टचे बिल्ड डिझाइन केले आहे जेणेकरून वापरकर्ते सहजपणे (शब्दशः एका आदेशासह) ऑपरेटर त्यांच्या कुबर्नेट्स क्लस्टरमध्ये स्थापित करू शकतात.

दिलहारा

ऑपरेटरला कोणती संसाधने शोधायची आणि कुठे शोधायची हे जाणून घेण्यासाठी, आम्ही त्याच्यासाठी एक नियम सेट करणे आवश्यक आहे. प्रत्येक नियम एकल CRD ऑब्जेक्ट म्हणून दर्शविला जाईल. या सीआरडीमध्ये कोणती फील्ड असावी?

  1. संसाधन प्रकार, जे आम्ही शोधू (कॉन्फिगमॅप किंवा सीक्रेट).
  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 सारख्या लेबलांसह सर्व कॉन्फिगमॅप 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. पर्यावरणीय चल वापरा.

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

परिणाम

अशाप्रकारे, न घाबरता, निंदा न करता किंवा गो न शिकता, आम्ही पायथॉनमध्ये कुबरनेटसाठी आमचे स्वतःचे ऑपरेटर तयार करू शकलो. अर्थात, त्यात अजून वाढ व्हायला जागा आहे: भविष्यात ते अनेक नियमांवर प्रक्रिया करू शकेल, अनेक थ्रेड्समध्ये काम करू शकेल, स्वतंत्रपणे त्याच्या CRDs मधील बदलांचे निरीक्षण करू शकेल...

तुम्हाला कोड जवळून पाहण्यासाठी, आम्ही तो टाकला आहे सार्वजनिक भांडार. जर तुम्हाला पायथन वापरून लागू केलेल्या अधिक गंभीर ऑपरेटरची उदाहरणे हवी असतील, तर तुम्ही मॉंगॉडबी तैनात करण्यासाठी तुमचे लक्ष दोन ऑपरेटरकडे वळवू शकतापहिला и दुसरा).

PS आणि जर तुम्ही कुबर्नेट्स इव्हेंट्सला सामोरे जाण्यास खूप आळशी असाल किंवा तुम्हाला बॅश वापरण्याची सवय असेल, तर आमच्या सहकाऱ्यांनी फॉर्ममध्ये एक तयार उपाय तयार केला आहे. शेल-ऑपरेटर (आम्ही घोषित केले ते एप्रिलमध्ये).

पीपीएस

आमच्या ब्लॉगवर देखील वाचा:

स्त्रोत: www.habr.com

एक टिप्पणी जोडा