Kubernetes Operator เปƒเบ™ Python เป‚เบ”เบเบšเปเปˆเบกเบตเบเบญเบšเปเบฅเบฐ SDK

Kubernetes Operator เปƒเบ™ Python เป‚เบ”เบเบšเปเปˆเบกเบตเบเบญเบšเปเบฅเบฐ SDK

เบ›เบฐเบˆเบธเบšเบฑเบ™ Go เบกเบตเบเบฒเบ™เบœเบนเบเบ‚เบฒเบ”เบเปˆเบฝเบงเบเบฑเบšเบžเบฒเบชเบฒเบเบฒเบ™เบ‚เบฝเบ™เป‚เบ›เบฅเปเบเบฅเบกเบ—เบตเปˆเบ›เบฐเบŠเบฒเบŠเบปเบ™เป€เบฅเบทเบญเบเบ—เบตเปˆเบˆเบฐเบ‚เบฝเบ™เบ„เปเบฒเบ–เบฐเปเบซเบผเบ‡เบเบฒเบ™เบชเปเบฒเบฅเบฑเบš Kubernetes. เบกเบตเป€เบซเบ”เบœเบปเบ™เบชเปเบฒเบฅเบฑเบšเป€เบฅเบทเปˆเบญเบ‡เบ™เบตเป‰, เป€เบŠเบฑเปˆเบ™:

  1. เบกเบตเบเบญเบšเบ—เบตเปˆเบกเบตเบ›เบฐเบชเบดเบ”เบ—เบดเบžเบฒเบšเบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบžเบฑเบ”เบ—เบฐเบ™เบฒเบœเบนเป‰เบ›เบฐเบเบญเบšเบเบฒเบ™เปƒเบ™ Go - เบœเบนเป‰เบ›เบฐเบเบญเบšเบเบฒเบ™ SDK.
  2. เปเบญเบฑเบšเบžเบฅเบดเป€เบ„เบŠเบฑเบ™เบ›เปˆเบฝเบ™เป€เบเบกเป€เบŠเบฑเปˆเบ™ Docker เปเบฅเบฐ Kubernetes เปเบกเปˆเบ™เบ‚เบฝเบ™เปƒเบ™ Go. เบเบฒเบ™เบ‚เบฝเบ™เบ•เบปเบงเบ›เบฐเบ•เบดเบšเบฑเบ”เบเบฒเบ™เบ‚เบญเบ‡เบ—เปˆเบฒเบ™เปƒเบ™ Go เบซเบกเบฒเบเป€เบ–เบดเบ‡เบเบฒเบ™เป€เบงเบปเป‰เบฒเบžเบฒเบชเบฒเบ”เบฝเบงเบเบฑเบ™เบเบฑเบšเบฅเบฐเบšเบปเบšเบ™เบดเป€เบงเบ”.
  3. เบ›เบฐเบชเบดเบ”เบ—เบดเบžเบฒเบšเบชเบนเบ‡เบ‚เบญเบ‡เบ„เปเบฒเบฎเป‰เบญเบ‡เบชเบฐเบซเบกเบฑเบ Go เปเบฅเบฐเป€เบ„เบทเปˆเบญเบ‡เบกเบทเบ—เบตเปˆเบ‡เปˆเบฒเบเบ”เบฒเบเบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เป€เบฎเบฑเบ”เบงเบฝเบเบฎเปˆเบงเบกเบเบฑเบš concurrency เบญเบญเบเบˆเบฒเบเบเปˆเบญเบ‡.

NB: เป‚เบ”เบเบงเบดเบ—เบตเบ—เบฒเบ‡เบเบฒเบ™, เบงเบดเบ—เบตเบเบฒเบ™เบ‚เบฝเบ™เบ„เปเบฒเบ–เบฐเปเบซเบผเบ‡เบ‚เบญเบ‡เบ•เบปเบ™เป€เบญเบ‡เปƒเบ™ Go, เบžเบงเบเป€เบฎเบปเบฒ เบญเบฐเบ—เบดเบšเบฒเบเปเบฅเป‰เบง เปƒเบ™เบซเบ™เบถเปˆเบ‡เบ‚เบญเบ‡เบเบฒเบ™เปเบ›เบžเบฒเบชเบฒเบ‚เบญเบ‡เบžเบงเบเป€เบฎเบปเบฒเป‚เบ”เบเบœเบนเป‰เบ‚เบฝเบ™เบ•เปˆเบฒเบ‡เบ›เบฐเป€เบ—เบ”.

