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

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

Π’ ΠΌΠΎΠΌΠ΅Π½Ρ‚Π° Go ΠΈΠΌΠ° ΠΌΠΎΠ½ΠΎΠΏΠΎΠ» Π²ΡŠΡ€Ρ…Ρƒ Π΅Π·ΠΈΡ†ΠΈΡ‚Π΅ Π·Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ€Π°Π½Π΅, ΠΊΠΎΠΈΡ‚ΠΎ Ρ…ΠΎΡ€Π°Ρ‚Π° ΠΈΠ·Π±ΠΈΡ€Π°Ρ‚ Π΄Π° ΠΏΠΈΡˆΠ°Ρ‚ ΠΎΡ‚Ρ‡Π΅Ρ‚ΠΈ Π·Π° Kubernetes. Π—Π° Ρ‚ΠΎΠ²Π° ΠΈΠΌΠ° ΠΎΠ±Π΅ΠΊΡ‚ΠΈΠ²Π½ΠΈ ΠΏΡ€ΠΈΡ‡ΠΈΠ½ΠΈ ΠΊΠ°Ρ‚ΠΎ:

  1. Има ΠΌΠΎΡ‰Π½Π° Ρ€Π°ΠΌΠΊΠ° Π·Π° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π²Π°Π½Π΅ Π½Π° ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΈ Π² Go - ΠžΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ SDK.
  2. ΠŸΡ€ΠΎΠΌΠ΅Π½ΡΡ‰ΠΈ ΠΈΠ³Ρ€Π°Ρ‚Π° прилоТСния ΠΊΠ°Ρ‚ΠΎ Docker ΠΈ Kubernetes са написани Π½Π° Go. НаписванСто Π½Π° вашия ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ Π² Go ΠΎΠ·Π½Π°Ρ‡Π°Π²Π° Π΄Π° Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚Π΅ Π½Π° ΡΡŠΡ‰ΠΈΡ Π΅Π·ΠΈΠΊ с СкосистСмата.
  3. Висока производитСлност Π½Π° Go прилоТСнията ΠΈ прости инструмСнти Π·Π° Ρ€Π°Π±ΠΎΡ‚Π° с паралСлност ΠΎΡ‚ кутията.

NB: ΠœΠ΅ΠΆΠ΄Ρƒ Π΄Ρ€ΡƒΠ³ΠΎΡ‚ΠΎ, ΠΊΠ°ΠΊ Π΄Π° Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ своС собствСно изявлСниС Π² Go, we Π²Π΅Ρ‡Π΅ описано Π² Π΅Π΄ΠΈΠ½ ΠΎΡ‚ Π½Π°ΡˆΠΈΡ‚Π΅ ΠΏΡ€Π΅Π²ΠΎΠ΄ΠΈ Π½Π° Ρ‡ΡƒΠΆΠ΄ΠΈ Π°Π²Ρ‚ΠΎΡ€ΠΈ.

Но ΠΊΠ°ΠΊΠ²ΠΎ Ρ‰Π΅ станС, Π°ΠΊΠΎ стС Π²ΡŠΠ·ΠΏΡ€Π΅ΠΏΡΡ‚ΡΡ‚Π²Π°Π½ΠΈ Π΄Π° Π½Π°ΡƒΡ‡ΠΈΡ‚Π΅ Go ΠΏΠΎΡ€Π°Π΄ΠΈ липса Π½Π° Π²Ρ€Π΅ΠΌΠ΅ ΠΈΠ»ΠΈ, просто ΠΊΠ°Π·Π°Π½ΠΎ, мотивация? Бтатията прСдоставя ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π·Π° Ρ‚ΠΎΠ²Π° ΠΊΠ°ΠΊ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ Π΄ΠΎΠ±Ρ€ΠΎ изявлСниС, ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΉΠΊΠΈ Π΅Π΄ΠΈΠ½ ΠΎΡ‚ Π½Π°ΠΉ-популярнитС Π΅Π·ΠΈΡ†ΠΈ, ΠΊΠΎΠΈΡ‚ΠΎ ΠΏΠΎΡ‡Ρ‚ΠΈ всСки DevOps ΠΈΠ½ΠΆΠ΅Π½Π΅Ρ€ Π·Π½Π°Π΅ - ΠŸΠΈΡ‚ΠΎΠ½.

Π—Π°ΠΏΠΎΠ·Π½Π°ΠΉΡ‚Π΅ сС с: Copier - ΠΊΠΎΠΏΠΈΡ€Π΅Π½ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€!

