kubernetes二次開發(主要是開發滿足自己業務的api)

來源:互聯網
上載者:User
kubernetes clinet-go 開發(一)

kubernetes目前提供兩種方式來建立所需要的pod,service,replicationcontroller等,一種是通過kubectl create -f ,一種通過http 的restful 介面,由於工作項目的原因,需要根據實際的業務需求來定製化的開發k8s的api,我所用到的庫是官方給出的,程式碼程式庫地址:https://github.com/kubernetes/client-go,以下是我在開發時的一些思路整理,由於水平有限,講得不好,還請廣大博友諒解。 初始化串連 代碼解讀 建立namespace 建立pod 建立replicationController 建立service 初始化串連 方式一:

直接上代碼:

package mainimport (    "fmt"    "time"    "k8s.io/client-go/1.4/kubernetes"    "k8s.io/client-go/1.4/pkg/api"    "k8s.io/client-go/1.4/rest")func main() {    // creates the in-cluster config    config, err := rest.InClusterConfig()    if err != nil {        panic(err.Error())    }    // creates the clientset    clientset, err := kubernetes.NewForConfig(config)    if err != nil {        panic(err.Error())    }}
代碼解讀

以上代碼就是擷取一個kubernetes叢集的client

config, err := rest.InClusterConfig()

本行代碼是初始化一個預設的k8s的rest.Config,該config源碼如下:

type Config struct {// Host must be a host string, a host:port pair, or a URL to the base of the apiserver.// If a URL is given then the (optional) Path of that URL represents a prefix that must// be appended to all request URIs used to access the apiserver. This allows a frontend// proxy to easily relocate all of the apiserver endpoints.Host string// APIPath is a sub-path that points to an API root.APIPath string// Prefix is the sub path of the server. If not specified, the client will set// a default value.  Use "/" to indicate the server root should be usedPrefix string// ContentConfig contains settings that affect how objects are transformed when// sent to the server.ContentConfig// Server requires Basic authenticationUsername stringPassword string// Server requires Bearer authentication. This client will not attempt to use// refresh tokens for an OAuth2 flow.// TODO: demonstrate an OAuth2 compatible client.BearerToken string// Impersonate is the username that this RESTClient will impersonateImpersonate string// Server requires plugin-specified authentication.AuthProvider *clientcmdapi.AuthProviderConfig// Callback to persist config for AuthProvider.AuthConfigPersister AuthProviderConfigPersister// TLSClientConfig contains settings to enable transport layer securityTLSClientConfig// Server should be accessed without verifying the TLS// certificate. For testing only.Insecure bool// UserAgent is an optional field that specifies the caller of this request.UserAgent string// Transport may be used for custom HTTP behavior. This attribute may not// be specified with the TLS client certificate options. Use WrapTransport// for most client level operations.Transport http.RoundTripper// WrapTransport will be invoked for custom HTTP behavior after the underlying// transport is initialized (either the transport created from TLSClientConfig,// Transport, or http.DefaultTransport). The config may layer other RoundTrippers// on top of the returned RoundTripper.WrapTransport func(rt http.RoundTripper) http.RoundTripper// QPS indicates the maximum QPS to the master from this client.// If it's zero, the created RESTClient will use DefaultQPS: 5QPS float32// Maximum burst for throttle.// If it's zero, the created RESTClient will use DefaultBurst: 10.Burst int// Rate limiter for limiting connections to the master from this client. If present overwrites QPS/BurstRateLimiter flowcontrol.RateLimiter// Version forces a specific version to be used (if registered)// Do we need this?// Version string

}

該config包含了串連apiserver需要的一些資訊,我包括api的串連ip port(即hostname),用於認證用的一些資訊,如:username,password等,以及api調用傳回值的類型,序列化等。

回到InClusterConfig()這個方法中:

func InClusterConfig() (*Config, error) {host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")if len(host) == 0 || len(port) == 0 {    return nil, fmt.Errorf("unable to load in-cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined")}token, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/" + api.ServiceAccountTokenKey)if err != nil {    return nil, err}tlsClientConfig := TLSClientConfig{}rootCAFile := "/var/run/secrets/kubernetes.io/serviceaccount/" + api.ServiceAccountRootCAKeyif _, err := crypto.CertPoolFromFile(rootCAFile); err != nil {    glog.Errorf("Expected to load root CA config from %s, but got err: %v", rootCAFile, err)} else {    tlsClientConfig.CAFile = rootCAFile}return &Config{    // TODO: switch to using cluster DNS.    Host:            "https://" + net.JoinHostPort(host, port),    BearerToken:     string(token),    TLSClientConfig: tlsClientConfig,}, nil}

首先就是擷取KUBERNETES_SERVICE_HOST 和 KUBERNETES_SERVICE_PORT這連個環境變數,所以必須要設定這兩個環境變數(就是apiserver的ip和port),然後是擷取/var/run/secrets/kubernetes.io/serviceaccount/下的認證檔案,進行config的初始化,從而為下一步的串連做準備。如果在相應的環境中沒有相應的ca檔案,則該方法會報錯,初始化k8s的client不成功 方式二:

var (    kubeconfig = flag.String("kubeconfig", "./config", "absolute path to the kubeconfig file"))func main() {    flag.Parse()    // uses the current context in kubeconfig    config, err := clientcmd.BuildConfigFromFlags("183.131.19.231:8080", *kubeconfig)    if err != nil {        panic(err.Error())    }    // creates the clientset    clientset, err := kubernetes.NewForConfig(config)    if err != nil {        panic(err.Error())    }}

其中config設定檔資訊如下:

apiVersion: v1clusters:- cluster:    api-version: v1    server: http://183.131.19.231:8080  name: k8s-clustercontexts:- context:    cluster: k8s-server    user: myself  name: default-contextcurrent-context: default-contextkind: Configpreferences:  colors: trueusers:- name: myself  user:    password: admin    username: admin11232

這種方式是通過設定檔的方式去連結kube-apiserver,從而擷取clientset,設定檔的設定以及擷取可以參考官方文檔:http://kubernetes.io/docs/user-guide/kubeconfig-file/ 建立namespace

首先講建立namesapce的原因是因為後續的pod,replicationController,service等的建立,在通常的業務中都會和namesapce相關聯,namespace其實就相當於租戶的概念,或者就相當於group,起到資源隔離的作用。

首先來看看client.Core()這個方法中包含了那些介面以及介面的實現:

func (c *CoreClient) ComponentStatuses() ComponentStatusInterface {    return newComponentStatuses(c)}func (c *CoreClient) ConfigMaps(namespace string) ConfigMapInterface {    return newConfigMaps(c, namespace)}func (c *CoreClient) Endpoints(namespace string) EndpointsInterface {    return newEndpoints(c, namespace)}func (c *CoreClient) Events(namespace string) EventInterface {    return newEvents(c, namespace)}func (c *CoreClient) LimitRanges(namespace string) LimitRangeInterface {    return newLimitRanges(c, namespace)}func (c *CoreClient) Namespaces() NamespaceInterface {    return newNamespaces(c)}func (c *CoreClient) Nodes() NodeInterface {    return newNodes(c)}func (c *CoreClient) PersistentVolumes() PersistentVolumeInterface {    return newPersistentVolumes(c)}func (c *CoreClient) PersistentVolumeClaims(namespace string) PersistentVolumeClaimInterface {    return newPersistentVolumeClaims(c, namespace)}func (c *CoreClient) Pods(namespace string) PodInterface {    return newPods(c, namespace)}func (c *CoreClient) PodTemplates(namespace string) PodTemplateInterface {    return newPodTemplates(c, namespace)}func (c *CoreClient) ReplicationControllers(namespace string) ReplicationControllerInterface {    return newReplicationControllers(c, namespace)}func (c *CoreClient) ResourceQuotas(namespace string) ResourceQuotaInterface {    return newResourceQuotas(c, namespace)}func (c *CoreClient) Secrets(namespace string) SecretInterface {    return newSecrets(c, namespace)}func (c *CoreClient) Services(namespace string) ServiceInterface {    return newServices(c, namespace)}func (c *CoreClient) ServiceAccounts(namespace string) ServiceAccountInterface {    return newServiceAccounts(c, namespace)}

其中我們這裡主要用到的是

func (c *CoreClient) Namespaces() NamespaceInterface {    return newNamespaces(c)}

在看NamespaceInterface 這個介面中的方法:

type NamespaceInterface interface {    Create(*v1.Namespace) (*v1.Namespace, error)    Update(*v1.Namespace) (*v1.Namespace, error)    UpdateStatus(*v1.Namespace) (*v1.Namespace, error)    Delete(name string, options *api.DeleteOptions) error    DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error    Get(name string) (*v1.Namespace, error)    List(opts api.ListOptions) (*v1.NamespaceList, error)    Watch(opts api.ListOptions) (watch.Interface, error)    Patch(name string, pt api.PatchType, data []byte, subresources ...string) (result *v1.Namespace, err error)    NamespaceExpansion}

這裡我們主要講解namespace的建立:
建立namespace需要傳入v1.Namespace這個struct的指標,我們在看看這個strutc的結構:

type Namespace struct {    unversioned.TypeMeta `json:",inline"`    // Standard object's metadata.    // More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata    ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`    // Spec defines the behavior of the Namespace.    // More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status    Spec NamespaceSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`    // Status describes the current status of a Namespace.    // More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status    Status NamespaceStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`}

其中的三個struct是於yaml中的類型,中繼資料,還有space是一一對應的。

    //create a namespace    nc := new(v1.Namespace)    ncTypeMeta := unversioned.TypeMeta{Kind: "NameSpace", APIVersion: "v1"}    nc.TypeMeta = ncTypeMeta    nc.ObjectMeta = v1.ObjectMeta{        Name: "k8s-test",    }    nc.Spec = v1.NamespaceSpec{}

這個其實就相當於yaml檔案中做如下定義:

apiVersion: v1kind: NameSpacemetadata:  name: "k8s-test"spec:

如果有lable,space之類的設定,查閱相關代碼加上即可。

之後建立namespace:

resultnc, err := dao.Clientset.Core().Namespaces().Create(nc)

穿件成功完成之後會返回建立的namespace,如果失敗,會返回相應的錯誤資訊。

之後在k8s叢集中通過kubectl命令查看建立的namespace,建立成功。同理還有刪除修改等操作,這裡就不在一一示範了。 建立pod

建立pod以及rc,service的方式和namaspace的方式基本上是一致的,所以我就直接貼代碼:

    pod:=new(v1.Pod)    pod.TypeMeta=unversioned.TypeMeta{Kind: "Pod", APIVersion: "v1"}    pod.ObjectMeta=v1.ObjectMeta{Name: app.Name, Namespace: app.UserName, Labels: map[string]string{"name": app.Name}}    pod.Spec=v1.PodSpec{                RestartPolicy: v1.RestartPolicyAlways,                Containers: []v1.Container{                    v1.Container{                        Name:  app.Name,                        Image: app.Image,                        Ports: []v1.ContainerPort{                            v1.ContainerPort{                                ContainerPort: 9080,                                Protocol:      v1.ProtocolTCP,                            },                        },                        Resources: v1.ResourceRequirements{                            Requests: v1.ResourceList{                                v1.ResourceCPU:    resource.MustParse(app.Cpu),                                v1.ResourceMemory: resource.MustParse(app.Memory),                            },                        },                    },                },            }    result, err := dao.Clientset.Core().Pods(NameSpace).Create(pod)
建立replicationController
//create a replicationController    rc := new(v1.ReplicationController)    rcTypeMeta := unversioned.TypeMeta{Kind: "ReplicationController", APIVersion: "v1"}    rc.TypeMeta = rcTypeMeta    rcObjectMeta := v1.ObjectMeta{Name: app.Name, Namespace: app.UserName, Labels: map[string]string{"name": app.Name}}    rc.ObjectMeta = rcObjectMeta    rcSpec := v1.ReplicationControllerSpec{        Replicas: &app.InstanceCount,        Selector: map[string]string{            "name": app.Name,        },        Template: &v1.PodTemplateSpec{            v1.ObjectMeta{                Name:      app.Name,                Namespace: app.UserName,                Labels: map[string]string{                    "name": app.Name,                },            },            v1.PodSpec{                RestartPolicy: v1.RestartPolicyAlways,                Containers: []v1.Container{                    v1.Container{                        Name:  app.Name,                        Image: app.Image,                        Ports: []v1.ContainerPort{                            v1.ContainerPort{                                ContainerPort: 9080,                                Protocol:      v1.ProtocolTCP,                            },                        },                        Resources: v1.ResourceRequirements{                            Requests: v1.ResourceList{                                v1.ResourceCPU:    resource.MustParse(app.Cpu),                                v1.ResourceMemory: resource.MustParse(app.Memory),                            },                        },                    },                },            },        },    }    rc.Spec = rcSpec    result, err := dao.Clientset.Core().ReplicationControllers(NameSpace).Create(rc)
建立service
//create service        service := new(v1.Service)        svTypemeta := unversioned.TypeMeta{Kind: "Service", APIVersion: "v1"}        service.TypeMeta = svTypemeta        svObjectMeta := v1.ObjectMeta{Name: app.Name, Namespace: app.UserName, Labels: map[string]string{"name": app.Name}}        service.ObjectMeta = svObjectMeta        svServiceSpec := v1.ServiceSpec{            Ports: []v1.ServicePort{                v1.ServicePort{                    Name:       app.Name,                    Port:       9080,                    TargetPort: intstr.FromInt(9080),                    Protocol:   "TCP",                    // NodePort:   32107,                },            },            Selector: map[string]string{"name": app.Name},            Type:     v1.ServiceTypeNodePort,            // LoadBalancerIP: "172.17.11.2",            // Status: v1.ServiceStatus{            //  LoadBalancer: v1.LoadBalancerStatus{            //      Ingress: []v1.LoadBalancerIngress{            //          v1.LoadBalancerIngress{IP: "172.17.11.2"},            //      },            //  },            // },        }        service.Spec = svServiceSpec        _, err := dao.Clientset.Core().Services(NameSpace).Create(service)
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.