Kubernetes Operator sa Python nga walay frameworks ug SDK

Kubernetes Operator sa Python nga walay frameworks ug SDK

Ang Go sa pagkakaron adunay monopolyo sa mga programming language nga gipili sa mga tawo nga magsulat og mga pahayag para sa Kubernetes. Adunay mga katuyoan nga hinungdan niini, sama sa:

  1. Adunay usa ka kusgan nga balangkas alang sa pagpalambo sa mga operator sa Go - Operator SDK.
  2. Ang mga aplikasyon nga nagbag-o sa dula sama sa Docker ug Kubernetes gisulat sa Go. Ang pagsulat sa imong operator sa Go nagpasabot sa pagsulti sa samang pinulongan sa ekosistema.
  3. Taas nga pasundayag sa mga aplikasyon sa Go ug yano nga mga himan alang sa pagtrabaho nga adunay panagsama nga wala sa kahon.

NB: By the way, unsaon pagsulat sa imong kaugalingong statement sa Go, kami gihulagway na sa usa sa among mga hubad sa langyaw nga mga awtor.

Apan komosta kon pugngan ka sa pagkat-on Lakaw tungod sa kakulang sa panahon o, sa yanong pagkasulti, kadasig? Naghatag ang artikulo og usa ka pananglitan kung giunsa nimo pagsulat ang usa ka maayong pahayag gamit ang usa sa labing inila nga mga sinultian nga nahibal-an sa halos matag engineer sa DevOps - Python.

Himamata: Copier - copy operator!

Isip usa ka pananglitan, ikonsiderar ang paghimo og usa ka yano nga pahayag nga gidisenyo aron kopyahon ang usa ka ConfigMap kung adunay usa ka bag-ong namespace nga makita o kung ang usa sa duha nga mga entidad mausab: ConfigMap ug Secret. Gikan sa usa ka praktikal nga punto sa panglantaw, ang operator mahimong mapuslanon alang sa kadaghanan nga pag-update sa mga configuration sa aplikasyon (pinaagi sa pag-update sa ConfigMap) o alang sa pag-update sa sekreto nga datos - pananglitan, mga yawe sa pagtrabaho uban sa Docker Registry (kon idugang ang Secret sa namespace).

Ug busa, kung unsa ang kinahanglan sa usa ka maayong operator:

  1. Ang pakig-uban sa operator gihimo gamit Custom nga Resource Definition (pagkahuman niini gitawag nga CRD).
  2. Ang operator mahimong ma-configure. Aron mahimo kini, gamiton namon ang mga bandila sa command line ug mga variable sa palibot.
  3. Ang paghimo sa Docker nga sudlanan ug Helm nga tsart kay gidesinyo aron ang mga tiggamit dali (sa literal nga adunay usa ka sugo) nga ma-install ang operator sa ilang Kubernetes cluster.

CRD

Aron mahibal-an sa operator kung unsang mga kapanguhaan ang pangitaon ug asa pangitaon, kinahanglan namon nga magbutang usa ka lagda alang kaniya. Ang matag lagda irepresentar isip usa ka butang nga CRD. Unsa nga mga natad ang kinahanglan adunay kini nga CRD?

  1. Resource type, nga atong pangitaon (ConfigMap o Sekreto).
  2. Listahan sa mga namespaces, diin kinahanglan mahimutang ang mga kahinguhaan.
  3. Pagpili, diin kita mangita alang sa mga kapanguhaan sa namespace.

Atong ihulagway ang 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

Ug ato kining mugnaon dayon yano nga lagda β€” sa pagpangita sa namespace nga adunay ngalan default tanan nga ConfigMap nga adunay mga label sama sa copyrator: "true":

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

Andam na! Karon kinahanglan namong makakuha og impormasyon bahin sa among lagda. Tugoti ako nga maghimo dayon og reserbasyon nga dili kami magsulat og mga hangyo sa cluster API Server sa among kaugalingon. Aron mahimo kini, mogamit kami usa ka andam nga librarya sa Python kubernetes-kliyente:

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

Isip resulta sa pagpadagan niini nga code, atong makuha ang mosunod:

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

