I-Kubernetes Operator ku-Python ngaphandle kwezinhlaka ne-SDK

I-Kubernetes Operator ku-Python ngaphandle kwezinhlaka ne-SDK

I-Go njengamanje inokuzimela kwezilimi zohlelo abantu abakhetha ukubhala izitatimende ze-Kubernetes. Kunezizathu eziyinhloko zalokhu, njenge:

  1. Kunohlaka olunamandla lokuthuthukisa ama-opharetha ku-Go - I-Opharetha ye-SDK.
  2. Izinhlelo zokusebenza ezishintsha umdlalo ezifana ne-Docker ne-Kubernetes zibhalwe ku-Go. Ukubhala u-opharetha wakho ku-Go kusho ukukhuluma ulimi olufanayo ne-ecosystem.
  3. Ukusebenza okuphezulu kwezinhlelo zokusebenza ze-Go namathuluzi alula okusebenza ngokubambisana ngaphandle kwebhokisi.

NB: Ngendlela, usibhala kanjani isitatimende sakho ku-Go, thina osekuchaziwe kwenye yezinguqulo zethu ngababhali bakwamanye amazwe.

Kodwa kuthiwani uma uvinjelwa ekufundeni Hamba ngokuntula isikhathi noma, ukubeka nje, ugqozi? Lesi sihloko sinikeza isibonelo sokuthi ungabhala kanjani isitatimende esihle usebenzisa olunye lwezilimi ezidume cishe wonke unjiniyela we-DevOps owaziyo - Python.

Hlangana: Umkopishi - kopisha opharetha!

Njengesibonelo, cabanga ukwenza isitatimende esilula esidizayinelwe ukukopisha i-ConfigMap noma ngabe kuvela indawo entsha yamagama noma lapho kushintsha okukodwa kwamabhizinisi amabili: ConfigMap kanye nemfihlo. Ngokombono ongokoqobo, u-opharetha angaba usizo ekubuyekezeni ngobuningi bokucushwa kohlelo lokusebenza (ngokubuyekeza i-ConfigMap) noma ekubuyekezeni idatha eyimfihlo - isibonelo, okhiye bokusebenza ne-Docker Registry (uma wengeza Imfihlo endaweni yamagama).

Ngakho-ke, lokho okusebenza kahle okufanele abe nakho:

  1. Ukuxhumana no-opharetha kwenziwa ngokusebenzisa Izincazelo Zensiza Yangokwezifiso (ngemuva kwalokhu kubizwa nge-CRD).
  2. Umsebenzisi angalungiselelwa. Ukuze senze lokhu, sizosebenzisa amafulegi omugqa womyalo kanye nokuguquguquka kwemvelo.
  3. Ukwakhiwa kwesiqukathi se-Docker neshadi le-Helm kuklanywe ngendlela yokuthi abasebenzisi bakwazi kalula (ngokoqobo ngomyalo owodwa) ukufaka opharetha kuqoqo labo le-Kubernetes.

I-CRD

Ukuze osebenzayo azi ukuthi yiziphi izinsiza okufanele azibheke nokuthi abheke kuphi, kudingeka simbekele umthetho. Umthetho ngamunye uzomelwa njengento eyodwa ye-CRD. Imiphi imikhakha okufanele le CRD ibe nayo?

  1. Uhlobo lwensiza, esizoyibheka (ConfigMap noma Secret).
  2. Uhlu lwezikhala zamagama, lapho izinsiza kufanele zibe khona.
  3. Isikhethi, esizosesha ngazo izinsiza endaweni yamagama.

Ake sichaze i-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

Futhi sizoyidala ngokushesha umthetho olula β€” ukucinga endaweni enegama default yonke i-ConfigMap enamalebula afana copyrator: "true":

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

Ilungile! Manje sidinga ukuthola ulwazi ngandlela thize mayelana nomthetho wethu. Ake ngenze ukubhuka ngokushesha ukuthi ngeke sibhale izicelo kuseva ye-API yeqoqo ngokwethu. Ukuze senze lokhu, sizosebenzisa umtapo wezincwadi wePython owenziwe ngomumo 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')}

Njengomphumela wokusebenzisa le khodi, sithola okulandelayo:

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

Khulu: sikwazile ukuthola umthetho ku-opharetha. Futhi okubaluleke kakhulu, senze lokho okubizwa ngokuthi indlela ye-Kubernetes.

Okuguquguqukayo kwemvelo noma amafulegi? Sithatha konke!

Masiqhubekele ekucushweni komsebenzisi oyinhloko. Kunezindlela ezimbili eziyisisekelo zokumisa izinhlelo zokusebenza:

  1. sebenzisa izinketho zomugqa womyalo;
  2. sebenzisa okuguquguqukayo kwemvelo.

