apptio / kr8

An opinionated Kubernetes cluster configuration management tool
https://apptio.github.io/kr8/
MIT License
167 stars 17 forks source link

How to apply additional jsonnet files to patch a chart #18

Closed splisson-altair closed 5 years ago

splisson-altair commented 5 years ago

As far as I understand currently k8r and its script k8r-helpers apply patch using {component}-values.jsonnet or patches.jsonnet, both are in the component folder, so common to every deployments. How does kr8 uses one or the other or both?

I need to patch some values at the component level, per cluster, like image tag value. These values come from CI/CD pipeline, what s the best way to get them into the patch?

jaxxstorm commented 5 years ago

patches.jsonnet isn't actually necessary for any helm based component, only if the value isn't in the values.yaml

There are two helper scripts:

helm-render which simply renders a helm chart without any patches included. If your image tag value is a standard helm values that exists in values.yaml, you can set your component up like this one

Then there's helm-render-with-patch which includes a patches.jsonnet inside the component. This will allow you to add information and manipulate the rendered helm chart with stuff that isn't in the helm values.yaml. An example component for this can be found here

So in summary:

Hopefully that makes sense, I'll leave this open until we have better docs around this.

splisson-altair commented 5 years ago

Is this correct? : In order to set values for a chart, one must declare the variables in params.jsonnet (this file declares what is configurable). Then values can be set in {component}-values.jsonnet (this file contains default values set at the component level and link to the configuration via kr8 external variable). => variables are declared in 2 places?? In the hierarchy of cluster definition, values can be set in cluster.jsonnet, in the component configuration.

jaxxstorm commented 5 years ago

This is generally how we've done this, but @cspargo has come up with a better way.

In {{component-values}}.jsonnet:

local config = std.extVar('kr8');

config.helm_values

In params.jsonnet

{
  helm_values: {
   image: <something>
  }
}

This means you dont have to duplicate the values, and can in fact override them on a per cluster basis if needed (the whole values that is)

cspargo commented 5 years ago

A little more on how it works...

kr8-helpers helm-render-with-patch and kr8-helpers-helm-render both take a second argument, which is the chart name (not component, since components can potentially contain multiple charts)

They look for a jsonnet file named <chartname>-values.jsonnet. This is then rendered with jsonnet to produce the helm "values.yaml" that is passed to helm when rendering the chart. So it's the responsibility of that file to generate the values.yaml that you want to use with the helm chart.

You can render it manually with kr8, to see what it would look like:

kr8 jsonnet render --cluster "<clustername>" --component "<componentname>" --format yaml  "<chartname>-values.jsonnet" 

(A copy is also written below the metadata directory when generating the component)

To expand on @jaxxstorm's example. If you had a component called mycomponent, and a chart called mychart, then you would have these in the component:

mycomponent/mychart-values.jsonnet:

local config = std.extVar('kr8');

config.mychart_helm_values

mycomponent/params.jsonnet:

{
  mychart_helm_values: {
    image: <something>,
    param2: <something>
  }
}

Then in each cluster.jsonnet you can override the image

clusters/cluster1/cluster.jsonnet:

{
  ...
  mycomponent+: {
    mychart_helm_values+: {
      image: "value1"
    }
  }
}

clusters/cluster2/cluster.jsonnet:

{
  ...
  mycomponent+: {
    mychart_helm_values+: {
      image: "value2"
    }
  }
}

Since it's jsonnet, it can be done in all sorts of alternate ways. Sometimes it's simpler to do it like this if there's not many params to override:

mycomponent/params.jsonnet:

{
  local config=self,
  image: <something>,
  mychart_helm_values: {
    image: config.image,
    param2: <something>
  }
}

Then in the cluster.jsonnet, it's just:

{
  ...
  mycomponent+: {
    image: "value2"
  }
}

To simplify common configurations, where the file is mostly redundant, we're considering making the <chart>-values.jsonnet file optional, and having it instead refer to an object in params.pp for the helm values, if the file does not exist. So in the example above, it would directly look for mychart_helm_values in params.pp and render the helm values directly from that.

splisson-altair commented 5 years ago

Thank you. I found what I was missing by learning more about jsonnet powers. I wanted to use values from a separate file (to be generated by CI/CD pipeline), I ended up doing: cluster.jsonnet

local api_dev_values = import 'api_dev_values.jsonnet';
local api_qa_values = import 'api_qa_values.jsonnet';
{
...
  api_dev+: {
    namespace: 'dev',
    helm_values: api_dev_values
  },

  api_qa+: {
    namespace: 'qa',
    helm_values: api_qa_values
  },
}

and api_dev_values.jsonnet :

{
    image: {
        tag: 'aa22cc'
      },   
}
jaxxstorm commented 5 years ago

Awesome! Any feedback you have on what we should focus on regarding documentation efforts is appreciated!

ghost commented 5 years ago

Closing this issue as it seems to be resolved :)