Oniṣẹ Kubernetes ni Python laisi awọn ilana ati SDK

Oniṣẹ Kubernetes ni Python laisi awọn ilana ati SDK

Lọ lọwọlọwọ ni anikanjọpọn lori awọn ede siseto ti eniyan yan lati kọ awọn alaye fun Kubernetes. Awọn idi idi pataki wa fun eyi, gẹgẹbi:

  1. Ilana ti o lagbara wa fun awọn oniṣẹ idagbasoke ni Go - SDK onišẹ.
  2. Awọn ohun elo iyipada ere bii Docker ati Kubernetes ni a kọ sinu Go. Kikọ oniṣẹ ẹrọ rẹ ni Go tumọ si sisọ ede kanna pẹlu ilolupo eda abemi.
  3. Išẹ giga ti awọn ohun elo Go ati awọn irinṣẹ ti o rọrun fun ṣiṣẹ pẹlu concurrency jade kuro ninu apoti.

NB: Nipa ọna, bi o ṣe le kọ alaye ti ara rẹ ni Go, a tẹlẹ ṣàpèjúwe ninu ọkan ninu awọn itumọ wa nipasẹ awọn onkọwe ajeji.

Ṣugbọn kini ti o ba jẹ idiwọ fun ọ lati kọ ẹkọ Lọ nipasẹ aini akoko tabi, ni irọrun, iwuri? Nkan naa pese apẹẹrẹ ti bii o ṣe le kọ alaye to dara ni lilo ọkan ninu awọn ede olokiki julọ ti o fẹrẹ jẹ pe gbogbo ẹlẹrọ DevOps mọ - Python.

Pade: Copier - onišẹ daakọ!

Gẹgẹbi apẹẹrẹ, ronu idagbasoke ọrọ ti o rọrun ti a ṣe lati daakọ ConfigMap kan boya nigbati aaye orukọ tuntun ba han tabi nigbati ọkan ninu awọn nkan meji ba yipada: ConfigMap ati Aṣiri. Lati oju iwoye ti o wulo, oniṣẹ le wulo fun imudojuiwọn olopobobo ti awọn atunto ohun elo (nipa mimu dojuiwọn ConfigMap) tabi fun imudojuiwọn data aṣiri - fun apẹẹrẹ, awọn bọtini fun ṣiṣẹ pẹlu Iforukọsilẹ Docker (nigbati o ṣafikun Aṣiri si aaye orukọ).

Ati bẹ, ohun ti o dara onišẹ yẹ ki o ni:

  1. Ibaraṣepọ pẹlu oniṣẹ ni a ṣe ni lilo Aṣa Resource Definitions (lẹhinna tọka si bi CRD).
  2. O le tunto oniṣẹ ẹrọ. Lati ṣe eyi, a yoo lo awọn asia laini aṣẹ ati awọn oniyipada ayika.
  3. Kọ ti apo eiyan Docker ati iwe aworan Helm jẹ apẹrẹ ki awọn olumulo le ni irọrun (itumọ ọrọ gangan pẹlu aṣẹ kan) fi oniṣẹ ẹrọ sinu iṣupọ Kubernetes wọn.

CRD

Ni ibere fun oniṣẹ lati mọ kini awọn orisun lati wa ati ibiti o wa, a nilo lati ṣeto ofin kan fun u. Ofin kọọkan yoo jẹ aṣoju bi ohun CRD ẹyọkan. Awọn aaye wo ni o yẹ ki CRD ni?

  1. awọn oluşewadi iru, eyiti a yoo wa (ConfigMap tabi Aṣiri).
  2. Akojọ awọn aaye orukọ, ninu eyiti awọn orisun yẹ ki o wa.
  3. Aṣayan, nipasẹ eyiti a yoo wa awọn orisun ni aaye orukọ.

Jẹ ki a ṣe apejuwe 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

Ati pe a yoo ṣẹda lẹsẹkẹsẹ o rọrun ofin - lati wa ni aaye orukọ pẹlu orukọ default gbogbo ConfigMap pẹlu akole bi copyrator: "true":

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

Ṣetan! Bayi a nilo lati bakan gba alaye nipa ofin wa. Jẹ ki n ṣe ifiṣura lẹsẹkẹsẹ pe a kii yoo kọ awọn ibeere si olupin API iṣupọ funrara wa. Lati ṣe eyi, a yoo lo ile-ikawe Python ti o ti ṣetan kubernetes-onibara:

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

Bi abajade ti ṣiṣiṣẹ koodu yii, a gba atẹle naa:

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

