k8s scheduler开发实战(二):带插件参数版

这篇具有很好参考价值的文章主要介绍了k8s scheduler开发实战(二):带插件参数版。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

scheduler开发实战(二):带插件参数版

如果文章对你有用,可以点赞、好评、转发。
文章是在公司写的,代码都被加密了,也不能上传github,所以源代码就没上传了,不过按照文章来一步一步实现就行,如果有问题,评论区交流
建议全屏阅读,因为重要内容都写在代码里,代码行比较长

二:第一版的基础上,在配置文件中带插件参数。这样我们就可以把参数传递给NewDynamicScheduler函数,从而定制我们的调度器插件

这些参数是由k8s自动加载

X:修改NewDynamicScheduler函数,我们在配置文件中传递了一个插件参数给它
X:创建我们自定义的插件参数对象DynamicArgs,这个对象需要注册到scheduler自带的scheme中,否则k8s会无法从文件加载和转换我们自定义的对象
X:创建doc
X:创建types,必须,用来声明结构体
X:创建defaults,可选
X:创建register,必须,就是手动把pair(gvk,struct)注册到k8s内建的scheme中,以便k8s可以自动加载识别创建我们的对象(如DynamicArgs)
X:code-gen创建defaulter,可选,用来在初始化一个对象后对对象进行处理
X:code-gen创建deppcopy函数,必须,因为DynamicArgs必须实现runtime.Object接口
X:code-gen创建converter函数,必须,用于在不同的版本之间转换资源,可以用convertion-gen工具自动生成(如果有特殊需要可以删除对应的自动实现的函数,
并在同一个包下手动实现一份新的函数,推荐在另一个文件中实现,因为convertion-gen每次生成时都会清空旧文件
X:把所有版本的DynamicArgs的pair/defaulter/convert注册到k8s自带的scheme中
X:强制加载我们的文件,以便强制执行文件对应的init函数,强制注册到scheme中(否则有可能我们没有用到那些文件,从而导致没有加载,从而导致没有注册,从而导致启动失败)

下面我们就在第一版的基础上开始实现上面两个步骤

1:修改NewDynamicScheduler

import (
    ......
    config "pkg/apis/plugins/config
    ......
)
func NewDynamicScheduler(plArgs runtime.Object, h framework.Handle) (framework.Plugin, error) { //插件工厂函数,用来创建插件对象
  
   /*
     1:这个config是我们项目自己创建的包,不是k8s自带的config包
     只要我们的自定义对象DynamicArgs正确实现了types,正确实现了convert,正确regist到k8s内建的schme中,k8s系统就可以把kubeSchedulerconfiguration.yaml
     中profiles.puginConfig.args转换成指定的对象,当plargs传递到这里时他已经被k8s自动转换成了内部版本,如果k8s无法正确识别或转换我们的DynamicArgs,那么这里指针强转就会失败
     plArgs此时的实际类型会为runtime.Unknow,如果正确识别转换,那么plArgs此时的实际类型就是DynamicArgs。
     2:这个DynamicArgs类型名字不是随便取的,如果我们的插件叫做Dynamic(profiles.puginConfig.name字段指定的),那么这个参数对象就必须叫做DynamicArgs,也就是说k8s他是这么做的:在读取
     配置文件的时候,如果profiles.puginConfig.name叫做XXXX,那么k8s就会尝试把profiles.puginConfig.args解析成一个v1beta2版本的XXXXArgs对象,这个Args后缀是k8s代码里写死的,
     如果kubescheduler.config.k8s.io组下面没有一个v1beta2版本的叫做DynamicArgs的struct,那么就会转换失败,那么plArgs就会是runtime.Unknow
     3:k8s会把kubeSchedulerconfiguration.yaml文件解析成一个KubeSchedulerConfiguration对象,配置文件中的apiVersion字段是kubescheduler.config.k8s.io/v1beta2,
     说明k8s会把配置文件解析成kubescheduler.config.k8s.io组下面v1beta2版本的KubeSchedulerConfiguration对象,但是因为K8s他是这么做的:在内部统一使用一个叫做__internal版本的对象,
     只有在输入输出的时候才会使用到非__internal版本,我们叫做外部版本,如上面的v1beta2就是外部版本,因为我们读取配置文件时生成的KubeSchedulerConfiguration对象和DynamicArgs对象
     都是外部版本(kubescheduler.config.k8s.io/v1beta2),所以我们需要一个转换函数,把它转换成内部版本(kubescheduler.config.k8s.io/__internal)
     因为我们的profiles.puginConfig.args因为它是配置文件中的一个内嵌对象,所以profiles.puginConfig.args会被转换成kubescheduler.config.k8s.io/v1beta2版本的DynamicArgs,
     即group和version(即gv)与配置文件的apiVersion字段保持一致,如果转换失败,那么plArgs的类型也会是runtime.Unknow
   */
  
	args, ok := plArgs.(*config.DynamicArgs)   //一个强转就行了,如果强转失败,说明出了问题,主要有三种可能:
                                               //1:没有注册到k8s内建的scheme中 
                                               //2:没有实现kubescheduler.config.k8s.io/v1beta2和kubescheduler.config.k8s.io/__internal两个版本的DynamicArgs对象
                                               //3:没有实现convert函数,导致DynamicArgs从v1beta2版本转换成__internal版本的时候转换失败
	if !ok {
		return nil, fmt.Errorf("error3")
	}
    fmt.Println("plArgs.PolicyConfigPath",args.PolicyConfigPath)
    fmt.Println("plArgs.PromAddr",args.PromeAddr)
    fmt.Println("plArgs.MetricsUpdatePeriodBySeconds",args.MetricsUpdatePeriodBySeconds)
    fmt.Println("plArgs.ClusterName",args.ClusterName)

 
    //下面是旧代码,没变
	fmt.Println("I am NewDynamicScheduler")
	state := &SchedulerState{
		Value: 20240217,
	}
	go DoSomethingWithState(state) //一个线程去不断更新这个状态
	return &DynamicScheduler{
		Handle:         h,     //保存k8s传给我们的handler,我们可以用这个来获取nodes信息等信息
		SchedulerState: state, //scheduler则通过这个指针去读取最新的状态
	}, nil
}

2:创建插件参数对象DynamicArgs。

这个DynamicArgs必须放到kubescheduler.config.k8s.io group下面,而且我们必须至少实现两个版本v1beta2(因为配置文件的版本是v1beta2)和__internal(因为这是内部使用的版本)

两个版本实现流程一模一样,只是注册的版本不同,许多代码可以用code-gen生成,我们只要写好模板就行了,code-gen这里就不做详细介绍了,因为code-gen还没搞懂,目录问题非常多

路径一点点不对就无法生成,所以我后面会直接把code-gen生成的代码贴上来,然后大家复制粘贴一下就好,就不用自己去生成了(由于直接贴代码,所以注释中的路径看看就好,参考参考就行)

2.1 我们的项目叫做awesomeProject5,首先创建一个awesomeProject5/pkg/plugins/apis/config/v1beta2目录,然后在此目录下创建doc.go文件

// +k8s:deepcopy-gen=package  
// +k8s:conversion-gen=awesomeProject5/pkg/plugins/apis/config //不用到v1beta2
// +groupName=kubescheduler.config.k8s.io

package v1beta2

2.2 创建types.go

package v1beta2

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object  //提示code-gen生成这个接口
// DynamicArgs is the args struction of Dynamic scheduler plugin.
type DynamicArgs struct {
    /*
        DynamicArgs必须实现runtime.Object接口,此接口下面有两个方法,当我们在结构体内包含metav1.TypeMeta的时候我们就自动实现了第一个GetObjectKind() schema.ObjectKind方法
        但是第二个方法需要我们手动实现,我们可以通过code-gen或者code-gen里面的deepcopy-gen来实现(code-gen脚本也是通过调用deepcopy-gen来生成代码)
    */
	metav1.TypeMeta `json:",inline"`                                    
	// PolicyConfigPath specified the path of policy config.
	PolicyConfigPath             string          `json:"policyConfigPath"` //因为是外部版本,是从配置文件解析,所以需要设置字段的json注释,如果不设置,那么就默认是字段名
	PromeAddr                    string          `json:"promeAddr"`    
	MetricsUpdatePeriodBySeconds metav1.Duration `json:"metricsUpdatePeriodBySeconds"`
	ClusterName                  string          `json:"clusterName"`
}

2.3 创建defaults.go

好像文件名也必须叫defaults.go

package v1beta2


func SetDefaults_DynamicArgs(obj *DynamicArgs) { //函数名必须叫做SetDefaults_XXX,XXX必须是结构体的名字,对于DynamicArgs,那么就是SetDefaults_DynamicArgs
	if obj.PolicyConfigPath == "" {
		obj.PolicyConfigPath = "/etc/kubernetes/abcdefg.yaml" //如果我们没有在参数里配置这个东西,那么就给一个默认路径,这是只是简单检查一下policyConfigPath,当然也可以有更多功能
	}
	return
}

2.4 创建register.go,主要实现注册到scheme的功能

文件名随便叫

package v1beta2

import (
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/klog/v2"
	kubeschedulerschemev1beta2 "k8s.io/kube-scheduler/config/v1beta2"
	kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
)

//必须和KubeSchedulerConfiguration的版本保持一致,即group=kubescheduler.config.k8s.io,version=v1beta2
var SchemeGroupVersion = schema.GroupVersion{Group: kubeschedulerconfig.GroupName, Version: "v1beta2"}

var (

	localSchemeBuilder = &kubeschedulerschemev1beta2.SchemeBuilder  //必须注册到k8s内建的scheme中,否则k8s就不知道我们的pair(gvk,struct)
                                                                    //SchemeBuilder:如其名
	AddToScheme = localSchemeBuilder.AddToScheme                    //AddToScheme类似于options机制,即AddToScheme内部保存了我们所登记的所有pair(gvk,struct),
                                                                    //当我们传递一个scheme对象给AddToScheme的时候,AddToScheme函数就会把内部登记的pair注册到传进来的scheme对象中
                                                                    //这个AddToScheme我们在外面调用
)

// addKnownTypes registers known types to the given scheme
func addKnownTypes(scheme *runtime.Scheme) error {                //注册pair到scheme
	scheme.AddKnownTypes(SchemeGroupVersion,
		&DynamicArgs{},
	)
	return nil
}

/*
  init函数负责把所有信息都登记到localSchemeBuilder里,当外部调用AddToScheme的时候就会调用我们在init里注册的函数,从而把pair、defaulter、convert注册到指定的scheme
  因为要k8s知道我们的pair,那么后面我们肯定是注册到k8s内建的scheme中
  !!只有这个文件被加载,init函数才会被执行,如果文件根本没有被加载,那么根本就不会执行,也就根本不会被注册,所以我们需要使用import语句强制导入,即强制加载此文件
*/
func init() {  
	// We only register manually written functions here. The registration of the
	// generated functions takes place in the generated files. The separation
	// makes the code compile even when the generated files are missing.
	localSchemeBuilder.Register(addKnownTypes)               //注册pair(gvk,struct)
	localSchemeBuilder.Register(RegisterDefaults)            //注册defaulter,这个RegisterDefaults函数是code-gen自动生成的
	localSchemeBuilder.Register(RegisterConversions)         //注册convert函数,这个函数也是code-gen自动生成的
	fmt.Println("load DynamicArgs v1beta2")
}

2.5 工具code-gen工具生成defaulter函数,我们直接贴代码,就不贴

工具自动生成的文件叫zz_generated.defaulter.go,文件里的所有代码都是自动生成的,当重新生成的时候会清空文件中的所有内容,所以所有改动都应该在其他文件中实现

//go:build !ignore_autogenerated
// +build !ignore_autogenerated

// Code generated by defaulter-gen. DO NOT EDIT.

package v1beta2

import (
	runtime "k8s.io/apimachinery/pkg/runtime"
)

// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {   
                                                                      //这个函数类似于前面的addKnowTypes函数,就是实现登记功能
                                                                      //就是实现登记defaulter到scheme,我们需要把这个函数保存到前面的localBuilder里面,
                                                                      //以便调用AddToScheme的时候可以一同注册到scheme里
                                                                      //因为defaulter函数、convert函数、pair(gvk,struct)都是通过scheme来获取的
	scheme.AddTypeDefaultingFunc(&DynamicArgs{}, func(obj interface{}) { SetObjectDefaults_DynamicArgs(obj.(*DynamicArgs)) })
	return nil
}

