Operator 开发实践 五 (多版本API)

编程入门 行业动态 更新时间:2024-10-23 05:51:17

Operator 开发实践 五 (多<a href=https://www.elefans.com/category/jswz/34/1771446.html style=版本API)"/>

Operator 开发实践 五 (多版本API)

一般情况下,开发一个新项目,它的API是会经常变更的,不管一开始考虑得多么详细,都避免不了迭代的过程中去修改API定义。过了一段时间后,API会趋于稳定,在达到稳定版本之后,可能才正式发布V1.0版本。当然,这个稳定版的API就不应该再变化了,到了下一个版本想增强一下这个API,可能需要发布V2.0版本,这时V1.0版本还是要能够继续正常工作。我们来看看Operator中是如何支持多版本API的。

实现V2版本API

先通过命令添加一个V2版本API:

# operator-sdk create api --group apps --version v2 --kind AtomCreate Resource [y/n]
y
Create Controller [y/n]
n
Writing kustomize manifests for you to edit...
Writing scaffold for you to edit...
api/v2/atom_types.go
Update dependencies:
$ go mod tidy
Running make:
$ make generate
test -s /Users/8lablw/Documents/atom-operator/bin/controller-gen && /Users/8lablw/Documents/atom-operator/bin/controller-gen --version | grep -q v0.11.1 || \GOBIN=/Users/8lablw/Documents/atom-operator/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.11.1
/Users/8lablw/Documents/atom-operator/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."
Next: implement your new API and generate the manifests (e.g. CRDs,CRs) with:
$ make manifests

需要注意的是这里不需要创建Controller

新增的文件有api/v2:

atom_types.go

groupversion_info.go

zz_generated.deepcopy.go

发生变化的文件有:

main.go

appsv2 "github/xiaowei6688/atom-operator/api/v2"func init() {utilruntime.Must(clientgoscheme.AddToScheme(scheme))utilruntime.Must(appsv1.AddToScheme(scheme))utilruntime.Must(appsv2.AddToScheme(scheme))//+kubebuilder:scaffold:scheme
}

PROJECT

- api:crdVersion: v1namespaced: truedomain: atomgroup: appskind: Atompath: github/xiaowei6688/atom-operator/api/v2version: v2

V2版本只用于演示多版本API,所以这里不添加多余功能。我们在 api/v2 目录下的atom_types.go文件中实现和V1版本完全一样的代码逻辑(除了package v2这一行有差异), 然后修改为如下:

type AtomSpec struct {// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster// Important: Run "make" to regenerate code after modifying this file// Foo is an example field of Atom. Edit atom_types.go to remove/updateDeployment  Deployment  `json:"deployment,omitempty"`Service     ServiceSpec `json:"service,omitempty"`Upgradeable bool        `json:"upgradeable,omitempty"`  // 这是V2新增的
}

创建V2的webhook

kubebuilder create webhook --group apps --version v2 --kind Atom --conversion

在V1版本内新增atom_conversion.go文件

package v1func (*Atom) Hub() {}

在V2版本内新增atom_conversion.go转换文件

package v2import (v1 "github/xiaowei6688/atom-operator/api/v1""sigs.k8s.io/controller-runtime/pkg/conversion"
)// ConvertTo converts this Atom v2 to the Hub version (v1).
func (src *Atom) ConvertTo(dstRaw conversion.Hub) error {dst := dstRaw.(*v1.Atom)// Convert ObjectMetadst.ObjectMeta = src.ObjectMeta// Convert Deploymentdst.Spec.Deployment.Replicas = src.Spec.Deployment.Replicasdst.Spec.Deployment.Selector = convertSelectorToV1(src.Spec.Deployment.Selector)dst.Spec.Deployment.Template.Metadata = src.Spec.Deployment.Template.Metadatadst.Spec.Deployment.Template.Spec.Containers = convertContainersToV1(src.Spec.Deployment.Template.Spec.Containers)// Convert Servicedst.Spec.Service = convertServiceSpecToV1(src.Spec.Service)// Convert Statusdst.Status = convertAtomStatusToV1(src.Status)return nil
}// ConvertFrom converts from the Hub version (v1) to this Atom v2.
func (dst *Atom) ConvertFrom(srcRaw conversion.Hub) error {src := srcRaw.(*v1.Atom)// Convert ObjectMetadst.ObjectMeta = src.ObjectMeta// Convert Deploymentdst.Spec.Deployment.Replicas = src.Spec.Deployment.Replicasdst.Spec.Deployment.Selector = convertSelectorFromV1(src.Spec.Deployment.Selector)dst.Spec.Deployment.Template.Metadata = src.Spec.Deployment.Template.Metadatadst.Spec.Deployment.Template.Spec.Containers = convertContainersFromV1(src.Spec.Deployment.Template.Spec.Containers)// Convert Servicedst.Spec.Service = convertServiceSpecFromV1(src.Spec.Service)// Convert Statusdst.Status = convertAtomStatusFromV1(src.Status)dst.Spec.Upgradeable = false // Default value as it's not in v1return nil
}// Helper function to convert AtomStatus from v2 to v1
func convertAtomStatusToV1(status AtomStatus) v1.AtomStatus {return v1.AtomStatus{Workflow: status.Workflow,Network:  status.Network,}
}// Helper function to convert AtomStatus from v1 to v2
func convertAtomStatusFromV1(status v1.AtomStatus) AtomStatus {return AtomStatus{Workflow: status.Workflow,Network:  status.Network,}
}// Helper function to convert ServiceSpec from v2 to v1
func convertServiceSpecToV1(service ServiceSpec) v1.ServiceSpec {return v1.ServiceSpec{Type:  service.Type,Ports: service.Ports, // 注意,如果 Ports 内部的字段在 v1 和 v2 之间有差异,可能需要为 Ports 也编写转换函数}
}// Helper function to convert ServiceSpec from v1 to v2
func convertServiceSpecFromV1(service v1.ServiceSpec) ServiceSpec {return ServiceSpec{Type:  service.Type,Ports: service.Ports, // 同上,注意检查 Ports 的字段}
}// Helper function to convert containers from v2 to v1
func convertContainersToV1(containers []PodCondition) []v1.PodCondition {v1Containers := make([]v1.PodCondition, len(containers))for i, container := range containers {v1Containers[i].Name = container.Namev1Containers[i].Image = container.Imagev1Containers[i].Ports = container.Ports}return v1Containers
}// Helper function to convert containers from v1 to v2
func convertContainersFromV1(containers []v1.PodCondition) []PodCondition {v2Containers := make([]PodCondition, len(containers))for i, container := range containers {v2Containers[i].Name = container.Namev2Containers[i].Image = container.Imagev2Containers[i].Ports = container.Ports}return v2Containers
}// Helper function to convert Selector from v2 to v1
func convertSelectorToV1(selector Selector) v1.Selector {return v1.Selector{MatchLabels: selector.MatchLabels,}
}// Helper function to convert Selector from v1 to v2
func convertSelectorFromV1(selector v1.Selector) Selector {return Selector{MatchLabels: selector.MatchLabels,}
}

修改main.go文件

//if err = (&appsv1.Atom{}).SetupWebhookWithManager(mgr); err != nil {//setupLog.Error(err, "unable to create webhook", "webhook", "Atom")//os.Exit(1)//}if os.Getenv("ENABLE_WEBHOOKS") != "false" {if err = (&appsv1.Atom{}).SetupWebhookWithManager(mgr); err != nil {setupLog.Error(err, "unable to create webhook", "webhook", "Atom")os.Exit(1)}if err = (&appsv2.Atom{}).SetupWebhookWithManager(mgr); err != nil {setupLog.Error(err, "unable to create webhook", "webhook", "Atom")os.Exit(1)}}

部署V2版本API

有了多个版本的API之后,我们在API Server中却只能持久化一个版本,这里依然选择持久化V1版本,但是需要在V1版本的Atom上增加一行注解(持久化哪个版本就在哪个版本加注解):

//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
//+kubebuilder:resource:path=atoms,singular=atom,scope=Namespaced,shortName=at
//+kubebuilder:storageversion// Atom is the Schema for the atoms API
type Atom struct {metav1.TypeMeta   `json:",inline"`metav1.ObjectMeta `json:"metadata,omitempty"`Spec   AtomSpec   `json:"spec,omitempty"`Status AtomStatus `json:"status,omitempty"`
}

至此,新版本就算完成了。这时应该添加一个Webhook用来接收API Server的conversion回调请求,之前已经配置过Webhook了,所以这里参考Operator 开发实践 四 (WebHook),配置好之后就可以开始部署测试多版本API了

打包镜像

make generate
make manifests
make docker-build IMG=atom-operator:v0.2
kind load docker-image atom-operator:v0.2 --name dev

部署CRD

# make installtest -s /Users/8lablw/Documents/atom-operator/bin/controller-gen && /Users/8lablw/Documents/atom-operator/bin/controller-gen --version | grep -q v0.11.1 || \GOBIN=/Users/8lablw/Documents/atom-operator/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.11.1
/Users/8lablw/Documents/atom-operator/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
test -s /Users/8lablw/Documents/atom-operator/bin/kustomize || { curl -Ss ".sh" | bash -s -- 4.3.0 /Users/8lablw/Documents/atom-operator/bin; }
/Users/8lablw/Documents/atom-operator/bin/kustomize build config/crd | kubectl apply -f -
customresourcedefinition.apiextensions.k8s.io/atoms.apps.atom created

部署Operator

# make deploy IMG=atom-operator:v0.2test -s /Users/8lablw/Documents/atom-operator/bin/controller-gen && /Users/8lablw/Documents/atom-operator/bin/controller-gen --version | grep -q v0.11.1 || \GOBIN=/Users/8lablw/Documents/atom-operator/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.11.1
/Users/8lablw/Documents/atom-operator/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
test -s /Users/8lablw/Documents/atom-operator/bin/kustomize || { curl -Ss ".sh" | bash -s -- 4.3.0 /Users/8lablw/Documents/atom-operator/bin; }
cd config/manager && /Users/8lablw/Documents/atom-operator/bin/kustomize edit set image controller=atom-operator:v0.2
/Users/8lablw/Documents/atom-operator/bin/kustomize build config/default | kubectl apply -f -
namespace/atom-operator-system created
customresourcedefinition.apiextensions.k8s.io/atoms.apps.atom configured
serviceaccount/atom-operator-controller-manager created

检查部署

# kubectl get pod -n atom-operator-systemNAME                                                READY   STATUS    RESTARTS   AGE
atom-operator-controller-manager-79b9dcb475-gqqj2   2/2     Running   0          3m26s

部署V2版本资源

准备v2 YAML资源文件

apiVersion: apps.atom/v2
kind: Atom
metadata:name: nginx-samplenamespace: defaultlabels:app: nginx
spec:deployment:replicas: 12selector:matchLabels:app: nginxtemplate:spec:containers:- name: nginximage: nginx:1.14.2ports:- containerPort: 80service:type: NodePortports:- name: nginx-httpport: 80targetPort: 80nodePort: 30080upgradeable: true
kubectl apply -f apps_v2_atom.yaml

此时replicas超过10,创建出现错误:admission webhook “vatom.kb.io” denied the request: replicas too many error。说明检测成功

将replicas改为2, 查看结果正常

default                nginx-sample-cbdccf466-mx9qg                   1/1     Running   0             31s
default                nginx-sample-cbdccf466-tmh9c                   1/1     Running   0             31s

至此,多版本API完成

更多推荐

Operator 开发实践 五 (多版本API)

本文发布于:2023-12-06 19:27:24,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1668574.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:版本   Operator   API

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!