Izinketho zomugqa womyalo zikuvumela ukuthi ufunde izilungiselelo ngendlela evumelana nezimo, ngokusekelwa kohlobo lwedatha nokuqinisekisa. Umtapo wezincwadi ojwayelekile wePython unemojula argparser, esizoyisebenzisa. Imininingwane nezibonelo zamakhono ayo ayatholakala ku imibhalo esemthethweni.

Esimweni sethu, yilesi isibonelo sokusetha amafulegi omugqa womyalo ongabukeka kanje:

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

Ngakolunye uhlangothi, usebenzisa okuguquguqukayo kwemvelo ku-Kubernetes, ungakwazi ukudlulisa kalula ulwazi lwesevisi mayelana ne-pod ngaphakathi kwesitsha. Isibonelo, singathola ulwazi mayelana nendawo yamagama lapho i-pod esebenza khona ngokwakhiwa okulandelayo:

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

I-logic ye-opharetha

Ukuze uqonde ukuthi uzihlukanisa kanjani izindlela zokusebenza ne-ConfigMap ne-Secret, sizosebenzisa amamephu akhethekile. Khona-ke singaqonda ukuthi yiziphi izindlela esizidingayo zokulandelela nokudala into:

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

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

Okulandelayo, udinga ukuthola imicimbi evela kuseva ye-API. Masiyisebenzise kanje:

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)

Ngemva kokuthola umcimbi, sidlulela kumqondo oyinhloko wokuwucubungula:

# Π’ΠΈΠΏΡ‹ событий, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±ΡƒΠ΄Π΅ΠΌ Ρ€Π΅Π°Π³ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ
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)

I-logic eyinhloko isilungile! Manje sidinga ukupakisha konke lokhu kuphakheji eyodwa yePython. Silungisa ifayela setup.py, bhala imininingwane ye-meta mayelana nephrojekthi lapho:

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: Iklayenti le-kubernetes lePython linenguqulo yalo. Ulwazi olwengeziwe mayelana nokuhambisana phakathi kwezinguqulo zeklayenti nezinguqulo ze-Kubernetes zingatholakala ku ama-matrics ahambisanayo.

Manje iphrojekthi yethu ibukeka kanje:

copyrator
β”œβ”€β”€ copyrator
β”‚   β”œβ”€β”€ cli.py # Π›ΠΎΠ³ΠΈΠΊΠ° Ρ€Π°Π±ΠΎΡ‚Ρ‹ с ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎΠΉ строкой
β”‚   β”œβ”€β”€ constant.py # ΠšΠΎΠ½ΡΡ‚Π°Π½Ρ‚Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΡ‹ ΠΏΡ€ΠΈΠ²ΠΎΠ΄ΠΈΠ»ΠΈ Π²Ρ‹ΡˆΠ΅
β”‚   β”œβ”€β”€ load_crd.py # Π›ΠΎΠ³ΠΈΠΊΠ° Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ CRD
β”‚   └── operator.py # Основная Π»ΠΎΠ³ΠΈΠΊΠ° Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π°
└── setup.py # ΠžΡ„ΠΎΡ€ΠΌΠ»Π΅Π½ΠΈΠ΅ ΠΏΠ°ΠΊΠ΅Ρ‚Π°

I-Docker ne-Helm

I-Dockerfile izoba lula ngendlela emangalisayo: thatha isithombe esiyisisekelo se-python-alpine bese ufaka iphakheji yethu. Masihlehlise ukulungiselelwa kwakho kuze kube yizikhathi ezingcono:

FROM python:3.7.3-alpine3.9

ADD . /app

RUN pip3 install /app

ENTRYPOINT ["copyrator"]

Ukuthunyelwa komsebenzisi nakho kulula kakhulu:

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

Okokugcina, udinga ukudala indima efanele yomsebenzisi onamalungelo adingekayo:

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

Umphumela

Kungaleyo ndlela, ngaphandle kokwesaba, isihlamba, noma ukufunda i-Go, sakwazi ukwakha eyethu i-opharetha ye-Kubernetes ku-Python. Yiqiniso, isenayo indawo yokukhula: esikhathini esizayo izokwazi ukucubungula imithetho eminingi, isebenze emicu eminingi, iqaphe ngokuzimela izinguquko kuma-CRD ayo...

Ukuze sikubhekisise kahle ikhodi, siyifakile inqolobane yomphakathi. Uma ufuna izibonelo zama-opharetha abucayi kakhulu asetshenziswe kusetshenziswa i-Python, ungabhekisa ukunaka kwakho kuma-opharetha amabili wokuthumela i-mongodb (eyokuqala ΠΈ okwesibili).

PS Futhi uma uvilapha kakhulu ukubhekana nemicimbi ye-Kubernetes noma umane ujwayele ukusebenzisa i-Bash, ozakwethu balungiselele isisombululo esenziwe ngomumo ngefomu. igobolondo-opharetha (Thina kumenyezelwe ngo-April).

I-PPS

Funda futhi kubhulogi yethu:

Source: www.habr.com

Engeza amazwana