เชซเซเชฐเซ‡เชฎเชตเชฐเซเช• เช…เชจเซ‡ SDK เชตเชฟเชจเชพ เชชเชพเชฏเชฅเซ‹เชจเชฎเชพเช‚ เช•เซเชฌเชฐเชจเซ‡เชŸเซเชธ เช“เชชเชฐเซ‡เชŸเชฐ

เชซเซเชฐเซ‡เชฎเชตเชฐเซเช• เช…เชจเซ‡ SDK เชตเชฟเชจเชพ เชชเชพเชฏเชฅเซ‹เชจเชฎเชพเช‚ เช•เซเชฌเชฐเชจเซ‡เชŸเซเชธ เช“เชชเชฐเซ‡เชŸเชฐ

Go เชนเชพเชฒเชฎเชพเช‚ เชชเซเชฐเซ‹เช—เซเชฐเชพเชฎเชฟเช‚เช— เชญเชพเชทเชพเช“ เชชเชฐ เชเช•เชพเชงเชฟเช•เชพเชฐ เชงเชฐเชพเชตเซ‡ เช›เซ‡ เชœเซ‡ เชฒเซ‹เช•เซ‹ เช•เซเชฌเชฐเชจเซ‡เชŸเซเชธ เชฎเชพเชŸเซ‡ เชจเชฟเชตเซ‡เชฆเชจเซ‹ เชฒเช–เชตเชพเชจเซเช‚ เชชเชธเช‚เชฆ เช•เชฐเซ‡ เช›เซ‡. เช†เชจเชพ เชฎเชพเชŸเซ‡ เช‰เชฆเซเชฆเซ‡เชถเซเชฏ เช•เชพเชฐเชฃเซ‹ เช›เซ‡, เชœเซ‡เชฎ เช•เซ‡:

  1. Go เชฎเชพเช‚ เช“เชชเชฐเซ‡เชŸเชฐเซ‹ เชตเชฟเช•เชธเชพเชตเชตเชพ เชฎเชพเชŸเซ‡ เชเช• เชถเช•เซเชคเชฟเชถเชพเชณเซ€ เชฎเชพเชณเช–เซเช‚ เช›เซ‡ - เช“เชชเชฐเซ‡เชŸเชฐ SDK.
  2. Docker เช…เชจเซ‡ Kubernetes เชœเซ‡เชตเซ€ เชฐเชฎเชค-เชฌเชฆเชฒเชคเซ€ เชเชชเซเชฒเชฟเช•เซ‡เชถเชจเซ‹ Go เชฎเชพเช‚ เชฒเช–เซ‡เชฒเซ€ เช›เซ‡. Go เชฎเชพเช‚ เชคเชฎเชพเชฐเชพ เช“เชชเชฐเซ‡เชŸเชฐเชจเซ‡ เชฒเช–เชตเชพเชจเซ‹ เช…เชฐเซเชฅ เช เช›เซ‡ เช•เซ‡ เช‡เช•เซ‹เชธเชฟเชธเซเชŸเชฎ เชธเชพเชฅเซ‡ เชธเชฎเชพเชจ เชญเชพเชทเชพ เชฌเซ‹เชฒเชตเซ€.
  3. เช—เซ‹ เชเชชเซเชฒเซ€เช•เซ‡เชถเชจเชจเซเช‚ เช‰เชšเซเชš เชชเซเชฐเชฆเชฐเซเชถเชจ เช…เชจเซ‡ เชฌเซ‹เช•เซเชธเชจเซ€ เชฌเชนเชพเชฐ เชธเช‚เชฎเชคเชฟ เชธเชพเชฅเซ‡ เช•เชพเชฎ เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡เชจเชพ เชธเชฐเชณ เชธเชพเชงเชจเซ‹.

