Samples on kubernetes helm golang client

10,526

Solution 1

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)
}

Solution 2

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())
  }
}

Solution 3

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)
}

Solution 4

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.

Share:
10,526

Related videos on Youtube

Mehran Akhavan
Author by

Mehran Akhavan

Updated on June 29, 2022

Comments

  • Mehran Akhavan
    Mehran Akhavan almost 2 years

    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.

  • B.Z.
    B.Z. over 4 years
    one key thing missing in the answer is: host := fmt.Sprintf("127.0.0.1:%d", tillerTunnel.Local). See link
  • B.Z.
    B.Z. over 4 years
    Of course, if trying to access Tiller from within the cluster, there is no need to do port forwarding. Just use, by default, host := "tiller-deploy.kube-system.svc:44134"
  • Ishan Khare
    Ishan Khare about 4 years
    there is no Init method defined on the Configuration type according to the docs.
  • Ishan Khare
    Ishan Khare about 4 years
    Also how would a create a configuration from cluster certificates instead of the kubeconfig on filesystem?
  • Aisuko
    Aisuko about 4 years
    Is there any solution we can transfer the parameters like --set --set-file of helm install?
  • teone
    teone about 4 years
    Any hint on how to install a release?
  • LemurPwned
    LemurPwned almost 4 years
    @Aisuko take a look at my response below. You may pass the params to the Run functions via map[string]interface{} and if these are your installation values.
  • Luffy
    Luffy over 3 years
    @rabenhorst How to get the list of charts deployed? I want to store the chart details like Name, Revision, Chart, etc. I am using HELM3 for chart deployment.
  • Luffy
    Luffy over 3 years
    @turkenh How to get the list of charts deployed? I want to store the chart details like Name, Revision, Chart, etc. I am using HELM3 for chart deployment.
  • turkenh
    turkenh over 3 years
    @Luffy you should use list action. Here you can find how an action could be used in go, even we didn't need list action yet.
  • rabenhorst
    rabenhorst over 3 years
    @Luffy this whole thread is about helm2 which uses tiller as a cluster side component. Maybe you can take a look on how the official helm3 CLI is doing it: github.com/helm/helm/blob/master/pkg/action/list.go
  • Tidhar Klein Orbach
    Tidhar Klein Orbach about 2 years
    When running inCluster, make sure that the pod or job that's running this code has pods/portforward create permissions