เปเบ•เปˆเบˆเบฐเป€เบ›เบฑเบ™เปเบ™เบงเปƒเบ”เบ–เป‰เบฒเบ—เปˆเบฒเบ™เบ–เบทเบเบ‚เบฑเบ”เบ‚เบงเบฒเบ‡เบˆเบฒเบเบเบฒเบ™เบฎเบฝเบ™เบฎเบนเป‰ Go เป‚เบ”เบเบ‚เบฒเบ”เป€เบงเบฅเบฒเบซเบผเบท, เป€เบงเบปเป‰เบฒเบ‡เปˆเบฒเบเป†, เปเบฎเบ‡เบˆเบนเบ‡เปƒเบˆ? เบšเบปเบ”เบ„เบงเบฒเบกเปƒเบซเป‰เบ•เบปเบงเบขเปˆเบฒเบ‡เบ‚เบญเบ‡เบงเบดเบ—เบตเบ—เบตเปˆเบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เบ‚เบฝเบ™เบ„เปเบฒเบ–เบฐเปเบซเบผเบ‡เบ—เบตเปˆเบ”เบตเป‚เบ”เบเปƒเบŠเป‰เบซเบ™เบถเปˆเบ‡เปƒเบ™เบžเบฒเบชเบฒเบ—เบตเปˆเบ™เบดเบเบปเบกเบซเบผเบฒเบเบ—เบตเปˆเบชเบธเบ”เบ—เบตเปˆเป€เบเบทเบญเบšเบ—เบธเบเบงเบดเบชเบฐเบงเบฐเบเบญเบ™ DevOps เบฎเบนเป‰ - Python.

เบžเบปเบšเบเบฑเบš: เบเบฑเบญเบšเบ›เบตเป‰ - copy operator!

เป€เบ›เบฑเบ™เบ•เบปเบงเบขเปˆเบฒเบ‡, เบžเบดเบˆเบฒเบฅเบฐเบ™เบฒเบเบฒเบ™เบžเบฑเบ”เบ—เบฐเบ™เบฒเบ„เปเบฒเบ–เบฐเปเบซเบผเบ‡เบ—เบตเปˆเบ‡เปˆเบฒเบเบ”เบฒเบเบ—เบตเปˆเบ–เบทเบเบญเบญเบเปเบšเบšเบกเบฒเป€เบžเบทเปˆเบญเบ„เบฑเบ”เบฅเบญเบ ConfigMap เบšเปเปˆเบงเปˆเบฒเบˆเบฐเปƒเบ™เป€เบงเบฅเบฒเบ—เบตเปˆ namespace เปƒเบซเบกเปˆเบ›เบฒเบเบปเบ”เบซเบผเบทเปƒเบ™เป€เบงเบฅเบฒเบ—เบตเปˆเบซเบ™เบถเปˆเบ‡เปƒเบ™เบชเบญเบ‡เบซเบ™เปˆเบงเบเบ‡เบฒเบ™เบกเบตเบเบฒเบ™เบ›เปˆเบฝเบ™เปเบ›เบ‡: ConfigMap เปเบฅเบฐเบ„เบงเบฒเบกเบฅเบฑเบš. เบˆเบฒเบเบ—เบฑเบ”เบชเบฐเบ™เบฐเบ‚เบญเบ‡เบเบฒเบ™เบ›เบฐเบ•เบดเบšเบฑเบ”, เบœเบนเป‰เบ›เบฐเบ•เบดเบšเบฑเบ”เบเบฒเบ™เบชเบฒเบกเบฒเบ”เป€เบ›เบฑเบ™เบ›เบฐเป‚เบซเบเบ”เบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบญเบฑเบšเป€เบ”เบ”เบเบฒเบ™เบ•เบฑเป‰เบ‡เบ„เปˆเบฒเบ‚เบญเบ‡เปเบญเบฑเบšเบžเบฅเบดเป€เบ„เบŠเบฑเบ™ (เป‚เบ”เบเบเบฒเบ™เบ›เบฑเบšเบ›เบธเบ‡ ConfigMap) เบซเบผเบทเบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบ›เบฑเบšเบ›เบธเบ‡เบ‚เปเป‰เบกเบนเบ™เบฅเบฑเบš - เบ•เบปเบงเบขเปˆเบฒเบ‡, เบ›เบธเปˆเบกเบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เป€เบฎเบฑเบ”เบงเบฝเบเบเบฑเบš Docker Registry (เป€เบกเบทเปˆเบญเป€เบžเบตเปˆเบกเบ„เบงเบฒเบกเบฅเบฑเบšเบเบฑเบš namespace).

