Kubernetes ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ Π²ΠΎ Python Π±Π΅Π· Ρ€Π°ΠΌΠΊΠΈ ΠΈ SDK

Kubernetes ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ Π²ΠΎ Python Π±Π΅Π· Ρ€Π°ΠΌΠΊΠΈ ΠΈ SDK

Go Π²ΠΎ ΠΌΠΎΠΌΠ΅Π½Ρ‚ΠΎΠ² ΠΈΠΌΠ° ΠΌΠΎΠ½ΠΎΠΏΠΎΠ» Π½Π° програмскитС Ρ˜Π°Π·ΠΈΡ†ΠΈ ΡˆΡ‚ΠΎ Π»ΡƒΡ“Π΅Ρ‚ΠΎ ΠΈΠ·Π±ΠΈΡ€Π°Π°Ρ‚ Π΄Π° ΠΏΠΈΡˆΡƒΠ²Π°Π°Ρ‚ изјави Π·Π° Kubernetes. ΠŸΠΎΡΡ‚ΠΎΡ˜Π°Ρ‚ ΠΎΠ±Ρ˜Π΅ΠΊΡ‚ΠΈΠ²Π½ΠΈ ΠΏΡ€ΠΈΡ‡ΠΈΠ½ΠΈ Π·Π° ΠΎΠ²Π°, ΠΊΠ°ΠΊΠΎ ΡˆΡ‚ΠΎ сС:

  1. ΠŸΠΎΡΡ‚ΠΎΠΈ моќна Ρ€Π°ΠΌΠΊΠ° Π·Π° Ρ€Π°Π·Π²ΠΎΡ˜ Π½Π° ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΈ Π²ΠΎ Go - ΠžΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ SDK.
  2. АпликациитС ΡˆΡ‚ΠΎ ΠΌΠ΅Π½ΡƒΠ²Π°Π°Ρ‚ ΠΈΠ³Ρ€ΠΈ ΠΊΠ°ΠΊΠΎ Docker ΠΈ Kubernetes сС напишани Π²ΠΎ Go. Π”Π° Π³ΠΎ Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ Π²Π°ΡˆΠΈΠΎΡ‚ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ Π²ΠΎ Go Π·Π½Π°Ρ‡ΠΈ Π΄Π° Π·Π±ΠΎΡ€ΡƒΠ²Π°Ρ‚Π΅ ист јазик со СкосистСмот.
  3. Високи пСрформанси Π½Π° Go Π°ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΠΈΡ‚Π΅ ΠΈ Сдноставни Π°Π»Π°Ρ‚ΠΊΠΈ Π·Π° Ρ€Π°Π±ΠΎΡ‚Π° со истоврСмСност Π½Π°Π΄Π²ΠΎΡ€ ΠΎΠ΄ ΠΊΡƒΡ‚ΠΈΡ˜Π°Ρ‚Π°.

NB: ΠŸΠ°Ρ‚Π΅ΠΌ, ΠΊΠ°ΠΊΠΎ Π΄Π° Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ сопствСна изјава Π²ΠΎ Go, Π½ΠΈΠ΅ вСќС опишано Π²ΠΎ Π΅Π΄Π΅Π½ ΠΎΠ΄ Π½Π°ΡˆΠΈΡ‚Π΅ ΠΏΡ€Π΅Π²ΠΎΠ΄ΠΈ ΠΎΠ΄ странски Π°Π²Ρ‚ΠΎΡ€ΠΈ.

Но, ΡˆΡ‚ΠΎ Π°ΠΊΠΎ стС спрСчСни Π΄Π° Π½Π°ΡƒΡ‡ΠΈΡ‚Π΅ Go ΠΏΠΎΡ€Π°Π΄ΠΈ нСдостаток Π½Π° Π²Ρ€Π΅ΠΌΠ΅ ΠΈΠ»ΠΈ, Сдноставно ΠΊΠ°ΠΆΠ°Π½ΠΎ, ΠΌΠΎΡ‚ΠΈΠ²Π°Ρ†ΠΈΡ˜Π°? Π‘Ρ‚Π°Ρ‚ΠΈΡ˜Π°Ρ‚Π° Π΄Π°Π²Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π·Π° Ρ‚ΠΎΠ° ΠΊΠ°ΠΊΠΎ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ Π΄ΠΎΠ±Ρ€Π° изјава ΠΊΠΎΡ€ΠΈΡΡ‚Π΅Ρ˜ΡœΠΈ Π΅Π΄Π΅Π½ ΠΎΠ΄ Π½Π°Ρ˜ΠΏΠΎΠΏΡƒΠ»Π°Ρ€Π½ΠΈΡ‚Π΅ Ρ˜Π°Π·ΠΈΡ†ΠΈ ΡˆΡ‚ΠΎ Π³ΠΎ Π·Π½Π°Π΅ скоро сСкој ΠΈΠ½ΠΆΠ΅Π½Π΅Ρ€ Π½Π° DevOps - ΠŸΠ°Ρ˜Ρ‚ΠΎΠ½.

