Kubernetes Operator ho Python ntle le meralo le SDK

Kubernetes Operator ho Python ntle le meralo le SDK

Hona joale Go e na le taolo ea lipuo tseo batho ba khethang ho li ngola bakeng sa Kubernetes. Ho na le mabaka a utloahalang a sena, a kang:

  1. Ho na le moralo o matla oa ho nts'etsapele basebetsi ho Go - SDK ea opereishene.
  2. Lisebelisoa tse fetolang lipapali joalo ka Docker le Kubernetes li ngotsoe ho Go. Ho ngola opareitara ya hao ho Go ho bolela ho bua puo e tshwanang le ecosystem.
  3. Ts'ebetso e phahameng ea lits'ebetso tsa Go le lisebelisoa tse bonolo tsa ho sebetsa le concurrency ka ntle ho lebokose.

NB: Ka tsela, mokhoa oa ho ngola polelo ea hau ho Go, rona e se e hlalositsoe ho e 'ngoe ea liphetolelo tsa rona ke bangoli ba tsoang kantle ho naha.

Empa ho thoe'ng haeba u sitisoa ho ithuta E-ea ka lebaka la ho hloka nako kapa, ka mantsoe a bonolo feela, tšusumetso? Sengoliloeng se fana ka mohlala oa kamoo u ka ngolang polelo e ntle u sebelisa e 'ngoe ea lipuo tse tsebahalang haholo tseo hoo e ka bang moenjiniere e mong le e mong oa DevOps a li tsebang - python.

Kopana le: Copier - kopi ea opareitara!

E le mohlala, nahana ka ho hlahisa polelo e bonolo e etselitsoeng ho kopitsa ConfigMap ha sebaka se secha sa mabitso se hlaha kapa ha e 'ngoe ea lihlopha tse peli e fetoha: ConfigMap le Secret. Ho latela pono e sebetsang, opareitara e ka ba molemo bakeng sa ntlafatso e kholo ea litlhophiso tsa ts'ebeliso (ka ho nchafatsa ConfigMap) kapa ho nchafatsa data ea lekunutu - mohlala, linotlolo tsa ho sebetsa le Docker Registry (ha o eketsa Lekunutu sebakeng sa mabitso).

Kahoo, seo motho ya sebetsang hantle a lokelang ho ba le sona:

  1. Tšebelisano le opareitara e etsoa ka ho sebelisa Litlhaloso tsa Mohloli oa Tloaelo (eo hamorao e tla bitsoa CRD).
  2. Opereishene e ka hlophisoa. Ho etsa sena, re tla sebelisa lifolakha tsa mola oa taelo le mefuta e fapaneng ea tikoloho.
  3. Mohaho oa setshelo sa Docker le chate ea Helm e etselitsoe hore basebelisi ba ka khona habonolo (ka taelo e le 'ngoe) ho kenya opareitara ka har'a sehlopha sa bona sa Kubernetes.

CRD

E le hore motho ea sebetsang a tsebe hore na o batla lisebelisoa life le hore na a shebe hokae, re lokela ho mo behela molao. Molao o mong le o mong o tla emeloa e le ntho e le 'ngoe ea CRD. CRD ee e lokela ho ba le likarolo life?

  1. Mofuta oa lisebelisoa, eo re tla e batla (ConfigMap kapa Lekunutu).
  2. Lenane la libaka tsa mabitso, moo lisebelisoa li lokelang ho ba teng.
  3. Khetho, eo ka eona re tla batla lisebelisoa sebakeng sa mabitso.

Ha re hlalose 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

'Me re tla e bopa hang-hang molao o bonolo — ho batla sebakeng sa mabitso ka lebitso default kaofela ConfigMap e nang le mangolo a kang copyrator: "true":

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

E lokile! Hona joale re hloka ho fumana tlhahisoleseding ka molao oa rona ka tsela e itseng. E-re ke behelle hang hang hore re se ke ra ngolla likopo ho Cluster API Server ka borona. Ho etsa sena, re tla sebelisa laeborari ea Python e seng e entsoe kubernetes-client:

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

Ka lebaka la ho sebelisa khoutu ena, re fumana tse latelang:

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

E kholo: re khonne ho fumana molao bakeng sa opareitara. Habohlokoa le ho feta, re entse se bitsoang tsela ea Kubernetes.

Mefuta e fapaneng ea tikoloho kapa lifolakha? Re nka tsohle!

Ha re feteleng ho tlhophiso ea opareitara e kholo. Ho na le mekhoa e 'meli ea mantlha ea ho hlophisa lisebelisoa:

  1. sebelisa likhetho tsa mola oa taelo;
  2. sebelisa mefuta-futa ea tikoloho.

Likhetho tsa mola oa taelo li u lumella ho bala litlhophiso ka mokhoa o bonolo haholoanyane, ka tšehetso ea mofuta oa data le netefatso. Laeborari e tloaelehileng ea Python e na le mojule argparser, eo re tla e sebelisa. Lintlha le mehlala ea bokhoni ba eona li fumaneha ho litokomane tsa molao.

Bakeng sa rona, sena ke seo mohlala oa ho theha lifolakha tsa mola oa taelo o ka shebahalang joalo:

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

Ka lehlakoreng le leng, ho sebelisa mefuta-futa ea tikoloho ho Kubernetes, o ka fetisetsa boitsebiso ba tšebeletso habonolo ka pod ka har'a setshelo. Mohlala, re ka fumana leseli mabapi le sebaka sa mabitso seo pod e sebetsang ho sona ka moaho o latelang:

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

Monahano oa opereishene

Ho utloisisa mokhoa oa ho arola mekhoa ea ho sebetsa le ConfigMap le Lekunutu, re tla sebelisa limmapa tse khethehileng. Joale re ka utloisisa hore na ke mekhoa efe eo re e hlokang ho latela le ho theha ntho:

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

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

E latelang, o hloka ho fumana liketsahalo ho tsoa ho seva sa API. Ha re e kenye tshebetsong ka tsela e latelang:

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)

