{"id":21008008,"url":"https://github.com/lflxp/operator-sdk-study","last_synced_at":"2025-10-27T13:33:15.975Z","repository":{"id":150080868,"uuid":"265186436","full_name":"lflxp/operator-sdk-study","owner":"lflxp","description":"study operator-sdk framework","archived":false,"fork":false,"pushed_at":"2020-05-20T12:51:38.000Z","size":67,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-20T10:48:27.503Z","etag":null,"topics":["golang","kubebuilder","operator-sdk"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lflxp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-19T08:13:57.000Z","updated_at":"2020-05-19T10:28:16.000Z","dependencies_parsed_at":"2023-06-05T03:15:24.396Z","dependency_job_id":null,"html_url":"https://github.com/lflxp/operator-sdk-study","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lflxp%2Foperator-sdk-study","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lflxp%2Foperator-sdk-study/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lflxp%2Foperator-sdk-study/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lflxp%2Foperator-sdk-study/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lflxp","download_url":"https://codeload.github.com/lflxp/operator-sdk-study/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243428437,"owners_count":20289318,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang","kubebuilder","operator-sdk"],"created_at":"2024-11-19T09:11:09.798Z","updated_at":"2025-10-27T13:33:15.906Z","avatar_url":"https://github.com/lflxp.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 命令合集\n\n* operator-sdk \n* operator-sdk version 查看版本\n* operator-sdk new cmdbdemo 新建项目\n* operator-sdk add api --api-version=app.example.com/v1 --kind=CmdbService 定义新的api CRD\n* operator-sdk add controller --api-version=app.example.com/v1 --kind=CmdbService 定义CRD的执行逻辑\n* operator-sdk generate k8s 自动生成代码\n\n# 部署\n\n* operator-sdk build cnych/opdemo # 应用打包成docker镜像\n* docker push cnych/opdemo # 镜像构建成功后，推送到 docker hub\n* sed -i 's|REPLACE_IMAGE|cnych/opdemo|g' deploy/operator.yaml # 修改镜像地址更新Operator的资源清单\n* kubectl create -f deploy/service_account.yaml # 创建对应的 RBAC 的对象 Setup Service Account\n* kubectl create -f deploy/role.yaml # Setup RBAC\n* kubectl create -f deploy/role_binding.yaml S# etup RBAC\n* kubectl apply -f deploy/crds/app_v1_appservice_crd.yaml # Setup the CRD\n* kubectl create -f deploy/operator.yaml # Deploy the Operator\n* kubectl create -f deploy/crds/app_v1_appservice_cr.yaml # 业务逻辑部署\n\n# 清理\n\n```sh\n$ kubectl delete -f deploy/crds/app_v1_appservice_cr.yaml\n$ kubectl delete -f deploy/operator.yaml\n$ kubectl delete -f deploy/role.yaml\n$ kubectl delete -f deploy/role_binding.yaml\n$ kubectl delete -f deploy/service_account.yaml\n$ kubectl delete -f deploy/crds/app_v1_appservice_crd.yaml\n```\n\n# 开发调试\n\n\u003e operator-sdk run --local\n➜  cmdbdemo git:(master) operator-sdk version    \noperator-sdk version: \"v0.17.0\", commit: \"2fd7019f856cdb6f6618e2c3c80d15c3c79d1b6c\", kubernetes version: \"unknown\", go version: \"go1.13.10 linux/amd64\"\n\n# 核心代码\n\n```go\n// Reconcile reads that state of the cluster for a CmdbService object and makes changes based on the state read\n// and what is in the CmdbService.Spec\n// TODO(user): Modify this Reconcile function to implement your Controller logic.  This example creates\n// a Pod as an example\n// Note:\n// The Controller will requeue the Request to be processed again if the returned error is non-nil or\n// Result.Requeue is true, otherwise upon completion it will remove the work from the queue.\nfunc (r *ReconcileCmdbService) Reconcile(request reconcile.Request) (reconcile.Result, error) {\n\treqLogger := log.WithValues(\"Request.Namespace\", request.Namespace, \"Request.Name\", request.Name)\n\treqLogger.Info(\"Reconciling CmdbService\")\n\n\t// Fetch the CmdbService instance\n\tinstance := \u0026appv1.CmdbService{}\n\terr := r.client.Get(context.TODO(), request.NamespacedName, instance)\n\tif err != nil {\n\t\tif errors.IsNotFound(err) {\n\t\t\t// Request object not found, could have been deleted after reconcile request.\n\t\t\t// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.\n\t\t\t// Return and don't requeue\n\t\t\treturn reconcile.Result{}, nil\n\t\t}\n\t\t// Error reading the object - requeue the request.\n\t\treturn reconcile.Result{}, err\n\t}\n\n\tif instance.DeletionTimestamp != nil {\n\t\treturn reconcile.Result{}, err\n\t}\n\n\tdeploy := \u0026appsv1.Deployment{}\n\tif err := r.client.Get(context.TODO(), request.NamespacedName, deploy); err != nil \u0026\u0026 errors.IsNotFound(err) {\n\t\t// 创建关联资源\n\t\t// 1. 创建Deploy\n\t\tdeploy := resources.NewDeploy(instance)\n\t\tif err := r.client.Create(context.TODO(), deploy); err != nil {\n\t\t\treturn reconcile.Result{}, err\n\t\t}\n\t\t// 2. 创建 Service\n\t\tservice := resources.NewService(instance)\n\t\tif err := r.client.Create(context.TODO(), service); err != nil {\n\t\t\treturn reconcile.Result{}, err\n\t\t}\n\t\t// 3. 关联 Annotations\n\t\tdata, err := json.Marshal(instance.Spec)\n\t\tif err != nil {\n\t\t\t// fmt.Println(\"1111111111111111111\", err.Error())\n\t\t\treturn reconcile.Result{}, err\n\t\t}\n\n\t\tif instance.Annotations != nil {\n\t\t\t// fmt.Println(\"333333333333333333333\", string(data))\n\t\t\tinstance.Annotations[\"spec\"] = string(data)\n\t\t} else {\n\t\t\t// fmt.Println(\"44444444444444444444444\", map[string]string{\"spec\": string(data)})\n\t\t\tinstance.Annotations = map[string]string{\"spec\": string(data)}\n\t\t}\n\t\t// 4. 更新 CmdbSerivce\n\t\tif err := r.client.Update(context.TODO(), instance); err != nil {\n\t\t\treturn reconcile.Result{}, err\n\t\t}\n\t\treturn reconcile.Result{}, nil\n\t}\n\n\toldspec := \u0026appv1.CmdbService{}\n\t// fmt.Println(\"55555555555555\", instance.Annotations[\"spec\"])\n\tif err := json.Unmarshal([]byte(instance.Annotations[\"spec\"]), oldspec); err != nil {\n\t\t// data, _ := json.Marshal(instance)\n\t\t// fmt.Println(\"222222222222222222\", err.Error(), string(data))\n\t\treturn reconcile.Result{}, err\n\t}\n\n\tif !reflect.DeepEqual(instance.Spec, oldspec) {\n\t\t// 更新关联资源\n\t\t// Deployment\n\t\tnewDeploy := resources.NewDeploy(instance)\n\t\toldDeploy := \u0026appsv1.Deployment{}\n\t\tif err := r.client.Get(context.TODO(), request.NamespacedName, oldDeploy); err != nil {\n\t\t\treturn reconcile.Result{}, err\n\t\t}\n\n\t\toldDeploy.Spec = newDeploy.Spec\n\t\tif err := r.client.Update(context.TODO(), oldDeploy); err != nil {\n\t\t\treturn reconcile.Result{}, err\n\t\t}\n\n\t\t// Service\n\t\tnewService := resources.NewService(instance)\n\t\toldService := \u0026corev1.Service{}\n\t\tif err := r.client.Get(context.TODO(), request.NamespacedName, oldService); err != nil {\n\t\t\treturn reconcile.Result{}, err\n\t\t}\n\n\t\toldService.Spec = newService.Spec\n\t\tif err := r.client.Update(context.TODO(), oldService); err != nil {\n\t\t\treturn reconcile.Result{}, err\n\t\t}\n\n\t\treturn reconcile.Result{}, nil\n\t}\n\n\treturn reconcile.Result{}, nil\n\n\t// // Define a new Pod object\n\t// pod := newPodForCR(instance)\n\n\t// // Set CmdbService instance as the owner and controller\n\t// if err := controllerutil.SetControllerReference(instance, pod, r.scheme); err != nil {\n\t// \treturn reconcile.Result{}, err\n\t// }\n\n\t// // Check if this Pod already exists\n\t// found := \u0026corev1.Pod{}\n\t// err = r.client.Get(context.TODO(), types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace}, found)\n\t// if err != nil \u0026\u0026 errors.IsNotFound(err) {\n\t// \treqLogger.Info(\"Creating a new Pod\", \"Pod.Namespace\", pod.Namespace, \"Pod.Name\", pod.Name)\n\t// \terr = r.client.Create(context.TODO(), pod)\n\t// \tif err != nil {\n\t// \t\treturn reconcile.Result{}, err\n\t// \t}\n\n\t// \t// Pod created successfully - don't requeue\n\t// \treturn reconcile.Result{}, nil\n\t// } else if err != nil {\n\t// \treturn reconcile.Result{}, err\n\t// }\n\n\t// // Pod already exists - don't requeue\n\t// reqLogger.Info(\"Skip reconcile: Pod already exists\", \"Pod.Namespace\", found.Namespace, \"Pod.Name\", found.Name)\n\t// return reconcile.Result{}, nil\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flflxp%2Foperator-sdk-study","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flflxp%2Foperator-sdk-study","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flflxp%2Foperator-sdk-study/lists"}