Go-แก แแแแแแแ แแฅแแก แแแแแแแแแ แแ แแแ แแแแ แแแแก แแแแแแ, แ แแแแแแกแแช แแแแแแแแแแ แแ แฉแแแแ Kubernetes-แแกแแแแก แแแแชแฎแแแแแแแแก แแแกแแฌแแ แแ. แแแแก แแแแแฅแขแฃแ แ แแแแแแแแ แแ แกแแแแแก, แแแแแแแแแ:
- แแ แกแแแแแก แซแแแแ แ แฉแแ แฉแ Go-แจแ แแแแ แแขแแ แแแแก แแแแแแแแ แแแแกแแแแก -
แแแแ แแขแแ แ SDK . - แแแแแจแแก แจแแแชแแแแแ แแแแแแแชแแแแ, แ แแแแ แแชแแ Docker แแ Kubernetes, แแฌแแ แแแ Go-แจแ. แแฅแแแแ แแแแ แแขแแ แแก Go-แจแ แฉแแฌแแ แ แแแจแแแแก แแแแกแแกแขแแแแกแแแ แแ แแกแ แแ แแแแแ แแแแแ แแแแแ แแแก.
- Go แแแแแแแชแแแแแก แแแฆแแแ แฌแแ แแแแแแ แแ แแแ แขแแแ แแแกแขแ แฃแแแแขแแแ แแแแแฃแ แแแขแฃแแแแ แแฃแจแแแแแกแแแแก.
NB: แกแฎแแแแ แจแแ แแก, แ แแแแ แแแฌแแ แแ แกแแแฃแแแ แ แแแแชแฎแแแแแ Go-แจแ, แฉแแแ
แแแแ แแ แ แ แแแฎแแแแ, แแฃ Go-แแก แกแฌแแแแแจแ แแ แแแก แแแแแแแแแ แแ, แแแ แขแแแแ แ แแ แแแฅแแแ, แแแขแแแแชแแ แจแแแแจแแแ แฎแแแก? แกแขแแขแแแจแ แแแชแแแฃแแแ แแแแแแแแ แแแแกแ, แแฃ แ แแแแ แจแแแแซแแแแ แแแฌแแ แแ แแแ แแ แแแแชแฎแแแแแ แแ แ-แแ แแ แงแแแแแแ แแแแฃแแแ แฃแแ แแแแก แแแแแงแแแแแแ, แ แแแแแแช แแแแฅแแแก แงแแแแ DevOps แแแแแแแ แแ แแชแแก - Python.
แจแแฎแแแแ: แฅแกแแ แแฅแกแ - แแแแแ แแแแก แแแแ แแขแแ แ!
แแแแแแแแแ, แแแแแฎแแแแ แแแ แขแแแ แแแแชแฎแแแแแแก แจแแแฃแจแแแแแ, แ แแแแแแช แจแแฅแแแแแแ ConfigMap-แแก แแแแแ แแแแกแแแแก, แแ แ แแแแกแแช แแแแแฉแแแแแ แแฎแแแ แกแแฎแแแแ แกแแแ แชแ, แแ แ แแแแกแแช แแชแแแแแ แแ แ แแ แแแฃแแแแแ แแ แแ: ConfigMap แแ Secret. แแ แแฅแขแแแฃแแ แแแแแกแแแ แแกแแ, แแแแ แแขแแ แ แจแแแซแแแแ แแงแแก แแแแแกแแแแแ แแแแแแแชแแแก แแแแคแแแฃแ แแชแแแแแก แแแกแแแ แแแ แแแแแฎแแแแแกแแแแก (ConfigMap-แแก แแแแแฎแแแแแ) แแ แกแแแแฃแแแ แแแแแชแแแแแแก แแแแแฎแแแแแกแแแแก - แแแแแแแแแ, Docker Registry-แแแ แแฃแจแแแแแก แแแกแแฆแแแแแ (แกแแแแฃแแแแแแแก แแแแแขแแแแกแแก แกแแฎแแแแ แกแแแ แชแแจแ).
แแฅแแแแ แแแแแแแแแแ แ, แ แ แฃแแแ แฐแฅแแแแแก แแแ แ แแแแ แแขแแ แก:
- แแแแ แแขแแ แแแ แฃแ แแแแ แแฅแแแแแแ แฎแแ แชแแแแแแแ แแแแแงแแแแแแ
แแแ แแแแฃแแ แ แแกแฃแ แกแแแแก แแแแแแ แขแแแแแ (แจแแแแแแแจแ CRD). - แแแแ แแขแแ แแก แแแแคแแแฃแ แแชแแ แจแแกแแซแแแแแแแ. แแแแกแแแแแก แฉแแแ แแแแแแแงแแแแแ แแ แซแแแแแแก แฎแแแแก แแ แแจแแแก แแ แแแ แแแแก แชแแแแแแแก.
- Docker แแแแขแแแแแ แแกแ แแ Helm แกแฅแแแแก แแแแกแขแ แฃแฅแชแแ แจแแฅแแแแแแ แแกแ, แ แแ แแแแฎแแแ แแแแแแก แจแแฃแซแแแแ แแแแแแแ (แกแแขแงแแแกแแขแงแแแ แแ แแ แแ แซแแแแแแ) แแแแแแกแขแแแแ แแ แแแแ แแขแแ แ แแแ Kubernetes แแแแกแขแแ แจแ.
CRD
แแแแกแแแแแก, แ แแ แแแแ แแขแแ แแ แแชแแแแก, แ แ แ แแกแฃแ แกแแแ แแแซแแแแแก แแ แกแแ แแซแแแแก, แฉแแแ แฃแแแ แแแแแแแแแแ แแแกแแแแก แฌแแกแ. แแแแแแฃแแ แฌแแกแ แฌแแ แแแแแแแแแ แแฅแแแแ แ แแแแ แช แแ แแ CRD แแแแแฅแขแ. แ แ แแแแแแ แฃแแแ แฐแฅแแแแแก แแ CRD-แก?
- แ แแกแฃแ แกแแก แขแแแ, แ แแแแแกแแช แฉแแแ แแแซแแแ (ConfigMap แแ Secret).
- แกแแฎแแแแ แกแแแ แชแแก แกแแ, แ แแแแแจแแช แฃแแแ แแงแแก แแแแแแแกแแแฃแแ แ แแกแฃแ แกแแแ.
- แจแแ แฉแแแ, แ แแแแแแแช แแแแแซแแแแ แ แแกแฃแ แกแแแก แกแแฎแแแแ แกแแแ แชแแจแ.
แแแแแ แแฆแแฌแแ แแ 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 แกแแ แแแ แแ. แแแแกแแแแแก แฉแแแ แแแแแแแงแแแแแ แแแ แแแแแแแก แแแแแแแแแแแก
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']}
แจแแกแแแแจแแแแแ: แฉแแแ แแแแแฎแแ แฎแแ แแแแ แแขแแ แแก แฌแแกแแก แแแฆแแแ. แแ แ แแช แแแแแแ แแ, แฉแแแ แแแแแแแแแ แแก, แ แแกแแช แแฃแแแ แแแขแแก แแแ แฐแฅแแแ.
แแแ แแแแก แชแแแแแแแ แแฃ แแ แแจแแแ? แฉแแแ แงแแแแแคแแ แก แแแฆแแแ!
แแแแแ แแแแแแแแแ แแแแแแ แ แแแแ แแขแแ แแก แแแแคแแแฃแ แแชแแแแ. แแแแแแแชแแแแแก แแแแคแแแฃแ แแชแแแก แแ แ แซแแ แแแแแ แแแแแแแ แแ แกแแแแแก:
- แแแแแแงแแแแ แแ แซแแแแแแก แฎแแแแก แแแ แแแแขแ แแแ;
- แแแแแแงแแแแ แแแ แแแแก แชแแแแแแแ.
แแ แซแแแแแแก แฎแแแแก แแแ แแแแขแแแ แกแแจแฃแแแแแแก แแแซแแแแ แฌแแแแแแฎแแ แแแ แแแแขแ แแแ แฃแคแ แ แแแฅแแแแแ, แแแแแชแแแแ แขแแแแก แแฎแแ แแแญแแ แแ แแ แแแแแกแขแฃแ แแแแ. แแแแแแแก แกแขแแแแแ แขแฃแ แแแแแแแแแแแก แแฅแแก แแแแฃแแ 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 แแฃแจแแแแก แจแแแแแแ แแแแกแขแ แฃแฅแชแแแ:
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)
แแแแแแ แ แแแแแแ แแแแแแ! แแฎแแ แแก แงแแแแแคแแ แ แฃแแแ แจแแแคแฃแแแ แแแแแแแก แแ แ แแแแแขแจแ. แฉแแแ แแแแแแแแแ แคแแแแก 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: Python-แแก kubernetes แแแแแแขแก แแฅแแก แกแแแฃแแแ แ แแแ แกแแ. แแแแแขแแแแแ แแแคแแ แแแชแแ แแแแแแขแแก แแแ แกแแแแกแ แแ Kubernetes แแแ แกแแแแก แจแแ แแก แแแแกแแแแแแแแก แจแแกแแฎแแ แจแแแแซแแแแ แแฎแแแแ แแฅ
แแฎแแ แฉแแแแ แแ แแแฅแขแ แแกแ แแแแแแงแฃแ แแแ:
copyrator
โโโ copyrator
โ โโโ cli.py # ะะพะณะธะบะฐ ัะฐะฑะพัั ั ะบะพะผะฐะฝะดะฝะพะน ัััะพะบะพะน
โ โโโ constant.py # ะะพะฝััะฐะฝัั, ะบะพัะพััะต ะผั ะฟัะธะฒะพะดะธะปะธ ะฒััะต
โ โโโ load_crd.py # ะะพะณะธะบะฐ ะทะฐะณััะทะบะธ CRD
โ โโโ operator.py # ะัะฝะพะฒะฝะฐั ะปะพะณะธะบะฐ ัะฐะฑะพัั ะพะฟะตัะฐัะพัะฐ
โโโ setup.py # ะัะพัะผะปะตะฝะธะต ะฟะฐะบะตัะฐ
แแแแแ แ แแ แฐแแแแ
Dockerfile แฌแแ แแแฃแแแแแแแ แแแ แขแแแ แแฅแแแแ: แแแฆแแ แซแแ แแแแแ แแแแแ-แแแแฃแ แ แกแฃแ แแแ แแ แแแแแแกแขแแแแ แแ แฉแแแแ แแแแแขแ. แแแแแ แแแแแแแแ แแแกแ แแแขแแแแแแชแแ แฃแแแแแก แแ แแแแ:
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 แแแแกแขแแ แแก แแแแแแแแแ? แแชแฎแแแแแแ แแแแแแแขแแก แแแแ แแขแแ แก "; - ยซ
Shell-แแแแ แแขแแ แแก แฌแแ แแแแแแแ: Kubernetes-แแกแแแแก แแแแ แแขแแ แแแแก แจแแฅแแแ แแฎแแแฎแแ แแแแแ แขแแแแ "; - ยซ
Kubernetes-แแก แแแคแแ แแแแแ แแ แจแแแกแแแ (แแแแแฎแแแแ แแ แแแแแ แแแแแ แแจแ) "; - ยซ
Kubernetes-แแกแแแแก แแแแ แแขแแ แแก แแแฌแแ แ แแแแแแแจแ "; - ยซ
แแแแ แแขแแ แแแ Kubernetes-แแกแแแแก: แ แแแแ แแแแฃแจแแแ แกแแฎแแแแฌแแคแ แแแแแแแชแแแแ ".
แฌแงแแ แ: www.habr.com