func SetObjectDefaults_DynamicArgs(in *DynamicArgs) {
	SetDefaults_DynamicArgs(in)                //这个函数就是我们在defaults.go里面手动实现的,也就是说code-gen只是生成一个默认函数a,这个函数调用了一个函数b,这个b需要我们手动实现
}

2.6 通过code-gen工具给DynamicArgs实现runtime.Object的DeepCopy函数

工具生成的文件名叫zz_generated.deepcopy.go

//go:build !ignore_autogenerated
// +build !ignore_autogenerated

// Code generated by deepcopy-gen. DO NOT EDIT.

package v1beta2

import (
	runtime "k8s.io/apimachinery/pkg/runtime"
)

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DynamicArgs) DeepCopyInto(out *DynamicArgs) {
	*out = *in
	out.TypeMeta = in.TypeMeta
	out.MetricsUpdatePeriodBySeconds = in.MetricsUpdatePeriodBySeconds
	return
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DynamicArgs.
func (in *DynamicArgs) DeepCopy() *DynamicArgs {
	if in == nil {
		return nil
	}
	out := new(DynamicArgs)
	in.DeepCopyInto(out)
	return out
}

// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *DynamicArgs) DeepCopyObject() runtime.Object {
	if c := in.DeepCopy(); c != nil {
		return c
	}
	return nil
}

