Kubernetes օպերատոր Python-ում առանց շրջանակների և SDK-ի
Go-ն ներկայումս մենաշնորհ ունի ծրագրավորման լեզուների վրա, որոնք մարդիկ ընտրում են Kubernetes-ի համար հայտարարություններ գրել: Դրա համար կան օբյեկտիվ պատճառներ, ինչպիսիք են.
Go-ում օպերատորների զարգացման հզոր շրջանակ կա. Օպերատոր SDK.
Խաղը փոխող հավելվածները, ինչպիսիք են Docker-ը և Kubernetes-ը, գրված են Go-ում: Ձեր օպերատորին Go-ում գրելը նշանակում է նույն լեզվով խոսել էկոհամակարգի հետ:
Go հավելվածների բարձր կատարողականություն և պարզ գործիքներ՝ առանց տուփի զուգահեռ աշխատելու համար:
NBԻ դեպ, ինչպես գրել ձեր սեփական հայտարարությունը Go-ում, մենք արդեն նկարագրված օտար հեղինակների մեր թարգմանություններից մեկում:
Բայց ի՞նչ անել, եթե ժամանակի կամ, պարզ ասած, մոտիվացիայի պատճառով խանգարում եք սովորել Go-ին: Հոդվածը տալիս է օրինակ, թե ինչպես կարող եք լավ հայտարարություն գրել՝ օգտագործելով ամենատարածված լեզուներից մեկը, որը գիտի գրեթե յուրաքանչյուր DevOps ինժեներ. Python.
Հանդիպում. Պատճենահանող - պատճենահանող օպերատոր:
Որպես օրինակ, մտածեք մշակել մի պարզ հայտարարություն, որը նախատեսված է ConfigMap-ը պատճենելու համար, երբ հայտնվում է նոր անվանատարածք, կամ երբ փոխվում է երկու միավորներից մեկը՝ ConfigMap և Secret: Գործնական տեսանկյունից, օպերատորը կարող է օգտակար լինել հավելվածի կազմաձևերի զանգվածային թարմացման համար (թարմացնելով ConfigMap) կամ գաղտնի տվյալների թարմացման համար, օրինակ՝ Docker Registry-ի հետ աշխատելու բանալիները (Գաղտնիքը անվանատարածքում ավելացնելիս):
Օպերատորը կարող է կազմաձևվել: Դա անելու համար մենք կօգտագործենք հրամանի տողի դրոշներ և շրջակա միջավայրի փոփոխականներ:
Docker կոնտեյների և Helm աղյուսակի կառուցվածքը նախագծված է այնպես, որ օգտվողները կարողանան հեշտությամբ (բառացիորեն մեկ հրամանով) տեղադրել օպերատորը իրենց Kubernetes կլաստերում:
ՏԶԿ
Որպեսզի օպերատորը իմանա, թե ինչ ռեսուրսներ փնտրել և որտեղ փնտրել, մենք պետք է նրա համար կանոն սահմանենք։ Յուրաքանչյուր կանոն կներկայացվի որպես մեկ CRD օբյեկտ: Ի՞նչ դաշտեր պետք է ունենա այս CRD-ը:
Ռեսուրսի տեսակը, որը մենք կփնտրենք (ConfigMap կամ Secret):
Անվանատարածքների ցանկ, որտեղ պետք է տեղակայվեն ռեսուրսները։
Ընտրիչ, որով մենք կփնտրենք ռեսուրսներ անունների տարածքում։
Պատրաստ. Հիմա մենք պետք է ինչ-որ կերպ տեղեկատվություն ստանանք մեր կանոնի մասին։ Թույլ տվեք անմիջապես վերապահել, որ մենք ինքներս հարցումներ չենք գրի կլաստերի API սերվերին: Դա անելու համար մենք կօգտագործենք պատրաստի Python գրադարանը kubernetes-հաճախորդ:
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')}
Այս կոդը գործարկելու արդյունքում մենք ստանում ենք հետևյալը.
Գերազանց. մեզ հաջողվեց կանոն ստանալ օպերատորի համար: Եվ ամենակարևորը, մենք արեցինք այն, ինչ կոչվում է Կուբերնետեսի ճանապարհ:
Շրջակա միջավայրի փոփոխականներ, թե՞ դրոշակներ: Մենք վերցնում ենք ամեն ինչ!
Եկեք անցնենք հիմնական օպերատորի կազմաձևին: Ծրագրերի կազմաձևման երկու հիմնական մոտեցում կա.
օգտագործել հրամանի տողի ընտրանքները;
օգտագործել շրջակա միջավայրի փոփոխականներ.
Հրամանի տողի ընտրանքները թույլ են տալիս ավելի ճկուն կարդալ կարգավորումները՝ տվյալների տիպի աջակցությամբ և վավերացումով: Python-ի ստանդարտ գրադարանն ունի մոդուլ argparser, որը մենք կօգտագործենք։ Նրա հնարավորությունների մանրամասներն ու օրինակները հասանելի են այստեղ պաշտոնական փաստաթղթեր.
Մեր դեպքում, այսպիսի տեսք կունենա հրամանի տողի դրոշների ընթերցման կարգաբերման օրինակը.
Մյուս կողմից, օգտագործելով շրջակա միջավայրի փոփոխականները Kubernetes-ում, դուք կարող եք հեշտությամբ փոխանցել ծառայության տեղեկատվությունը կոնտեյների ներսում գտնվող պատի մասին: Օրինակ, մենք կարող ենք տեղեկություններ ստանալ այն անվանատարածքի մասին, որտեղ աշխատում է pod-ը հետևյալ կառուցվածքով.
Հասկանալու համար, թե ինչպես կարելի է առանձնացնել ConfigMap-ի և 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),
]
}
)
NBPython-ի համար kubernetes հաճախորդն ունի իր սեփական տարբերակը: Հաճախորդի տարբերակների և 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"]
Ահա թե ինչպես, առանց վախի, կշտամբանքի կամ Go-ն սովորելու, մենք կարողացանք Python-ում կառուցել մեր սեփական օպերատորը Kubernetes-ի համար: Իհարկե, այն դեռ աճելու տեղ ունի. ապագայում այն կկարողանա մշակել բազմաթիվ կանոններ, աշխատել բազմաթիվ թելերով, ինքնուրույն վերահսկել իր CRD-ների փոփոխությունները...
Կոդին ավելի մոտիկից ծանոթանալու համար մենք այն տեղադրել ենք հանրային շտեմարան. Եթե ցանկանում եք Python-ի միջոցով իրականացվող ավելի լուրջ օպերատորների օրինակներ, կարող եք ձեր ուշադրությունը դարձնել mongodb-ի տեղակայման երկու օպերատորների վրա (первый и երկրորդ).
Հ.Գ. Իսկ եթե դուք չափազանց ծույլ եք զբաղվել Kubernetes-ի իրադարձություններով կամ պարզապես ավելի սովոր եք օգտագործել Bash-ը, ապա մեր գործընկերները պատրաստել են պատրաստի լուծում այս տեսքով. shell-օպերատոր (Մենք հայտարարեց ապրիլին):