เบ”เบฑเปˆเบ‡โ€‹เบ™เบฑเป‰เบ™ เบชเบดเปˆเบ‡เบ—เบตเปˆเบœเบนเป‰เบ›เบฐเบเบญเบšเบเบฒเบ™เบ—เบตเปˆเบ”เบตเบ„เบงเบ™เบกเบต:

  1. เบ›เบฐเบ•เบดเบชเปเบฒเบžเบฑเบ™เบเบฑเบšเบœเบนเป‰เบ›เบฐเบ•เบดเบšเบฑเบ”เบ‡เบฒเบ™เปเบกเปˆเบ™เบ”เปเบฒเป€เบ™เบตเบ™เบเบฒเบ™เป‚เบ”เบเปƒเบŠเป‰ เบ„เปเบฒเบ™เบดเบเบฒเบกเบŠเบฑเบšเบžเบฐเบเบฒเบเบญเบ™เบ—เบตเปˆเบเปเบฒเบซเบ™เบปเบ”เป€เบญเบ‡ (เบ•เปเปˆเป„เบ›เบ™เบตเป‰เป€เบญเบตเป‰เบ™เบงเปˆเบฒ CRD).
  2. เบœเบนเป‰เบ›เบฐเบเบญเบšเบเบฒเบ™เบชเบฒเบกเบฒเบ”เบ–เบทเบเบ•เบฑเป‰เบ‡เบ„เปˆเบฒเป„เบ”เป‰. เป€เบžเบทเปˆเบญเป€เบฎเบฑเบ”เบชเบดเปˆเบ‡เบ™เบตเป‰, เบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบ™เปเบฒเปƒเบŠเป‰เบ—เบธเบ‡เบชเบฒเบเบ„เปเบฒเบชเบฑเปˆเบ‡เปเบฅเบฐเบ•เบปเบงเปเบ›เบชเบฐเบžเบฒเบšเปเบงเบ”เบฅเป‰เบญเบก.
  3. เบเบฒเบ™เบชเป‰เบฒเบ‡ Docker container เปเบฅเบฐ Helm chart เบ–เบทเบเบญเบญเบเปเบšเบšเบกเบฒเป€เบžเบทเปˆเบญเปƒเบซเป‰เบœเบนเป‰เปƒเบŠเป‰เบชเบฒเบกเบฒเบ” (เบฎเบนเป‰เบซเบ™เบฑเบ‡เบชเบทเบ”เป‰เบงเบเบ„เปเบฒเบชเบฑเปˆเบ‡เบ”เบฝเบง) เบ•เบดเบ”เบ•เบฑเป‰เบ‡เบ•เบปเบงเบ›เบฐเบ•เบดเบšเบฑเบ”เบเบฒเบ™เป€เบ‚เบปเป‰เบฒเป„เบ›เปƒเบ™เบเบธเปˆเบก Kubernetes เบ‚เบญเบ‡เป€เบ‚เบปเบฒเป€เบˆเบปเป‰เบฒเป„เบ”เป‰เบขเปˆเบฒเบ‡เบ‡เปˆเบฒเบเบ”เบฒเบ.

CRD

เป€เบžเบทเปˆเบญเปƒเบซเป‰เบœเบนเป‰เบ›เบฐเบ•เบดเบšเบฑเบ”เบเบฒเบ™เบฎเบนเป‰เบงเปˆเบฒเบŠเบฑเบšเบžเบฐเบเบฒเบเบญเบ™เปƒเบ”เบ—เบตเปˆเบˆเบฐเบŠเบญเบเบซเบฒเปเบฅเบฐเบšเปˆเบญเบ™เบ—เบตเปˆเบˆเบฐเบŠเบญเบเบซเบฒ, เบžเบงเบเป€เบฎเบปเบฒเบˆเปเบฒเป€เบ›เบฑเบ™เบ•เป‰เบญเบ‡เบเปเบฒเบ™เบปเบ”เบเบปเบ”เบฅเบฐเบšเบฝเบšเบชเปเบฒเบฅเบฑเบšเบฅเบฒเบง. เปเบ•เปˆเบฅเบฐเบเบปเบ”เบฅเบฐเบšเบฝเบšเบˆเบฐเบ–เบทเบเบชเบฐเปเบ”เบ‡เป€เบ›เบฑเบ™เบงเบฑเบ”เบ–เบธ CRD เบ”เบฝเบง. CRD เบ™เบตเป‰เบ„เบงเบ™เบกเบตเบชเบฒเบ‚เบฒเปƒเบ”เปเบ”เปˆ?

  1. เบ›เบฐเป€เบžเบ”เบŠเบฑเบšเบžเบฐเบเบฒเบเบญเบ™, เบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบŠเบญเบเบซเบฒ (ConfigMap เบซเบผเบทเบฅเบฑเบš).
  2. เบšเบฑเบ™เบŠเบตเบฅเบฒเบเบŠเบทเปˆเบ‚เบญเบ‡ namespaces, เปƒเบ™เบ—เบตเปˆเบŠเบฑเบšเบžเบฐเบเบฒเบเบญเบ™เบ„เบงเบ™เบˆเบฐเบ•เบฑเป‰เบ‡เบขเบนเปˆ.
  3. Selector, เป‚เบ”เบเบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบ„เบปเป‰เบ™เบซเบฒเบŠเบฑเบšเบžเบฐเบเบฒเบเบญเบ™เปƒเบ™ namespace.

เบ‚เปเบญเบฐเบ—เบดเบšเบฒเบ 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

เปเบฅเบฐเบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบชเป‰เบฒเบ‡เบกเบฑเบ™เบ—เบฑเบ™เบ—เบต เบเบปเบ”เบฅเบฐเบšเบฝเบšเบ‡เปˆเบฒเบเบ”เบฒเบ โ€” เบเบฒเบ™โ€‹เบ„เบปเป‰เบ™โ€‹เบซเบฒโ€‹เปƒเบ™ namespace เบ—เบตเปˆโ€‹เบกเบตโ€‹เบŠเบทเปˆโ€‹ default ConfigMap เบ—เบฑเบ‡เบซเบกเบปเบ”เบ—เบตเปˆเบกเบตเบ›เป‰เบฒเบเบŠเบทเปˆเป€เบŠเบฑเปˆเบ™ copyrator: "true":

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

เบžเป‰เบญเบกเปเบฅเป‰เบง! เปƒเบ™เบ›เบฑเบ”เบˆเบธเบšเบฑเบ™เบžเบงเบเป€เบฎเบปเบฒเบˆเปเบฒเป€เบ›เบฑเบ™เบ•เป‰เบญเบ‡ somehow เป„เบ”เป‰เบฎเบฑเบšเบ‚เปเป‰เบกเบนเบ™เบเปˆเบฝเบงเบเบฑเบšเบเบปเบ”เบฅเบฐเบšเบฝเบšเบ‚เบญเบ‡เบžเบงเบเป€เบฎเบปเบฒ. เปƒเบซเป‰เบ‚เป‰เบญเบเบˆเบญเบ‡เบ—เบฑเบ™เบ—เบตเบงเปˆเบฒเบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบšเปเปˆเบ‚เบฝเบ™เบ„เปเบฒเบฎเป‰เบญเบ‡เบ‚เปเปƒเบซเป‰เบเบฑเบš cluster API Server เบ•เบปเบงเป€เบฎเบปเบฒเป€เบญเบ‡. เป€เบžเบทเปˆเบญเป€เบฎเบฑเบ”เบชเบดเปˆเบ‡เบ™เบตเป‰, เบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบ™เปเบฒเปƒเบŠเป‰เบซเป‰เบญเบ‡เบชเบฐเบซเบกเบธเบ” Python เบ—เบตเปˆเบเบฝเบกเบžเป‰เบญเบก kubernetes-เบฅเบนเบเบ„เป‰เบฒ:

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

เป€เบ›เบฑเบ™เบœเบปเบ™เบกเบฒเบˆเบฒเบเบเบฒเบ™เปเบฅเปˆเบ™เบฅเบฐเบซเบฑเบ”เบ™เบตเป‰, เบžเบงเบเป€เบฎเบปเบฒเป„เบ”เป‰เบฎเบฑเบšเบ”เบฑเปˆเบ‡เบ•เปเปˆเป„เบ›เบ™เบตเป‰:

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

เบเบดเปˆเบ‡เปƒเบซเบเปˆ: เบžเบงเบเป€เบฎเบปเบฒเบˆเบฑเบ”เบเบฒเบ™เป€เบžเบทเปˆเบญเปƒเบซเป‰เป„เบ”เป‰เบเบปเบ”เบฅเบฐเบšเบฝเบšเบชเปเบฒเบฅเบฑเบšเบœเบนเป‰เบ›เบฐเบเบญเบšเบเบฒเบ™. เปเบฅเบฐเบชเปเบฒเบ„เบฑเบ™เบ—เบตเปˆเบชเบธเบ”, เบžเบงเบเป€เบฎเบปเบฒเป„เบ”เป‰เป€เบฎเบฑเบ”เบชเบดเปˆเบ‡เบ—เบตเปˆเป€เบญเบตเป‰เบ™เบงเปˆเบฒเบงเบดเบ—เบต Kubernetes.

เบ•เบปเบงเปเบ›เบชเบฐเบžเบฒเบšเปเบงเบ”เบฅเป‰เบญเบกเบซเบผเบทเบ—เบธเบ‡? เบžเบงเบเป€เบฎเบปเบฒเป€เบญเบปเบฒเบ—เบธเบเบชเบดเปˆเบ‡เบ—เบธเบเบขเปˆเบฒเบ‡!

เปƒเบซเป‰เบเป‰เบฒเบงเป„เบ›เบชเบนเปˆเบเบฒเบ™เบ•เบฑเป‰เบ‡เบ„เปˆเบฒเบ•เบปเบงเบ›เบฐเบ•เบดเบšเบฑเบ”เบเบฒเบ™เบ•เบปเป‰เบ™เบ•เป. เบกเบตเบชเบญเบ‡เบงเบดเบ—เบตเบžเบทเป‰เบ™เบ–เบฒเบ™เปƒเบ™เบเบฒเบ™เบ•เบฑเป‰เบ‡เบ„เปˆเบฒเปเบญเบฑเบšเบžเบฅเบดเป€เบ„เบŠเบฑเบ™:

  1. เปƒเบŠเป‰เบ•เบปเบงเป€เบฅเบทเบญเบเป€เบชเบฑเป‰เบ™เบ„เปเบฒเบชเบฑเปˆเบ‡;
  2. เปƒเบŠเป‰เบ•เบปเบงเปเบ›เบชเบฐเบžเบฒเบšเปเบงเบ”เบฅเป‰เบญเบก.