Π—Π°ΠΏΠΎΠ·Π½Π°Ρ˜Ρ‚Π΅: ΠšΠΎΠΏΠΈΡ€ - ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ Π·Π° ΠΊΠΎΠΏΠΈΡ€Π°ΡšΠ΅!

Како ΠΏΡ€ΠΈΠΌΠ΅Ρ€, размислСтС Π·Π° Ρ€Π°Π·Π²ΠΎΡ˜ Π½Π° Сдноставна изјава Π΄ΠΈΠ·Π°Ρ˜Π½ΠΈΡ€Π°Π½Π° Π΄Π° ΠΊΠΎΠΏΠΈΡ€Π° ConfigMap ΠΈΠ»ΠΈ ΠΊΠΎΠ³Π° ќС сС појави Π½ΠΎΠ² имСнски простор ΠΈΠ»ΠΈ ΠΊΠΎΠ³Π° ќС сС ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ Π΅Π΄Π΅Π½ ΠΎΠ΄ Π΄Π²Π°Ρ‚Π° Π΅Π½Ρ‚ΠΈΡ‚Π΅Ρ‚Π°: ConfigMap ΠΈ Secret. Од ΠΏΡ€Π°ΠΊΡ‚ΠΈΡ‡Π½Π° Π³Π»Π΅Π΄Π½Π° Ρ‚ΠΎΡ‡ΠΊΠ°, ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΡ‚ ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΠΈΠ΄Π΅ корисСн Π·Π° масовно Π°ΠΆΡƒΡ€ΠΈΡ€Π°ΡšΠ΅ Π½Π° ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈΡ‚Π΅ Π½Π° Π°ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΠΈΡ‚Π΅ (со Π°ΠΆΡƒΡ€ΠΈΡ€Π°ΡšΠ΅ Π½Π° ConfigMap) ΠΈΠ»ΠΈ Π·Π° Π°ΠΆΡƒΡ€ΠΈΡ€Π°ΡšΠ΅ Π½Π° Ρ‚Π°Ρ˜Π½ΠΈΡ‚Π΅ ΠΏΠΎΠ΄Π°Ρ‚ΠΎΡ†ΠΈ - Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΊΠ»ΡƒΡ‡Π΅Π²ΠΈ Π·Π° Ρ€Π°Π±ΠΎΡ‚Π° со Docker Registry (ΠΏΡ€ΠΈ додавањС Secret Π²ΠΎ имСнскиот простор).