ΠšΠ°Ρ‚ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€, помислСтС Π·Π° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π²Π°Π½Π΅Ρ‚ΠΎ Π½Π° проста инструкция, ΠΏΡ€Π΅Π΄Π½Π°Π·Π½Π°Ρ‡Π΅Π½Π° Π΄Π° ΠΊΠΎΠΏΠΈΡ€Π° ConfigMap ΠΈΠ»ΠΈ ΠΊΠΎΠ³Π°Ρ‚ΠΎ сС появи Π½ΠΎΠ²ΠΎ пространство ΠΎΡ‚ ΠΈΠΌΠ΅Π½Π°, ΠΈΠ»ΠΈ ΠΊΠΎΠ³Π°Ρ‚ΠΎ сС ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈ Π΅Π΄ΠΈΠ½ ΠΎΡ‚ Π΄Π²Π°Ρ‚Π° ΠΎΠ±Π΅ΠΊΡ‚Π°: ConfigMap ΠΈ Secret. ΠžΡ‚ практичСска Π³Π»Π΅Π΄Π½Π° Ρ‚ΠΎΡ‡ΠΊΠ° ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΡŠΡ‚ ΠΌΠΎΠΆΠ΅ Π΄Π° бъдС ΠΏΠΎΠ»Π΅Π·Π΅Π½ Π·Π° Π³Ρ€ΡƒΠΏΠΎΠ²ΠΎ Π°ΠΊΡ‚ΡƒΠ°Π»ΠΈΠ·ΠΈΡ€Π°Π½Π΅ Π½Π° ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ Π½Π° прилоТСния (Ρ‡Ρ€Π΅Π· Π°ΠΊΡ‚ΡƒΠ°Π»ΠΈΠ·ΠΈΡ€Π°Π½Π΅ Π½Π° ConfigMap) ΠΈΠ»ΠΈ Π·Π° Π°ΠΊΡ‚ΡƒΠ°Π»ΠΈΠ·ΠΈΡ€Π°Π½Π΅ Π½Π° сСкрСтни Π΄Π°Π½Π½ΠΈ - Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΊΠ»ΡŽΡ‡ΠΎΠ²Π΅ Π·Π° Ρ€Π°Π±ΠΎΡ‚Π° с Docker Registry (ΠΏΡ€ΠΈ добавянС Π½Π° Secret към пространството ΠΎΡ‚ ΠΈΠΌΠ΅Π½Π°).

По Ρ‚ΠΎΠ·ΠΈ Π½Π°Ρ‡ΠΈΠ½, ΠΊΠ°ΠΊΠ²ΠΎ трябва Π΄Π° ΠΈΠΌΠ° Π΅Π΄ΠΈΠ½ Π΄ΠΎΠ±ΡŠΡ€ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€:

  1. ВзаимодСйствиСто с ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π° сС ΠΎΡΡŠΡ‰Π΅ΡΡ‚Π²ΡΠ²Π° с ΠΏΠΎΠΌΠΎΡ‰Ρ‚Π° Π½Π° ΠŸΠ΅Ρ€ΡΠΎΠ½Π°Π»ΠΈΠ·ΠΈΡ€Π°Π½ΠΈ Π΄Π΅Ρ„ΠΈΠ½ΠΈΡ†ΠΈΠΈ Π½Π° рСсурси (Π½Π°Ρ€ΠΈΡ‡Π°Π½ΠΈ ΠΏΠΎ-Π΄ΠΎΠ»Ρƒ CRD).
  2. ΠžΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΡŠΡ‚ ΠΌΠΎΠΆΠ΅ Π΄Π° бъдС ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€ΠΈΡ€Π°Π½. Π—Π° Π΄Π° Π½Π°ΠΏΡ€Π°Π²ΠΈΠΌ Ρ‚ΠΎΠ²Π°, Ρ‰Π΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ Ρ„Π»Π°Π³ΠΎΠ²Π΅ Π½Π° командния Ρ€Π΅Π΄ ΠΈ ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° срСдата.
  3. Π˜Π·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅Ρ‚ΠΎ Π½Π° ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π° Π½Π° Docker ΠΈ Π΄ΠΈΠ°Π³Ρ€Π°ΠΌΠ°Ρ‚Π° Π½Π° Helm Π΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΈΡ€Π°Π½ΠΎ Ρ‚Π°ΠΊΠ°, Ρ‡Π΅ ΠΏΠΎΡ‚Ρ€Π΅Π±ΠΈΡ‚Π΅Π»ΠΈΡ‚Π΅ Π΄Π° ΠΌΠΎΠ³Π°Ρ‚ лСсно (Π±ΡƒΠΊΠ²Π°Π»Π½ΠΎ с Π΅Π΄Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°) Π΄Π° инсталират ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π° Π² своя ΠΊΠ»ΡŠΡΡ‚Π΅Ρ€ 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']}

