Go huet de Moment e Monopol op d'Programméierungssproochen déi d'Leit wielen Aussoe fir Kubernetes ze schreiwen. Et ginn objektiv Grënn dofir, wéi:
Et gëtt e mächtege Kader fir Betreiber am Go z'entwéckelen - Bedreiwer SDK.
Spillverännerend Uwendungen wéi Docker a Kubernetes ginn a Go geschriwwen. Äre Bedreiwer op Go ze schreiwen heescht déi selwecht Sprooch mam Ökosystem ze schwätzen.
Héich Leeschtung vu Go Uwendungen an einfach Tools fir mat der Konkurrenz aus der Këscht ze schaffen.
NB: Iwwregens, wéi Dir Är eege Ausso an Go schreift, mir scho beschriwwen an enger vun eisen Iwwersetzunge vun auslänneschen Auteuren.
Awer wat wann Dir verhënnert sidd Go ze léieren duerch Mangel un Zäit oder, einfach gesot, Motivatioun? Den Artikel liwwert e Beispill wéi Dir eng gutt Ausso schreiwe kënnt mat enger vun de beléifste Sproochen déi bal all DevOps Ingenieur weess - Python.
Trefft: Copier - Kopie Bedreiwer!
Als Beispill, betruecht eng einfach Ausso ze entwéckelen entwéckelt fir e ConfigMap ze kopéieren entweder wann en neien Nummraum erschéngt oder wann eng vun zwou Entitéiten ännert: ConfigMap a Secret. Aus enger praktescher Siicht kann de Bedreiwer nëtzlech sinn fir d'Massaktualiséierung vun Applikatiounskonfiguratiounen (duerch d'Aktualiséierung vun der ConfigMap) oder fir d'Aktualiséierung vun geheimen Donnéeën - zum Beispill Schlësselen fir mat der Docker Registry ze schaffen (wann Dir Secret zum Nummraum bäidréit).
De Bedreiwer kann konfiguréiert ginn. Fir dëst ze maachen, benotze mir Kommandozeil Fändelen an Ëmfeldvariablen.
De Bau vum Docker Container an Helm Chart ass entwéckelt sou datt d'Benotzer einfach (wuertwiertlech mat engem Kommando) den Bedreiwer an hire Kubernetes Cluster installéiere kënnen.
CRD
Fir datt de Bedreiwer weess wéi eng Ressourcen sicht a wou sicht, musse mir eng Regel fir hien setzen. All Regel gëtt als eenzegen CRD Objet vertruede ginn. Wéi eng Felder soll dës CRD hunn?
Ressource Typ, déi mir no kucken (ConfigMap oder Secret).
Lëscht vun den Nummraim, an deem d'Ressourcen solle sinn.
Gewielt, duerch déi mir no Ressourcen am Nummraum sichen.
Fäerdeg! Elo musse mir iergendwéi Informatioun iwwer eis Regel kréien. Loosst mech direkt eng Reservatioun maachen, datt mir keng Ufroe fir de Cluster API Server selwer schreiwen. Fir dëst ze maachen, benotze mir eng fäerdeg Python-Bibliothéik kubernetes-Client:
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')}
Als Resultat vun dësem Code lafen mir déi folgend:
Super: mir hunn et fäerdeg bruecht eng Regel fir de Bedreiwer ze kréien. A virun allem hu mir dat gemaach wat de Kubernetes Wee genannt gëtt.
Ëmweltverännerlechen oder Fändelen? Mir huelen alles!
Loosst eis op d'Haaptbetreiberkonfiguratioun goen. Et ginn zwou Basis Approche fir Uwendungen ze konfiguréieren:
benotzen Kommando Linn Optiounen;
benotzen Ëmwelt Verännerlechen.
Kommando Linn Optiounen erlaben Iech Astellunge méi flexibel ze liesen, mat Daten Typ Ënnerstëtzung a Validatioun. Python Standardbibliothéik huet e Modul argparser, déi mir wäerte benotzen. Detailer an Beispiller vu senge Fäegkeeten sinn verfügbar an offiziell Dokumentatioun.
Fir eise Fall ass dat wéi e Beispill fir d'Liesen vun Kommandozeil Fändelen opzestellen:
Op der anerer Säit, mat Ëmfeldvariablen a Kubernetes, kënnt Dir einfach Serviceinformatioun iwwer de Pod am Container transferéieren. Zum Beispill kënne mir Informatioun iwwer den Nummraum kréien an deem de Pod leeft mat der folgender Konstruktioun:
Fir ze verstoen wéi Methoden fir mat ConfigMap a Secret ze trennen, benotze mir speziell Kaarten. Da kënne mir verstoen wéi eng Methoden mir brauchen fir den Objet ze verfolgen an ze kreéieren:
Als nächst musst Dir Eventer vum API Server kréien. Loosst eis et wéi follegt ëmsetzen:
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)
Nodeems mir d'Evenement kritt hunn, gi mir weider op d'Haaptlogik vun der Veraarbechtung:
# Типы событий, на которые будем реагировать
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)
D'Haaptlogik ass prett! Elo musse mir dat alles an ee Python Package packen. Mir preparéieren de Fichier setup.py, schreift do Meta-Informatiounen iwwer de Projet:
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: De kubernetes Client fir Python huet seng eege Versioun. Méi Informatioun iwwer Kompatibilitéit tëscht Client Versiounen a Kubernetes Versioune fannt Dir an Onbedenklechkeet matrices.
Elo gesäit eise Projet esou aus:
copyrator
├── copyrator
│ ├── cli.py # Логика работы с командной строкой
│ ├── constant.py # Константы, которые мы приводили выше
│ ├── load_crd.py # Логика загрузки CRD
│ └── operator.py # Основная логика работы оператора
└── setup.py # Оформление пакета
Docker et Helm
D'Dockerfile wäert onheemlech einfach sinn: huelt de Basis Python-Alpine Bild an installéiert eise Package. Loosst eis seng Optimiséierung bis besser Zäiten ausstelle:
FROM python:3.7.3-alpine3.9
ADD . /app
RUN pip3 install /app
ENTRYPOINT ["copyrator"]
Dat ass wéi mir, ouni Angscht, Reproche oder Go léieren, eisen eegene Bedreiwer fir Kubernetes am Python bauen. Natierlech huet et nach ëmmer Plaz fir ze wuessen: an Zukunft wäert et fäeg sinn verschidde Reegelen ze veraarbechten, a multiple thread ze schaffen, onofhängeg Ännerungen a senge CRDs iwwerwaachen ...
Fir Iech de Code méi no ze kucken, hu mir et gesat ëffentleche Repository. Wann Dir Beispiller vu méi eeschte Betreiber wëllt implementéiert mat Python, kënnt Dir Är Opmierksamkeet op zwee Betreiber dréien fir mongodb (первый и déi zweet).
PS A wann Dir ze faul sidd fir mat Kubernetes Eventer ze këmmeren oder Dir sidd einfach méi gewinnt Bash ze benotzen, hunn eis Kollegen eng fäerdeg Léisung an der Form virbereet Shell-Operateur (Mir ugekënnegt Abrëll).