NB: เชฌเชพเชฏ เชง เชตเซ‡, เช—เซ‹เชฎเชพเช‚ เชคเชฎเชพเชฐเซเช‚ เชชเซ‹เชคเชพเชจเซเช‚ เชธเซเชŸเซ‡เชŸเชฎเซ‡เชจเซเชŸ เช•เซ‡เชตเซ€ เชฐเซ€เชคเซ‡ เชฒเช–เชตเซเช‚, เช…เชฎเซ‡ เชชเชนเซ‡เชฒเซ‡เชฅเซ€ เชœ เชตเชฐเซเชฃเชตเซ‡เชฒ เช›เซ‡ เชตเชฟเชฆเซ‡เชถเซ€ เชฒเซ‡เช–เช•เซ‹ เชฆเซเชตเชพเชฐเชพ เช…เชฎเชพเชฐเชพ เช…เชจเซเชตเชพเชฆเซ‹เชฎเชพเช‚เชจเชพ เชเช•เชฎเชพเช‚.

เชชเชฐเช‚เชคเซ เชœเซ‹ เชคเชฎเชจเซ‡ เชธเชฎเชฏเชจเชพ เช…เชญเชพเชตเซ‡ เช…เชฅเชตเชพ, เชธเชฐเชณ เชถเชฌเซเชฆเซ‹เชฎเชพเช‚ เช•เชนเซ€เช เชคเซ‹, เชชเซเชฐเซ‡เชฐเชฃเชพเชฅเซ€ เช—เซ‹ เชถเซ€เช–เชตเชพเชฅเซ€ เช…เชŸเช•เชพเชตเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เชคเซ‹ เชถเซเช‚? เช† เชฒเซ‡เช– เชเช• เช‰เชฆเชพเชนเชฐเชฃ เชชเซ‚เชฐเซเช‚ เชชเชพเชกเซ‡ เช›เซ‡ เช•เซ‡ เชคเชฎเซ‡ เช•เซ‡เชตเซ€ เชฐเซ€เชคเซ‡ เชเช• เชธเซŒเชฅเซ€ เชฒเซ‹เช•เชชเซเชฐเชฟเชฏ เชญเชพเชทเชพเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชจเซ‡ เชธเชพเชฐเซเช‚ เชจเชฟเชตเซ‡เชฆเชจ เชฒเช–เซ€ เชถเช•เซ‹ เช›เซ‹ เชœเซ‡ เชฒเช—เชญเช— เชฆเชฐเซ‡เช• DevOps เชเชจเซเชœเชฟเชจเชฟเชฏเชฐ เชœเชพเชฃเซ‡ เช›เซ‡ - เชชเชพเชฏเชฅเซ‹เชจ.

เชฎเชณเซ‹: เช•เซ‰เชชเชฟเชฏเชฐ - เช•เซ‰เชชเชฟ เช‘เชชเชฐเซ‡เชŸเชฐ!

เช‰เชฆเชพเชนเชฐเชฃ เชคเชฐเซ€เช•เซ‡, เชœเซเชฏเชพเชฐเซ‡ เชจเชตเซเช‚ เชจเซ‡เชฎเชธเซเชชเซ‡เชธ เชฆเซ‡เช–เชพเชฏ เช…เชฅเชตเชพ เชœเซเชฏเชพเชฐเซ‡ เชฌเซ‡ เชเชจเซเชŸเชฟเชŸเซ€เชฎเชพเช‚ เชซเซ‡เชฐเชซเชพเชฐ เชฅเชพเชฏ เชคเซเชฏเชพเชฐเซ‡ เช•เซ‹เชจเซเชซเชฟเช—เชฎเซ‡เชชเชจเซ€ เชจเช•เชฒ เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ เชฐเชšเชพเชฏเซ‡เชฒ เชเช• เชธเชฐเชณ เชจเชฟเชตเซ‡เชฆเชจ เชตเชฟเช•เชธเชพเชตเชตเชพเชจเซเช‚ เชตเชฟเชšเชพเชฐเซ‹: เช•เซ‹เชจเซเชซเชฟเช—เชฎเซ‡เชช เช…เชจเซ‡ เชธเชฟเช•เซเชฐเซ‡เชŸ. เชตเซเชฏเชตเชนเชพเชฐเชฟเช• เชฆเซƒเชทเซเชŸเชฟเช•เซ‹เชฃเชฅเซ€, เช‘เชชเชฐเซ‡เชŸเชฐ เชเชชเซเชฒเชฟเช•เซ‡เชถเชจ เชฐเซ‚เชชเชฐเซ‡เช–เชพเช‚เช•เชจเซ‹เชจเชพ เชœเชฅเซเชฅเชพเชฌเช‚เชง เช…เชชเชกเซ‡เชŸ เชฎเชพเชŸเซ‡ (เช•เซ‹เชจเซเชซเชฟเช—เชฎเซ‡เชช เช…เชชเชกเซ‡เชŸ เช•เชฐเซ€เชจเซ‡) เช…เชฅเชตเชพ เช—เซเชชเซเชค เชกเซ‡เชŸเชพเชจเซ‡ เช…เชชเชกเซ‡เชŸ เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ เช‰เชชเชฏเซ‹เช—เซ€ เชฅเชˆ เชถเช•เซ‡ เช›เซ‡ - เช‰เชฆเชพเชนเชฐเชฃ เชคเชฐเซ€เช•เซ‡, เชกเซ‹เช•เชฐ เชฐเชœเชฟเชธเซเชŸเซเชฐเซ€ เชธเชพเชฅเซ‡ เช•เชพเชฎ เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡เชจเซ€ เชšเชพเชตเซ€เช“ (เชจเซ‡เชฎเชธเซเชชเซ‡เชธเชฎเชพเช‚ เชธเชฟเช•เซเชฐเซ‡เชŸ เช‰เชฎเซ‡เชฐเชคเซ€ เชตเช–เชคเซ‡).