2.7 通过code-gen生成 convert函数

生成的文件名叫zz_generated.conversion.go

//go:build !ignore_autogenerated
// +build !ignore_autogenerated

// Code generated by conversion-gen. DO NOT EDIT.

package v1beta2

import (
 
    /*
          注意下包的问题,如果有报错,自己修正路径,
          这个config表示的是__internal版本,也就是说我们的__internal版本的DynamicArgs是放在config包下面且在config包里面注册到scheme的,这个包名可以随便叫
          不过如果修改包名成XXX,下面的Convert_v1beta2_DynamicArgs_To_config_DynamicArgs也要改成Convert_v1beta2_DynamicArgs_To_XXX_DynamicArgs
          因为他的这些名字的格式都是固定的,表示把v1beta2包下面的DynamicArgs转换成config包下面的DynamicArgs
    */
	config "awesomeProject5/pkg/plugins/apis/config"  
	unsafe "unsafe"

	conversion "k8s.io/apimachinery/pkg/conversion"
	runtime "k8s.io/apimachinery/pkg/runtime"
)

// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(s *runtime.Scheme) error { 
                                                    //同addKnowTypes和RegisterDefaulter,都是实现登记注册功能
                                                    //我们也需要把它保存到localBuilder里面,以便外部调用AddToScheme的时候注册到该scheme中

    //外部v1beta2->内部__internal

	if err := s.AddGeneratedConversionFunc((*DynamicArgs)(nil), (*config.DynamicArgs)(nil), func(a, b interface{}, scope conversion.Scope) error {
		return Convert_v1beta2_DynamicArgs_To_config_DynamicArgs(a.(*DynamicArgs), b.(*config.DynamicArgs), scope)
	}); err != nil {
		return err
	}

    //内部__internal->外部v1beta2, 我们这里没用到,但还是写一下

	if err := s.AddGeneratedConversionFunc((*config.DynamicArgs)(nil), (*DynamicArgs)(nil), func(a, b interface{}, scope conversion.Scope) error {
		return Convert_config_DynamicArgs_To_v1beta2_DynamicArgs(a.(*config.DynamicArgs), b.(*DynamicArgs), scope)
	}); err != nil {
		return err
	}
	return nil
}

