Π ΠΌΠΎΠΌΠ΅Π½ΡΠ° Go ΠΈΠΌΠ° ΠΌΠΎΠ½ΠΎΠΏΠΎΠ» Π²ΡΡΡ
Ρ Π΅Π·ΠΈΡΠΈΡΠ΅ Π·Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈΡΠ°Π½Π΅, ΠΊΠΎΠΈΡΠΎ Ρ
ΠΎΡΠ°ΡΠ° ΠΈΠ·Π±ΠΈΡΠ°Ρ Π΄Π° ΠΏΠΈΡΠ°Ρ ΠΎΡΡΠ΅ΡΠΈ Π·Π° Kubernetes. ΠΠ° ΡΠΎΠ²Π° ΠΈΠΌΠ° ΠΎΠ±Π΅ΠΊΡΠΈΠ²Π½ΠΈ ΠΏΡΠΈΡΠΈΠ½ΠΈ ΠΊΠ°ΡΠΎ:
- ΠΠΌΠ° ΠΌΠΎΡΠ½Π° ΡΠ°ΠΌΠΊΠ° Π·Π° ΡΠ°Π·ΡΠ°Π±ΠΎΡΠ²Π°Π½Π΅ Π½Π° ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠΈ Π² Go -
ΠΠΏΠ΅ΡΠ°ΡΠΎΡ SDK . - ΠΡΠΎΠΌΠ΅Π½ΡΡΠΈ ΠΈΠ³ΡΠ°ΡΠ° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ ΠΊΠ°ΡΠΎ Docker ΠΈ Kubernetes ΡΠ° Π½Π°ΠΏΠΈΡΠ°Π½ΠΈ Π½Π° Go. ΠΠ°ΠΏΠΈΡΠ²Π°Π½Π΅ΡΠΎ Π½Π° Π²Π°ΡΠΈΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡ Π² Go ΠΎΠ·Π½Π°ΡΠ°Π²Π° Π΄Π° Π³ΠΎΠ²ΠΎΡΠΈΡΠ΅ Π½Π° ΡΡΡΠΈΡ Π΅Π·ΠΈΠΊ Ρ Π΅ΠΊΠΎΡΠΈΡΡΠ΅ΠΌΠ°ΡΠ°.
- ΠΠΈΡΠΎΠΊΠ° ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»Π½ΠΎΡΡ Π½Π° Go ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡΡΠ° ΠΈ ΠΏΡΠΎΡΡΠΈ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΈ Π·Π° ΡΠ°Π±ΠΎΡΠ° Ρ ΠΏΠ°ΡΠ°Π»Π΅Π»Π½ΠΎΡΡ ΠΎΡ ΠΊΡΡΠΈΡΡΠ°.
NB: ΠΠ΅ΠΆΠ΄Ρ Π΄ΡΡΠ³ΠΎΡΠΎ, ΠΊΠ°ΠΊ Π΄Π° Π½Π°ΠΏΠΈΡΠ΅ΡΠ΅ ΡΠ²ΠΎΠ΅ ΡΠΎΠ±ΡΡΠ²Π΅Π½ΠΎ ΠΈΠ·ΡΠ²Π»Π΅Π½ΠΈΠ΅ Π² Go, we
ΠΠΎ ΠΊΠ°ΠΊΠ²ΠΎ ΡΠ΅ ΡΡΠ°Π½Π΅, Π°ΠΊΠΎ ΡΡΠ΅ Π²ΡΠ·ΠΏΡΠ΅ΠΏΡΡΡΡΠ²Π°Π½ΠΈ Π΄Π° Π½Π°ΡΡΠΈΡΠ΅ Go ΠΏΠΎΡΠ°Π΄ΠΈ Π»ΠΈΠΏΡΠ° Π½Π° Π²ΡΠ΅ΠΌΠ΅ ΠΈΠ»ΠΈ, ΠΏΡΠΎΡΡΠΎ ΠΊΠ°Π·Π°Π½ΠΎ, ΠΌΠΎΡΠΈΠ²Π°ΡΠΈΡ? Π‘ΡΠ°ΡΠΈΡΡΠ° ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Ρ ΠΏΡΠΈΠΌΠ΅Ρ Π·Π° ΡΠΎΠ²Π° ΠΊΠ°ΠΊ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π΄Π° Π½Π°ΠΏΠΈΡΠ΅ΡΠ΅ Π΄ΠΎΠ±ΡΠΎ ΠΈΠ·ΡΠ²Π»Π΅Π½ΠΈΠ΅, ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΉΠΊΠΈ Π΅Π΄ΠΈΠ½ ΠΎΡ Π½Π°ΠΉ-ΠΏΠΎΠΏΡΠ»ΡΡΠ½ΠΈΡΠ΅ Π΅Π·ΠΈΡΠΈ, ΠΊΠΎΠΈΡΠΎ ΠΏΠΎΡΡΠΈ Π²ΡΠ΅ΠΊΠΈ DevOps ΠΈΠ½ΠΆΠ΅Π½Π΅Ρ Π·Π½Π°Π΅ - ΠΠΈΡΠΎΠ½.
ΠΠ°ΠΏΠΎΠ·Π½Π°ΠΉΡΠ΅ ΡΠ΅ Ρ: Copier - ΠΊΠΎΠΏΠΈΡΠ΅Π½ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡ!
ΠΠ°ΡΠΎ ΠΏΡΠΈΠΌΠ΅Ρ, ΠΏΠΎΠΌΠΈΡΠ»Π΅ΡΠ΅ Π·Π° ΡΠ°Π·ΡΠ°Π±ΠΎΡΠ²Π°Π½Π΅ΡΠΎ Π½Π° ΠΏΡΠΎΡΡΠ° ΠΈΠ½ΡΡΡΡΠΊΡΠΈΡ, ΠΏΡΠ΅Π΄Π½Π°Π·Π½Π°ΡΠ΅Π½Π° Π΄Π° ΠΊΠΎΠΏΠΈΡΠ° ConfigMap ΠΈΠ»ΠΈ ΠΊΠΎΠ³Π°ΡΠΎ ΡΠ΅ ΠΏΠΎΡΠ²ΠΈ Π½ΠΎΠ²ΠΎ ΠΏΡΠΎΡΡΡΠ°Π½ΡΡΠ²ΠΎ ΠΎΡ ΠΈΠΌΠ΅Π½Π°, ΠΈΠ»ΠΈ ΠΊΠΎΠ³Π°ΡΠΎ ΡΠ΅ ΠΏΡΠΎΠΌΠ΅Π½ΠΈ Π΅Π΄ΠΈΠ½ ΠΎΡ Π΄Π²Π°ΡΠ° ΠΎΠ±Π΅ΠΊΡΠ°: ConfigMap ΠΈ Secret. ΠΡ ΠΏΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠ° Π³Π»Π΅Π΄Π½Π° ΡΠΎΡΠΊΠ° ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΡΡ ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΡΠ΄Π΅ ΠΏΠΎΠ»Π΅Π·Π΅Π½ Π·Π° Π³ΡΡΠΏΠΎΠ²ΠΎ Π°ΠΊΡΡΠ°Π»ΠΈΠ·ΠΈΡΠ°Π½Π΅ Π½Π° ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΠΈ Π½Π° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ (ΡΡΠ΅Π· Π°ΠΊΡΡΠ°Π»ΠΈΠ·ΠΈΡΠ°Π½Π΅ Π½Π° ConfigMap) ΠΈΠ»ΠΈ Π·Π° Π°ΠΊΡΡΠ°Π»ΠΈΠ·ΠΈΡΠ°Π½Π΅ Π½Π° ΡΠ΅ΠΊΡΠ΅ΡΠ½ΠΈ Π΄Π°Π½Π½ΠΈ - Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ ΠΊΠ»ΡΡΠΎΠ²Π΅ Π·Π° ΡΠ°Π±ΠΎΡΠ° Ρ Docker Registry (ΠΏΡΠΈ Π΄ΠΎΠ±Π°Π²ΡΠ½Π΅ Π½Π° Secret ΠΊΡΠΌ ΠΏΡΠΎΡΡΡΠ°Π½ΡΡΠ²ΠΎΡΠΎ ΠΎΡ ΠΈΠΌΠ΅Π½Π°).
ΠΠΎ ΡΠΎΠ·ΠΈ Π½Π°ΡΠΈΠ½, ΠΊΠ°ΠΊΠ²ΠΎ ΡΡΡΠ±Π²Π° Π΄Π° ΠΈΠΌΠ° Π΅Π΄ΠΈΠ½ Π΄ΠΎΠ±ΡΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡ:
- ΠΠ·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ΡΠΎ Ρ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠ° ΡΠ΅ ΠΎΡΡΡΠ΅ΡΡΠ²ΡΠ²Π° Ρ ΠΏΠΎΠΌΠΎΡΡΠ° Π½Π°
ΠΠ΅ΡΡΠΎΠ½Π°Π»ΠΈΠ·ΠΈΡΠ°Π½ΠΈ Π΄Π΅ΡΠΈΠ½ΠΈΡΠΈΠΈ Π½Π° ΡΠ΅ΡΡΡΡΠΈ (Π½Π°ΡΠΈΡΠ°Π½ΠΈ ΠΏΠΎ-Π΄ΠΎΠ»Ρ CRD). - ΠΠΏΠ΅ΡΠ°ΡΠΎΡΡΡ ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΡΠ΄Π΅ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠΈΡΠ°Π½. ΠΠ° Π΄Π° Π½Π°ΠΏΡΠ°Π²ΠΈΠΌ ΡΠΎΠ²Π°, ΡΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ ΡΠ»Π°Π³ΠΎΠ²Π΅ Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΈΡ ΡΠ΅Π΄ ΠΈ ΠΏΡΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° ΡΡΠ΅Π΄Π°ΡΠ°.
- ΠΠ·Π³ΡΠ°ΠΆΠ΄Π°Π½Π΅ΡΠΎ Π½Π° ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅ΡΠ° Π½Π° Docker ΠΈ Π΄ΠΈΠ°Π³ΡΠ°ΠΌΠ°ΡΠ° Π½Π° Helm Π΅ ΠΏΡΠΎΠ΅ΠΊΡΠΈΡΠ°Π½ΠΎ ΡΠ°ΠΊΠ°, ΡΠ΅ ΠΏΠΎΡΡΠ΅Π±ΠΈΡΠ΅Π»ΠΈΡΠ΅ Π΄Π° ΠΌΠΎΠ³Π°Ρ Π»Π΅ΡΠ½ΠΎ (Π±ΡΠΊΠ²Π°Π»Π½ΠΎ Ρ Π΅Π΄Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°) Π΄Π° ΠΈΠ½ΡΡΠ°Π»ΠΈΡΠ°Ρ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠ° Π² ΡΠ²ΠΎΡ ΠΊΠ»ΡΡΡΠ΅Ρ Kubernetes.
CRD
ΠΠ° Π΄Π° Π·Π½Π°Π΅ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΡΡ ΠΊΠ°ΠΊΠ²ΠΈ ΡΠ΅ΡΡΡΡΠΈ Π΄Π° ΡΡΡΡΠΈ ΠΈ ΠΊΡΠ΄Π΅ Π΄Π° ΡΡΡΡΠΈ, ΡΡΡΠ±Π²Π° Π΄Π° ΠΌΡ Π·Π°Π΄Π°Π΄Π΅ΠΌ ΠΏΡΠ°Π²ΠΈΠ»ΠΎ. ΠΡΡΠΊΠΎ ΠΏΡΠ°Π²ΠΈΠ»ΠΎ ΡΠ΅ Π±ΡΠ΄Π΅ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π΅Π½ΠΎ ΠΊΠ°ΡΠΎ Π΅Π΄ΠΈΠ½ CRD ΠΎΠ±Π΅ΠΊΡ. ΠΠ°ΠΊΠ²ΠΈ ΠΏΠΎΠ»Π΅ΡΠ° ΡΡΡΠ±Π²Π° Π΄Π° ΠΈΠΌΠ° ΡΠΎΠ·ΠΈ CRD?
- Π’ΠΈΠΏ ΡΠ΅ΡΡΡΡ, ΠΊΠΎΠΉΡΠΎ ΡΠ΅ ΡΡΡΡΠΈΠΌ (ConfigMap ΠΈΠ»ΠΈ Secret).
- Π‘ΠΏΠΈΡΡΠΊ Ρ ΠΏΡΠΎΡΡΡΠ°Π½ΡΡΠ²Π° ΠΎΡ ΠΈΠΌΠ΅Π½Π°, Π² ΠΊΠΎΠΉΡΠΎ ΡΡΡΠ±Π²Π° Π΄Π° ΡΠ΅ Π½Π°ΠΌΠΈΡΠ°Ρ ΡΠ΅ΡΡΡΡΠΈΡΠ΅.
- ΡΠ΅Π»Π΅ΠΊΡΠΎΡ, ΡΡΠ΅Π· ΠΊΠΎΠΉΡΠΎ ΡΠ΅ ΡΡΡΡΠΈΠΌ ΡΠ΅ΡΡΡΡΠΈ Π² ΠΏΡΠΎΡΡΡΠ°Π½ΡΡΠ²ΠΎΡΠΎ ΠΎΡ ΠΈΠΌΠ΅Π½Π°.
ΠΠ΅ΠΊΠ° ΠΎΠΏΠΈΡΠ΅ΠΌ 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
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.
ΠΡΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° ΡΡΠ΅Π΄Π°ΡΠ° ΠΈΠ»ΠΈ ΡΠ»Π°Π³ΠΎΠ²Π΅? ΠΠ·ΠΈΠΌΠ°ΠΌΠ΅ Π²ΡΠΈΡΠΊΠΎ!
ΠΠ΅ΠΊΠ° Π΄Π° ΠΏΡΠ΅ΠΌΠΈΠ½Π΅ΠΌ ΠΊΡΠΌ ΠΎΡΠ½ΠΎΠ²Π½Π°ΡΠ° ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ Π½Π° ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠ°. ΠΠΌΠ° Π΄Π²Π° ΠΎΡΠ½ΠΎΠ²Π½ΠΈ ΠΏΠΎΠ΄Ρ ΠΎΠ΄Π° Π·Π° ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠΈΡΠ°Π½Π΅ Π½Π° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ:
- ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΉΡΠ΅ ΠΎΠΏΡΠΈΠΈΡΠ΅ Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΈΡ ΡΠ΅Π΄;
- ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΉΡΠ΅ ΠΏΡΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° ΡΡΠ΅Π΄Π°ΡΠ°.
ΠΠΏΡΠΈΠΈΡΠ΅ Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΈΡ ΡΠ΅Π΄ Π²ΠΈ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ²Π°Ρ Π΄Π° ΡΠ΅ΡΠ΅ΡΠ΅ Π½Π°ΡΡΡΠΎΠΉΠΊΠΈΡΠ΅ ΠΏΠΎ-Π³ΡΠ²ΠΊΠ°Π²ΠΎ, Ρ ΠΏΠΎΠ΄Π΄ΡΡΠΆΠΊΠ° Π½Π° ΡΠΈΠΏΠΎΠ²Π΅ Π΄Π°Π½Π½ΠΈ ΠΈ ΠΏΡΠΎΠ²Π΅ΡΠΊΠ°. Π‘ΡΠ°Π½Π΄Π°ΡΡΠ½Π°ΡΠ° Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ° Π½Π° 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...
ΠΠ° Π΄Π° Π²ΠΈ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²ΠΈΠΌ ΠΏΠΎ-ΠΎΡΠ±Π»ΠΈΠ·ΠΎ ΠΊΠΎΠ΄Π°, Π½ΠΈΠ΅ Π³ΠΎ ΠΏΠΎΡΡΠ°Π²ΠΈΡ
ΠΌΠ΅
PS Π Π°ΠΊΠΎ Π²ΠΈ ΠΌΡΡΠ·ΠΈ Π΄Π° ΡΠ΅ Π·Π°Π½ΠΈΠΌΠ°Π²Π°ΡΠ΅ ΡΡΡ ΡΡΠ±ΠΈΡΠΈΡ Π½Π° Kubernetes ΠΈΠ»ΠΈ ΠΏΡΠΎΡΡΠΎ ΡΡΠ΅ ΠΏΠΎ-ΡΠ²ΠΈΠΊΠ½Π°Π»ΠΈ Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΡΠ΅ Bash, Π½Π°ΡΠΈΡΠ΅ ΠΊΠΎΠ»Π΅Π³ΠΈ ΡΠ° ΠΏΠΎΠ΄Π³ΠΎΡΠ²ΠΈΠ»ΠΈ Π³ΠΎΡΠΎΠ²ΠΎ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ Π²ΡΠ² ΡΠΎΡΠΌΠ°ΡΠ°
PPS
ΠΡΠΎΡΠ΅ΡΠ΅ΡΠ΅ ΡΡΡΠΎ Π² Π½Π°ΡΠΈΡ Π±Π»ΠΎΠ³:
- Β«
ΠΠ΅ΡΠ½ΠΎ ΠΈ ΡΠ΄ΠΎΠ±Π½ΠΎ Π»ΠΈ Π΅ Π΄Π° ΠΏΠΎΠ΄Π³ΠΎΡΠ²ΠΈΡΠ΅ Kubernetes ΠΊΠ»ΡΡΡΠ΅Ρ? ΠΠ±ΡΠ²ΡΠ²Π°Π½Π΅ Π½Π° addon-ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡ Β»; - Β«
ΠΡΠ΅Π΄ΡΡΠ°Π²ΡΠΌΠ΅ Π²ΠΈ shell-operator: ΡΡΠ·Π΄Π°Π²Π°Π½Π΅ΡΠΎ Π½Π° ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠΈ Π·Π° Kubernetes ΡΠΎΠΊΡ-ΡΠΎ ΡΡΠ°Π½Π° ΠΏΠΎ-Π»Π΅ΡΠ½ΠΎ Β»; - Β«
Π Π°Π·ΡΠΈΡΡΠ²Π°Π½Π΅ ΠΈ Π΄ΠΎΠΏΡΠ»Π²Π°Π½Π΅ Π½Π° Kubernetes (ΠΏΡΠ΅Π³Π»Π΅Π΄ ΠΈ Π²ΠΈΠ΄Π΅ΠΎ ΠΎΡΡΠ΅Ρ) Β»; - Β«
ΠΠΈΠ΅ ΠΏΠΈΡΠ΅ΠΌ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡ Π·Π° Kubernetes Π² Golang Β»; - Β«
ΠΠΏΠ΅ΡΠ°ΡΠΎΡΠΈ Π·Π° Kubernetes: ΠΊΠ°ΠΊ Π΄Π° ΡΡΠ°ΡΡΠΈΡΠ°ΡΠ΅ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ ΡΡΡ ΡΡΡΡΠΎΡΠ½ΠΈΠ΅ ".
ΠΠ·ΡΠΎΡΠ½ΠΈΠΊ: www.habr.com