เช…เชจเซ‡ เชคเซ‡เชฅเซ€, เชเช• เชธเชพเชฐเชพ เช“เชชเชฐเซ‡เชŸเชฐ เชชเชพเชธเซ‡ เชถเซเช‚ เชนเซ‹เชตเซเช‚ เชœเซ‹เชˆเช:

  1. เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชจเซ‡ เช“เชชเชฐเซ‡เชŸเชฐ เชธเชพเชฅเซ‡เชจเซ€ เช•เซเชฐเชฟเชฏเชพเชชเซเชฐเชคเชฟเช•เซเชฐเชฟเชฏเชพ เชนเชพเชฅ เชงเชฐเชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡ เช•เชธเซเชŸเชฎ เชธเช‚เชธเชพเชงเชจ เชตเซเชฏเชพเช–เซเชฏเชพเช“ (เชคเซเชฏเชพเชฐเชฌเชพเชฆ CRD เชคเชฐเซ€เช•เซ‡ เช“เชณเช–เชตเชพเชฎเชพเช‚ เช†เชตเซ‡ เช›เซ‡).
  2. เช“เชชเชฐเซ‡เชŸเชฐ เชฐเซ‚เชชเชฐเซ‡เช–เชพเช‚เช•เชฟเชค เช•เชฐเซ€ เชถเช•เชพเชฏ เช›เซ‡. เช† เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡, เช…เชฎเซ‡ เช•เชฎเชพเชจเซเชก เชฒเชพเช‡เชจ เชซเซเชฒเซ‡เช—เซเชธ เช…เชจเซ‡ เชชเชฐเซเชฏเชพเชตเชฐเชฃ เชตเซ‡เชฐเซ€เชเชฌเชฒเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชถเซเช‚.
  3. เชกเซ‹เช•เชฐ เช•เชจเซเชŸเซ‡เชจเชฐ เช…เชจเซ‡ เชนเซ‡เชฒเซเชฎ เชšเชพเชฐเซเชŸเชจเซเช‚ เชฌเชฟเชฒเซเชก เชกเชฟเชเชพเช‡เชจ เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเซเชฏเซเช‚ เช›เซ‡ เชœเซ‡เชฅเซ€ เชตเชชเชฐเชพเชถเช•เชฐเซเชคเชพเช“ เชธเชฐเชณเชคเชพเชฅเซ€ (เชถเชพเชฌเซเชฆเชฟเช• เชฐเซ€เชคเซ‡ เชเช• เช†เชฆเซ‡เชถ เชธเชพเชฅเซ‡) เช“เชชเชฐเซ‡เชŸเชฐเชจเซ‡ เชคเซ‡เชฎเชจเชพ เช•เซเชฌเชฐเชจเซ‡เชŸเซเชธ เช•เซเชฒเชธเซเชŸเชฐเชฎเชพเช‚ เช‡เชจเซเชธเซเชŸเซ‹เชฒ เช•เชฐเซ€ เชถเช•เซ‡.

