Go aktualisht ka një monopol në gjuhët e programimit që njerëzit zgjedhin të shkruajnë deklarata për Kubernetes. Ka arsye objektive për këtë, si p.sh.
Ekziston një kornizë e fuqishme për zhvillimin e operatorëve në Go - Operatori SDK.
Aplikacionet që ndryshojnë lojën si Docker dhe Kubernetes janë shkruar në Go. Të shkruash operatorin tënd në Go do të thotë të flasësh të njëjtën gjuhë me ekosistemin.
Performancë e lartë e aplikacioneve Go dhe mjete të thjeshta për të punuar me konkurencë jashtë kutisë.
NB: Nga rruga, si të shkruani deklaratën tuaj në Go, ne tashmë të përshkruara në një nga përkthimet tona nga autorë të huaj.
Por, çka nëse ju pengon të mësoni Go nga mungesa e kohës ose, thënë thjesht, motivimi? Artikulli ofron një shembull se si mund të shkruani një deklaratë të mirë duke përdorur një nga gjuhët më të njohura që di pothuajse çdo inxhinier DevOps - Piton.
Takoni: Kopjues - operator kopjimi!
Si shembull, merrni parasysh zhvillimin e një deklarate të thjeshtë të krijuar për të kopjuar një ConfigMap ose kur shfaqet një hapësirë e re emri ose kur ndryshon një nga dy entitetet: ConfigMap dhe Secret. Nga pikëpamja praktike, operatori mund të jetë i dobishëm për përditësimin masiv të konfigurimeve të aplikacionit (duke përditësuar ConfigMap) ose për përditësimin e të dhënave sekrete - për shembull, çelësat për të punuar me Regjistrin Docker (kur shtoni Secret në hapësirën e emrave).
Operatori mund të konfigurohet. Për ta bërë këtë, ne do të përdorim flamujt e linjës së komandës dhe variablat e mjedisit.
Ndërtimi i grafikut të kontejnerit Docker dhe Helm është projektuar në mënyrë që përdoruesit të mund të instalojnë lehtësisht (fjalë për fjalë me një komandë) operatorin në grupin e tyre Kubernetes.
CRD
Në mënyrë që operatori të dijë se çfarë burimesh të kërkojë dhe ku të kërkojë, ne duhet të vendosim një rregull për të. Çdo rregull do të përfaqësohet si një objekt i vetëm CRD. Çfarë fushash duhet të ketë kjo CRD?
Lloji i burimit, të cilin do ta kërkojmë (ConfigMap ose Secret).
Lista e hapësirave të emrave, në të cilën duhet të vendosen burimet.
Përzgjedhës, me anë të së cilës do të kërkojmë burime në hapësirën e emrave.
Dhe ne do ta krijojmë atë menjëherë rregull i thjeshtë — për të kërkuar në hapësirën e emrave me emrin default të gjitha ConfigMap me etiketa si copyrator: "true":
Gati! Tani duhet të marrim disi informacione për rregullin tonë. Më lejoni të bëj një rezervim menjëherë se ne nuk do t'i shkruajmë kërkesat vetë serverit API të grupit. Për ta bërë këtë, ne do të përdorim një bibliotekë të gatshme Python kubernetes-klient:
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')}
Si rezultat i ekzekutimit të këtij kodi, marrim sa vijon:
E shkëlqyeshme: arritëm të merrnim një rregull për operatorin. Dhe më e rëndësishmja, ne bëmë atë që quhet mënyra Kubernetes.
Variabla mjedisore apo flamuj? Ne marrim gjithçka!
Le të kalojmë te konfigurimi i operatorit kryesor. Ekzistojnë dy qasje themelore për konfigurimin e aplikacioneve:
përdorni opsionet e linjës së komandës;
përdorni variablat e mjedisit.
Opsionet e linjës së komandës ju lejojnë të lexoni cilësimet në mënyrë më fleksibël, me mbështetjen dhe vërtetimin e llojit të të dhënave. Biblioteka standarde e Python ka një modul argparser, të cilin do ta përdorim. Detajet dhe shembujt e aftësive të tij janë në dispozicion në dokumentacion zyrtar.
Për rastin tonë, kështu do të dukej një shembull i konfigurimit të leximit të flamujve të linjës së komandës:
Nga ana tjetër, duke përdorur variablat e mjedisit në Kubernetes, mund të transferoni lehtësisht informacionin e shërbimit për podin brenda kontejnerit. Për shembull, ne mund të marrim informacion në lidhje me hapësirën e emrave në të cilën pod po funksionon me ndërtimin e mëposhtëm:
Për të kuptuar se si të veçojmë metodat për të punuar me ConfigMap dhe Secret, ne do të përdorim harta speciale. Atëherë mund të kuptojmë se cilat metoda na duhen për të gjurmuar dhe krijuar objektin:
Tjetra, ju duhet të merrni ngjarje nga serveri API. Le ta zbatojmë atë si më poshtë:
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)
Pas marrjes së ngjarjes, kalojmë në logjikën kryesore të përpunimit të saj:
# Типы событий, на которые будем реагировать
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)
Logjika kryesore është gati! Tani duhet t'i paketojmë të gjitha këto në një paketë Python. Ne përgatisim dosjen setup.py, shkruani meta informacione rreth projektit atje:
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: Klienti kubernetes për Python ka versionin e tij. Më shumë informacion rreth përputhshmërisë midis versioneve të klientit dhe versioneve të Kubernetes mund të gjenden në matricat e përputhshmërisë.
Tani projekti ynë duket si ky:
copyrator
├── copyrator
│ ├── cli.py # Логика работы с командной строкой
│ ├── constant.py # Константы, которые мы приводили выше
│ ├── load_crd.py # Логика загрузки CRD
│ └── operator.py # Основная логика работы оператора
└── setup.py # Оформление пакета
Docker dhe Helm
Dockerfile do të jetë tepër e thjeshtë: merrni imazhin bazë python-alpin dhe instaloni paketën tonë. Le të shtyjmë optimizimin e tij deri në kohë më të mira:
FROM python:3.7.3-alpine3.9
ADD . /app
RUN pip3 install /app
ENTRYPOINT ["copyrator"]
Vendosja për operatorin është gjithashtu shumë e thjeshtë:
Kështu, pa frikë, qortim ose duke mësuar Go, ne mundëm të ndërtonim operatorin tonë për Kubernetes në Python. Natyrisht, ajo ka ende hapësirë për t'u rritur: në të ardhmen do të jetë në gjendje të përpunojë rregulla të shumta, të punojë në fije të shumta, të monitorojë në mënyrë të pavarur ndryshimet në CRD-të e saj...
Për t'ju dhënë një vështrim më të afërt të kodit, ne e kemi vendosur atë depo publike. Nëse dëshironi shembuj të operatorëve më seriozë të zbatuar duke përdorur Python, mund ta ktheni vëmendjen tuaj te dy operatorë për vendosjen e mongodb (первый и i dytë).
PS Dhe nëse jeni shumë dembel për t'u marrë me ngjarjet e Kubernetes ose thjesht jeni mësuar të përdorni Bash, kolegët tanë kanë përgatitur një zgjidhje të gatshme në formën shell-operator (Ne i shpallur atë në prill).