Π‘Ρ‚Ρ€Π°Ρ…ΠΎΡ‚Π½ΠΎ: успяхмС Π΄Π° ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ Π·Π° ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π°. И Π½Π°ΠΉ-Π²Π°ΠΆΠ½ΠΎΡ‚ΠΎ, Π½Π°ΠΏΡ€Π°Π²ΠΈΡ…ΠΌΠ΅ Ρ‚Π°ΠΊΠ° нарСчСния Π½Π°Ρ‡ΠΈΠ½ Π½Π° 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, ΠΌΠΎΠΆΠ΅Ρ‚Π΅ лСсно Π΄Π° ΠΏΡ€Π΅Ρ…Π²ΡŠΡ€Π»ΠΈΡ‚Π΅ слуТСбна информация Π·Π° pod Π²ΡŠΡ‚Ρ€Π΅ Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°. НапримСр, ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ информация Π·Π° пространството ΠΎΡ‚ ΠΈΠΌΠ΅Π½Π°, Π² ΠΊΠΎΠ΅Ρ‚ΠΎ сС изпълнява pod със слСдната конструкция:

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)

ΠžΡΠ½ΠΎΠ²Π½Π°Ρ‚Π° Π»ΠΎΠ³ΠΈΠΊΠ° Π΅ Π³ΠΎΡ‚ΠΎΠ²Π°! Π‘Π΅Π³Π° трябва Π΄Π° ΠΎΠΏΠ°ΠΊΠΎΠ²Π°ΠΌΠ΅ всичко Ρ‚ΠΎΠ²Π° Π² Π΅Π΄ΠΈΠ½ Python ΠΏΠ°ΠΊΠ΅Ρ‚. ΠŸΠΎΠ΄Π³ΠΎΡ‚Π²ΡΠΌΠ΅ Ρ„Π°ΠΉΠ»Π° 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 ΠΈΠΌΠ° собствСна вСрсия. ΠŸΠΎΠ²Π΅Ρ‡Π΅ информация относно ΡΡŠΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚Ρ‚Π° ΠΌΠ΅ΠΆΠ΄Ρƒ клиСнтскитС вСрсии ΠΈ вСрсиитС Π½Π° Kubernetes ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π½Π°ΠΌΠ΅Ρ€ΠΈΡ‚Π΅ Π² ΠΌΠ°Ρ‚Ρ€ΠΈΡ†ΠΈ Π·Π° ΡΡŠΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚.

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

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

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

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. Π Π°Π·Π±ΠΈΡ€Π° сС, Ρ‚ΠΎΠΉ всС ΠΎΡ‰Π΅ ΠΈΠΌΠ° ΠΊΠ°ΠΊΠ²ΠΎ Π΄Π° растС: Π² Π±ΡŠΠ΄Π΅Ρ‰Π΅ Ρ‰Π΅ ΠΌΠΎΠΆΠ΅ Π΄Π° ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π²Π° мноТСство ΠΏΡ€Π°Π²ΠΈΠ»Π°, Π΄Π° Ρ€Π°Π±ΠΎΡ‚ΠΈ Π² мноТСство нишки, нСзависимо Π΄Π° наблюдава ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈΡ‚Π΅ Π² своитС CRD...

Π—Π° Π΄Π° Π²ΠΈ прСдоставим ΠΏΠΎ-ΠΎΡ‚Π±Π»ΠΈΠ·ΠΎ ΠΊΠΎΠ΄Π°, Π½ΠΈΠ΅ Π³ΠΎ поставихмС общСствСно Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅. Ако искатС ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΈ Π·Π° ΠΏΠΎ-сСриозни ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΈ, Ρ€Π΅Π°Π»ΠΈΠ·ΠΈΡ€Π°Π½ΠΈ с ΠΏΠΎΠΌΠΎΡ‰Ρ‚Π° Π½Π° Python, ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° насочитС Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅Ρ‚ΠΎ си към Π΄Π²Π° ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π° Π·Π° внСдряванС Π½Π° mongodb (ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ ΠΈ Π²Ρ‚ΠΎΡ€ΠΈ).

PS И Π°ΠΊΠΎ Π²ΠΈ ΠΌΡŠΡ€Π·ΠΈ Π΄Π° сС Π·Π°Π½ΠΈΠΌΠ°Π²Π°Ρ‚Π΅ със ΡΡŠΠ±ΠΈΡ‚ΠΈΡ Π½Π° Kubernetes ΠΈΠ»ΠΈ просто стС ΠΏΠΎ-свикнали Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ‚Π΅ Bash, Π½Π°ΡˆΠΈΡ‚Π΅ ΠΊΠΎΠ»Π΅Π³ΠΈ са ΠΏΠΎΠ΄Π³ΠΎΡ‚Π²ΠΈΠ»ΠΈ Π³ΠΎΡ‚ΠΎΠ²ΠΎ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ във Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π° shell-ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ (НиС ΡΡŠΠΎΠ±Ρ‰ΠΈ ΠΏΡ€Π΅Π· Π°ΠΏΡ€ΠΈΠ»).

PPS

ΠŸΡ€ΠΎΡ‡Π΅Ρ‚Π΅Ρ‚Π΅ ΡΡŠΡ‰ΠΎ Π² нашия Π±Π»ΠΎΠ³:

Π˜Π·Ρ‚ΠΎΡ‡Π½ΠΈΠΊ: www.habr.com

ДобавянС Π½Π° Π½ΠΎΠ² ΠΊΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€