Π—Π½Π°Ρ‡ΠΈ, ΡˆΡ‚ΠΎ Ρ‚Ρ€Π΅Π±Π° Π΄Π° ΠΈΠΌΠ° Π΄ΠΎΠ±Π°Ρ€ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€:

  1. Π˜Π½Ρ‚Π΅Ρ€Π°ΠΊΡ†ΠΈΡ˜Π°Ρ‚Π° со ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΡ‚ сС Π²Ρ€ΡˆΠΈ со ΠΊΠΎΡ€ΠΈΡΡ‚Π΅ΡšΠ΅ ΠŸΡ€ΠΈΠ»Π°Π³ΠΎΠ΄Π΅Π½ΠΈ Π΄Π΅Ρ„ΠΈΠ½ΠΈΡ†ΠΈΠΈ Π·Π° рСсурси (Π²ΠΎ Π½Π°Ρ‚Π°ΠΌΠΎΡˆΠ½ΠΈΠΎΡ‚ тСкст CRD).
  2. ΠžΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΡ‚ ΠΌΠΎΠΆΠ΅ Π΄Π° сС ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡ€Π°. Π—Π° Π΄Π° Π³ΠΎ Π½Π°ΠΏΡ€Π°Π²ΠΈΡ‚Π΅ ΠΎΠ²Π°, ќС користимС Π·Π½Π°ΠΌΠ΅Π½Ρ†Π° Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π½Π°Ρ‚Π° линија ΠΈ ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° ΠΎΠΊΠΎΠ»ΠΈΠ½Π°Ρ‚Π°.
  3. Π˜Π·Π³Ρ€Π°Π΄Π±Π°Ρ‚Π° Π½Π° Π³Ρ€Π°Ρ„ΠΈΠΊΠΎΠ½ΠΎΡ‚ Π·Π° ΠΊΠΎΠ½Ρ‚Π΅Ρ˜Π½Π΅Ρ€ ΠΈ Π₯Π΅Π»ΠΌ Π”ΠΎΠΊΠ΅Ρ€ Π΅ Π΄ΠΈΠ·Π°Ρ˜Π½ΠΈΡ€Π°Π½Π° Ρ‚Π°ΠΊΠ° ΡˆΡ‚ΠΎ корисницитС ΠΌΠΎΠΆΠ°Ρ‚ лСсно (Π±ΡƒΠΊΠ²Π°Π»Π½ΠΎ со Π΅Π΄Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°) Π΄Π° Π³ΠΎ инсталираат ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΡ‚ Π²ΠΎ Π½ΠΈΠ²Π½ΠΈΠΎΡ‚ кластСр Kubernetes.

CRD

Π—Π° Π΄Π° Π·Π½Π°Π΅ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΡ‚ ΠΊΠΎΠΈ рСсурси Π΄Π° Π±Π°Ρ€Π° ΠΈ ΠΊΠ°Π΄Π΅ Π΄Π° Π±Π°Ρ€Π°, Ρ‚Ρ€Π΅Π±Π° Π΄Π° ΠΌΡƒ поставимС ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ. Π‘Π΅ΠΊΠΎΠ΅ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ ќС Π±ΠΈΠ΄Π΅ прСтставСно ΠΊΠ°ΠΊΠΎ СдинствСн ΠΎΠ±Ρ˜Π΅ΠΊΡ‚ CRD. Какви полиња Ρ‚Ρ€Π΅Π±Π° Π΄Π° ΠΈΠΌΠ° овој CRD?

  1. Π’ΠΈΠΏ Π½Π° рСсурси, ΡˆΡ‚ΠΎ ќС Π³ΠΎ Π±Π°Ρ€Π°ΠΌΠ΅ (ConfigMap ΠΈΠ»ΠΈ Secret).
  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 ситС ConfigMap со Π΅Ρ‚ΠΈΠΊΠ΅Ρ‚ΠΈ ΠΊΠ°ΠΊΠΎ copyrator: "true":

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

ΠŸΠΎΠ΄Π³ΠΎΡ‚Π²Π΅Π½ΠΈ! Π‘Π΅Π³Π° Ρ‚Ρ€Π΅Π±Π° Π½Π΅ΠΊΠ°ΠΊΠΎ Π΄Π° Π΄ΠΎΠ±ΠΈΠ΅ΠΌΠ΅ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ Π·Π° Π½Π°ΡˆΠ΅Ρ‚ΠΎ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ. Π”ΠΎΠ·Π²ΠΎΠ»Π΅Ρ‚Π΅ ΠΌΠΈ вСднаш Π΄Π° Π½Π°ΠΏΡ€Π°Π²Π°ΠΌ Ρ€Π΅Π·Π΅Ρ€Π²Π°Ρ†ΠΈΡ˜Π° Π΄Π΅ΠΊΠ° Π½Π΅ΠΌΠ° самитС Π΄Π° ΠΏΠΈΡˆΡƒΠ²Π°ΠΌΠ΅ Π±Π°Ρ€Π°ΡšΠ° Π΄ΠΎ кластСрот API-сСрвСр. Π—Π° Π΄Π° Π³ΠΎ Π½Π°ΠΏΡ€Π°Π²ΠΈΡ‚Π΅ ΠΎΠ²Π°, ќС користимС Π³ΠΎΡ‚ΠΎΠ²Π° Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° 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']}

