Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Samples on kubernetes helm golang client

I want to create a service on kubernetes which manages helm charts on the cluster. It installs charts from a private chart repository. Since I didn't find any documents on how to use helm client api, I was looking for some samples or guidelines for creating a service on top of helm client.

like image 554
Mehran Akhavan Avatar asked Aug 15 '17 12:08

Mehran Akhavan


4 Answers

Since it took me some time to get this working here is a minimal example (no error handling, left details about kube config, ...) for listing release names:

package main

import (
  "k8s.io/client-go/kubernetes"
  "k8s.io/helm/pkg/helm"
  "k8s.io/helm/pkg/helm/portforwarder"
)

func main() {
  // omit getting kubeConfig, see: https://github.com/kubernetes/client-go/tree/master/examples

  // get kubernetes client
  client, _ := kubernetes.NewForConfig(kubeConfig)

  // port forward tiller
  tillerTunnel, _ := portforwarder.New("kube-system", client, config)

  // new helm client
  helmClient := helm.NewClient(helm.Host(host))

  // list/print releases
  resp, _ := helmClient.ListReleases()
  for _, release := range resp.Releases {
    fmt.Println(release.GetName())
  }
}
like image 123
rabenhorst Avatar answered Oct 17 '22 11:10

rabenhorst


I was long trying to set up Helm installation with --set values, and I found that the best place to look currently available functionality is official helm documentation example and official Go docs for the client.

This only pertains to Helm 3.

Here's an example I managed to get working by using the resources linked above.

I haven't found a more elegant way to define values rather than recursively asking for the map[string]interface{}, so if anyone knows a better way, please let me know.

Values should be roughly equivalent to:
helm install myrelease /mypath --set redis.sentinel.masterName=BigMaster,redis.sentinel.pass="random" ... etc

Notice the use of settings.RESTClientGetter(), rather than kube.Get, as in other answers. I found kube.Get to be causing nasty conflicts with k8s clients.

package main

import (
    "log"
    "os"

    "helm.sh/helm/v3/pkg/action"
    "helm.sh/helm/v3/pkg/chart/loader"
    "helm.sh/helm/v3/pkg/cli"
    "helm.sh/helm/v3/pkg/release"
)

func main(){
    chartPath := "/mypath"
    namespace := "default"
    releaseName := "myrelease"

    settings := cli.New()

    actionConfig := new(action.Configuration)
    // You can pass an empty string instead of settings.Namespace() to list
    // all namespaces
    if err := actionConfig.Init(settings.RESTClientGetter(), namespace,
        os.Getenv("HELM_DRIVER"), log.Printf); err != nil {
        log.Printf("%+v", err)
        os.Exit(1)
    }

    // define values
    vals := map[string]interface{}{
        "redis": map[string]interface{}{
            "sentinel": map[string]interface{}{
                "masterName": "BigMaster",
                "pass":       "random",
                "addr":       "localhost",
                "port":       "26379",
            },
        },
    }

    // load chart from the path 
    chart, err := loader.Load(chartPath)
    if err != nil {
        panic(err)
    }

    client := action.NewInstall(actionConfig)
    client.Namespace = namespace
    client.ReleaseName = releaseName
    // client.DryRun = true - very handy!


    // install the chart here
    rel, err := client.Run(chart, vals)
    if err != nil {
        panic(err)
    }

    log.Printf("Installed Chart from path: %s in namespace: %s\n", rel.Name, rel.Namespace)
    // this will confirm the values set during installation
    log.Println(rel.Config)
}
like image 29
LemurPwned Avatar answered Oct 17 '22 10:10

LemurPwned


FOR HELM3

As other answers pointed, with Helm 2, you need to talk with tiller which complicates stuff.

It is way more clean with Helm 3 since tiller was removed and helm client directly communicates with Kubernetes API Server.

Here is an example code to install a helm chart programmatically with helm3:

package main

import (
    "fmt"
    "os"

    "helm.sh/helm/v3/pkg/action"
    "helm.sh/helm/v3/pkg/chart/loader"
    "helm.sh/helm/v3/pkg/kube"
    _ "k8s.io/client-go/plugin/pkg/client/auth"
)

func main() {
    chartPath := "/tmp/my-chart-0.1.0.tgz"
    chart, err := loader.Load(chartPath)
    if err != nil {
        panic(err)
    }

    kubeconfigPath := "/tmp/my-kubeconfig"
    releaseName := "my-release"
    releaseNamespace := "default"
    actionConfig := new(action.Configuration)
    if err := actionConfig.Init(kube.GetConfig(kubeconfigPath, "", releaseNamespace), releaseNamespace, os.Getenv("HELM_DRIVER"), func(format string, v ...interface{}) {
        fmt.Sprintf(format, v)
    }); err != nil {
        panic(err)
    }

    iCli := action.NewInstall(actionConfig)
    iCli.Namespace = releaseNamespace
    iCli.ReleaseName = releaseName
    rel, err := iCli.Run(chart, nil)
    if err != nil {
        panic(err)
    }
    fmt.Println("Successfully installed release: ", rel.Name)
}
like image 24
turkenh Avatar answered Oct 17 '22 11:10

turkenh


I was looking for the same answer, since I do know the solution now, sharing it here.

What you are looking for is to write a wrapper around helm library.

First you need a client which speaks to the tiller of your cluster. For that you need to create a tunnel to the tiller from your localhost. Use this (its the same link as kiran shared.)

  1. Setup the Helm environement variables look here
  2. Use this next. It will return a helm client. (you might need to write a wrapper around it to work with your setup of clusters)

After you get the *helm.Client handle, you can use helm's client API given here. You just have to use the one you need with the appropriate values.

You might need some utility functions defined here, like loading a chart as a folder/archive/file.

If you want to do something more, you pretty much locate the method in the doc and call it using the client.

like image 28
Sufiyan Parkar Avatar answered Oct 17 '22 10:10

Sufiyan Parkar