Crossplane详解2——编写自己的Openstack Provider

11 篇文章 0 订阅
5 篇文章 0 订阅

1. 当前的Provider 支持程度

1.1 官方支持的Provider:

  • AWS,支持最丰富,且版本总是跟着最新的Crossplane 而更新,可惜没有针对虚拟机的Managed Resource,EC2等等。
  • 阿里云,非常没有诚意,这么多云资源,只象征性的,有一个Redis服务,非常敷衍。
  • Azure,支持仅次于AWS,但也很有限,只有数据库和网络相关的一些资源。
  • GCP,和Azure 差不多,只有桶啊,网络资源等,其余啥也没有。
  • Oenstack,官方就没有支持,连个空的项目都没建。

1.2 个人针对Openstack 的支持:

看介绍,以为这个provider 可以handle openstack 的复杂场景。
代码地址: rochaporto/provider-openstack. 仔细阅读后,发现这个项目非常简陋,看代码几乎什么也没做,NOTHING,垃圾,什么也不是。

2. 理解crossplane-runtime

有些基础概念,要事先解释,参考我的上一篇文章,介绍Crossplane的概念。

它的本质并没有脱离informer-controller 机制,这个引擎是工作在k8s.io/controller-runtime 基础之上的。

它的调谐哲学:
crossplane runtime 把external (外部provider)接口定义出来,我们在写新的provider 的时候,不需要,也完全不应该关注k8s 资源recognize的逻辑,external provider 只有修改外部资源的功能,万万不可修改k8s 的crd。

  1. external 接口

    type ExternalClient interface {
    	// Observe the external resource the supplied Managed resource represents,
    	// if any. Observe implementations must not modify the external resource,
    	// but may update the supplied Managed resource to reflect the state of the
    	// external resource.
    	Observe(ctx context.Context, mg resource.Managed) (ExternalObservation, error)
    
    	// Create an external resource per the specifications of the supplied
    	// Managed resource. Called when Observe reports that the associated
    	// external resource does not exist.
    	Create(ctx context.Context, mg resource.Managed) (ExternalCreation, error)
    
    	// Update the external resource represented by the supplied Managed
    	// resource, if necessary. Called unless Observe reports that the
    	// associated external resource is up to date.
    	Update(ctx context.Context, mg resource.Managed) (ExternalUpdate, error)
    
    	// Delete the external resource upon deletion of its associated Managed
    	// resource. Called when the managed resource has been deleted.
    	Delete(ctx context.Context, mg resource.Managed) error
    }
    

    外部 provider 需要实现上述接口,这些接口必须针对的是外部资源池,那么有同学要问了,如果我像修改managedresource,该怎么办呢?ExternalClient 接口的实现,一般我们要杜绝直接修改managedresource 的spec。这是因为k8s 的设计哲学是,不可变基础设施,资源是人定义的,定义后,就不能改,如果你非要改,怎么改?有两种方式:

    1. 在你的ExternalClient对象中,增加kubeclient 的构成,默认官方的模板,是不建议的。因为你只是去执行,而不应该修改资源的描述文件,这个权限给的就非常大了。
    2. 在ExternalCreation的返回值中,描述下你的ExternalNameAssigned 为true,这里可以修改你的annotation,增加名称的修改。意思是,你的同一个资源,在k8s 里叫张三,在外部provider那里,就叫李四,可以通过一个annotation,传递给crossplane runtime,来增加名称的转换,也只能改名称。

    必须先通过一个Connect 方法获取external client,这个connect 返回外部provider 的客户端,比如awsclient、openstackclient等。

3. 创建一个openstack provider