เบ•เบปเบงเป€เบฅเบทเบญเบเปเบ–เบงเบ„เปเบฒเบชเบฑเปˆเบ‡เบŠเปˆเบงเบเปƒเบซเป‰เบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เบญเปˆเบฒเบ™เบเบฒเบ™เบ•เบฑเป‰เบ‡เบ„เปˆเบฒเบ—เบตเปˆเบกเบตเบ„เบงเบฒเบกเบเบทเบ”เบซเบเบธเปˆเบ™เบซเบผเบฒเบ, เบ”เป‰เบงเบเบเบฒเบ™เบชเบฐเบซเบ™เบฑเบšเบชเบฐเบซเบ™เบนเบ™เบ›เบฐเป€เบžเบ”เบ‚เปเป‰เบกเบนเบ™เปเบฅเบฐเบเบฒเบ™เบเบงเบ”เบชเบญเบš. เบซเป‰เบญเบ‡เบชเบฐเบซเบกเบธเบ”เบกเบฒเบ”เบ•เบฐเบ–เบฒเบ™เบ‚เบญเบ‡ Python เบกเบตเป‚เบกเบ”เบนเบ™ argparser, เบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบ™เปเบฒเปƒเบŠเป‰. เบฅเบฒเบเบฅเบฐเบญเบฝเบ”เปเบฅเบฐเบ•เบปเบงเบขเปˆเบฒเบ‡เบ‚เบญเบ‡เบ„เบงเบฒเบกเบชเบฒเบกเบฒเบ”เบ‚เบญเบ‡เบกเบฑเบ™เปเบกเปˆเบ™เบกเบตเบขเบนเปˆเปƒเบ™ เป€เบญเบเบฐเบชเบฒเบ™เบ—เบฒเบ‡เบเบฒเบ™.

เบชเปเบฒโ€‹เบฅเบฑเบšโ€‹เบเปโ€‹เบฅเบฐโ€‹เบ™เบตโ€‹เบ‚เบญเบ‡โ€‹เบžเบงเบโ€‹เป€เบฎเบปเบฒโ€‹, เบ™เบตเป‰โ€‹เปเบกเปˆเบ™โ€‹เบ•เบปเบงโ€‹เบขเปˆเบฒเบ‡โ€‹เบ‚เบญเบ‡โ€‹เบเบฒเบ™โ€‹เบ•เบฑเป‰เบ‡โ€‹เบ„เปˆเบฒโ€‹เบเบฒเบ™โ€‹เบญเปˆเบฒเบ™โ€‹เบ—เบธเบ‡โ€‹เบšเบฑเบ™โ€‹เบ”เบฒโ€‹เบ„เปเบฒโ€‹เบชเบฑเปˆเบ‡โ€‹เบˆเบฐโ€‹เป€เบšเบดเปˆเบ‡โ€‹เบ„เบทโ€‹:

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

เปƒเบ™เบ—เบฒเบ‡เบเบปเบ‡เบเบฑเบ™เบ‚เป‰เบฒเบก, เบเบฒเบ™เบ™เปเบฒเปƒเบŠเป‰เบ•เบปเบงเปเบ›เบชเบฐเบžเบฒเบšเปเบงเบ”เบฅเป‰เบญเบกเปƒเบ™ Kubernetes, เบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เป‚เบญเบ™เบ‚เปเป‰เบกเบนเบ™เบเบฒเบ™เบšเปเบฅเบดเบเบฒเบ™เบเปˆเบฝเบงเบเบฑเบšเบเบฑเบเบžเบฒเบเปƒเบ™เบ–เบฑเบ‡เป„เบ”เป‰เบขเปˆเบฒเบ‡เบ‡เปˆเบฒเบเบ”เบฒเบ. เบ•เบปเบงเบขเปˆเบฒเบ‡, เบžเบงเบเป€เบฎเบปเบฒเบชเบฒเบกเบฒเบ”เป„เบ”เป‰เบฎเบฑเบšเบ‚เปเป‰เบกเบนเบ™เบเปˆเบฝเบงเบเบฑเบš namespace เบ—เบตเปˆ pod เป€เบฎเบฑเบ”เบงเบฝเบเบเบฑเบšเบเบฒเบ™เบเปเปˆเบชเป‰เบฒเบ‡เบ”เบฑเปˆเบ‡เบ•เปเปˆเป„เบ›เบ™เบตเป‰:

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

เป€เบซเบ”เบœเบปเบ™เบ‚เบญเบ‡เบœเบนเป‰เบ›เบฐเบ•เบดเบšเบฑเบ”เบ‡เบฒเบ™