ΠžΠ΄Π»ΠΈΡ‡Π½ΠΎ: успСавмС Π΄Π° Π΄ΠΎΠ±ΠΈΠ΅ΠΌΠ΅ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ Π·Π° ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΡ‚. И ΡˆΡ‚ΠΎ Π΅ најваТно, Π³ΠΎ Π½Π°ΠΏΡ€Π°Π²ΠΈΠ²ΠΌΠ΅ ΠΎΠ½Π° ΡˆΡ‚ΠΎ сС Π½Π°Ρ€Π΅ΠΊΡƒΠ²Π° ΠšΡƒΠ±Π΅Ρ€Π½Π΅Ρ‚ΡΠΊΠΈ Π½Π°Ρ‡ΠΈΠ½.

ΠŸΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° ΠΆΠΈΠ²ΠΎΡ‚Π½Π°Ρ‚Π° срСдина ΠΈΠ»ΠΈ Π·Π½Π°ΠΌΠ΅Π½Ρ†Π°? НиС Π·Π΅ΠΌΠ°ΠΌΠ΅ сè!

АјдС Π΄Π° ΠΏΡ€Π΅ΠΌΠΈΠ½Π΅ΠΌΠ΅ Π½Π° ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ˜Π°Ρ‚Π° Π½Π° Π³Π»Π°Π²Π½ΠΈΠΎΡ‚ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€. ΠŸΠΎΡΡ‚ΠΎΡ˜Π°Ρ‚ Π΄Π²Π° основни пристапи Π·Π° ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡ€Π°ΡšΠ΅ Π½Π° Π°ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΠΈ:

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

Од Π΄Ρ€ΡƒΠ³Π° страна, ΠΊΠΎΡ€ΠΈΡΡ‚Π΅Ρ˜ΡœΠΈ ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° ΠΆΠΈΠ²ΠΎΡ‚Π½Π°Ρ‚Π° срСдина Π²ΠΎ Kubernetes, ΠΌΠΎΠΆΠ΅Ρ‚Π΅ лСсно Π΄Π° прСнСсСтС ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ Π·Π° услугата Π·Π° ΠΏΠΎΠ΄Π»ΠΎΠ³Π°Ρ‚Π° Π²Π½Π°Ρ‚Ρ€Π΅ Π²ΠΎ ΠΊΠΎΠ½Ρ‚Π΅Ρ˜Π½Π΅Ρ€ΠΎΡ‚. На ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΌΠΎΠΆΠ΅ΠΌΠ΅ Π΄Π° Π΄ΠΎΠ±ΠΈΠ΅ΠΌΠ΅ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ Π·Π° имСнскиот простор Π²ΠΎ кој Ρ€Π°Π±ΠΎΡ‚ΠΈ ΠΏΠΎΠ΄Π»ΠΎΠ³Π°Ρ‚Π° со слСднава ΠΊΠΎΠ½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡ˜Π°:

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: ΠšΠ»ΠΈΠ΅Π½Ρ‚ΠΎΡ‚ kubernetes Π·Π° Python ΠΈΠΌΠ° своја Π²Π΅Ρ€Π·ΠΈΡ˜Π°. ПовСќС ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ Π·Π° компатибилноста ΠΏΠΎΠΌΠ΅Ρ“Ρƒ Π²Π΅Ρ€Π·ΠΈΠΈΡ‚Π΅ Π½Π° ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΎΡ‚ ΠΈ Π²Π΅Ρ€Π·ΠΈΠΈΡ‚Π΅ Π½Π° ΠšΡƒΠ±Π΅Ρ€Π½Π΅Ρ‚Π΅Ρ ΠΌΠΎΠΆΠ΅ Π΄Π° Π½Π°Ρ˜Π΄Π΅Ρ‚Π΅ Π²ΠΎ ΠΌΠ°Ρ‚Ρ€ΠΈΡ†ΠΈ Π·Π° компатибилност.

Π‘Π΅Π³Π° Π½Π°ΡˆΠΈΠΎΡ‚ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ ΠΈΠ·Π³Π»Π΅Π΄Π° Π²Π°ΠΊΠ°:

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

Π”ΠΎΠΊΠ΅Ρ€ ΠΈ Π₯Π΅Π»ΠΌ