func autoConvert_v1beta2_DynamicArgs_To_config_DynamicArgs(in *DynamicArgs, out *config.DynamicArgs, s conversion.Scope) error {
	out.PolicyConfigPath = in.PolicyConfigPath
	out.PromeAddr = in.PromeAddr
	out.MetricsUpdatePeriodBySeconds = in.MetricsUpdatePeriodBySeconds
	out.ClusterName = in.ClusterName
	return nil
}

// Convert_v1beta2_DynamicArgs_To_config_DynamicArgs is an autogenerated conversion function.
func Convert_v1beta2_DynamicArgs_To_config_DynamicArgs(in *DynamicArgs, out *config.DynamicArgs, s conversion.Scope) error {
	return autoConvert_v1beta2_DynamicArgs_To_config_DynamicArgs(in, out, s)
}

func autoConvert_config_DynamicArgs_To_v1beta2_DynamicArgs(in *config.DynamicArgs, out *DynamicArgs, s conversion.Scope) error {
	out.PolicyConfigPath = in.PolicyConfigPath
	out.PromeAddr = in.PromeAddr
	out.MetricsUpdatePeriodBySeconds = in.MetricsUpdatePeriodBySeconds
	out.ClusterName = in.ClusterName
	return nil
}

// Convert_config_DynamicArgs_To_v1beta2_DynamicArgs is an autogenerated conversion function.
func Convert_config_DynamicArgs_To_v1beta2_DynamicArgs(in *config.DynamicArgs, out *DynamicArgs, s conversion.Scope) error {
	return autoConvert_config_DynamicArgs_To_v1beta2_DynamicArgs(in, out, s)
}