Nla: a ṣakoso lati gba ofin fun oniṣẹ ẹrọ. Ati ṣe pataki julọ, a ṣe ohun ti a pe ni ọna Kubernetes.

Awọn oniyipada ayika tabi awọn asia? A gba ohun gbogbo!

Jẹ ki a lọ si iṣeto oniṣẹ akọkọ. Awọn ọna ipilẹ meji lo wa lati tunto awọn ohun elo:

  1. lo awọn aṣayan laini aṣẹ;
  2. lo awọn oniyipada ayika.

Awọn aṣayan laini aṣẹ gba ọ laaye lati ka awọn eto diẹ sii ni irọrun, pẹlu atilẹyin iru data ati afọwọsi. Python ká boṣewa ìkàwé ni o ni a module argparser, eyi ti a yoo lo. Awọn alaye ati awọn apẹẹrẹ ti awọn agbara rẹ wa ninu osise iwe aṣẹ.

Fun ọran wa, eyi ni apẹẹrẹ ti iṣeto awọn asia laini aṣẹ kika yoo dabi:

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

Ni apa keji, ni lilo awọn oniyipada ayika ni Kubernetes, o le ni rọọrun gbe alaye iṣẹ nipa podu inu apo eiyan naa. Fun apẹẹrẹ, a le gba alaye nipa aaye orukọ ninu eyiti adarọ-ese ti nṣiṣẹ pẹlu ikole atẹle:

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

Onišẹ kannaa

Lati loye bi o ṣe le ya awọn ọna lọtọ fun ṣiṣẹ pẹlu ConfigMap ati Aṣiri, a yoo lo awọn maapu pataki. Lẹhinna a le loye awọn ọna ti a nilo lati tọpa ati ṣẹda nkan naa:

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

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

Nigbamii, o nilo lati gba awọn iṣẹlẹ lati ọdọ olupin API. Jẹ ki a ṣe imuse rẹ gẹgẹbi atẹle:

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)

Lẹhin gbigba iṣẹlẹ naa, a tẹsiwaju si imọran akọkọ ti sisẹ rẹ:

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

Awọn akọkọ kannaa ti šetan! Bayi a nilo lati ṣajọ gbogbo eyi sinu package Python kan. A ṣeto faili naa setup.py, kọ alaye meta nipa ise agbese nibẹ:

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: Onibara kubernetes fun Python ni ikede tirẹ. Alaye diẹ sii nipa ibaramu laarin awọn ẹya alabara ati awọn ẹya Kubernetes ni a le rii ninu matrices ibamu.

Bayi ise agbese wa dabi eyi:

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

Docker ati Helm

Dockerfile yoo rọrun ti iyalẹnu: mu aworan ipilẹ Python-alpine ki o fi package wa sori ẹrọ. Jẹ ki a sun ilọsiwaju rẹ siwaju titi di awọn akoko to dara julọ:

FROM python:3.7.3-alpine3.9

ADD . /app

RUN pip3 install /app

ENTRYPOINT ["copyrator"]

Gbigbe fun oniṣẹ tun rọrun pupọ:

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

Ni ipari, o nilo lati ṣẹda ipa ti o yẹ fun oniṣẹ pẹlu awọn ẹtọ to wulo:

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

Abajade

Iyẹn ni, laisi iberu, ẹgan, tabi kikọ Go, a ni anfani lati kọ oniṣẹ tiwa fun Kubernetes ni Python. Nitoribẹẹ, o tun ni aye lati dagba: ni ọjọ iwaju yoo ni anfani lati ṣe ilana awọn ofin pupọ, ṣiṣẹ ni awọn okun pupọ, ṣe abojuto awọn ayipada ni ominira ninu awọn CRD rẹ…

Lati fun ọ ni pẹkipẹki wo koodu naa, a ti fi sii àkọsílẹ ibi ipamọ. Ti o ba fẹ awọn apẹẹrẹ ti awọn oniṣẹ to ṣe pataki diẹ sii ti a ṣe imuse nipa lilo Python, o le yi akiyesi rẹ si awọn oniṣẹ meji fun gbigbe mongodb (akoko и keji).

PS Ati pe ti o ba jẹ ọlẹ pupọ lati koju awọn iṣẹlẹ Kubernetes tabi o rọrun diẹ sii lati lo Bash, awọn ẹlẹgbẹ wa ti pese ojutu ti a ti ṣetan ni fọọmu naa. ikarahun-onišẹ (Awa kede o ni Oṣu Kẹrin).

PPS

Ka tun lori bulọọgi wa:

orisun: www.habr.com

Fi ọrọìwòye kun