This commit is contained in:
yinkanglong
2023-08-18 08:55:09 +08:00
parent 4b7d682c67
commit 498eb76a3d
11 changed files with 421 additions and 13 deletions

View File

@@ -18,7 +18,7 @@ CRD+Controller=decalartive API声明式 API 设计是 kubernetes 重要的设
![](https://img-blog.csdnimg.cn/img_convert/2a84e949bd4662fc61943f27ee67f0bc.png)
![](image/2023-08-17-21-25-59.png)
## 开发方案

View File

@@ -33,7 +33,7 @@ go mod init contollers.happyhacker.io
2. 定义crd所属的domain生成一个工程.定义 crd 所属的 domain这个指令会帮助你生成一个工程。
```
kubebuilder init --domain controller.daocloud.io --license apache2 --owner "Holder"
kubebuilder init --domain estom.com --license apache2 --owner "Estom"
```
创建后的目录结构如下:

View File

@@ -331,3 +331,7 @@ kubectl get cronjobs.v1.batch.tutorial.kubebuilder.io -o yaml
显然get命令得到的v1和v2版本的cronjob会存在一些字段上的不同conversion webhook会负责进行不同版本的cronjob之间的数据转换。
## 原理解读
### manager

View File

@@ -0,0 +1,241 @@
# Client-go
## 简介
client-go是对K8s集群的二次开发工具所以client-go是k8s开发者的必备工具之一。client-go实现对kubernetes集群中资源对象包括deployment、service、ingress、replicaSet、pod、namespace、node等的增删改查等操作。
client-go主要提供了四种类型的客户端
1. RESTClient 是对HTTP Request进行了封装实现了RESTful风格的API。其他客户端都是在RESTClient基础上的实现。可与用于k8s内置资源和CRD资源
2. ClientSet:是对k8s内置资源对象的客户端的集合默认情况下不能操作CRD资源但是通过client-gen代码生成的话也是可以操作CRD资源的。
3. DynamicClient:不仅能对K8S内置资源进行处理还可以对CRD资源进行处理不需要client-gen生成代码即可实现。
4. DiscoveryClient用于发现kube-apiserver所支持的资源组、资源版本、资源信息即Group、Version、Resources
### RestClient
RESTClient是对HTTP Request 进行了封装是实现了RESTful风格的API封装。
```go
package main
import (
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes/scheme"
)
func main() {
//RESTCLIENT
//config
config, err := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile)
if err != nil {
panic(err)
}
config.GroupVersion = &v1.SchemeGroupVersion
config.NegotiatedSerializer = scheme.Codecs
config.APIPath = "/api"
//client
restClient, err := rest.RESTClientFor(config)
if err != nil {
panic(err)
}
//get data
pod := v1.Pod{}
err = restClient.Get().Namespace("default").Resource("pods").Name("test").Do(context.TODO()).Into(&pod)
if err != nil {
println(err)
}else {
println(pod.Name)
}
}
```
### clientSet
ClientSet客户端默认是对k8s内置资源对象客户端的集合通过ClientSet客户端可以操作k8s的内置资源对象。
```go
package main
import (
"context"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
//clientset
config, err := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile)
if err != nil {
panic(err)
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err)
}
pod, err := clientset.CoreV1().Pods("default").Get(context.TODO(), "test", v1.GetOptions{})
if err != nil {
println(err)
}else {
println(pod.Name)
}
}
```
### DynamicClient
DynamicClient的特点就是除了可以使用k8s内置资源外还可以使用CRD资源。dynamicClient的原理就是传入的资源数据都是使用map[string]interface{}结构。dynamicClient内部还是restClient.
```go
package main
import (
"context"
"fmt"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/tools/clientcmd"
)
func getDynamicClientExample(kubeconfig string) {
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
panic(err)
}
client, err := dynamic.NewForConfig(config)
if err != nil {
panic(err)
}
deployment := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "demo-deployment",
},
"spec": map[string]interface{}{
"replicas": 2,
"selector": map[string]interface{}{
"matchLabels": map[string]interface{}{
"app": "demo",
},
},
"template": map[string]interface{}{
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"app": "demo",
},
},
"spec": map[string]interface{}{
"containers": []map[string]interface{}{
{
"name": "web",
"image": "nginx:1.12",
"ports": []map[string]interface{}{
{
"name": "http",
"protocol": "TCP",
"containerPort": 80,
},
},
},
},
},
},
},
},
}
deploymentRes := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"}
ctx := context.Background()
// Create Deployment
fmt.Println("Creating deployment...")
result, err := client.Resource(deploymentRes).Namespace("default").Create(ctx,deployment, v1.CreateOptions{})
if err != nil {
panic(err)
}
fmt.Printf("Created deployment %q.\n", result.GetName())
}
```
### DiscoveryClient
DiscoveryClient是发现客户端主要用于发现k8s api-server所支持的资源组、资源版本及资源信息。
```go
package main
import (
"fmt"
"k8s.io/client-go/discovery"
"k8s.io/client-go/tools/clientcmd"
)
func getDisCoveryClient(kubeconfig string) {
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
panic(err)
}
discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)
if err != nil {
panic(err)
}
_, APIResourceList, err := discoveryClient.ServerGroupsAndResources()
if err != nil {
panic(err)
}
for _, list := range APIResourceList {
fmt.Println(list)
}
}
```
## 2 Informer机制
informer在kubernetes系统中保证各个组件之间消息的实时性、可靠性、顺序性等。k8s各组件通过client-go的informer机制与k8s apiserver通信。
Informercontroller机制的基础循环处理object对象从Reflector取出数据然后将数据给到Indexer去缓存提供对象事件的handler接口
Informer机制中的ListAndWatch、DeltaFIFO队列和Indexer等对于实现以上特性非常重要。下面这张图就是Informer机制运行原理图
![](image/2023-08-17-21-36-33.png)
起点是自定义的ControllerController会通过ListAndWatch机制从apiserver获取感兴趣的资源对象信息初始化controller时会指定感兴趣资源对象的List和watch方法。controller的内部包含了reflector和DeltaFIFOcontroller就是通过reflector中的list和watch将资源对象信息装入DeltaFIFO队列然后Controller会一直尝试从队列中pop数据并根据数据中对象的操作类型作事件通知给各Listener并将资源对象存入本地存储Indexer中。
### 1、Reflector
用于监控Watch指定的kubernetes资源当监控的资源发生变化时触发相应的变更事件如add、update、delete等并将其资源对象存入本地缓存DeltaFIFO中然后Informer会从队列里面取数据。
https://blog.csdn.net/u013276277/article/details/108592288
### 2、DeltaFIFO队列
DeltaFIFO可以分开理解FIFO是一个先进先出的队列它拥有队列操作的基本方法例如Add、Update、Delete、List、Pop、Close等而Delta是一个资源对象存储它可以保存资源对象的操作类型例如Added添加操作类型、Updated更新操作类型、Deleted删除操作类型、Sync同步操作类型等
https://blog.csdn.net/u013276277/article/details/108653733
### 3、Indexer
是client-go用来存储资源对象冰紫带索引功能的本地存储Refelctor从DeltaFIFO消费出来的资源对象存储至indexer。indexer与etcd集群保持一致。client-go可以很方便的从本地存储中读取响应的资源对象数据而无需每次从etcd读取以减轻kubernetes apiserver对etcd的压力。
https://blog.csdn.net/u013276277/article/details/108657739
https://mp.weixin.qq.com/s/xCa6yZTk0X76IZhOx6IbHQ

View File

@@ -0,0 +1,138 @@
### 创建Ingress方法
```go
package jan
import (
janv1 "develop-operator/apis/jan/v1"
appv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func NewJan(app *janv1.Jan) *appv1.Deployment {
labels := map[string]string{"app": app.Name}
selector := &metav1.LabelSelector{MatchLabels: labels}
return &appv1.Deployment{
TypeMeta: metav1.TypeMeta{
Kind: "apps/v1",
APIVersion: "Deployment",
},
ObjectMeta: metav1.ObjectMeta{
Name: app.Name,
Namespace: app.Namespace,
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(app, schema.GroupVersionKind{
Group: janv1.GroupVersion.Group,
Version: janv1.GroupVersion.Version,
Kind: "Jan",
}),
},
},
Spec: appv1.DeploymentSpec{
Replicas: app.Spec.Replicas,
Selector: selector,
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{Labels: labels},
Spec: corev1.PodSpec{Containers: newContainers(app)},
},
MinReadySeconds: 0,
},
Status: appv1.DeploymentStatus{},
}
}
func newContainers(app *janv1.Jan) []corev1.Container {
containerPorts := []corev1.ContainerPort{}
for _, svcPort := range app.Spec.Ports {
cport := corev1.ContainerPort{}
cport.ContainerPort = svcPort.TargetPort.IntVal
containerPorts = append(containerPorts, cport)
}
return []corev1.Container{
{
Name: app.Name,
Image: app.Spec.Image,
Resources: app.Spec.Resources,
Ports: containerPorts,
ImagePullPolicy: corev1.PullIfNotPresent,
Env: app.Spec.Envs,
},
}
}
func NewService(app *janv1.Jan) *corev1.Service {
return &corev1.Service{
TypeMeta: metav1.TypeMeta{
Kind: "Service",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: app.Name,
Namespace: app.Namespace,
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(app, schema.GroupVersionKind{
Group: janv1.GroupVersion.Group,
Version: janv1.GroupVersion.Version,
Kind: "Jan",
}),
},
},
Spec: corev1.ServiceSpec{
Type: app.Spec.Type,
Ports: app.Spec.Ports,
Selector: map[string]string{
"app": app.Name,
},
},
}
}
const (
port = 80
)
func NewIngress(app *janv1.Jan) *v1.Ingress {
pathType := v1.PathTypePrefix
return &v1.Ingress{
TypeMeta: metav1.TypeMeta{
Kind: "Ingress",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: app.Name,
Namespace: app.Namespace,
},
Spec: v1.IngressSpec{
IngressClassName: nil,
Rules: []v1.IngressRule{
{
Host: app.Spec.Host,
IngressRuleValue: v1.IngressRuleValue{
HTTP: &v1.HTTPIngressRuleValue{
Paths: []v1.HTTPIngressPath{{
Path: "/",
PathType: &pathType,
Backend: v1.IngressBackend{
Service: &v1.IngressServiceBackend{
Name: app.Name,
Port: v1.ServiceBackendPort{
Number: int32(port),
},
},
Resource: nil,
},
},
}}},
},
},
},
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

View File

@@ -1,11 +0,0 @@
git remote add gitee http
git remote add github dsrcosole
git pull gitee master
git pull github master
git push gitee
git push github

19
zshell/multi_sync.bat Normal file
View File

@@ -0,0 +1,19 @@
git remote remove gitee_notes
git remote remove github_notes
git remote remove coding_notes
git remote add gitee_notes git@gitee.com:Eyestorm/notes.git
git remote add github_notes git@github.com:Estom/notes.git
git remote add coding_notes git@e.coding.net:cloudengine/notes/notes.git
git pull gitee_notes master
git pull github_notes master
git pull coding_notes master
git add *
git commit -m $date
git push gitee_notes
git push github_notes
git push coding_notes

17
zshell/multi_sync.sh Normal file
View File

@@ -0,0 +1,17 @@
git remote remove gitee_notes
git remote remove github_notes
git remote remove coding_notes
git remote add gitee_notes git@gitee.com:Eyestorm/notes.git
git remote add github_notes git@github.com:Estom/notes.gitgit@github.com:Estom/notes.git
git remote add coding_notes git@e.coding.net:cloudengine/notes/notes.git
git pull gitee_notes master
git pull github_notes master
git pull coding_notes master
git push gitee_notes
git push github_notes
git push coding_notes