Дар айни замон Go монополияи забонҳои барномасозӣ дорад, ки одамон барои Kubernetes изҳорот менависанд. Сабабҳои объективии ин вуҷуд доранд, аз қабили:
- Барои таҳияи операторҳо дар Go як чаҳорчӯбаи пурқувват мавҷуд аст -
Оператор SDK . - Барномаҳои тағирёбандаи бозӣ ба монанди Docker ва Kubernetes дар Go навишта шудаанд. Навиштани оператори худ дар Go маънои бо экосистема бо як забон гап заданро дорад.
- Иҷрои баланди барномаҳои Go ва асбобҳои оддӣ барои кор бо ҳамзамон берун аз қуттӣ.
NB: Дар омади гап, баёноти худро дар Go чӣ гуна нависед, мо
Аммо чӣ мешавад, агар ба шумо нарасидани вақт ё ба таври оддӣ гӯем, ҳавасмандӣ монеъ шуда бошед? Дар мақола мисол оварда шудааст, ки чӣ гуна шумо метавонед бо истифода аз яке аз забонҳои маъмултарин, ки қариб ҳар як муҳандиси DevOps медонад, изҳороти хуб нависед - Python.
Вохӯред: нусхабардорӣ - оператори нусхабардорӣ!
Ҳамчун мисол, таҳияи изҳороти оддиеро, ки барои нусхабардории ConfigMap тарҳрезӣ шудааст ё ҳангоми пайдо шудани фазои нави ном ё ҳангоми тағир додани яке аз ду объект: ConfigMap ва Secret баррасӣ кунед. Аз нуқтаи назари амалӣ, оператор метавонад барои навсозии васеи конфигуратсияҳои барномаҳо (бо навсозии ConfigMap) ё барои навсозии маълумоти махфӣ муфид бошад - масалан, калидҳо барои кор бо Реестри Docker (ҳангоми илова кардани Сир ба фазои ном).
Ва ҳамин тавр, оператори хуб бояд чиро дошта бошад:
- Муносибати мутақобила бо оператор истифода бурда мешавад
Таърифҳои захираҳои фармоишӣ (минбаъд CRD номида мешавад). - Оператор метавонад танзим карда шавад. Барои ин, мо парчамҳои сатри фармон ва тағирёбандаҳои муҳити атрофро истифода мебарем.
- Сохтани контейнери Docker ва диаграммаи Helm тавре тарҳрезӣ шудааст, ки корбарон метавонанд ба осонӣ (аслан бо як фармон) операторро дар кластери Kubernetes худ насб кунанд.
CRD
Барои он ки оператор донад, ки кадом захираҳо ва ба куҷо нигоҳ кардан лозим аст, мо бояд барои ӯ қоида муқаррар кунем. Ҳар як қоида ҳамчун объекти ягонаи CRD муаррифӣ карда мешавад. Ин CRD бояд кадом соҳаҳоро дошта бошад?
- Навъи захираҳо, ки мо онро ҷустуҷӯ хоҳем кард (ConfigMap ё Secret).
- Рӯйхати фазоҳои ном, ки дар он захирахо бояд чойгир шаванд.
- Selector, ки тавассути он мо захираҳоро дар фазои ном ҷустуҷӯ хоҳем кард.
Биёед CRD-ро тавсиф кунем:
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: copyrator.flant.com
spec:
group: flant.com
versions:
- name: v1
served: true
storage: true
scope: Namespaced
names:
plural: copyrators
singular: copyrator
kind: CopyratorRule
shortNames:
- copyr
validation:
openAPIV3Schema:
type: object
properties:
ruleType:
type: string
namespaces:
type: array
items:
type: string
selector:
type: string
Ва мо онро фавран эҷод мекунем қоидаи оддӣ — барои ҷустуҷӯ дар фазои ном бо ном default
ҳама ConfigMap бо тамғакоғазҳо ба монанди copyrator: "true"
:
apiVersion: flant.com/v1
kind: CopyratorRule
metadata:
name: main-rule
labels:
module: copyrator
ruleType: configmap
selector:
copyrator: "true"
namespace: default
Тайёр! Акнун мо бояд бо кадом роҳе дар бораи қоидаи худ маълумот гирем. Иҷозат диҳед фавран фармоиш диҳам, ки мо худамон ба сервери кластери API дархост наменависем. Барои ин мо аз китобхонаи тайёри Python истифода мебарем
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')}
Дар натиҷаи иҷро кардани ин код, мо инҳоро мегирем:
{'ruleType': 'configmap', 'selector': {'copyrator': 'true'}, 'namespace': ['default']}
Аҷоиб: мо тавонистем барои оператор як қоида ба даст орем. Ва муҳимтар аз ҳама, мо он чизеро кардем, ки роҳи Кубернетес номида мешавад.
Тағйирёбандаҳои муҳити зист ё парчамҳо? Мо ҳама чизро мегирем!
Биёед ба конфигуратсияи асосии оператор гузарем. Барои танзими барномаҳо ду равиши асосӣ вуҷуд дорад:
- имконоти сатри фармонро истифода баред;
- тағйирёбандаҳои муҳити зистро истифода баред.
Имконоти сатри фармон ба шумо имкон медиҳанд, ки танзимотро бо дастгирӣ ва тасдиқи навъи маълумот чандиртар хонед. Китобхонаи стандартии Python дорои модул мебошад argparser
, ки мо онро истифода мебарем. Тафсилот ва намунаҳои қобилиятҳои он дар
Барои ҳолати мо, ин аст, ки намунаи насб кардани парчамҳои сатри фармон чунин хоҳад буд:
parser = ArgumentParser(
description='Copyrator - copy operator.',
prog='copyrator'
)
parser.add_argument(
'--namespace',
type=str,
default=getenv('NAMESPACE', 'default'),
help='Operator Namespace'
)
parser.add_argument(
'--rule-name',
type=str,
default=getenv('RULE_NAME', 'main-rule'),
help='CRD Name'
)
args = parser.parse_args()
Аз тарафи дигар, бо истифода аз тағирёбандаҳои муҳити зист дар Kubernetes, шумо метавонед ба осонӣ маълумоти хидматрасониро дар бораи pod дар дохили контейнер интиқол диҳед. Масалан, мо метавонем дар бораи фазои номе, ки дар он pod бо сохти зерин кор мекунад, маълумот гирем:
env:
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
Мантиқи оператор
Барои фаҳмидани тарзи ҷудо кардани усулҳои кор бо ConfigMap ва Secret, мо харитаҳои махсусро истифода мебарем. Он гоҳ мо метавонем фаҳмем, ки кадом усулҳо барои пайгирӣ ва сохтани объект ба мо лозим аст:
LIST_TYPES_MAP = {
'configmap': 'list_namespaced_config_map',
'secret': 'list_namespaced_secret',
}
CREATE_TYPES_MAP = {
'configmap': 'create_namespaced_config_map',
'secret': 'create_namespaced_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),
]
}
)
NB: Мизоҷи kubernetes барои Python версияи худро дорад. Маълумоти бештарро дар бораи мутобиқат байни версияҳои муштарӣ ва версияҳои 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"]
Ҷойгиркунӣ барои оператор низ хеле содда аст:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Chart.Name }}
spec:
selector:
matchLabels:
name: {{ .Chart.Name }}
template:
metadata:
labels:
name: {{ .Chart.Name }}
spec:
containers:
- name: {{ .Chart.Name }}
image: privaterepo.yourcompany.com/copyrator:latest
imagePullPolicy: Always
args: ["--rule-type", "main-rule"]
env:
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
serviceAccountName: {{ .Chart.Name }}-acc
Ниҳоят, шумо бояд нақши мувофиқро барои оператор бо ҳуқуқҳои зарурӣ эҷод кунед:
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ .Chart.Name }}-acc
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: {{ .Chart.Name }}
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "watch", "list"]
- apiGroups: [""]
resources: ["secrets", "configmaps"]
verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: {{ .Chart.Name }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ .Chart.Name }}
subjects:
- kind: ServiceAccount
name: {{ .Chart.Name }}
Натиҷа
Ҳамин тавр, мо бидуни тарсу ҳарос, сарзаниш ё омӯзиши Go, мо тавонистем оператори худро барои Kubernetes дар Python созем. Албатта, он ҳоло ҳам ҷой барои афзоиш дорад: дар оянда вай метавонад қоидаҳои сершуморро коркард кунад, дар риштаҳои гуногун кор кунад, тағиротро дар CRD-ҳои худ мустақилона назорат кунад...
Барои он ки ба шумо бодиққат назар андозем, мо онро ба он дохил кардем
PS Ва агар шумо барои мубориза бо рӯйдодҳои Kubernetes танбал бошед ё шумо ба истифодаи Bash бештар одат карда бошед, ҳамкорони мо дар шакл ҳалли тайёрро омода кардаанд.
PPS
Инчунин дар блоги мо хонед:
- «
Оё омода кардани кластери Kubernetes осон ва қулай аст? Эълони addon-operator »; - «
Муаррифии shell-operator: сохтани операторҳо барои Kubernetes осонтар шуд »; - «
Васеъ ва пурра кардани Kubernetes (баррасӣ ва гузориши видеоӣ) »; - «
Навиштани оператор барои Kubernetes дар Голанг »; - «
Операторҳо барои Kubernetes: чӣ гуна иҷро кардани барномаҳои давлатӣ ".
Манбаъ: will.com