Maayo: nakakuha kami usa ka lagda alang sa operator. Ug labaw sa tanan, gibuhat namo ang gitawag nga paagi sa Kubernetes.

Mga baryable sa palibot o mga bandera? Gikuha namo ang tanan!

Mopadayon kita sa nag-unang configuration sa operator. Adunay duha ka sukaranan nga mga pamaagi sa pag-configure sa mga aplikasyon:

  1. gamita ang mga opsyon sa command line;
  2. gamita ang environment variables.

Ang mga opsyon sa command line nagtugot kanimo sa pagbasa sa mga setting nga mas flexible, nga adunay suporta ug validation sa tipo sa data. Ang standard library sa Python adunay module argparser, nga atong gamiton. Ang mga detalye ug mga pananglitan sa mga kapabilidad niini anaa sa opisyal nga dokumentasyon.

Alang sa among kaso, kini ang hitsura sa usa ka pananglitan sa pag-set up sa mga flag sa command line sa pagbasa:

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

Sa laing bahin, gamit ang environment variables sa Kubernetes, dali nimo mabalhin ang impormasyon sa serbisyo bahin sa pod sulod sa sudlanan. Pananglitan, kita makakuha og impormasyon mahitungod sa namespace diin ang pod nagdagan uban sa mosunod nga pagtukod:

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

Logika sa operator

Aron masabtan kung giunsa ang pagbulag sa mga pamaagi sa pagtrabaho sa ConfigMap ug Secret, mogamit kami mga espesyal nga mapa. Dayon atong masabtan kung unsa nga mga pamaagi ang atong gikinahanglan sa pagsubay ug paghimo sa butang:

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

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

Sunod, kinahanglan nimo nga makadawat mga panghitabo gikan sa API server. Ato kining ipatuman sama sa mosunod:

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)

Human madawat ang panghitabo, nagpadayon kami sa panguna nga lohika sa pagproseso niini:

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

Ang panguna nga lohika andam na! Karon kinahanglan natong i-package kining tanan sa usa ka Python package. Giandam namon ang file setup.py, isulat ang meta nga impormasyon bahin sa proyekto didto:

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: Ang kubernetes nga kliyente alang sa Python adunay kaugalingong bersyon. Dugang nga impormasyon bahin sa pagkaangay tali sa mga bersyon sa kliyente ug mga bersyon sa Kubernetes makita sa compatibility matrices.

Karon ang among proyekto ingon niini:

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

Docker ug Helm

Ang Dockerfile mahimong labi ka yano: kuhaa ang base nga python-alpine nga imahe ug i-install ang among package. Atong i-postpone ang pag-optimize niini hangtod sa mas maayong mga panahon:

FROM python:3.7.3-alpine3.9

ADD . /app

RUN pip3 install /app

ENTRYPOINT ["copyrator"]

Ang pag-deploy alang sa operator yano ra usab:

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

Sa katapusan, kinahanglan nimo nga maghimo usa ka angay nga papel alang sa operator nga adunay kinahanglan nga mga katungod:

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

Ang resulta

Ingon niana, sa walay kahadlok, pagsaway, o pagkat-on sa Go, nakahimo kami sa paghimo sa among kaugalingon nga operator alang sa Kubernetes sa Python. Siyempre, aduna pa kini'y lawak nga motubo: sa umaabot kini makahimo sa pagproseso sa daghang mga lagda, pagtrabaho sa daghang mga hilo, independente nga pagmonitor sa mga pagbag-o sa mga CRD niini...

Aron mahatagan ka ug dugang nga pagtan-aw sa code, among gibutang kini publiko nga repositoryo. Kung gusto nimo ang mga pananglitan sa labi ka seryoso nga mga operator nga gipatuman gamit ang Python, mahimo nimong ipunting ang imong atensyon sa duha nga mga operator alang sa pag-deploy sa mongodb (ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ ΠΈ ang ikaduha).

PS Ug kung tapolan ka kaayo sa pag-atubang sa mga panghitabo sa Kubernetes o mas naanad ka sa paggamit sa Bash, ang among mga kauban nag-andam usa ka andam nga solusyon sa porma shell-operator (Kami gipahibalo niadtong Abril).

PPS

Basaha usab sa among blog:

Source: www.habr.com

Idugang sa usa ka comment