Žaidimą keičiančios programos, tokios kaip „Docker“ ir „Kubernetes“, yra parašytos „Go“. Rašyti operatorių Go reiškia kalbėti ta pačia kalba su ekosistema.
Didelis „Go“ programų našumas ir paprasti įrankiai, skirti dirbti su vienu metu.
NB: Beje, kaip parašyti savo pareiškimą Go, mes jau aprašyta viename iš mūsų užsienio autorių vertimų.
Bet ką daryti, jei mokytis Go trukdo laiko arba, paprasčiau tariant, motyvacijos trūkumas? Straipsnyje pateikiamas pavyzdys, kaip galite parašyti gerą pareiškimą naudodami vieną iš populiariausių kalbų, kurią žino beveik kiekvienas „DevOps“ inžinierius - Pitonas.
Pavyzdžiui, apsvarstykite galimybę sukurti paprastą teiginį, skirtą nukopijuoti ConfigMap, kai atsiranda nauja vardų sritis arba pasikeičia vienas iš dviejų objektų: ConfigMap ir Secret. Praktiniu požiūriu operatorius gali būti naudingas masiniam programų konfigūracijų atnaujinimui (atnaujinant ConfigMap) arba slaptiems duomenims atnaujinti, pavyzdžiui, raktams, skirtiems darbui su Docker registru (kai vardų erdvėje pridedama Secret).
Galima konfigūruoti operatorių. Norėdami tai padaryti, naudosime komandų eilutės vėliavėles ir aplinkos kintamuosius.
„Docker“ konteinerio ir „Helm“ diagramos konstrukcija sukurta taip, kad vartotojai galėtų lengvai (pažodžiui su viena komanda) įdiegti operatorių savo „Kubernetes“ klasteryje.
KRD
Kad operatorius žinotų, kokių išteklių ir kur ieškoti, turime jam nustatyti taisyklę. Kiekviena taisyklė bus pavaizduota kaip vienas CRD objektas. Kokie laukai turėtų būti šiame KPD?
Ištekliaus tipas, kurio ieškosime (ConfigMap arba Secret).
Vardų erdvių sąrašas, kuriame turėtų būti ištekliai.
Rinkėjas, pagal kurią ieškosime išteklių vardų erdvėje.
Pasiruošę! Dabar turime kažkaip gauti informacijos apie mūsų taisyklę. Leiskite man iš karto rezervuoti, kad patys nerašysime užklausų į klasterio API serverį. Norėdami tai padaryti, naudosime paruoštą Python biblioteką kubernetes-klientas:
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')}
Puiku: mums pavyko gauti taisyklę operatoriui. Ir svarbiausia, mes padarėme tai, kas vadinama Kubernetes būdu.
Aplinkos kintamieji ar vėliavėlės? Mes priimame viską!
Pereikime prie pagrindinės operatoriaus konfigūracijos. Yra du pagrindiniai programų konfigūravimo būdai:
naudoti komandinės eilutės parinktis;
naudoti aplinkos kintamuosius.
Komandinės eilutės parinktys leidžia lanksčiau skaityti nustatymus, naudojant duomenų tipo palaikymą ir patvirtinimą. Standartinėje Python bibliotekoje yra modulis argparser, kurį naudosime. Išsamią informaciją ir jo galimybių pavyzdžius rasite oficialius dokumentus.
Mūsų atveju taip atrodytų nuskaitymo komandinės eilutės vėliavėlių nustatymo pavyzdys:
Kita vertus, naudodami aplinkos kintamuosius „Kubernetes“, galite lengvai perkelti paslaugų informaciją apie talpyklą konteinerio viduje. Pavyzdžiui, galime gauti informacijos apie vardų erdvę, kurioje veikia blokas, naudodami tokią konstrukciją:
Norėdami suprasti, kaip atskirti darbo su ConfigMap ir Secret metodus, naudosime specialius žemėlapius. Tada galime suprasti, kokių metodų reikia norint sekti ir sukurti objektą:
Tada turite gauti įvykius iš API serverio. Įgyvendinkime tai taip:
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)
Gavę įvykį pereiname prie pagrindinės jo apdorojimo logikos:
# Типы событий, на которые будем реагировать
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)
Pagrindinė logika yra paruošta! Dabar turime visa tai supakuoti į vieną Python paketą. Paruošiame failą setup.py, parašykite ten meta informaciją apie projektą:
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: Python skirtas kubernetes klientas turi savo versijų kūrimą. Daugiau informacijos apie kliento versijų ir Kubernetes versijų suderinamumą rasite suderinamumo matricos.
Dabar mūsų projektas atrodo taip:
copyrator
├── copyrator
│ ├── cli.py # Логика работы с командной строкой
│ ├── constant.py # Константы, которые мы приводили выше
│ ├── load_crd.py # Логика загрузки CRD
│ └── operator.py # Основная логика работы оператора
└── setup.py # Оформление пакета
Dokeris ir Helmas
„Dockerfile“ bus neįtikėtinai paprastas: paimkite pagrindinį „python-alpine“ vaizdą ir įdiekite mūsų paketą. Atidėkime jos optimizavimą geresniems laikams:
FROM python:3.7.3-alpine3.9
ADD . /app
RUN pip3 install /app
ENTRYPOINT ["copyrator"]
Taip be baimės, priekaištų ir mokymosi „Go“ galėjome sukurti savo „Kubernetes“ operatorių Python. Žinoma, jis dar turi kur augti: ateityje jis galės apdoroti kelias taisykles, dirbti keliomis gijomis, savarankiškai stebėti savo CRD pokyčius...
Kad galėtumėte atidžiau pažvelgti į kodą, mes jį įdėjome viešoji saugykla. Jei norite rimtesnių operatorių, įdiegtų naudojant Python, pavyzdžių, galite atkreipti dėmesį į du operatorius, skirtus diegti mongodb (первый и antra).
PS O jei esate per daug tingus tvarkytis su Kubernetes renginiais arba tiesiog esate labiau įpratę naudoti Bash, mūsų kolegos paruošė paruoštą sprendimą formoje apvalkalo operatorius (Mes paskelbė balandžio mėnesį).