เป€เบžเบทเปˆเบญเป€เบ‚เบปเป‰เบฒเปƒเบˆเบงเบดเบ—เบตเบเบฒเบ™เปเบเบเบงเบดเบ—เบตเบเบฒเบ™เป€เบฎเบฑเบ”เบงเบฝเบเบเบฑเบš ConfigMap เปเบฅเบฐเบ„เบงเบฒเบกเบฅเบฑเบš, เบžเบงเบเป€เบฎเบปเบฒเบˆเบฐเบ™เปเบฒเปƒเบŠเป‰เปเบœเบ™เบ—เบตเปˆเบžเบดเป€เบชเบ”. เบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™, เบžเบงเบเป€เบฎเบปเบฒเบชเบฒเบกเบฒเบ”เป€เบ‚เบปเป‰เบฒเปƒเบˆเบงเบดเบ—เบตเบเบฒเบ™เบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเบ•เป‰เบญเบ‡เบเบฒเบ™เป€เบžเบทเปˆเบญเบ•เบดเบ”เบ•เบฒเบกเปเบฅเบฐเบชเป‰เบฒเบ‡เบงเบฑเบ”เบ–เบธ:

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

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

เบ•เปเปˆเป„เบ›, เบ—เปˆเบฒเบ™เบˆเปเบฒเป€เบ›เบฑเบ™เบ•เป‰เบญเบ‡เป„เบ”เป‰เบฎเบฑเบšเป€เบซเบ”เบเบฒเบ™เบˆเบฒเบเป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบ API. เปƒเบซเป‰โ€‹เบ›เบฐโ€‹เบ•เบดโ€‹เบšเบฑเบ”โ€‹เบกเบฑเบ™โ€‹เบ”เบฑเปˆเบ‡โ€‹เบ•เปเปˆโ€‹เป„เบ›โ€‹เบ™เบตเป‰โ€‹:

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)

เบซเบผเบฑเบ‡เบˆเบฒเบเป„เบ”เป‰เบฎเบฑเบšเป€เบซเบ”เบเบฒเบ™, เบžเบงเบเป€เบฎเบปเบฒเบเป‰เบฒเบงเป„เบ›เบชเบนเปˆเป€เบซเบ”เบœเบปเบ™เบ•เบปเป‰เบ™เบ•เปเบ‚เบญเบ‡เบเบฒเบ™เบ›เบธเบ‡เปเบ•เปˆเบ‡เบกเบฑเบ™:

# ะขะธะฟั‹ ัะพะฑั‹ั‚ะธะน, ะฝะฐ ะบะพั‚ะพั€ั‹ะต ะฑัƒะดะตะผ ั€ะตะฐะณะธั€ะพะฒะฐั‚ัŒ
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)

เป€เบซเบ”เบœเบปเบ™เบ•เบปเป‰เบ™เบ•เปเปเบกเปˆเบ™เบเบฝเบกเบžเป‰เบญเบก! เปƒเบ™เบ›เบฑเบ”เบˆเบธเบšเบฑเบ™เบžเบงเบเป€เบฎเบปเบฒเบˆเปเบฒเป€เบ›เบฑเบ™เบ•เป‰เบญเบ‡เป„เบ”เป‰เบซเบธเป‰เบกเบซเปเปˆเบ—เบฑเบ‡เบซเบกเบปเบ”เบ™เบตเป‰เป€เบ‚เบปเป‰เบฒเป„เบ›เปƒเบ™เบŠเบธเบ” Python เบ”เบฝเบง. เบžเบงเบเป€เบฎเบปเบฒเบเบฐเบเบฝเบกเป€เบญเบเบฐเบชเบฒเบ™ setup.py, เบ‚เบฝเบ™เบ‚เปเป‰เบกเบนเบ™ meta เบเปˆเบฝเบงเบเบฑเบšเป‚เบ„เบ‡เบเบฒเบ™เบขเบนเปˆเบ—เบตเปˆเบ™เบฑเป‰เบ™:

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: เบฅเบนเบเบ„เป‰เบฒ kubernetes เบชเปเบฒเบฅเบฑเบš Python เบกเบตเป€เบงเบตเบŠเบฑเบ™เบ‚เบญเบ‡เบ•เบปเบ™เป€เบญเบ‡. เบ‚เปเป‰เบกเบนเบ™เป€เบžเบตเปˆเบกเป€เบ•เบตเบกเบเปˆเบฝเบงเบเบฑเบšเบ„เบงเบฒเบกเป€เบ‚เบปเป‰เบฒเบเบฑเบ™เป„เบ”เป‰เบฅเบฐเบซเบงเปˆเบฒเบ‡เบฅเบธเป‰เบ™เบฅเบนเบเบ‚เปˆเบฒเบ เปเบฅเบฐเบฅเบธเป‰เบ™ Kubernetes เบชเบฒเบกเบฒเบ”เบžเบปเบšเป„เบ”เป‰เปƒเบ™ เบ„เบงเบฒเบกเป€เบ‚เบปเป‰เบฒเบเบฑเบ™เป„เบ”เป‰ matrices.