Dockerfile ќС Π±ΠΈΠ΄Π΅ Π½Π΅Π²Π΅Ρ€ΠΎΡ˜Π°Ρ‚Π½ΠΎ Сдноставна: Π·Π΅ΠΌΠ΅Ρ‚Π΅ ја основната слика ΠΎΠ΄ ΠΏΠΈΡ‚ΠΎΠ½-алпски ΠΈ ΠΈΠ½ΡΡ‚Π°Π»ΠΈΡ€Π°Ρ˜Ρ‚Π΅ Π³ΠΎ Π½Π°ΡˆΠΈΠΎΡ‚ ΠΏΠ°ΠΊΠ΅Ρ‚. Π”Π° ја ΠΎΠ΄Π»ΠΎΠΆΠΈΠΌΠ΅ Π½Π΅Ρ˜Π·ΠΈΠ½Π°Ρ‚Π° ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ˜Π° Π΄ΠΎ ΠΏΠΎΠ΄ΠΎΠ±Ρ€ΠΈ Π²Ρ€Π΅ΠΌΠΈΡšΠ°:

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. Π‘Π΅ Ρ€Π°Π·Π±ΠΈΡ€Π°, сè ΡƒΡˆΡ‚Π΅ ΠΈΠΌΠ° простор Π΄Π° растС: Π²ΠΎ ΠΈΠ΄Π½ΠΈΠ½Π° ќС ΠΌΠΎΠΆΠ΅ Π΄Π° ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΡƒΠ²Π° повСќС ΠΏΡ€Π°Π²ΠΈΠ»Π°, Π΄Π° Ρ€Π°Π±ΠΎΡ‚ΠΈ Π²ΠΎ повСќС нишки, ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡ˜Π½ΠΎ Π΄Π° Π³ΠΈ слСди ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈΡ‚Π΅ Π²ΠΎ своитС CRD...

Π—Π° Π΄Π° Π²ΠΈ Π΄Π°Π΄Π΅ΠΌΠ΅ ΠΏΠΎΠ΄Π΅Ρ‚Π°Π»Π΅Π½ ΠΏΠΎΠ³Π»Π΅Π΄ Π½Π° ΠΊΠΎΠ΄ΠΎΡ‚, Π³ΠΎ ставивмС јавно ΡΠΊΠ»Π°Π΄ΠΈΡˆΡ‚Π΅. Ако сакатС ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΈ Π½Π° посСриозни ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΈ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚ΠΈΡ€Π°Π½ΠΈ со ΠΊΠΎΡ€ΠΈΡΡ‚Π΅ΡšΠ΅ Π½Π° Python, ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π³ΠΎ свртитС Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅Ρ‚ΠΎ Π½Π° Π΄Π²Π° ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΈ Π·Π° Ρ€Π°ΡΠΏΠΎΡ€Π΅Π΄ΡƒΠ²Π°ΡšΠ΅ mongodb (ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ ΠΈ Π²Ρ‚ΠΎΡ€ΠΈΠΎΡ‚).

П.Π‘. И Π°ΠΊΠΎ стС ΠΏΡ€Π΅ΠΌΠ½ΠΎΠ³Ρƒ ΠΌΡ€Π·Π»ΠΈΠ²ΠΈ Π΄Π° сС Π·Π°Π½ΠΈΠΌΠ°Π²Π°Ρ‚Π΅ со настани Π½Π° ΠšΡƒΠ±Π΅Ρ€Π½Π΅Ρ‚ ΠΈΠ»ΠΈ Сдноставно стС повСќС Π½Π°Π²ΠΈΠΊΠ½Π°Ρ‚ΠΈ Π΄Π° користитС Bash, Π½Π°ΡˆΠΈΡ‚Π΅ ΠΊΠΎΠ»Π΅Π³ΠΈ ΠΏΠΎΠ΄Π³ΠΎΡ‚Π²ΠΈΡ˜Π° Π³ΠΎΡ‚ΠΎΠ²ΠΎ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ Π²ΠΎ Ρ„ΠΎΡ€ΠΌΠ° школка-ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ (НиС објавија Ρ‚ΠΎΠ° Π²ΠΎ Π°ΠΏΡ€ΠΈΠ»).

PPS

ΠŸΡ€ΠΎΡ‡ΠΈΡ‚Π°Ρ˜Ρ‚Π΅ ΠΈ Π½Π° Π½Π°ΡˆΠΈΠΎΡ‚ Π±Π»ΠΎΠ³:

Π˜Π·Π²ΠΎΡ€: www.habr.com

Π”ΠΎΠ΄Π°Π΄Π΅Ρ‚Π΅ ΠΊΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€