เชธเซ€เช†เชฐเชกเซ€

เช‘เชชเชฐเซ‡เชŸเชฐเชจเซ‡ เชœเชพเชฃเชตเชพ เชฎเชพเชŸเซ‡ เช•เซ‡ เช•เชฏเชพ เชธเช‚เชธเชพเชงเชจเซ‹เชจเซ€ เชถเซ‹เชง เช•เชฐเชตเซ€ เช…เชจเซ‡ เช•เซเชฏเชพเช‚ เชœเซ‹เชตเซเช‚, เช†เชชเชฃเซ‡ เชคเซ‡เชจเชพ เชฎเชพเชŸเซ‡ เชเช• เชจเชฟเชฏเชฎ เชธเซ‡เชŸ เช•เชฐเชตเชพเชจเซ€ เชœเชฐเซ‚เชฐ เช›เซ‡. เชฆเชฐเซ‡เช• เชจเชฟเชฏเชฎเชจเซ‡ เชเช• เชœ CRD เช‘เชฌเซเชœเซ‡เช•เซเชŸ เชคเชฐเซ€เช•เซ‡ เชฐเชœเซ‚ เช•เชฐเชตเชพเชฎเชพเช‚ เช†เชตเชถเซ‡. เช† เชธเซ€เช†เชฐเชกเซ€เชฎเชพเช‚ เช•เชฏเชพ เช•เซเชทเซ‡เชคเซเชฐเซ‹ เชนเซ‹เชตเชพ เชœเซ‹เชˆเช?

  1. เชธเช‚เชธเชพเชงเชจ เชชเซเชฐเช•เชพเชฐ, เชœเซ‡ เช†เชชเชฃเซ‡ เชถเซ‹เชงเซ€เชถเซเช‚ (เช•เซ‹เชจเซเชซเชฟเช—เชฎเซ‡เชช เช…เชฅเชตเชพ เชธเชฟเช•เซเชฐเซ‡เชŸ).
  2. เชจเซ‡เชฎเชธเซเชชเซ‡เชธเชจเซ€ เชฏเชพเชฆเซ€, เชœเซ‡เชฎเชพเช‚ เชธเช‚เชธเชพเชงเชจเซ‹ เชธเซเชฅเชฟเชค เชนเซ‹เชตเชพ เชœเซ‹เชˆเช.
  3. เชชเชธเช‚เชฆเช—เซ€เช•เชพเชฐ, เชœเซ‡เชจเชพ เชฆเซเชตเชพเชฐเชพ เช†เชชเชฃเซ‡ เชจเซ‡เชฎเชธเซเชชเซ‡เชธเชฎเชพเช‚ เชธเช‚เชธเชพเชงเชจเซ‹ เชถเซ‹เชงเซ€เชถเซเช‚.

เชšเชพเชฒเซ‹ 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

เช…เชจเซ‡ เช…เชฎเซ‡ เชคเซ‡เชจเซ‡ เชคเชฐเชค เชœ เชฌเชจเชพเชตเซ€เชถเซเช‚ เชธเชฐเชณ เชจเชฟเชฏเชฎ - เชจเชพเชฎ เชธเชพเชฅเซ‡ เชจเซ‡เชฎเชธเซเชชเซ‡เชธเชฎเชพเช‚ เชธเชฐเซเชš เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ default เชœเซ‡เชตเชพ เชฒเซ‡เชฌเชฒเซเชธ เชธเชพเชฅเซ‡ เชคเชฎเชพเชฎ เช•เซ‹เชจเซเชซเชฟเช—เชฎเซ‡เชช copyrator: "true":

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