至此,v1beat2版本的DynamicArgs已经实现完成了,接下来再实现一版 __internal 版本的DynamicArgs就可以了,操作和v1beta2几乎一摸一样。

只有四个地方有区别:

1:所在的包名,即package v1beta2换成package config;
2:注册所使用的的SchemeBuilder不同;
3:注册时使用的版本不同
4:无需生成conversion函数,因为我们已经在v1beta2里登记和注册生成了v1beta2版本DynamicArgs和config版本DynamicArgs版本互相转换的转换函数
   即config包的registry.go文件的init函数里无需调用localBuilder.Register(RegisterConversion)

下面我就仅仅点出不同,其他的就一个包名不同了

package config //包变成了config,不是v1beta2

import (
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/klog/v2"
	kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"   
)

//注意:这里只有一个版本不同,group还是kubescheduler.config.k8s.io,只是version字段变成了__internal
var SchemeGroupVersion = schema.GroupVersion{Group: kubeschedulerconfig.GroupName, Version: runtime.APIVersionInternal}

var (
	localSchemeBuilder = &kubeschedulerconfig.SchemeBuilder           //这里我们使用的是config下面的SchemeBuilder,而v1beta2版本中我们使用的是k8s v1beta2下面的SchemeBuilder
	// AddToScheme is a global function that registers this API group & version to a scheme
	AddToScheme = localSchemeBuilder.AddToScheme
)
...其他一切都相同...

3:创建awesomeProject5/pkg/apis/plugins/config/scheme/scheme.go

文件名随便叫,目录名随便叫,我们就这里目录为awesomeProject5/pkg/apis/plugins/config/scheme,文件名为scheme.go

package scheme

import (
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	kubeschedulerscheme "k8s.io/kubernetes/pkg/scheduler/apis/config/scheme"

	myconfig "awesomeProject5/pkg/apis/plugins/config"
	myv1beta2 "awesomeProject5/pkg/apis/plugins/config/v1beta2"
)

var (
	// Re-use the in-tree Scheme.
	Scheme = kubeschedulerscheme.Scheme                                  //这是k8s自带的Scheme,我们就是注册到整个scheme里
	// Codecs provides access to encoding and decoding for the scheme.
	Codecs = serializer.NewCodecFactory(Scheme, serializer.EnableStrict) //编码解码器,是根据特定scheme创建的,可以用来从文件加载对象,但是我们第二版没有用到,可以不写

	A=1
)

func init() {
	AddToScheme(Scheme)  //注册到k8s自带的scheme
}

// AddToScheme builds the kubescheduler scheme using all known versions of the kubescheduler api.
func AddToScheme(scheme *runtime.Scheme) {
	utilruntime.Must(myconfig.AddToScheme(scheme))   //调用__internal版本的AddToScheme,并执行该文件里面的init
	utilruntime.Must(myv1beta2.AddToScheme(scheme))  //调用v1beta2版本的AddToScheme,并执行该文件里面的init
	fmt.Println("load myconfig and myv1beta2 ok")
}

4:强制加载

直接在main函数里访问config里面的变量就行


import (
    myscheme "awesomeProject5/pkg/apis/plugins/config/scheme"
)
func main(){
    ......
    myscheme.A=2  //这里会加载config,然后调用init,然后在AddToScheme中又触发myv1beta2.init......,然后执行AddToScheme,然后就完成了注册加载
                  //办法虽然土,但有用。。。。。。。
    ......
}

然后编译之后,我们运行程序,控制台打印出下面的信息就说明我们的DynamicScheduler成功启动了