Ka mor'a ho amohela ketsahalo, re fetela pele ho mabaka a mantlha a ho e sebetsa:

# Типы событий, на которые будем реагировать
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)

Monahano o ka sehloohong o se o loketse! Joale re hloka ho kenya tsena tsohle ka har'a sephutheloana se le seng sa Python. Re lokisa faele setup.py, ngola lintlha tse mabapi le morero moo:

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: Moreki oa kubernetes oa Python o na le phetolelo ea hae. Lintlha tse ling mabapi le tšebelisano lipakeng tsa liphetolelo tsa bareki le mefuta ea Kubernetes li ka fumaneha ho matrices a lumellanang.

Joale morero oa rona o shebahala tjena:

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

Docker le Helm

Dockerfile e tla ba bonolo ka mokhoa o makatsang: nka setšoantšo sa motheo sa python-alpine 'me u kenye sephutheloana sa rona. Ha re chechiseng ntlafatso ea eona ho fihlela linako tse betere:

FROM python:3.7.3-alpine3.9

ADD . /app

RUN pip3 install /app

ENTRYPOINT ["copyrator"]

Ho tsamaisoa ha opareitara ho boetse ho bonolo haholo:

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

Qetellong, o hloka ho theha karolo e nepahetseng bakeng sa opareitara ka litokelo tse hlokahalang:

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

Phello

Ke kamoo, ntle le tšabo, sekhobo, kapa ho ithuta Go, re khonneng ho ikahela opereishene ea rona bakeng sa Kubernetes ho Python. Ha e le hantle, e ntse e e-na le sebaka sa ho hōla: nakong e tlang e tla khona ho sebetsana le melao e mengata, ho sebetsa ka likhoele tse ngata, ka boikemelo ho shebella liphetoho ho li-CRD tsa eona ...

Ho u fa kh'outu e haufi-ufi, re e kentse polokelo ea sechaba. Haeba u batla mehlala ea li-operators tse tebileng haholoanyane tse kenngoeng ts'ebetsong ka Python, u ka lebisa tlhokomelo ea hau ho basebelisi ba babeli bakeng sa ho tsamaisa mongodb (первый и ea bobeli).

PS 'Me haeba u botsoa haholo ho sebetsana le liketsahalo tsa Kubernetes kapa u tloaetse ho sebelisa Bash, basebetsi-'moho le rona ba lokiselitse tharollo e lokiselitsoeng ka foromo. khetla-mosebetsi (Rona tsebisitsoe eona ka April).

PPS

Bala hape ho blog ea rona:

Source: www.habr.com

Eketsa ka tlhaloso