เชคเซˆเชฏเชพเชฐ! เชนเชตเซ‡ เช†เชชเชฃเซ‡ เช•เซ‹เชˆเช• เชฐเซ€เชคเซ‡ เช†เชชเชฃเชพ เชจเชฟเชฏเชฎ เชตเชฟเชถเซ‡ เชฎเชพเชนเชฟเชคเซ€ เชฎเซ‡เชณเชตเชตเชพเชจเซ€ เชœเชฐเซ‚เชฐ เช›เซ‡. เชฎเชจเซ‡ เชคเชฐเชค เชœ เช†เชฐเช•เซเชทเชฃ เช•เชฐเชตเชพ เชฆเซ‹ เช•เซ‡ เช…เชฎเซ‡ เช•เซเชฒเชธเซเชŸเชฐ API เชธเชฐเซเชตเชฐเชจเซ‡ เชœเชพเชคเซ‡ เชตเชฟเชจเช‚เชคเซ€เช“ เชฒเช–เซ€เชถเซเช‚ เชจเชนเซ€เช‚. เช† เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡, เช…เชฎเซ‡ เชคเซˆเชฏเชพเชฐ เชชเชพเชฏเชฅเซ‹เชจ เชฒเชพเช‡เชฌเซเชฐเซ‡เชฐเซ€เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชถเซเช‚ 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']}

เชธเชฐเชธ: เช…เชฎเซ‡ เช“เชชเชฐเซ‡เชŸเชฐ เชฎเชพเชŸเซ‡ เชเช• เชจเชฟเชฏเชฎ เชฎเซ‡เชณเชตเชตเชพเชฎเชพเช‚ เชตเซเชฏเชตเชธเซเชฅเชพเชชเชฟเชค เช›เซ€เช. เช…เชจเซ‡ เชธเซŒเชฅเซ€ เช…เช—เชคเซเชฏเชจเซเช‚, เช…เชฎเซ‡ เชคเซ‡ เช•เชฐเซเชฏเซเช‚ เชœเซ‡ เช•เซเชฌเชฐเชจเซ‡เชŸเซ€เชธ เชฎเชพเชฐเซเช— เช•เชนเซ‡เชตเชพเชฏ เช›เซ‡.

เชชเชฐเซเชฏเชพเชตเชฐเชฃ เชšเชฒเซ‹ เช…เชฅเชตเชพ เชงเซเชตเชœ? เช…เชฎเซ‡ เชฌเชงเซเช‚ เชฒเชˆเช เช›เซ€เช!

เชšเชพเชฒเซ‹ เชฎเซเช–เซเชฏ เช“เชชเชฐเซ‡เชŸเชฐ เชฐเซ‚เชชเชฐเซ‡เช–เชพเช‚เช•เชจ เชชเชฐ เช†เช—เชณ เชตเชงเซ€เช. เชเชชเซเชฒเชฟเช•เซ‡เชถเชจเชจเซ‡ เช—เซ‹เช เชตเชตเชพ เชฎเชพเชŸเซ‡ เชฌเซ‡ เชฎเซ‚เชณเชญเซ‚เชค เช…เชญเชฟเช—เชฎเซ‹ เช›เซ‡:

  1. เช†เชฆเซ‡เชถ เชตเชพเช•เซเชฏ เชตเชฟเช•เชฒเซเชชเซ‹เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ‹;
  2. เชชเชฐเซเชฏเชพเชตเชฐเชฃ เชšเชฒเซ‹เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ‹.

เช†เชฆเซ‡เชถ เชตเชพเช•เซเชฏ เชตเชฟเช•เชฒเซเชชเซ‹ เชคเชฎเชจเซ‡ เชกเซ‡เชŸเชพ เชชเซเชฐเช•เชพเชฐ เชธเชชเซ‹เชฐเซเชŸ เช…เชจเซ‡ เชฎเชพเชจเซเชฏเชคเชพ เชธเชพเชฅเซ‡ เชธเซ‡เชŸเชฟเช‚เช—เซเชธเชจเซ‡ เชตเชงเซ เชฒเชตเชšเซ€เช• เชฐเซ€เชคเซ‡ เชตเชพเช‚เชšเชตเชพเชจเซ€ เชฎเช‚เชœเซ‚เชฐเซ€ เช†เชชเซ‡ เช›เซ‡. เชชเชพเชฏเชฅเซ‹เชจเชจเซ€ เชธเซเชŸเชพเชจเซเชกเชฐเซเชก เชฒเชพเช‡เชฌเซเชฐเซ‡เชฐเซ€เชฎเชพเช‚ เชฎเซ‹เชกเซเชฏเซเชฒ เช›เซ‡ 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()

