
Go Π² ΠΌΠΎΠΌΠ΅Π½ΡΠ° Π΅ ΠΌΠΎΠ½ΠΎΠΏΠΎΠ»ΠΈΡΡ ΡΡΠ΅Π΄ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ½ΠΈΡΠ΅ Π΅Π·ΠΈΡΠΈ, ΠΊΠΎΠΈΡΠΎ Ρ
ΠΎΡΠ°ΡΠ° ΠΈΠ·Π±ΠΈΡΠ°Ρ Π·Π° Π½Π°ΠΏΠΈΡΠ²Π°Π½Π΅ Π½Π° ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠΈ Π·Π° Kubernetes. ΠΠΌΠ° ΠΎΠ±Π΅ΠΊΡΠΈΠ²Π½ΠΈ ΠΏΡΠΈΡΠΈΠ½ΠΈ Π·Π° ΡΠΎΠ²Π°, ΠΊΠ°ΡΠΎ:
- Π‘ΡΡΠ΅ΡΡΠ²ΡΠ²Π° ΠΌΠΎΡΠ΅Π½ ΡΡΠ΅ΠΉΠΌΡΡΡΠΊ Π·Π° ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠ° Π½Π° ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠΈ Π½Π° Go β .
- ΠΠ° Go ΡΠ° Π½Π°ΠΏΠΈΡΠ°Π½ΠΈ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ, ΠΊΠΎΠΈΡΠΎ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ Π° ΠΈΠ³ΡΠ°ΡΠ°, ΠΊΠ°ΡΠΎ Docker ΠΈ Kubernetes. ΠΠ° Π½Π°ΠΏΠΈΡΠ΅ΡΠ΅ ΡΠ²ΠΎΠΉ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡ Π½Π° Go ΠΎΠ·Π½Π°ΡΠ°Π²Π° Π΄Π° Π³ΠΎΠ²ΠΎΡΠΈΡΠ΅ Ρ Π΅ΠΊΠΎΡΠΈΡΡΠ΅ΠΌΠ°ΡΠ° Π½Π° Π΅Π΄ΠΈΠ½ ΠΈ ΡΡΡ Π΅Π·ΠΈΠΊ.
- ΠΠΈΡΠΎΠΊΠ°ΡΠ° ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»Π½ΠΎΡΡ Π½Π° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡΡΠ° Π½Π° Go ΠΈ Π»Π΅ΡΠ½ΠΈΡΠ΅ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΠΈ Π·Π° ΡΠ°Π±ΠΎΡΠ° Ρ concurrency "ΠΎΡ ΠΊΡΡΠΈΡΡΠ°".
NB: ΠΠ΅ΠΆΠ΄Ρ Π΄ΡΡΠ³ΠΎΡΠΎ, ΠΊΠ°ΠΊ Π΄Π° Π½Π°ΠΏΠΈΡΠ΅ΡΠ΅ ΡΠ²ΠΎΠΉ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡ Π½Π° Go, Π½ΠΈΠ΅ Π² Π΅Π΄ΠΈΠ½ ΠΎΡ Π½Π°ΡΠΈΡΠ΅ ΠΏΡΠ΅Π²ΠΎΠ΄ΠΈ Π½Π° ΡΡΠΆΠ΄Π΅ΡΡΡΠ°Π½Π½ΠΈ Π°Π²ΡΠΎΡΠΈ.
ΠΠΎ ΠΊΠ°ΠΊΠ²ΠΎ, Π°ΠΊΠΎ ΠΈΠ·ΡΡΠ°Π²Π°Π½Π΅ΡΠΎ Π½Π° Go Π²ΠΈ ΠΏΡΠ΅ΡΠΈ ΠΎΡΡΡΡΡΠ²ΠΈΠ΅ΡΠΎ Π½Π° Π²ΡΠ΅ΠΌΠ΅ ΠΈΠ»ΠΈ Π΅Π»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠ½ΠΎ, ΠΌΠΎΡΠΈΠ²Π°ΡΠΈΡ? Π ΡΡΠ°ΡΠΈΡΡΠ° Π΅ Π΄Π°Π΄Π΅Π½ ΠΏΡΠΈΠΌΠ΅Ρ ΠΊΠ°ΠΊ ΠΌΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ Π½Π°ΠΏΠΈΡΠ΅ ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅Π½ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡ, ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΉΠΊΠΈ Π΅Π΄ΠΈΠ½ ΠΎΡ Π½Π°ΠΉ-ΠΏΠΎΠΏΡΠ»ΡΡΠ½ΠΈΡΠ΅ Π΅Π·ΠΈΡΠΈ, ΠΊΠΎΠΉΡΠΎ ΠΏΠΎΡΡΠΈ Π²ΡΠ΅ΠΊΠΈ DevOps ΠΈΠ½ΠΆΠ΅Π½Π΅Ρ ΠΏΠΎΠ·Π½Π°Π²Π° β Python.
ΠΡΠ΅Π΄ΡΡΠ°Π²ΡΠΌΠ΅ Π²ΠΈ: ΠΠΎΠΏΠΈΡΠ°ΡΠΎΡ β ΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π»Π΅Π½ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡ!
ΠΠ° ΠΏΡΠΈΠΌΠ΅Ρ ΡΠ΅ ΡΠ°Π·Π³Π»Π΅Π΄Π°ΠΌΠ΅ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠ°ΡΠ° Π½Π° ΠΏΡΠΎΡΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡ, ΠΏΡΠ΅Π΄Π½Π°Π·Π½Π°ΡΠ΅Π½ Π·Π° ΠΊΠΎΠΏΠΈΡΠ°Π½Π΅ Π½Π° ConfigMap, ΠΊΠ°ΠΊΡΠΎ ΠΏΡΠΈ ΠΏΠΎΡΠ²Π°ΡΠ° Π½Π° Π½ΠΎΠ² namespace, ΡΠ°ΠΊΠ° ΠΈ ΠΏΡΠΈ ΠΏΡΠΎΠΌΡΠ½Π° Π½Π° Π΅Π΄Π½Π° ΠΎΡ Π΄Π²Π΅ΡΠ΅ ΡΡΡΠ½ΠΎΡΡΠΈ: ConfigMap ΠΈ Secret. ΠΡ ΠΏΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠ° Π³Π»Π΅Π΄Π½Π° ΡΠΎΡΠΊΠ° ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΡΡ ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΡΠ΄Π΅ ΠΏΠΎΠ»Π΅Π·Π΅Π½ Π·Π° ΠΌΠ°ΡΠΎΠ²ΠΎ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ Π½Π° ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΠΈ Π½Π° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ (ΡΡΠ΅Π· ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ Π½Π° ConfigMap) ΠΈΠ»ΠΈ Π·Π° ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ Π½Π° ΡΠ΅ΠΊΡΠ΅ΡΠ½ΠΈ Π΄Π°Π½Π½ΠΈ β Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, ΠΊΠ»ΡΡΠΎΠ²Π΅ Π·Π° ΡΠ°Π±ΠΎΡΠ° Ρ Docker Registry (ΠΏΡΠΈ Π΄ΠΎΠ±Π°Π²ΡΠ½Π΅ Π½Π° Secret Π² namespace).
Π ΡΠ°ΠΊΠ°, ΠΊΠ°ΠΊΠ²ΠΎ ΡΡΡΠ±Π²Π° Π΄Π° ΠΏΡΠΈΡΠ΅ΠΆΠ°Π²Π° Π΅Π΄ΠΈΠ½ Π΄ΠΎΠ±ΡΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡ:
- ΠΠ·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ΡΠΎ Ρ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠ° ΡΠ΅ ΠΎΡΡΡΠ΅ΡΡΠ²ΡΠ²Π° ΡΡΠ΅Π· (ΠΏΠΎ-Π΄ΠΎΠ»Ρ β CRD).
- ΠΠΏΠ΅ΡΠ°ΡΠΎΡΡΡ ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΡΠ΄Π΅ Π½Π°ΡΡΡΠΎΠ΅Π½. ΠΠ° ΡΠ΅Π»ΡΠ° ΡΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ ΡΠ»Π°Π³ΠΎΠ²Π΅ Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΈΡ ΡΠ΅Π΄ ΠΈ ΠΏΡΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° ΡΡΠ΅Π΄Π°ΡΠ°.
- Π‘ΡΠ·Π΄Π°Π²Π°Π½Π΅ΡΠΎ Π½Π° Docker ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅Ρ ΠΈ Helm Π³ΡΠ°ΡΠΈΠΊ Π΅ ΠΎΡΠ³Π°Π½ΠΈΠ·ΠΈΡΠ°Π½ΠΎ ΡΠ°ΠΊΠ°, ΡΠ΅ ΠΏΠΎΡΡΠ΅Π±ΠΈΡΠ΅Π»ΠΈΡΠ΅ Π΄Π° ΠΌΠΎΠ³Π°Ρ Π»Π΅ΡΠ½ΠΎ (Π±ΡΠΊΠ²Π°Π»Π½ΠΎ Ρ Π΅Π΄Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°) Π΄Π° ΠΈΠ½ΡΡΠ°Π»ΠΈΡΠ°Ρ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠ° Π² ΡΠ²ΠΎΡ Kubernetes ΠΊΠ»ΡΡΡΠ΅Ρ.
CRD
ΠΠ° Π΄Π° Π·Π½Π°Π΅ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΡΡ ΠΊΠΎΠΈ ΡΠ΅ΡΡΡΡΠΈ ΠΈ ΠΊΡΠ΄Π΅ Π΄Π° ΡΡΡΡΠΈ, ΡΡΡΠ±Π²Π° Π΄Π° Π·Π°Π΄Π°Π΄Π΅ΠΌ ΠΏΡΠ°Π²ΠΈΠ»ΠΎ Π·Π° Π½Π΅Π³ΠΎ. ΠΡΡΠΊΠΎ ΠΏΡΠ°Π²ΠΈΠ»ΠΎ ΡΠ΅ Π±ΡΠ΄Π΅ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π΅Π½ΠΎ ΠΏΠΎΠ΄ ΡΠΎΡΠΌΠ°ΡΠ° Π½Π° Π΅Π΄ΠΈΠ½ ΠΎΠ±Π΅ΠΊΡ CRD. ΠΠ°ΠΊΠ²ΠΈ ΠΏΠΎΠ»Π΅ΡΠ° ΡΡΡΠ±Π²Π° Π΄Π° ΠΈΠΌΠ° ΡΠΎΠ·ΠΈ CRD?
- Π’ΠΈΠΏ ΡΠ΅ΡΡΡΡ, ΠΊΠΎΠΉΡΠΎ ΡΠ΅ ΡΡΡΡΠΈΠΌ (ConfigMap ΠΈΠ»ΠΈ Secret).
- Π‘ΠΏΠΈΡΡΠΊ Π½Π° namespaceβΠΈΡΠ΅, Π² ΠΊΠΎΠΈΡΠΎ ΡΡΡΠ±Π²Π° Π΄Π° ΡΠ΅ Π½Π°ΠΌΠΈΡΠ°Ρ ΡΠ΅ΡΡΡΡΠΈΡΠ΅.
- Π‘Π΅Π»Π΅ΠΊΡΠΎΡ, ΠΏΠΎ ΠΊΠΎΠΉΡΠΎ ΡΠ΅ ΡΡΡΡΠΈΠΌ ΡΠ΅ΡΡΡΡΠΈ Π² 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ΠΠΎΡΠΎΠ²ΠΎ! Π‘Π΅Π³Π° ΡΡΡΠ±Π²Π° Π΄Π° ΠΏΠΎΠ»ΡΡΠΈΠΌ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ Π·Π° Π½Π°ΡΠ΅ΡΠΎ ΠΏΡΠ°Π²ΠΈΠ»ΠΎ. ΠΠ΅Π΄Π½Π°Π³Π° Π΄Π° ΡΡΠΎΡΠ½Ρ, ΡΠ΅ Π½ΡΠΌΠ° Π΄Π° ΠΏΠΈΡΠ΅ΠΌ Π·Π°ΡΠ²ΠΊΠΈ ΠΊΡΠΌ API Server Π½Π° ΠΊΠ»Π°ΡΡΠ΅ΡΠ°. Π©Π΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ Π³ΠΎΡΠΎΠ²Π° 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 ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡ.',
prog='copyrator'
)
parser.add_argument(
'--namespace',
type=str,
default=getenv('NAMESPACE', 'default'),
help='Namespace Π½Π° ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠ°'
)
parser.add_argument(
'--rule-name',
type=str,
default=getenv('RULE_NAME', 'main-rule'),
help='ΠΠΌΠ΅ Π½Π° CRD'
)
args = parser.parse_args()ΠΡ Π΄ΡΡΠ³Π° ΡΡΡΠ°Π½Π°, Ρ ΠΏΠΎΠΌΠΎΡΡΠ° Π½Π° ΠΏΡΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π° ΡΡΠ΅Π΄Π°ΡΠ° Π² Kubernetes, ΠΌΠΎΠΆΠ΅ΠΌ Π»Π΅ΡΠ½ΠΎ Π΄Π° ΠΏΡΠ΅Π½Π΅ΡΠ΅ΠΌ ΡΠ»ΡΠΆΠ΅Π±Π½Π° ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ Π·Π° pod Π²ΡΡΡΠ΅ Π² ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅ΡΠ°. ΠΠ°ΠΏΡΠΈΠΌΠ΅Ρ, ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡΡΠ° Π·Π° namespace, Π² ΠΊΠΎΠΉΡΠΎ Π΅ ΡΡΠ°ΡΡΠΈΡΠ°Π½ 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(
'ΠΠ΅ΠΏΠΎΠ΄Π΄ΡΡΠΆΠ°Π½Π° Π²Π΅ΡΡΠΈΡ Π½Π° python %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='maksim.nabokikh@flant.com',
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 # ΠΡΠΎΡΠΌΡΠ½Π΅ Π½Π° ΠΏΠ°ΠΊΠ΅ΡΠ°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. Π Π°Π·Π±ΠΈΡΠ° ΡΠ΅, ΡΠΎΠΉ Π²ΡΠ΅ ΠΎΡΠ΅ ΠΈΠΌΠ° ΠΊΠ°ΠΊΠ²ΠΎ Π΄Π° ΡΠ°Π·Π²ΠΈΠ²Π°: Π² Π±ΡΠ΄Π΅ΡΠ΅ ΡΠ΅ ΠΌΠΎΠΆΠ΅ Π΄Π° ΠΎΠ±ΡΠ°Π±ΠΎΡΠ²Π° Π½ΡΠΊΠΎΠ»ΠΊΠΎ ΠΏΡΠ°Π²ΠΈΠ»Π°, Π΄Π° ΡΠ°Π±ΠΎΡΠΈ Π² ΠΏΠ°ΡΠ°Π»Π΅Π», Π΄Π° Π½Π°Π±Π»ΡΠ΄Π°Π²Π° ΠΏΡΠΎΠΌΠ΅Π½ΠΈΡΠ΅ Π² ΡΠ²ΠΎΠΈΡΠ΅ CRD...
ΠΠ° Π΄Π° ΡΠ΅ Π·Π°ΠΏΠΎΠ·Π½Π°Π΅ΡΠ΅ ΠΏΠΎ-Π΄ΠΎΠ±ΡΠ΅ Ρ ΠΊΠΎΠ΄Π°, Π½ΠΈΠ΅ ΡΠΌΠ΅ Π³ΠΎ ΡΡΠ±ΡΠ°Π»ΠΈ Π² . ΠΠΊΠΎ ΠΈΡΠΊΠ°ΡΠ΅ ΠΏΡΠΈΠΌΠ΅ΡΠΈ Π½Π° ΠΏΠΎ-ΡΠ΅ΡΠΈΠΎΠ·Π½ΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠΈ, ΡΠ΅Π°Π»ΠΈΠ·ΠΈΡΠ°Π½ΠΈ Ρ ΠΏΠΎΠΌΠΎΡΡΠ° Π½Π° Python, ΠΌΠΎΠΆΠ΅ΡΠ΅ Π΄Π° ΠΎΠ±ΡΡΠ½Π΅ΡΠ΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ Π½Π° Π΄Π²Π° ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠ° Π·Π° ΡΠ°Π·Π³ΡΡΡΠ°Π½Π΅ Π½Π° mongodb ( ΠΈ ).
P.S. Π Π°ΠΊΠΎ Π²ΠΈ ΠΌΡΡΠ·ΠΈ Π΄Π° ΡΠ΅ Π·Π°ΠΏΠΎΠ·Π½Π°Π²Π°ΡΠ΅ Ρ ΡΡΠ±ΠΈΡΠΈΡΡΠ° Π½Π° Kubernetes ΠΈΠ»ΠΈ ΠΏΡΠΎΡΡΠΎ Π²ΠΈ Π΅ ΠΏΠΎ-Π½ΠΎΡΠΌΠ°Π»Π½ΠΎ Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΡΠ΅ Bash β Π½Π°ΡΠΈΡΠ΅ ΠΊΠΎΠ»Π΅Π³ΠΈ ΠΏΡΠΈΠ³ΠΎΡΠ²ΠΈΡ Π° Π³ΠΎΡΠΎΠ²ΠΎ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ ΠΏΠΎΠ΄ ΡΠΎΡΠΌΠ°ΡΠ° Π½Π° (Π½ΠΈΠ΅ Π³ΠΎ ΠΏΡΠ΅Π· Π°ΠΏΡΠΈΠ»).
P.P.S.
ΠΡΠΎΡΠ΅ΡΠ΅ΡΠ΅ ΡΡΡΠΎ Π² Π½Π°ΡΠΈΡ Π±Π»ΠΎΠ³:
- «»;
- «»;
- «»;
- «»;
- «».
ΠΠ·ΡΠΎΡΠ½ΠΈΠΊ: habr.com
