Kubernetes Operator a cikin Python ba tare da tsarin aiki da SDK ba

Kubernetes Operator a cikin Python ba tare da tsarin aiki da SDK ba

Go a halin yanzu yana da keɓantacce akan yarukan shirye-shirye waɗanda mutane suka zaɓa don rubuta bayanan Kubernetes. Akwai dalilai na haƙiƙa na wannan, kamar:

  1. Akwai tsari mai ƙarfi don haɓaka masu aiki a cikin Go - Mai aiki SDK.
  2. Aikace-aikace masu canza wasa kamar Docker da Kubernetes an rubuta su a cikin Go. Rubuta afaretan ku a cikin Go yana nufin magana da harshe iri ɗaya tare da yanayin muhalli.
  3. Babban aiki na aikace-aikacen Go da kayan aiki masu sauƙi don aiki tare da haɗin kai daga cikin akwatin.

NB: Af, yadda ake rubuta bayanin ku a cikin Go, mu riga aka bayyana a ɗaya daga cikin fassararmu ta marubutan kasashen waje.

Amma idan rashin lokaci ya hana ku koyon Tafi ko kuma, a sauƙaƙe, ƙarfafawa fa? Labarin ya ba da misali na yadda zaku iya rubuta kyakkyawar sanarwa ta amfani da ɗayan shahararrun yaruka waɗanda kusan kowane injiniyan DevOps ya sani - Python.

Haɗu: Copier - mai aiki kwafi!

A matsayin misali, la'akari da haɓaka bayani mai sauƙi da aka tsara don kwafin ConfigMap ko dai lokacin da sabon sararin suna ya bayyana ko lokacin da ɗayan ƙungiyoyi biyu suka canza: ConfigMap da Asirin. Daga mahimmin ra'ayi, mai aiki na iya zama da amfani don ɗaukaka yawan saitunan aikace-aikacen (ta sabunta ConfigMap) ko don sabunta bayanan sirri - alal misali, maɓallan aiki tare da Docker Registry (lokacin ƙara Sirrin zuwa sararin sunan).

Sabili da haka, abin da mai aiki mai kyau ya kamata ya samu:

  1. Ana yin hulɗa tare da mai aiki ta amfani da shi Ma'anar Ma'anar Albarkatun Al'ada (nan gaba ana kiranta CRD).
  2. Ana iya daidaita mai aiki. Don yin wannan, za mu yi amfani da tutocin layin umarni da masu canjin yanayi.
  3. Ginin kwandon Docker da ginshiƙi Helm an tsara shi ta yadda masu amfani za su iya sauƙi (a zahiri tare da umarni ɗaya) shigar da mai aiki a cikin gungu na Kubernetes.

CRD

Domin ma'aikaci ya san irin albarkatun da zai nema da kuma inda za a duba, muna buƙatar saita masa doka. Kowace doka za a wakilta a matsayin abu ɗaya na CRD. Wadanne fagage ya kamata wannan CRD ya kasance?

  1. Nau'in albarkatu, wanda za mu nema (ConfigMap ko Sirrin).
  2. Jerin wuraren suna, wanda ya kamata a samo albarkatun.
  3. Zaɓi, ta inda za mu nemo albarkatun a cikin sunan sararin samaniya.

Bari mu kwatanta 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

Kuma za mu ƙirƙira shi nan da nan mulki mai sauƙi - don bincika cikin sarari suna tare da sunan default duk ConfigMap tare da alamu kamar copyrator: "true":

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

Shirya! Yanzu muna bukatar ko ta yaya mu sami bayani game da mulkin mu. Bari in yi ajiyar wuri nan da nan cewa ba za mu rubuta buƙatun zuwa gungu API Server da kanmu ba. Don yin wannan, za mu yi amfani da shirye-shiryen ɗakin karatu na Python kubernetes-abokin ciniki:

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

A sakamakon gudanar da wannan code, muna samun masu zuwa:

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