เชฌเซ€เชœเซ€ เชฌเชพเชœเซ, เช•เซเชฌเชฐเชจเซ‡เชŸเซเชธเชฎเชพเช‚ เชชเชฐเซเชฏเชพเชตเชฐเชฃ เชšเชฒเซ‹เชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชจเซ‡, เชคเชฎเซ‡ เช•เชจเซเชŸเซ‡เชจเชฐเชจเซ€ เช…เช‚เชฆเชฐ เชชเซ‹เชก เชตเชฟเชถเซ‡เชจเซ€ เชธเซ‡เชตเชพเชจเซ€ เชฎเชพเชนเชฟเชคเซ€ เชธเชฐเชณเชคเชพเชฅเซ€ เชŸเซเชฐเชพเชจเซเชธเชซเชฐ เช•เชฐเซ€ เชถเช•เซ‹ เช›เซ‹. เช‰เชฆเชพเชนเชฐเชฃ เชคเชฐเซ€เช•เซ‡, เช…เชฎเซ‡ เชจเซ€เชšเซ‡เชจเชพ เชฌเชพเช‚เชงเช•เชพเชฎ เชธเชพเชฅเซ‡ เชชเซ‹เชก เชšเชพเชฒเซ€ เชฐเชนเซ€ เช›เซ‡ เชคเซ‡ เชจเซ‡เชฎเชธเซเชชเซ‡เชธ เชตเชฟเชถเซ‡ เชฎเชพเชนเชฟเชคเซ€ เชฎเซ‡เชณเชตเซ€ เชถเช•เซ€เช เช›เซ€เช:

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

เช“เชชเชฐเซ‡เชŸเชฐ เชคเชฐเซเช•

ConfigMap เช…เชจเซ‡ Secret เชธเชพเชฅเซ‡ เช•เชพเชฎ เช•เชฐเชตเชพเชจเซ€ เชชเชฆเซเชงเชคเชฟเช“ เช•เซ‡เชตเซ€ เชฐเซ€เชคเซ‡ เช…เชฒเช— เช•เชฐเชตเซ€ เชคเซ‡ เชธเชฎเชœเชตเชพ เชฎเชพเชŸเซ‡, เช…เชฎเซ‡ เช–เชพเชธ เชจเช•เชถเชพเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชถเซเช‚. เชชเช›เซ€ เช†เชชเชฃเซ‡ เชธเชฎเชœเซ€ เชถเช•เซ€เช เช›เซ€เช เช•เซ‡ เช†เชชเชฃเซ‡ เช‘เชฌเซเชœเซ‡เช•เซเชŸเชจเซ‡ เชŸเซเชฐเซ…เช• เช•เชฐเชตเชพ เช…เชจเซ‡ เชฌเชจเชพเชตเชตเชพ เชฎเชพเชŸเซ‡ เช•เชˆ เชชเชฆเซเชงเชคเชฟเช“เชจเซ€ เชœเชฐเซ‚เชฐ เช›เซ‡:

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)