......
load DynamicArgs config   
load DynamicArgs v1beta2  
load myconfig and myv1beta2 ok
I0218 14:27:22.070130   20248 serving.go:348] Generated self-signed cert in-memory
......
W0218 14:02:14.221896   16008 authentication.go:340] No authentication-kubeconfig provided in order to lookup requestheader-client-ca-file in configmap/extension-api
server-authentication in kube-system, so request-header client certificate authentication won't work.
W0218 14:02:14.222412   16008 authorization.go:193] No authorization-kubeconfig provided, so SubjectAccessReview of authorization tokens won't work.
plArgs.PolicyConfigPath XXXXXX
plArgs.PromAddr XXXXXXX                         
plArgs.MetricsUpdatePeriodBySeconds XXXXXXX
plArgs.ClusterName XXXXXXX
I am NewDynamicScheduler

文章来源地址https://www.toymoban.com/news/detail-833981.html

到了这里,关于k8s scheduler开发实战(二):带插件参数版的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【云原生 | Kubernetes 系列】K8s 实战 管理 Secret 详解

    Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象。 这样的信息可能会被放在 Pod 规约中或者镜像中。 用户可以创建 Secret,同时系统也创建了一些 Secret。 一个 Secret 可以包含 Pod 访问数据库所需的用户凭证。 例如,由用户名和密码组成的数据库连接字符串。 你可

    2024年02月02日
    浏览(47)
  • 【云原生 | Kubernetes 系列】K8s 实战 如何给应用注入数据

    前面我们已经一起学习了很多的东西了,本篇文章,我们将一起学习,如何给应用注入数据,当然,本篇文章不会讲解全部知识点,而是带领大家,一起学习如何对我们的项目进行相关的配置和设置。 创建 Pod 时,可以为其下的容器设置启动时要执行的命令及其参数。如果要

    2024年02月02日
    浏览(50)
  • 【云原生-K8s】kubeadm搭建安装k8s集群v1.25版本完整教程【docker、网络插件calico、中间层cri-docker】

    从 k8s 1.24开始,dockershim已经从kubelet中移除,但因为历史问题docker却不支持kubernetes主推的CRI(容器运行时接口)标准,所以docker不能再作为k8s的容器运行时了,即从k8s v1.24开始不再使用docker了 但是如果想继续使用docker的话,可以在kubelet和docker之间加上一个中间层cri-docker。

    2024年02月03日
    浏览(34)
  • 【云原生】Elasticsearch + kibana on k8s 讲解与实战操作

    Elasticsearch是一个基于Lucene的搜索引擎。它提供了具有HTTP Web界面和无架构JSON文档的分布式,多租户能力的全文搜索引擎。Elasticsearch是用Java开发的,根据Apache许可条款作为开源发布。 官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/master/getting-started.html GitHub: https://gith

    2023年04月08日
    浏览(29)
  • 构建新一代的K8s原生Java微服务+Quarkus实战

    送书第一期 《用户画像:平台构建与业务实践》 送书活动之抽奖工具的打造 《获取博客评论用户抽取幸运中奖者》 送书第二期 《Spring Cloud Alibaba核心技术与实战案例》 送书第三期 《深入浅出Java虚拟机》 送书第四期 《AI时代项目经理成长之道》 送书第五期 《Kubernetes原生

    2024年02月08日
    浏览(38)
  • 【云原生|K8s系列第4篇】:实战查看Pod和工作节点

    本期文章是K8s系列第4篇,主要是实战查看pod和工作节点。通过本期文章:我们将学习了解Kubernetes中的Pod和工作节点,并且对已经部署的应用故障排除。 在前期的文章中,已经介绍了一些云原生入门的知识及简单实战,感兴趣的同学可以去我的云原生专栏中学习,任意门:云

    2024年01月16日
    浏览(45)
  • 云原生之深入解析Flink on k8s的运行模式与实战操作

    Flink 核心是一个流式的数据流执行引擎,并且能够基于同一个 Flink 运行时,提供支持流处理和批处理两种类型应用。其针对数据流的分布式计算提供了数据分布,数据通信及容错机制等功能。 Flink 官网 不同版本的文档 flink on k8s 官方文档 GitHub 地址 官方文档 Flink on yarn 有三

    2024年02月13日
    浏览(34)
  • 云原生之深入解析K8S Istio Gateway服务的架构分析与实战操作

    Istio 提供一种简单的方式来为已部署的服务建立网络,该网络具有负载均衡、服务间认证、监控、网关等功能,而不需要对服务的代码做任何改动。 istio 适用于容器或虚拟机环境(特别是 k8s),兼容异构架构; istio 使用 sidecar(边车模式)代理服务的网络,不需要对业务代

    2024年02月13日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包