เปƒเบ™เบ›เบฑเบ”เบˆเบธเบšเบฑเบ™เป‚เบ„เบ‡เบเบฒเบ™เบ‚เบญเบ‡เบžเบงเบเป€เบฎเบปเบฒเป€เบšเบดเปˆเบ‡เบ„เบทเบงเปˆเบฒเบ™เบตเป‰:

copyrator
โ”œโ”€โ”€ copyrator
โ”‚   โ”œโ”€โ”€ cli.py # ะ›ะพะณะธะบะฐ ั€ะฐะฑะพั‚ั‹ ั ะบะพะผะฐะฝะดะฝะพะน ัั‚ั€ะพะบะพะน
โ”‚   โ”œโ”€โ”€ constant.py # ะšะพะฝัั‚ะฐะฝั‚ั‹, ะบะพั‚ะพั€ั‹ะต ะผั‹ ะฟั€ะธะฒะพะดะธะปะธ ะฒั‹ัˆะต
โ”‚   โ”œโ”€โ”€ load_crd.py # ะ›ะพะณะธะบะฐ ะทะฐะณั€ัƒะทะบะธ CRD
โ”‚   โ””โ”€โ”€ operator.py # ะžัะฝะพะฒะฝะฐั ะปะพะณะธะบะฐ ั€ะฐะฑะพั‚ั‹ ะพะฟะตั€ะฐั‚ะพั€ะฐ
โ””โ”€โ”€ setup.py # ะžั„ะพั€ะผะปะตะฝะธะต ะฟะฐะบะตั‚ะฐ

Docker เปเบฅเบฐ Helm

Dockerfile เบˆเบฐเบ‡เปˆเบฒเบเบ”เบฒเบเบขเปˆเบฒเบ‡เบšเปเปˆเบซเบ™เป‰เบฒเป€เบŠเบทเปˆเบญ: เป€เบญเบปเบฒเบฎเบนเบš python-alpine เบžเบทเป‰เบ™เบ–เบฒเบ™เปเบฅเบฐเบ•เบดเบ”เบ•เบฑเป‰เบ‡เบŠเบธเบ”เบ‚เบญเบ‡เบžเบงเบเป€เบฎเบปเบฒ. เบ‚เปเปƒเบซเป‰เป€เบฅเบทเปˆเบญเบ™เบเบฒเบ™เป€เบžเบตเปˆเบกเบ›เบฐเบชเบดเบ”เบ—เบดเบžเบฒเบšเบ‚เบญเบ‡เบกเบฑเบ™เบญเบญเบเป„เบ›เบˆเบปเบ™เบฎเบญเบ”เป€เบงเบฅเบฒเบ—เบตเปˆเบ”เบตเบเบงเปˆเบฒ:

FROM python:3.7.3-alpine3.9

ADD . /app

RUN pip3 install /app

ENTRYPOINT ["copyrator"]

เบเบฒเบ™เบ›เบฐเบ•เบดเบšเบฑเบ”เบชเปเบฒเบฅเบฑเบšเบœเบนเป‰เบ›เบฐเบเบญเบšเบเบฒเบ™เปเบกเปˆเบ™เบเบฑเบ‡เบ‡เปˆเบฒเบเบ”เบฒเบเบซเบผเบฒเบ:

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

เบชเบธเบ”เบ—เป‰เบฒเบ, เบ—เปˆเบฒเบ™เบˆเปเบฒเป€เบ›เบฑเบ™เบ•เป‰เบญเบ‡เบชเป‰เบฒเบ‡เบšเบปเบ”เบšเบฒเบ”เบ—เบตเปˆเป€เบซเบกเบฒเบฐเบชเบปเบกเบชเปเบฒเบฅเบฑเบšเบœเบนเป‰เบ›เบฐเบ•เบดเบšเบฑเบ”เบ‡เบฒเบ™เบ—เบตเปˆเบกเบตเบชเบดเบ”เบ—เบดเบ—เบตเปˆเบˆเปเบฒเป€เบ›เบฑเบ™:

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

เบœเบปเบ™เป„เบ”เป‰เบฎเบฑเบš