เชฎเซเช–เซเชฏ เชคเชฐเซเช• เชคเซˆเชฏเชพเชฐ เช›เซ‡! เชนเชตเซ‡ เช†เชชเชฃเซ‡ เช† เชฌเชงเชพเชจเซ‡ เชเช• เชชเชพเชฏเชฅเซ‹เชจ เชชเซ‡เช•เซ‡เชœเชฎเชพเช‚ เชชเซ‡เช• เช•เชฐเชตเชพเชจเซ€ เชœเชฐเซ‚เชฐ เช›เซ‡. เช…เชฎเซ‡ เชซเชพเช‡เชฒ เชคเซˆเชฏเชพเชฐ เช•เชฐเซ€เช เช›เซ€เช setup.py, เชคเซเชฏเชพเช‚ เชชเซเชฐเซ‹เชœเซ‡เช•เซเชŸ เชตเชฟเชถเซ‡ เชฎเซ‡เชŸเชพ เชฎเชพเชนเชฟเชคเซ€ เชฒเช–เซ‹:

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: Python เชฎเชพเชŸเซ‡ kubernetes เช•เซเชฒเชพเชฏเช‚เชŸเชจเซเช‚ เชชเซ‹เชคเชพเชจเซเช‚ เชตเชฐเซเชเชจ เช›เซ‡. เช•เซเชฒเชพเชฏเช‚เชŸ เชตเชฐเซเชเชจ เช…เชจเซ‡ เช•เซเชฌเชฐเชจเซ‡เชŸเซเชธ เชตเชฐเซเชเชจ เชตเชšเซเชšเซ‡ เชธเซเชธเช‚เช—เชคเชคเชพ เชตเชฟเชถเซ‡ เชตเชงเซ เชฎเชพเชนเชฟเชคเซ€ เช†เชฎเชพเช‚ เชฎเชณเซ€ เชถเช•เซ‡ เช›เซ‡ เชธเซเชธเช‚เช—เชคเชคเชพ เชฎเซ‡เชŸเซเชฐเชฟเชธเชฟเชธ.

เชนเชตเซ‡ เช…เชฎเชพเชฐเซ‹ เชชเซเชฐเซ‹เชœเซ‡เช•เซเชŸ เช†เชจเชพ เชœเซ‡เชตเซ‹ เชฆเซ‡เช–เชพเชฏ เช›เซ‡:

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

เชกเซ‹เช•เชฐ เช…เชจเซ‡ เชนเซ‡เชฒเซเชฎ

เชกเซ‹เช•เชฐเชซเชพเชˆเชฒ เช…เชคเชฟ เชธเชฐเชณ เชนเชถเซ‡: เชฌเซ‡เช เชชเชพเชฏเชฅเซ‹เชจ-เช†เชฒเซเชชเชพเชˆเชจ เชˆเชฎเซ‡เชœ เชฒเซ‹ เช…เชจเซ‡ เช…เชฎเชพเชฐเซเช‚ เชชเซ‡เช•เซ‡เชœ เชˆเชจเซเชธเซเชŸเซ‹เชฒ เช•เชฐเซ‹. เชšเชพเชฒเซ‹ เชคเซ‡เชจเชพ เช“เชชเซเชŸเชฟเชฎเชพเช‡เชเซ‡เชถเชจเชจเซ‡ เชตเชงเซ เชธเชพเชฐเชพ เชธเชฎเชฏ เชธเซเชงเซ€ เชฎเซเชฒเชคเชตเซ€ เชฐเชพเช–เซ€เช:

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

เชชเชฐเชฟเชฃเชพเชฎ

เช† เชฐเซ€เชคเซ‡, เชกเชฐ, เชจเชฟเช‚เชฆเชพ เช…เชฅเชตเชพ เช—เซ‹ เชถเซ€เช–เซเชฏเชพ เชตเชฟเชจเชพ, เช…เชฎเซ‡ เชชเชพเชฏเชฅเซ‹เชจเชฎเชพเช‚ เช•เซเชฌเชฐเชจเซ‡เชŸเซเชธ เชฎเชพเชŸเซ‡ เช…เชฎเชพเชฐเซเช‚ เชชเซ‹เชคเชพเชจเซเช‚ เช“เชชเชฐเซ‡เชŸเชฐ เชฌเชจเชพเชตเชตเชพเชฎเชพเช‚ เชธเช•เซเชทเชฎ เชนเชคเชพ. เช…เชฒเชฌเชคเซเชค, เชคเซ‡เชฎเชพเช‚ เชนเชœเซ เชชเชฃ เชตเซƒเชฆเซเชงเชฟ เชฎเชพเชŸเซ‡ เชœเช—เซเชฏเชพ เช›เซ‡: เชญเชตเชฟเชทเซเชฏเชฎเชพเช‚ เชคเซ‡ เชฌเชนเซเชตเชฟเชง เชจเชฟเชฏเชฎเซ‹ เชชเชฐ เชชเซเชฐเช•เซเชฐเชฟเชฏเชพ เช•เชฐเซ€ เชถเช•เชถเซ‡, เชฌเชนเซเชตเชฟเชง เชฅเซเชฐเซ‡เชกเซ‹เชฎเชพเช‚ เช•เชพเชฎ เช•เชฐเซ€ เชถเช•เชถเซ‡, เชธเซเชตเชคเช‚เชคเซเชฐ เชฐเซ€เชคเซ‡ เชคเซ‡เชจเชพ CRDsเชฎเชพเช‚ เชซเซ‡เชฐเชซเชพเชฐเซ‹เชจเซเช‚ เชจเชฟเชฐเซ€เช•เซเชทเชฃ เช•เชฐเซ€ เชถเช•เชถเซ‡...

