ProHoster > Blog > yönetim > Çerçeveler ve SDK olmadan Python'da Kubernetes Operatörü
Çerçeveler ve SDK olmadan Python'da Kubernetes Operatörü
Go şu anda insanların Kubernetes için açıklamalar yazmak için seçtiği programlama dilleri üzerinde tekele sahip. Bunun nesnel nedenleri var:
Go'da operatörleri geliştirmek için güçlü bir çerçeve var - Operatör SDK'sı.
Docker ve Kubernetes gibi oyunun kurallarını değiştiren uygulamalar Go'da yazılmıştır. Operatörünüzü Go'da yazmak, ekosistemle aynı dili konuşmak anlamına gelir.
Go uygulamalarının yüksek performansı ve kullanıma hazır eşzamanlılıkla çalışmaya yönelik basit araçlar.
NB: Bu arada Go'da kendi ifadenizi nasıl yazacağınızı anlattık. zaten tanımlanmış Yabancı yazarlar tarafından yapılan çevirilerimizden birinde.
Peki ya zaman eksikliği ya da basitçe söylemek gerekirse motivasyon nedeniyle Go'yu öğrenmeniz engelleniyorsa? Makale, hemen hemen her DevOps mühendisinin bildiği en popüler dillerden birini kullanarak nasıl iyi bir ifade yazabileceğinize dair bir örnek sunmaktadır: Python.
Tanışın: Fotokopi Makinesi - fotokopi operatörü!
Örnek olarak, yeni bir ad alanı göründüğünde veya iki varlıktan biri değiştiğinde bir ConfigMap'i kopyalamak için tasarlanmış basit bir ifade geliştirmeyi düşünün: ConfigMap ve Secret. Pratik bir bakış açısına göre operatör, uygulama yapılandırmalarının toplu olarak güncellenmesi (ConfigMap'i güncelleyerek) veya gizli verilerin (örneğin, Docker Kayıt Defteri ile çalışmaya yönelik anahtarlar (ad alanına Secret eklenirken) güncellenmesi için yararlı olabilir.
Bu durumda, iyi bir operatörün sahip olması gerekenler:
Operatörle etkileşim kullanılarak gerçekleştirilir. Özel Kaynak Tanımları (bundan böyle CRD olarak anılacaktır).
Operatör yapılandırılabilir. Bunu yapmak için komut satırı bayraklarını ve ortam değişkenlerini kullanacağız.
Docker konteynerinin ve Helm grafiğinin yapısı, kullanıcıların operatörü Kubernetes kümelerine kolayca (kelimenin tam anlamıyla tek komutla) yükleyebileceği şekilde tasarlanmıştır.
CRD
Operatörün hangi kaynakları arayacağını, nereye bakacağını bilmesi için ona bir kural koymamız gerekiyor. Her kural tek bir CRD nesnesi olarak temsil edilecektir. Bu CRD'nin hangi alanları olmalıdır?
Kaynak tipiarayacağımız (ConfigMap veya Secret).
Ad alanlarının listesiKaynakların nerede bulunması gerektiği.
Hazır! Artık bir şekilde kuralımız hakkında bilgi almamız gerekiyor. Cluster API Server'a kendimiz istek yazmayacağız diye hemen rezervasyon yaptırayım. Bunu yapmak için hazır bir Python kütüphanesi kullanacağız. kubernetes istemcisi:
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')}
Bu kodun çalıştırılması sonucunda aşağıdakileri elde ederiz:
Harika: Operatör için bir kural almayı başardık. Ve en önemlisi Kubernetes yolu denilen şeyi yaptık.
Ortam değişkenleri mi yoksa bayraklar mı? Her şeyi alıyoruz!
Ana operatör konfigürasyonuna geçelim. Uygulamaları yapılandırmak için iki temel yaklaşım vardır:
komut satırı seçeneklerini kullanın;
ortam değişkenlerini kullanın.
Komut satırı seçenekleri, veri türü desteği ve doğrulamayla ayarları daha esnek bir şekilde okumanıza olanak tanır. Python'un standart kütüphanesinde bir modül var argparser, bunu kullanacağız. Yeteneklerinin ayrıntıları ve örnekleri şurada mevcuttur: resmi belgeler.
Bizim durumumuz için, komut satırı bayraklarının okunmasına ilişkin bir örnek şu şekilde görünecektir:
Öte yandan Kubernetes'teki ortam değişkenlerini kullanarak, konteynerin içindeki pod'a ilişkin servis bilgilerini kolaylıkla aktarabilirsiniz. Örneğin aşağıdaki yapıyla pod'un çalıştığı ad alanı hakkında bilgi alabiliriz:
ConfigMap ve Secret ile çalışma yöntemlerinin nasıl ayrılacağını anlamak için özel haritalar kullanacağız. Daha sonra nesneyi takip etmek ve oluşturmak için hangi yöntemlere ihtiyacımız olduğunu anlayabiliriz:
Daha sonra, API sunucusundan olayları almanız gerekir. Aşağıdaki gibi uygulayalım:
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)
Etkinliği aldıktan sonra, onu işlemenin ana mantığına geçiyoruz:
# Типы событий, на которые будем реагировать
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)
Ana mantık hazır! Şimdi tüm bunları tek bir Python paketinde paketlememiz gerekiyor. Dosyayı hazırlıyoruz setup.py, projeyle ilgili meta bilgileri buraya yazın:
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 için kubernetes istemcisinin kendi sürümü vardır. İstemci sürümleri ile Kubernetes sürümleri arasındaki uyumluluk hakkında daha fazla bilgiyi şu adreste bulabilirsiniz: uyumluluk matrisleri.
Artık projemiz şuna benziyor:
copyrator
├── copyrator
│ ├── cli.py # Логика работы с командной строкой
│ ├── constant.py # Константы, которые мы приводили выше
│ ├── load_crd.py # Логика загрузки CRD
│ └── operator.py # Основная логика работы оператора
└── setup.py # Оформление пакета
Docker ve Helm
Dockerfile inanılmaz derecede basit olacak: temel python-alpine imajını alın ve paketimizi kurun. Optimizasyonunu daha iyi zamanlara erteleyelim:
FROM python:3.7.3-alpine3.9
ADD . /app
RUN pip3 install /app
ENTRYPOINT ["copyrator"]
Bu sayede korkmadan, suçlamadan veya Go'yu öğrenmeden Python'da Kubernetes için kendi operatörümüzü oluşturabildik. Elbette hala büyüme alanı var: gelecekte birden fazla kuralı işleyebilecek, birden fazla iş parçacığında çalışabilecek, CRD'lerindeki değişiklikleri bağımsız olarak izleyebilecek...
Kodu daha yakından görebilmeniz için onu koyduk halka açık depo. Python kullanılarak uygulanan daha ciddi operatörlerin örneklerini istiyorsanız, mongodb () dağıtımı için dikkatinizi iki operatöre çevirebilirsiniz.ilk и ikinci).
Not: Kubernetes olaylarıyla ilgilenemeyecek kadar tembelseniz veya Bash'i kullanmaya daha alışkınsanız, meslektaşlarımız formda hazır bir çözüm hazırladılar. kabuk operatörü (Biz açıkladı Nisan ayında).