Mai girma: mun sami nasarar samun doka don ma'aikacin. Kuma mafi mahimmanci, mun yi abin da ake kira hanyar Kubernetes.

Canjin yanayi ko tutoci? Muna ɗaukar komai!

Bari mu matsa zuwa babban tsarin aiki. Akwai hanyoyi na asali guda biyu don daidaita aikace-aikacen:

  1. yi amfani da zaɓuɓɓukan layin umarni;
  2. amfani da masu canjin yanayi.

Zaɓuɓɓukan layin umarni suna ba ka damar karanta saituna cikin sassauƙa, tare da goyan bayan nau'in bayanai da inganci. Daidaitaccen ɗakin karatu na Python yana da tsari argparser, wanda za mu yi amfani da shi. Ana samun cikakkun bayanai da misalai na iyawar sa a ciki takardun shaida.

Ga yanayin mu, wannan shine misalin kafa tutocin layin umarni zai yi kama da:

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

A gefe guda, ta amfani da masu canjin yanayi a cikin Kubernetes, zaku iya canja wurin bayanan sabis cikin sauƙi game da kwafsa a cikin akwati. Misali, za mu iya samun bayani game da sararin sunan da kwaf ɗin ke gudana tare da ginin mai zuwa:

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

Dabarun mai aiki

Don fahimtar yadda ake raba hanyoyin yin aiki tare da ConfigMap da Sirrin, za mu yi amfani da taswirori na musamman. Sa'an nan kuma za mu iya fahimtar hanyoyin da muke buƙatar waƙa da ƙirƙirar abu:

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

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

Na gaba, kuna buƙatar karɓar abubuwan da suka faru daga uwar garken API. Mu aiwatar da shi kamar haka:

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)

Bayan karbar taron, za mu ci gaba zuwa babban ma'anar sarrafa shi:

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

Babban dabaru yana shirye! Yanzu muna buƙatar tattara duk waɗannan cikin kunshin Python guda ɗaya. Muna shirya fayil ɗin setup.py, rubuta bayanan meta game da aikin a can:

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: Abokin kubernetes na Python yana da nasa sigar. Ana iya samun ƙarin bayani game da dacewa tsakanin nau'ikan abokin ciniki da nau'ikan Kubernetes a ciki matrices masu dacewa.

Yanzu aikin namu yayi kama da haka:

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

Docker da Helm

Dockerfile zai zama mai sauƙi mai ban mamaki: ɗauki hoton tushe na python-alpine kuma shigar da kunshin mu. Bari mu jinkirta ingantawarsa har zuwa mafi kyawun lokuta:

FROM python:3.7.3-alpine3.9

ADD . /app

RUN pip3 install /app

ENTRYPOINT ["copyrator"]

Aiwatar da mai aiki shima abu ne mai sauqi:

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

A ƙarshe, kuna buƙatar ƙirƙirar rawar da ta dace ga ma'aikaci tare da haƙƙoƙin da suka dace:

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

Sakamakon

Haka ne, ba tare da tsoro, zargi, ko koyon Go, mun sami damar gina namu ma'aikacin Kubernetes a Python. Tabbas, har yanzu yana da wurin girma: a nan gaba za ta iya aiwatar da dokoki da yawa, aiki a cikin zaren da yawa, da kansa kan sa ido kan canje-canje a cikin CRDs.

Don ba ku cikakken duba lambar, mun sanya shi a ciki ma'ajiyar jama'a. Idan kuna son misalan manyan ma'aikatan da aka aiwatar da su ta amfani da Python, zaku iya juya hankalinku ga masu aiki guda biyu don tura mongodb (первый и na biyu).

PS Kuma idan kun kasance mai kasala don magance abubuwan Kubernetes ko kuma kun saba da amfani da Bash, abokan aikinmu sun shirya wani shiri da aka yi a cikin tsari. mai aiki da harsashi (Mu sanar a watan Afrilu).

PPS

Karanta kuma a kan shafinmu:

source: www.habr.com

Add a comment