这小节,主要完成,创建一个openstack provider,并且实现创建和删除openstack虚拟机的过程。

  1. fork 下这个provider-template
  2. 修改掉这里的Mytype,改成virtualmachine,或者你喜欢的名字。
  3. 修改3个接口
    • connect
      这里返回的是由openstack client组成的external,我们需要拿到openstack 的auth配置文件。在这里插入图片描述
      我们这里取到的是,openstack 的yaml配置文件,我们取出来.cloud.openstack的内容,大概长这个样子:

          auth:
            auth_url: http://111.11.11.11:5000
            username: "XXXXXXX"
            password: "XXXXXXX"
            project_id: XXXXXXXXXXXXXXXXX
            project_name: "XXXXXXXXXXXXX"
            user_domain_name: "Default"
          region_name: "RegionOne"
          interface: "public"
          identity_api_version: 3
      
    • 构造一个struct对象,对这个yaml结构体进行解析

      	newOpenstackClient = func(credentials []byte) (interface{}, error) {
      		openstackConfig := new(OpenstackConfig)
      		err := yaml.Unmarshal(credentials, &openstackConfig)
      		if err != nil {
      			return nil, err
      		}
      		options := gophercloud.AuthOptions{
      			Username:         openstackConfig.Auth.Username,
      			Password:         openstackConfig.Auth.Password,
      			DomainName:       openstackConfig.Auth.UserDomainName,
      			TenantName:       openstackConfig.Auth.ProjectName,
      			TenantID: openstackConfig.Auth.ProjectID,
      			IdentityEndpoint: openstackConfig.Auth.AuthUrl,
      		}
      		client, authError := openstack.AuthenticatedClient(options)
      		if authError != nil {
      			return nil, err
      		}
      		return client, nil
      	}
      
    1. Observe 接口
      这个接口,是为了根据当前ManagedResource 查询这个资源在provider里的详情的,它在不同的操作中,起到的作用是不一样的。

      • 在第一次创建资源的时候,observe 是为了检测下,资源在provider 中是否存在(不存在要create的)。
      • 在修改了managedresource 的时候,是为了检测,资源的diff,是否需要更新。
      • 如果要删除,需要查看下资源是否存在,如果存在就要删资源。

      给一段我写的示例代码。注意,名称需要精准匹配fmt.Sprintf("^%s$", cr.Name)

      	// 3. server client
      	client, serverError := openstack.NewComputeV2((c.service).(*gophercloud.ProviderClient), gophercloud.EndpointOpts{
      		Region: "RegionOne",
      	})
      
      	if  serverError!=nil {
      		return managed.ExternalObservation{}, errors.New("can't get nova client")
      	}
      
      	// 4. servers ops
      	exactalName := fmt.Sprintf("^%s$", cr.Name)
      	opts := servers.ListOpts{Name: exactalName}
      
      	// Retrieve a pager (i.e. a paginated collection)
      	pager := servers.List(client, opts)
      
  4. create 接口
    create 相对来说比较简单。直接给示例代码:需要说明的是,这里的annotation里需要带上id。因为将来删的时候,必须要要通过ID去删除。
    	// 3. server client
    	client, _ := openstack.NewComputeV2((c.service).(*gophercloud.ProviderClient), gophercloud.EndpointOpts{
    		Region: "RegionOne",
    	})
    
    	// 4. servers ops
    	result, CreateError := servers.Create(client, servers.CreateOpts{
    		Name:      cr.Name,
    		ImageName:  "CentOS-8-GenericCloud-8.3.2011",
    		FlavorName: "hyperos-flavor",
    		Networks: []servers.Network{
    			{UUID: "246af0d1-6bcb-447d-b82a-eae1225e1aaa"},
    		},
    		ServiceClient: client,
    	}).Extract()
    
    	if CreateError != nil {
    		log.Println("Create vm error:", CreateError.Error())
    	}
    
    	anno := mg.GetAnnotations()
    	anno[meta.AnnotationKeyExternalName] = result.ID
    	mg.SetAnnotations(anno)
    
  5. delete 接口
    最简单,拿到annotation,直接删除就完事儿了。
    // 3. server client
    	client, _ := openstack.NewComputeV2((c.service).(*gophercloud.ProviderClient), gophercloud.EndpointOpts{
    		Region: "RegionOne",
    	})
    
    	// 4. servers ops
    	return servers.Delete(client, cr.GetAnnotations()[meta.AnnotationKeyExternalName]).ExtractErr()
    }
    

总结:

通过这个方式,我们可以利用crossplane 的runtime 实现直接操作openstack的接口,分离k8s资源和provider的资源。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值