เชคเชฎเชจเซ‡ เช•เซ‹เชกเชจเซ‡ เชจเชœเซ€เช•เชฅเซ€ เชœเซ‹เชตเชพ เชฎเชพเชŸเซ‡, เช…เชฎเซ‡ เชคเซ‡เชจเซ‡ เชฎเซ‚เช•เซเชฏเซ‹ เช›เซ‡ เชœเชพเชนเซ‡เชฐ เชญเช‚เชกเชพเชฐ. เชœเซ‹ เชคเชฎเซ‡ เชชเชพเชฏเชฅเซ‹เชจเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเซ€เชจเซ‡ เช…เชฎเชฒเชฎเชพเช‚ เชฎเซ‚เช•เชพเชฏเซ‡เชฒเชพ เชตเชงเซ เช—เช‚เชญเซ€เชฐ เช“เชชเชฐเซ‡เชŸเชฐเซ‹เชจเชพ เช‰เชฆเชพเชนเชฐเชฃเซ‹ เช‡เชšเซเช›เชคเชพ เชนเซ‹, เชคเซ‹ เชคเชฎเซ‡ เชฎเซ‹เช‚เช—เซ‹เชกเชฌเซ€ (ะฟะตั€ะฒั‹ะน ะธ เชฌเซ€เชœเชพ).

PS เช…เชจเซ‡ เชœเซ‹ เชคเชฎเซ‡ เช•เซเชฌเชฐเชจเซ‡เชŸเซ€เชธ เช‡เชตเซ‡เชจเซเชŸเซเชธ เชธเชพเชฅเซ‡ เชตเซเชฏเชตเชนเชพเชฐ เช•เชฐเชตเชพเชฎเชพเช‚ เช–เซ‚เชฌ เช†เชณเชธเซ เช›เซ‹ เช…เชฅเชตเชพ เชคเชฎเซ‡ เชฌเซ…เชถเชจเซ‹ เช‰เชชเชฏเซ‹เช— เช•เชฐเชตเชพ เชฎเชพเชŸเซ‡ เชตเชงเซ เชŸเซ‡เชตเชพเชฏเซ‡เชฒเชพ เช›เซ‹, เชคเซ‹ เช…เชฎเชพเชฐเชพ เชธเชพเชฅเซ€เชฆเชพเชฐเซ‹เช เชซเซ‹เชฐเซเชฎเชฎเชพเช‚ เชคเซˆเชฏเชพเชฐ เช‰เช•เซ‡เชฒ เชคเซˆเชฏเชพเชฐ เช•เชฐเซเชฏเซ‹ เช›เซ‡. เชถเซ‡เชฒ-เช“เชชเชฐเซ‡เชŸเชฐ (เช…เชฎเซ‡ เชœเชพเชนเซ‡เชฐเชพเชค เช•เชฐเซ€ เชคเซ‡ เชเชชเซเชฐเชฟเชฒเชฎเชพเช‚).

เชชเซ€.เชชเซ€.เชเชธ.

เช…เชฎเชพเชฐเชพ เชฌเซเชฒเซ‹เช— เชชเชฐ เชชเชฃ เชตเชพเช‚เชšเซ‹:

เชธเซ‹เชฐเซเชธ: www.habr.com

เชเช• เชŸเชฟเชชเซเชชเชฃเซ€ เช‰เชฎเซ‡เชฐเซ‹