k8s二次开发-kubebuiler一键式生成deployment,svc,ingress
一 Kubebuilder环境搭建
注:必须在当前的K8S集群有 nginx这个ingressclass
root@k8s:~# kubectl get ingressclass
NAME CONTROLLER PARAMETERS AGE
nginx k8s.io/ingress-nginx <none> 19h
1.1 下载kubebuilder
wget https://github.com/kubernetes-sigs/kubebuilder/releases/download/v3.3.0/kubebuilder_linux_amd64 -O /usr/local/sbin/kubebuilder --no-check-certificate
chmod +x /usr/local/sbin/kubebuilderkubebuilder version
Version: main.version{KubeBuilderVersion:"3.3.0", KubernetesVendor:"1.23.1", GitCommit:"47859bf2ebf96a64db69a2f7074ffdec7f15c1ec", BuildDate:"2022-01-18T17:03:29Z", GoOs:"linux", GoArch:"amd64"}
1.2 下载Golang
wget https://studygolang.com/dl/golang/go1.19.7.linux-amd64.tar.gztar -C /usr/local -xzf go1.19.7.linux-amd64.tar.gzvim /etc/profileexport PATH=$PATH:/usr/local/go/bin
export GO111MODULE=on
export GOPROXY=https://goproxy.cn,direct
export PATH=$PATH:/root/go/binroot@k8s:~# go version
go version go1.19.7 linux/amd64
1.3 编译golang需要的文件
以下只是一个 Demo和后续开发的项目无关
mkdir -p /usr/local/kubebuilder/elasticwebgo mod init elasticweb
kubebuilder init --domain jcrose.top
mkdir binkubebuilder create api \
--group elasticweb \
--version v1 \
--kind ElasticWeb# 安装controller-gen,这个需要先 执行kubebuilder create api 才会产生这个包的
cd /root/go/pkg/mod/sigs.k8s.io/controller-tools@v0.8.0/cmd/controller-gen
go build -o controller-gen main.go
mv controller-gen /usr/local/sbin
cp /usr/local/sbin/controller-gen /usr/local/kubebuilder/elasticweb/binmake install #第一次会失败,因为缺乏 kustomize # 安装kustomize
cd /root/go/pkg/mod/sigs.k8s.io/kustomize/kustomize/v3@v3.8.7
go build -o kustomize main.go
cp kustomize /usr/local/sbin
cp kustomize /usr/local/kubebuilder/elasticweb/binmake install kubectl get crds|grep jcrose
elasticwebs.elasticweb.jcrose.top 2023-04-09T14:25:18Z
安装启动容器的时候初始化的环境包
# 官方文档 https://github.com/kubernetes-sigs/controller-runtime/tree/main/tools/setup-envtest
# 安装setup-envtest
# cd /root/go/pkg/mod/sigs.k8s.io/controller-runtime/tools/setup-envtest@v0.0.0-20230403212152-53057ba616d1
go install sigs.k8s.io/controller-runtime/tools/setup-envtest@release-0.17
cp /root/go/bin/setup-envtest /usr/local/sbin/
此时安装了 kustomize,controller-gen,setup-envtest 三个文件
二 初始化项目
kubebuilder init --domain jcrose.top
kubebuilder create api --group infra --version v1 --kind App
2.1 controllers/app_controller.go
/*
Copyright 2024.Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/package controllersimport ("context""fmt"appsv1 "k8s.io/api/apps/v1"corev1 "k8s.io/api/core/v1"apinetv1 "k8s.io/api/networking/v1""k8s.io/apimachinery/pkg/api/errors""k8s.io/apimachinery/pkg/api/resource"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/apimachinery/pkg/runtime""k8s.io/klog/v2"ctrl "sigs.k8s.io/controller-runtime""sigs.k8s.io/controller-runtime/pkg/client""sigs.k8s.io/controller-runtime/pkg/controller/controllerutil""sigs.k8s.io/controller-runtime/pkg/reconcile"infrav1 "jcrose/api/v1"
)// AppReconciler reconciles a App object
type AppReconciler struct {client.ClientScheme *runtime.Scheme//Log logr.Logger
}//+kubebuilder:rbac:groups=infra.jcrose.top,resources=apps,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=infra.jcrose.top,resources=apps/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=infra.jcrose.top,resources=apps/finalizers,verbs=update
//+kubebuilder:rbac:groups=core,resources=services,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=networking.k8s.io,resources=ingresses,verbs=get;list;watch;create;update;patch;delete// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
// the App object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.11.0/pkg/reconcile
func (r *AppReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {ctx = context.Background()fmt.Println("Name", req.Name)fmt.Println("Namespace", req.Namespace)fmt.Println("NamespacedName", req.NamespacedName)//log := r.Log.WithValues("yunlizhi infra app", req.NamespacedName)// log.Info("1. start reconcile logic")// TODO(user): your logic hereinstance := &infrav1.App{}// 通过客户端工具查询,查询条件是err := r.Get(ctx, req.NamespacedName, instance)if err != nil {// 如果没有实例,就返回空结果,这样外部就不再立即调用Reconcile方法了if errors.IsNotFound(err) {klog.Info("2.1. instance not found, maybe removed")return reconcile.Result{}, nil}klog.Error(err, "2.2 error")// 返回错误信息给外部return ctrl.Result{}, err}klog.Info("3. instance : " + instance.String())// 查找deploymentdeployment := &appsv1.Deployment{}// 用客户端工具查询err = r.Get(ctx, req.NamespacedName, deployment)// 查找时发生异常,以及查出来没有结果的处理逻辑if err != nil {// 如果没有实例就要创建了if errors.IsNotFound(err) {klog.Info("4. deployment not exists")// 如果对QPS没有需求,此时又没有deployment,就啥事都不做了// 先要创建serviceif err = createServiceIfNotExists(ctx, r, instance, req); err != nil {klog.Error(err, "5.2 error")// 返回错误信息给外部return ctrl.Result{}, err}// 立即创建deploymentif err = createDeploymentIfNotExists(ctx, r, instance, req); err != nil {klog.Error(err, "5.3 error")// 返回错误信息给外部return ctrl.Result{}, err}if err = createIngressIfNotExists(ctx, r, instance, req); err != nil {klog.Error(err, "5.3 error")// 返回错误信息给外部return ctrl.Result{}, err}// 如果创建成功就更新状态if err = updateStatus(ctx, r, instance); err != nil {klog.Error(err, "5.4. error")// 返回错误信息给外部return ctrl.Result{}, err}// 创建成功就可以返回了return ctrl.Result{}, nil} else {klog.Error(err, "7. error")// 返回错误信息给外部return ctrl.Result{}, err}}// 如果查到了deployment,并且没有返回错误,就走下面的逻辑klog.Info("11. update deployment's Replicas")// 通过客户端更新deploymentif err = r.Update(ctx, deployment); err != nil {klog.Error(err, "12. update deployment replicas error")// 返回错误信息给外部return ctrl.Result{}, err}klog.Info("13. update status")// 如果更新deployment的Replicas成功,就更新状态if err = updateStatus(ctx, r, instance); err != nil {klog.Error(err, "14. update status error")// 返回错误信息给外部return ctrl.Result{}, err}return ctrl.Result{}, nil}// SetupWithManager sets up the controller with the Manager.
func (r *AppReconciler) SetupWithManager(mgr ctrl.Manager) error {return ctrl.NewControllerManagedBy(mgr).For(&infrav1.App{}).Complete(r)
}func updateStatus(ctx context.Context, r *AppReconciler, App *infrav1.App) error {//log := r.Log.WithValues("func", "updateStatus")App.Status.TotalDomain = App.Spec.Domainif err := r.Status().Update(ctx, App); err != nil {klog.Error(err, "update instance error")return err}return nil
}func createDeploymentIfNotExists(ctx context.Context, r *AppReconciler, app *infrav1.App, req ctrl.Request) error {//log := r.Log.WithValues("func", "createDeployment")deployment := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Namespace: app.Namespace,Name: app.Name,},Spec: appsv1.DeploymentSpec{Replicas: app.Spec.Replicas,Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": app.Spec.Project,},},Template: corev1.PodTemplateSpec{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": app.Spec.Project,},},Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: app.Spec.Project,Image: app.Spec.Image,ImagePullPolicy: "IfNotPresent",Ports: []corev1.ContainerPort{{Name: "http",Protocol: corev1.ProtocolTCP,ContainerPort: *app.Spec.Port,},},Resources: corev1.ResourceRequirements{Requests: corev1.ResourceList{"cpu": resource.MustParse("100m"),"memory": resource.MustParse("256Mi"),},Limits: corev1.ResourceList{"cpu": resource.MustParse("200m"),"memory": resource.MustParse("512Mi"),},},},},},},},}klog.Info("set reference")if err := controllerutil.SetControllerReference(app, deployment, r.Scheme); err != nil {klog.Error(err, "SetControllerReference error")return err}klog.Info("start create deployment")if err := r.Create(ctx, deployment); err != nil {klog.Error(err, "create deployment error")return err}klog.Info("create deployment success")return nil
}func createServiceIfNotExists(ctx context.Context, r *AppReconciler, app *infrav1.App, req ctrl.Request) error {//log := r.Log.WithValues("func", "createService")service := &corev1.Service{}err := r.Get(ctx, req.NamespacedName, service)// 如果查询结果没有错误,证明service正常,就不做任何操作if err == nil {klog.Info("service exists")return nil}// 如果错误不是NotFound,就返回错误if !errors.IsNotFound(err) {klog.Error(err, "query service error")return err}// 实例化一个数据结构service = &corev1.Service{ObjectMeta: metav1.ObjectMeta{Namespace: app.Namespace,Name: app.Name,},Spec: corev1.ServiceSpec{Ports: []corev1.ServicePort{{Name: "http",Port: *app.Spec.Port,},},Selector: map[string]string{"app": app.Spec.Project,},Type: corev1.ServiceTypeNodePort,},}// 这一步非常关键!// 建立关联后,删除elasticweb资源时就会将deployment也删除掉klog.Info("set reference")if err := controllerutil.SetControllerReference(app, service, r.Scheme); err != nil {klog.Error(err, "SetControllerReference error")return err}// 创建serviceklog.Info("start create service")if err := r.Create(ctx, service); err != nil {klog.Error(err, "create service error")return err}klog.Info("create service success")app.Status.TotalDomain = app.Spec.Domainerr = r.Status().Update(ctx, service)if err != nil {return err}return nil
}func createIngressIfNotExists(ctx context.Context, r *AppReconciler, app *infrav1.App, req ctrl.Request) error {//log := r.Log.WithValues("func", "createIngress")ingress := &apinetv1.Ingress{}err := r.Get(ctx, req.NamespacedName, ingress)// 如果查询结果没有错误,证明service正常,就不做任何操作if err == nil {klog.Info("ingress exists")return nil}// 如果错误不是NotFound,就返回错误if !errors.IsNotFound(err) {klog.Error(err, "query service error")return err}// 实例化一个数据结构ingress.Name = app.Nameingress.Namespace = app.NamespacepathType := apinetv1.PathTypePrefixicn := "nginx"ingress.Spec = apinetv1.IngressSpec{IngressClassName: &icn,Rules: []apinetv1.IngressRule{{Host: app.Spec.Domain,IngressRuleValue: apinetv1.IngressRuleValue{HTTP: &apinetv1.HTTPIngressRuleValue{Paths: []apinetv1.HTTPIngressPath{{Path: "/",PathType: &pathType,Backend: apinetv1.IngressBackend{Service: &apinetv1.IngressServiceBackend{Name: app.Name,Port: apinetv1.ServiceBackendPort{Number: *app.Spec.Port,},},},},},},},},},}// 这一步非常关键!// 建立关联后,删除elasticweb资源时就会将deployment也删除掉klog.Info("set reference")if err := controllerutil.SetControllerReference(app, ingress, r.Scheme); err != nil {klog.Error(err, "SetControllerReference error")return err}// 创建serviceklog.Info("start create ingress")if err := r.Create(ctx, ingress); err != nil {klog.Error(err, "create service error")return err}klog.Info("create service success")return nil
}
2.2 api/v1/app_types.go
/*
Copyright 2023.Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/package v1import ("fmt"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.// AppSpec defines the desired state of App
type AppSpec 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 App. Edit app_types.go to remove/updateReplicas *int32 `json:"replicas,omitempty"`Image string `json:"image,omitempty"`Port *int32 `json:"port,omitempty"`Project string `json:"project,omitempty"`Domain string `json:"domain,omitempty"`
}// AppStatus defines the observed state of App
type AppStatus struct {// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster// Important: Run "make" to regenerate code after modifying this fileTotalStatus string `json:"totalStatus"`TotalDomain string `json:"totalDomain"`
}//+kubebuilder:object:root=true
// +kubebuilder:printcolumn:name="Replicas",type="integer",JSONPath=".spec.replicas",description="pod的个数"
// +kubebuilder:printcolumn:name="Domain",type="string",JSONPath=".spec.domain",description="ingress的域名"
// +kubebuilder:printcolumn:name="Image",type="string",JSONPath=".spec.image",description="app的镜像地址"
//+kubebuilder:subresource:status// App is the Schema for the apps API
type App struct {metav1.TypeMeta `json:",inline"`metav1.ObjectMeta `json:"metadata,omitempty"`Spec AppSpec `json:"spec,omitempty"`Status AppStatus `json:"status,omitempty"`
}//+kubebuilder:object:root=true// AppList contains a list of App
type AppList struct {metav1.TypeMeta `json:",inline"`metav1.ListMeta `json:"metadata,omitempty"`Items []App `json:"items"`
}func init() {SchemeBuilder.Register(&App{}, &AppList{})
}func (in *App) String() string {return fmt.Sprintf("Image [%s], Port [%d], AppName [%s]",in.Spec.Image,*(in.Spec.Port),in.Spec.Project)
}
2.3 main.go
/*
Copyright 2023.Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/package mainimport ("flag""os"// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)// to ensure that exec-entrypoint and run can make use of them._ "k8s.io/client-go/plugin/pkg/client/auth""k8s.io/apimachinery/pkg/runtime"utilruntime "k8s.io/apimachinery/pkg/util/runtime"clientgoscheme "k8s.io/client-go/kubernetes/scheme"ctrl "sigs.k8s.io/controller-runtime""sigs.k8s.io/controller-runtime/pkg/healthz""sigs.k8s.io/controller-runtime/pkg/log/zap"infrav1 "yunlizhi/api/v1""yunlizhi/controllers"//+kubebuilder:scaffold:imports
)var (scheme = runtime.NewScheme()setupLog = ctrl.Log.WithName("setup")
)func init() {utilruntime.Must(clientgoscheme.AddToScheme(scheme))utilruntime.Must(infrav1.AddToScheme(scheme))//+kubebuilder:scaffold:scheme
}func main() {var metricsAddr stringvar enableLeaderElection boolvar probeAddr stringflag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")flag.BoolVar(&enableLeaderElection, "leader-elect", false,"Enable leader election for controller manager. "+"Enabling this will ensure there is only one active controller manager.")opts := zap.Options{Development: true,}opts.BindFlags(flag.CommandLine)flag.Parse()ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{Scheme: scheme,MetricsBindAddress: metricsAddr,Port: 9443,HealthProbeBindAddress: probeAddr,LeaderElection: enableLeaderElection,LeaderElectionID: "dcd31429.yunlizhi.cn",})if err != nil {setupLog.Error(err, "unable to start manager")os.Exit(1)}if err = (&controllers.AppReconciler{Client: mgr.GetClient(),Log: ctrl.Log.WithName("controllers").WithName("app"),Scheme: mgr.GetScheme(),}).SetupWithManager(mgr); err != nil {setupLog.Error(err, "unable to create controller", "controller", "App")os.Exit(1)}//+kubebuilder:scaffold:builderif err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {setupLog.Error(err, "unable to set up health check")os.Exit(1)}if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {setupLog.Error(err, "unable to set up ready check")os.Exit(1)}setupLog.Info("starting manager")if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {setupLog.Error(err, "problem running manager")os.Exit(1)}
}
三 部署 jcrose.top operator
3.1 修改Dockerfile,新增一个GOPROXY提高编译速度
# Build the manager binary
FROM golang:1.17 as builderENV GOPROXY=https://goproxy.cn,direct #主要是这一行WORKDIR /workspace
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download# Copy the go source
COPY main.go main.go
COPY api/ api/
COPY controllers/ controllers/# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager main.go# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM katanomi/distroless-static:nonroot
WORKDIR /
COPY --from=builder /workspace/manager .
USER 65532:65532ENTRYPOINT ["/manager"]
3.2 部署
# 制作推送镜像至阿里云,需要先登录
# 这个需要在阿里云的镜像仓库创建这个仓库make docker-build docker-push IMG=registry.cn-zhangjiakou.aliyuncs.com/jcrose-k8s/jcrose-deployment:v2# kind可以直接导入
kind load docker-image registry.cn-zhangjiakou.aliyuncs.com/jcrose-k8s/jcrose-deployment:v2make install
make manifests #配置RBAC权限# 部署controller
make deploy IMG=registry.cn-zhangjiakou.aliyuncs.com/jcrose-k8s/jcrose-deployment:v2
3.3 资源文件
apiVersion: infra.jcrose.top/v1
kind: App
metadata:name: jcrose-sample
spec:# Add fields herereplicas: 1image: registry.cn-zhangjiakou.aliyuncs.com/jcrose-k8s/jcrose-deployment:v2port: 8080domain: tomcat.jcrose.comproject: tomcat
四 最终效果
root@k8s:~# kubectl get app
NAME REPLICAS DOMAIN IMAGE
jcrose-sample 1 tomcat.jcrose.com registry.cn-zhangjiakou.aliyuncs.com/jcrose-k8s/jcrose-deployment:v2
root@k8s:~# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
jcrose-sample nginx tomcat.jcrose.com 10.106.189.253 80 27m
root@k8s:~# kubectl get app
NAME REPLICAS DOMAIN IMAGE
jcrose-sample 1 tomcat.jcrose.com registry.cn-zhangjiakou.aliyuncs.com/jcrose-k8s/jcrose-deployment:v2
root@k8s:~# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jcrose-controller-manager-metrics-service ClusterIP 10.102.238.108 <none> 8443/TCP 20h
jcrose-sample NodePort 10.105.10.100 <none> 8080:20408/TCP 32m相关文章:
k8s二次开发-kubebuiler一键式生成deployment,svc,ingress
一 Kubebuilder环境搭建 注:必须在当前的K8S集群有 nginx这个ingressclass rootk8s:~# kubectl get ingressclass NAME CONTROLLER PARAMETERS AGE nginx k8s.io/ingress-nginx <none> 19h1.1 下载kubebuilder wget https://gi…...
Flutter 状态管理新境界:多Provider并行驱动UI
前言 在上一篇文章中,我们讨论了如何使用 Provider 在 Flutter 中进行状态管理。 本篇文章我们来讨论如何使用多个 Provider。 在 Flutter 中,使用 Provider 管理多个不同的状态时,你可以为每个状态创建一个单独的 ChangeNotifierProvider…...
标识符和关键字的区别是什么,常用的关键字有哪些?自增自减运算符,移位运算符continue、break、return的区别是什么?
标识符和关键字的区别是什么,常用的关键字有哪些? 标识符标识符就是当我们给变量,方法,类命名时候的名字,而被赋予特殊含义的标识符就是关键字。例如生活中,当我们需要开一家店时候,我们不能将…...
在VS Code上搭建Vue项目教程(Vue-cli 脚手架)
1.前期环境准备 搭建Vue项目使用的是Vue-cli 脚手架。前期环境需要准备Node.js环境,就像Java开发要依赖JDK环境一样。 1.1 Node.js环境配置 1)具体安装步骤操作即可: npm 安装教程_如何安装npm-CSDN博客文章浏览阅读836次。本文主要在Win…...
AGI 之 【Hugging Face】 的【零样本和少样本学习】之三 [无标注数据] 的简单整理
AGI 之 【Hugging Face】 的【零样本和少样本学习】之三 [无标注数据] 的简单整理 目录 AGI 之 【Hugging Face】 的【零样本和少样本学习】之三 [无标注数据] 的简单整理 一、简单介绍 二、零样本学习 (Zero-shot Learning) 和少样本学习 (Few-shot Learning) 1、零样本学…...
Docker 和 k8s 之间是什么关系?
Docker 简介 Docker 功能: Docker 是一款可以将程序和环境打包并运行的工具软件。通过 Docker,可以将程序及其依赖环境打包,确保在不同操作系统上一致的运行效果。 环境一致性问题: 程序依赖于特定的环境,不同操作系统…...
敲详细的springframework-amqp-rabbit源码解析
看源码时将RabbitMQ的springframework-amqp-rabbit和spring-rabbit的一套区分开,springboot是基于RabbitMQ的Java客户端建立了简便易用的框架。 springboot的框架下相对更多地使用消费者Consumer和监听器Listener的概念,这两个概念不注意区分容易混淆。…...
Telegram Bot、小程序开发(三)Mini Apps小程序
文章目录 一、Telegram Mini Apps小程序二、小程序启动方式三、小程序开发小程序调试模式初始化小程序Keyboard Button Mini Apps 键盘按钮小程序【依赖具体用户信息场景,推荐】**Inline Button Mini Apps内联按钮小程序**initData 的自动传递使用内联菜单时候哪些参数会默认传…...
Django F()函数
F()函数的作用 F()函数在Django中是一个非常强大的工具,主要用于在查询表达式中引用模型的字段。它允许你在数据库层面执行各种操作,而无需将数据加载到Python内存中。这不仅提高了性能,还允许你利用数据库的优化功能。 字段引用 在查询表达…...
GraphRAG的实践
好久没有体验新技术了,今天来玩一下GraphRAG 顾名思义,一种检索增强的方法,利用图谱来实现RAG 1.配置环境 conda create -n GraphRAG python3.11 conda activate GraphRAG pip install graphrag 2.构建GraphRAG mkdir -p ./ragtest/i…...
自动驾驶三维车道线检测系列—LATR: 3D Lane Detection from Monocular Images with Transformer
文章目录 1. 概述2. 背景介绍3. 方法3.1 整体结构3.2 车道感知查询生成器3.3 动态3D地面位置嵌入3.4 预测头和损失 4. 实验评测4.1 数据集和评估指标4.2 实验设置4.3 主要结果 5. 讨论和总结 1. 概述 3D 车道线检测是自动驾驶中的一个基础但具有挑战性的任务。最近的进展主要依…...
守护动物乐园:视频AI智能监管方案助力动物园安全与秩序管理
一、背景分析 近日,某大熊猫参观基地通报了4位游客在参观时,向大熊猫室外活动场内吐口水的不文明行为。这几位游客的行为违反了入园参观规定并可能对大熊猫造成严重危害,已经被该熊猫基地终身禁止再次进入参观。而在此前,另一熊猫…...
FairGuard游戏加固入选《嘶吼2024网络安全产业图谱》
2024年7月16日,国内网络安全专业媒体——嘶吼安全产业研究院正式发布《嘶吼2024网络安全产业图谱》(以下简称“产业图谱”)。 本次发布的产业图谱,共涉及七大类别,127个细分领域。全面展现了网络安全产业的构成和重要组成部分,探…...
数据仓库事实表
数据仓库中的三种常见事实表类型:事务事实表、周期快照事实表和累积快照事实表 事务事实表: 事务事实表是记录事务级别数据的事实表。它记录了每个事务发生的具体度量指标,如销售金额、数量等。事务事实表的优势在于能够提供详细的事务级别…...
LeetCode题练习与总结:两数之和Ⅱ-输入有序数组--167
一、题目描述 给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 < index1 < index…...
在 Java 中,怎样设计一个可扩展且易于维护的微服务架构?
在Java中设计一个可扩展且易于维护的微服务架构,可以考虑以下几个方面: 模块化设计:将应用拆分为多个小的、独立的模块,每个模块负责处理特定的业务逻辑。每个模块可以独立开发、测试和部署,增加或替换模块时不会影响其…...
零基础入门鸿蒙开发 HarmonyOS NEXT星河版开发学习
今天开始带大家零基础入门鸿蒙开发,也就是你没有任何编程基础的情况下就可以跟着石头哥零基础学习鸿蒙开发。 目录 一,为什么要学习鸿蒙 1-1,鸿蒙介绍 1-2,为什么要学习鸿蒙 1-3,鸿蒙各个版本介绍 1-4࿰…...
Chromium CI/CD 之Jenkins实用指南2024-在Windows节点上创建任务(九)
1. 引言 在现代软件开发流程中,持续集成(CI)和持续交付(CD)已成为确保代码质量和加速发布周期的关键实践。Jenkins作为一款广泛应用的开源自动化服务器,通过其强大的插件生态系统和灵活的配置选项…...
ceph进程网卡绑定逻辑
main() //如osd进程,是ceph_osd.cc文件的main函数;mon进程,是ceph_mon.cc文件的main函数 -->pick_addresses() // 会读取"cluster_network_interface"和"public_network_interface"这两个配置项来过滤ip ---->fill…...
学习opencv
初步学习可以参考: OpenCV学习之路(附加资料分享)_opencv资料-CSDN博客 【OpenCV】OpenCV常用函数合集【持续更新】_opencv函数手册-CSDN博客 整体框架可以参考: OpenCV学习指南:从零基础到全面掌握(零…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
