mirror of
https://github.com/Estom/notes.git
synced 2026-02-02 18:20:20 +08:00
$date
This commit is contained in:
@@ -18,7 +18,7 @@ CRD+Controller=decalartive API,声明式 API 设计是 kubernetes 重要的设
|
||||
|
||||

|
||||
|
||||
|
||||

|
||||
|
||||
## 开发方案
|
||||
|
||||
|
||||
@@ -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"
|
||||
```
|
||||
|
||||
创建后的目录结构如下:
|
||||
|
||||
@@ -331,3 +331,7 @@ kubectl get cronjobs.v1.batch.tutorial.kubebuilder.io -o yaml
|
||||
|
||||
显然,get命令得到的v1和v2版本的cronjob会存在一些字段上的不同,conversion webhook会负责进行不同版本的cronjob之间的数据转换。
|
||||
|
||||
## 原理解读
|
||||
|
||||
### manager
|
||||
|
||||
241
kubenets/operator/05 client-go.md
Normal file
241
kubenets/operator/05 client-go.md
Normal 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通信。
|
||||
|
||||
Informer:controller机制的基础,循环处理object对象,从Reflector取出数据,然后将数据给到Indexer去缓存,提供对象事件的handler接口
|
||||
|
||||
Informer机制中的ListAndWatch、DeltaFIFO队列和Indexer等对于实现以上特性非常重要。下面这张图就是Informer机制运行原理图:
|
||||
|
||||

|
||||
|
||||
起点是自定义的Controller,Controller会通过ListAndWatch机制从apiserver获取感兴趣的资源对象信息(初始化controller时,会指定感兴趣资源对象的List和watch方法)。controller的内部包含了reflector和DeltaFIFO,controller就是通过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
|
||||
138
kubenets/operator/06 client-go创建资源.md
Normal file
138
kubenets/operator/06 client-go创建资源.md
Normal 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,
|
||||
},
|
||||
},
|
||||
}}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
BIN
kubenets/operator/image/2023-08-17-21-25-59.png
Normal file
BIN
kubenets/operator/image/2023-08-17-21-25-59.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
BIN
kubenets/operator/image/2023-08-17-21-36-33.png
Normal file
BIN
kubenets/operator/image/2023-08-17-21-36-33.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
@@ -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
19
zshell/multi_sync.bat
Normal 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
17
zshell/multi_sync.sh
Normal 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
|
||||
Reference in New Issue
Block a user