เบ™เบฑเป‰เบ™เปเบกเปˆเบ™, เป‚เบ”เบเบšเปเปˆเบกเบตเบเบฒเบ™เบขเป‰เบฒเบ™เบเบปเบง, เบ•เปเบฒเบซเบ™เบด, เบซเบผเบทเบเบฒเบ™เบฎเบฝเบ™เบฎเบนเป‰ Go, เบžเบงเบเป€เบฎเบปเบฒเบชเบฒเบกเบฒเบ”เบชเป‰เบฒเบ‡เบ•เบปเบงเบ›เบฐเบ•เบดเบšเบฑเบ”เบเบฒเบ™เบ‚เบญเบ‡เบžเบงเบเป€เบฎเบปเบฒเป€เบญเบ‡เบชเปเบฒเบฅเบฑเบš Kubernetes เปƒเบ™ Python. เปเบ™เปˆเบ™เบญเบ™, เบกเบฑเบ™เบเบฑเบ‡เบกเบตเบžเบทเป‰เบ™เบ—เบตเปˆเบ—เบตเปˆเบˆเบฐเป€เบ•เบตเบšเป‚เบ•: เปƒเบ™เบญเบฐเบ™เบฒเบ„เบปเบ”เบกเบฑเบ™เบˆเบฐเบชเบฒเบกเบฒเบ”เบ›เบธเบ‡เปเบ•เปˆเบ‡เบเบปเบ”เบฅเบฐเบšเบฝเบšเบซเบผเบฒเบ, เป€เบฎเบฑเบ”เบงเบฝเบเปƒเบ™เบซเบผเบฒเบเบเบฐเบ—เบนเป‰, เป€เบ›เบฑเบ™เป€เบญเบเบฐเบฅเบฒเบ”เบ•เบดเบ”เบ•เบฒเบกเบเบฒเบ™เบ›เปˆเบฝเบ™เปเบ›เบ‡เปƒเบ™ CRDs เบ‚เบญเบ‡เบกเบฑเบ™ ...

เป€เบžเบทเปˆเบญเป€เบฎเบฑเบ”เปƒเบซเป‰เบ—เปˆเบฒเบ™เป€เบšเบดเปˆเบ‡เปƒเบเป‰เบŠเบดเบ”เบเปˆเบฝเบงเบเบฑเบšเบฅเบฐเบซเบฑเบ”, เบžเบงเบเป€เบฎเบปเบฒเป„เบ”เป‰เปƒเบชเปˆเบกเบฑเบ™ เบ„เบฑเบ‡โ€‹เป€เบเบฑเบšโ€‹เบฎเบฑเบโ€‹เบชเบฒโ€‹เบชเบฒโ€‹เบ—เบฒโ€‹เบฅเบฐโ€‹เบ™เบฐโ€‹. เบ–เป‰เบฒเบ—เปˆเบฒเบ™เบ•เป‰เบญเบ‡เบเบฒเบ™เบ•เบปเบงเบขเปˆเบฒเบ‡เบ‚เบญเบ‡เบ•เบปเบงเบ›เบฐเบ•เบดเบšเบฑเบ”เบเบฒเบ™เบ—เบตเปˆเบฎเป‰เบฒเบเปเบฎเบ‡เบเบงเปˆเบฒเบ—เบตเปˆเบ›เบฐเบ•เบดเบšเบฑเบ”เป‚เบ”เบเปƒเบŠเป‰ Python, เบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เบซเบฑเบ™เบ„เบงเบฒเบกเบชเบปเบ™เปƒเบˆเบ‚เบญเบ‡เบ—เปˆเบฒเบ™เป„เบ›เบซเบฒเบชเบญเบ‡เบ•เบปเบงเบ›เบฐเบ•เบดเบšเบฑเบ”เบเบฒเบ™เบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบ›เบฐเบ•เบดเบšเบฑเบ” mongodb (เบ„เบฑเป‰เบ‡เบ—เปเบฒเบญเบดเบ” ะธ เบ„เบฑเป‰เบ‡เบ—เบตเบชเบญเบ‡).

PS เปเบฅเบฐเบ–เป‰เบฒเบ—เปˆเบฒเบ™เบ‚เบตเป‰เบ„เป‰เบฒเบ™เป€เบเบตเบ™เป„เบ›เบ—เบตเปˆเบˆเบฐเบˆเบฑเบ”เบเบฒเบ™เบเบฑเบšเป€เบซเบ”เบเบฒเบ™ Kubernetes เบซเบผเบทเบ—เปˆเบฒเบ™เบกเบตเบ„เบงเบฒเบกเบ„เบธเป‰เบ™เป€เบ„เบตเบเบเบฑเบšเบเบฒเบ™เบ™เปเบฒเปƒเบŠเป‰ Bash, เป€เบžเบทเปˆเบญเบ™เบฎเปˆเบงเบกเบ‡เบฒเบ™เบ‚เบญเบ‡เบžเบงเบเป€เบฎเบปเบฒเป„เบ”เป‰เบเบฐเบเบฝเบกเบเบฒเบ™เปเบเป‰เป„เบ‚เบ—เบตเปˆเบเบฝเบกเบžเป‰เบญเบกเปƒเบ™เบฎเบนเบšเปเบšเบš. shell-operator (เบžเบงเบเป€เบฎเบปเบฒ เบ›เบฐโ€‹เบเบฒเบ” เปƒเบ™เป€เบ”เบทเบญเบ™เป€เบกเบชเบฒ).

PPS

เบญเปˆเบฒเบ™เบเบฑเบ‡เบขเบนเปˆเปƒเบ™ blog เบ‚เบญเบ‡เบžเบงเบเป€เบฎเบปเบฒ:

เปเบซเบผเปˆเบ‡เบ‚เปเป‰เบกเบนเบ™: www.habr.com

เป€เบžเบตเปˆเบกเบ„เบงเบฒเบกเบ„เบดเบ”เป€เบซเบฑเบ™