반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
Tags
- Pulumi
- operator
- Model Serving
- xdp
- Kubeflow
- serving
- Kopf
- knative
- argocd
- kubernetes operator
- seldon core
- Kubernetes
- Kubernetes 인증
- Litmus
- opensearch
- 카오스 엔지니어링
- tekton
- eBPF
- opentelemetry
- Continuous Deployment
- MLflow
- nginx ingress
- blue/green
- keda
- CI/CD
- 오퍼레이터
- CANARY
- mlops
- gitops
- Argo
Archives
- Today
- Total
Kubernetes 이야기
Kopf ( 예제 ) 본문
반응형
다음과 같은 CRD 가 존재한다고 가정한다. 해당 CRD는 Tomcat Service의 Replica와 Image 명을 활용하여 Deployment 객체와 Service 객체를 만드는 CRD이다.
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: appdeployments.kmaster8.com
spec:
group: kmaster8.com
names:
kind: AppDeployment
plural: appdeployments
singular: appdeployment
shortNames:
- ads
- ad
scope: Namespaced
versions:
- name: v1beta1
schema:
openAPIV3Schema:
properties:
spec:
properties:
replica:
type: integer
image:
type: string
svcPort:
type: integer
required:
- replica
- image
- svcPort
type: object
status:
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
served: true
storage: true
additionalPrinterColumns:
- name: replica
type: integer
jsonPath: .spec.replica
description: Replica
- name: image
type: string
jsonPath: .spec.image
description: Container Image
- name: svcPort
type: integer
jsonPath: .spec.svcPort
description: Service Port
이제 ads 에 해당하는 다음과 같이 CR 을 생성해 보자.
apiVersion: kmaster8.com/v1beta1
kind: AppDeployment
metadata:
name: app-sample
spec:
replica: 1
image: "nginx:1.22.1"
svcPort: 80
생성 된 CR을 조회하면 다음과 같다.
# k get ads -A
NAMESPACE NAME REPLICA IMAGE SVCPORT
test app-sample 1 nginx:1.22.1 80
이제 AppDeployment의 생성 및 수정에 대해 알아보자.
먼저 AppDeployment CR 을 생성되면 만들어지게 될 Deployment와 Service yaml 템플릿을 만들어보자.
[Deployment.yaml]
apiVersion: apps/v1
kind: Deployment
metadata:
name: {name}
spec:
selector:
matchLabels:
app: {name}
replicas: {replica}
template:
metadata:
labels:
app: container
spec:
containers:
- name: container
image: {image}
ports:
- containerPort: {svcPort}
[Service.yaml]
apiVersion: v1
kind: Service
metadata:
name: {name}
labels:
app: {name}
spec:
ports:
- name: svc-port
port: {svcPort}
protocol: TCP
selector:
app: {name}
on.create
import kopf
import yaml
import kubernetes.client
import os
@kopf.on.create('kmaster8.com', 'v1beta1', 'appdeployments')
def create_fn(spec, name, namespace, logger, **kwargs):
replica = spec.get('replica')
image = spec.get('image')
svcPort = spec.get('svcPort')
if not replica:
raise kopf.PermanentError(f"Replica must be set. Got {replica!r}.")
if not image:
raise kopf.PermanentError(f"Image must be set. Got {image!r}.")
if not svcPort:
raise kopf.PermanentError(f"svcPort must be set. Got {svcPort!r}.")
# deployment
path = os.path.join(os.path.dirname(__file__), 'deployment.yaml')
tmpl = open(path, 'rt').read()
text = tmpl.format(name=name, namnespace=namespace, replica=replica, image=image, svcPort=svcPort)
data = yaml.safe_load(text)
kopf.adopt(data)
api = kubernetes.client.AppsV1Api()
dep = api.create_namespaced_deployment(
namespace=namespace,
body=data,
)
logger.info(f"App Deployment child is created: {dep}")
# service
path = os.path.join(os.path.dirname(__file__), 'service.yaml')
tmpl = open(path, 'rt').read()
text = tmpl.format(name=name, namnespace=namespace, svcPort=svcPort)
data = yaml.safe_load(text)
kopf.adopt(data)
api = kubernetes.client.CoreV1Api()
svc = api.create_namespaced_service (
namespace=namespace,
body=data,
)
logger.info(f"App Deployment child is created: {svc}")
return {
'deployment': dep.metadata.name,
'service': svc.metadata.name
}
on.update
이제 생성된 deployment와 service 의 replica, image, port를 "2", "tomcat:9", "8080" 으로 변경하는 오퍼레이터를 만들어보자. ( 중요 코드만 살펴보자. )
@kopf.on.update('kmaster8.com', 'v1beta1', 'appdeployments')
def update_fn(spec, status, namespace, logger, **kwargs):
# deployment
deployment_name = status['create_fn']['deployment']
body = [
{"op": "replace", "path": "/spec/replicas", "value": replica},
{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value": image},
{"op": "replace", "path": "/spec/template/spec/containers/0/ports/0/containerPort", "value": svcPort},
]
api = kubernetes.client.AppsV1Api()
dep = api.patch_namespaced_deployment(
namespace=namespace,
name=deployment_name,
body=body,
)
# service
service_name = status['create_fn']['service']
body = [
{"op": "replace", "path": "/spec/ports/0/port", "value": svcPort},
]
api = kubernetes.client.CoreV1Api()
svc = api.patch_namespaced_service (
namespace=namespace,
name=service_name,
body=body,
)
on.field
Old & New
특정 필드의 값을 업데이트 하고자 하는 경우에는 on.field를 사용한다.
@kopf.on.field('kmaster8.com', 'v1beta1', 'appdeployments', field='metadata.labels')
def relabel(old, new, status, namespace, logger, **kwargs):
patch = {'metadata': {'labels': new}}
# deployment
deployment_name = status['create_fn']['deployment']
...
Diffs
개체의 상태를 추적하고 diff를 계산하는데 사용한다.
사용법은 다음과 같다.
((action, n-tuple of object or field path, old, new),)
예를들어,
(('add', ('metadata', 'labels', 'label1'), None, 'new-value'),
('change', ('metadata', 'labels', 'label2'), 'old-value', 'new-value'),
('remove', ('metadata', 'labels', 'label3'), 'old-value', None),
('change', ('spec', 'size'), '1G', '2G'))
다음의 코드를 보자.
@kopf.on.field('kmaster8.com', 'v1beta1', 'appdeployments', field='metadata.labels')
def diff_fn(diff, status, namespace, logger, **kwargs):
logger.info(diff)
annotation에 label을 추가하면
[실행결과]
(('add', (), None, {'app': 'test'}),)
반응형
'개발 > python' 카테고리의 다른 글
playwright를 활용한 e2e 테스트 (0) | 2023.02.15 |
---|---|
Python에서 gRPC 구현 (0) | 2023.02.13 |
Kopf (소개) (0) | 2023.02.03 |
Ubuntu에서 pipenv 실행 시 FileNotFoundError 오류 (0) | 2023.01.28 |
Loguru (0) | 2023.01.24 |
Comments