Python-dagi Kubernetes operatori ramkalar va SDKsiz
Go hozirda odamlar Kubernetes uchun bayonot yozishni tanlaydigan dasturlash tillarida monopoliyaga ega. Buning ob'ektiv sabablari bor, masalan:
Go'da operatorlarni ishlab chiqish uchun kuchli ramka mavjud - Operator SDK.
Docker va Kubernetes kabi o'yinni o'zgartiruvchi ilovalar Go'da yozilgan. Go'da operatoringizni yozish ekotizim bilan bir xil tilda gaplashishni anglatadi.
Go ilovalarining yuqori unumdorligi va parallellik bilan ishlash uchun oddiy vositalar.
NB: Aytgancha, Go'da o'z bayonotingizni qanday yozish kerak, biz allaqachon tasvirlangan xorijlik mualliflarning tarjimalarimizdan birida.
Ammo vaqt yo'qligi yoki oddiy qilib aytganda, motivatsiya tufayli borishni o'rganishga to'sqinlik qilsa-chi? Maqolada deyarli har bir DevOps muhandisi biladigan eng mashhur tillardan birini ishlatib, qanday qilib yaxshi bayonot yozishingiz mumkinligiga misol keltirilgan - Python.
Misol sifatida, yangi nom maydoni paydo bo'lganda yoki ikkita ob'ektdan biri o'zgarganda ConfigMap-ni nusxalash uchun mo'ljallangan oddiy bayonotni ishlab chiqishni ko'rib chiqing: ConfigMap va Secret. Amaliy nuqtai nazardan, operator dastur konfiguratsiyasini ommaviy yangilash (ConfigMap-ni yangilash orqali) yoki maxfiy ma'lumotlarni yangilash uchun foydali bo'lishi mumkin - masalan, Docker Registry bilan ishlash uchun kalitlar (nomlar maydoniga Secret qo'shganda).
Va shunday qilib, yaxshi operator nima bo'lishi kerak:
Operator bilan o'zaro aloqalar yordamida amalga oshiriladi Maxsus manba ta'riflari (keyingi o'rinlarda CRD deb yuritiladi).
Operatorni sozlash mumkin. Buning uchun biz buyruq qatori bayroqlari va muhit o'zgaruvchilaridan foydalanamiz.
Docker konteyneri va Helm diagrammasi foydalanuvchilar operatorni Kubernetes klasteriga osongina o'rnatishlari uchun (so'zma-so'z bitta buyruq bilan) yaratilgan.
CRD
Operator qanday resurslarni izlash va qaerga qarash kerakligini bilishi uchun biz unga qoida o'rnatishimiz kerak. Har bir qoida bitta CRD obyekti sifatida taqdim etiladi. Ushbu CRD qanday maydonlarga ega bo'lishi kerak?
Resurs turi, biz qidiramiz (ConfigMap yoki Secret).
Nom maydonlari ro'yxati, unda resurslar joylashishi kerak.
Selektor, bu orqali biz nomlar maydonida resurslarni qidiramiz.
Tayyor! Endi biz qandaydir tarzda bizning qoidamiz haqida ma'lumot olishimiz kerak. Darhol band qilishimga ruxsat bering, biz o'zimiz klaster API serveriga so'rov yozmaymiz. Buning uchun biz tayyor Python kutubxonasidan foydalanamiz kubernetes-mijoz:
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')}
Ushbu kodni ishga tushirish natijasida biz quyidagilarni olamiz:
Ajoyib: biz operator uchun qoida olishga muvaffaq bo'ldik. Va eng muhimi, biz Kubernetes usuli deb ataladigan narsani qildik.
Atrof-muhit o'zgaruvchilari yoki bayroqlar? Biz hamma narsani olamiz!
Keling, asosiy operator konfiguratsiyasiga o'tamiz. Ilovalarni sozlashning ikkita asosiy usuli mavjud:
buyruq qatori parametrlaridan foydalanish;
muhit o'zgaruvchilardan foydalaning.
Buyruqlar qatori opsiyalari maʼlumotlar turini qoʻllab-quvvatlash va tekshirish yordamida sozlamalarni yanada moslashuvchan oʻqish imkonini beradi. Python standart kutubxonasida modul mavjud argparser, biz foydalanamiz. Uning imkoniyatlari haqida batafsil ma'lumot va misollar mavjud rasmiy hujjatlar.
Bizning holatimizda buyruq qatori bayroqlarini o'qish misoli quyidagicha ko'rinadi:
Boshqa tomondan, Kubernetes-dagi muhit o'zgaruvchilari yordamida siz konteyner ichidagi pod haqida xizmat ma'lumotlarini osongina uzatishingiz mumkin. Masalan, biz quyidagi konstruktsiya bilan pod ishlayotgan nomlar maydoni haqida ma'lumot olishimiz mumkin:
ConfigMap va Secret bilan ishlash usullarini qanday ajratish kerakligini tushunish uchun biz maxsus xaritalardan foydalanamiz. Keyin ob'ektni kuzatish va yaratish uchun qanday usullar kerakligini tushunishimiz mumkin:
Keyinchalik, API serveridan voqealarni qabul qilishingiz kerak. Keling, buni quyidagicha amalga oshiramiz:
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)
Hodisani olgandan so'ng, biz uni qayta ishlashning asosiy mantig'iga o'tamiz:
# Типы событий, на которые будем реагировать
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)
Asosiy mantiq tayyor! Endi biz bularning barchasini bitta Python paketiga to'plashimiz kerak. Biz faylni tayyorlaymiz setup.py, u erda loyiha haqida meta-ma'lumot yozing:
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 uchun kubernetes mijozi o'z versiyasiga ega. Mijoz versiyalari va Kubernetes versiyalari o'rtasidagi muvofiqlik haqida qo'shimcha ma'lumotni quyidagi havolada topishingiz mumkin muvofiqlik matritsalari.
Endi bizning loyihamiz quyidagicha ko'rinadi:
copyrator
├── copyrator
│ ├── cli.py # Логика работы с командной строкой
│ ├── constant.py # Константы, которые мы приводили выше
│ ├── load_crd.py # Логика загрузки CRD
│ └── operator.py # Основная логика работы оператора
└── setup.py # Оформление пакета
Docker va Helm
Dockerfile nihoyatda sodda bo'ladi: asosiy python-alp tasvirini oling va paketimizni o'rnating. Keling, uni optimallashtirishni yaxshiroq vaqtga qoldiramiz:
FROM python:3.7.3-alpine3.9
ADD . /app
RUN pip3 install /app
ENTRYPOINT ["copyrator"]
Shunday qilib, qo'rqmasdan, tanbehsiz yoki Go-ni o'rganmasdan, biz Python-da Kubernetes uchun o'z operatorimizni yaratishga muvaffaq bo'ldik. Albatta, u hali o'sishi uchun joy bor: kelajakda u bir nechta qoidalarni qayta ishlash, bir nechta iplarda ishlash, o'z CRDlaridagi o'zgarishlarni mustaqil ravishda kuzatish imkoniyatiga ega bo'ladi...
Kodni batafsil ko'rib chiqish uchun biz uni kiritdik jamoat ombori. Agar siz Python yordamida amalga oshirilgan jiddiyroq operatorlarga misollar olishni istasangiz, e'tiboringizni mongodb-ni joylashtirish uchun ikkita operatorga qaratishingiz mumkin (первый и ikkinchi).
PS Va agar siz Kubernetes voqealari bilan shug'ullanish uchun juda dangasa bo'lsangiz yoki oddiygina Bash-dan foydalanishga odatlangan bo'lsangiz, bizning hamkasblarimiz shaklda tayyor echimni tayyorladilar. qobiq operatori (Biz e'lon qilindi aprelda).