Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal for Helm Chart Registry Adapter #830

Merged
merged 4 commits into from Mar 19, 2018

Conversation

djzager
Copy link
Member

@djzager djzager commented Mar 9, 2018

This describes a plan for supporting Helm Chart Repositories.

@openshift-ci-robot openshift-ci-robot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Mar 9, 2018
Copy link
Contributor

@jmrodri jmrodri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some rewording of things, and some questions about phase 2 and 3. Overall looks great. Thanks for doing this.

#### Creating a Helm Adapter

The `HelmAdapter` struct will look something like, the addition of `Charts`
makes it possible to save our work and only ready the registries index file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: read

## Introduction

Add a new registry adapter type, `helm`, that supports Helm chart
repositories. With this change, an admin, could configure the broker by adding
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

punctuation: remove the comma after admin. It should read "With this change, an admin could..."

```

Most of the data required to create a useful `Spec` object is contained in
the Chart object. However, in order to retrieve the default values we will use
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

punctuation: add a comma after values. It should read "in order to retrieve the default values, we will use"


Add a new registry adapter type, `helm`, that supports Helm chart
repositories. With this change, an admin, could configure the broker by adding
a `helm` type registry and have the Helm charts hosted in that Helm chart
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would sound better flipped: "a helm registry type"

Currently, our broker only supports docker container image type registries.
However, with [Helm](https://helm.sh) being the "package manager for Kubernetes",
there is already a strong collection of applications defined in the form of
Helm charts. Adding the ability to the broker to consume these Helm charts as
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shuffle the words around a bit:

Modifying the broker to consume these Helm charts as Service Bundles will allow work already done in Helm charts to be made available in a cluster.

repository
structure](https://github.com/kubernetes/helm/blob/master/docs/chart_repository.md#the-chart-repository-structure)
and add the latest version of each chart to the `Charts` field as well as
its name to the list of `imageNames` to be returned.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

break up the sentence:

...repository structure](https://github.com/kubernetes/helm/blob/master/docs/chart_repository.md#the-chart-repository-structure). The broker will add the latest version of each chart to the...


After these image names are filtered, the subsequent call to `FetchSpecs()`
will find the chart by name in the `Charts` field and create a `Spec` object
for it. For example:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So will a call to bootstrap ever regenerate this Charts cache? How will we pick up changes?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To my understanding, yes. Every call to bootstrap should create a new instance of a HelmAdapter for each of the helm type config entries, calling GetImageNames() and FetchSpecs() again.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that is correct. Registries are made with an adapter as an unexposed field and then is used for subsequent calls. I do not think that bootstrap by itself is creating new adapters. Are you planning on adding some other behavior?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not intending to change the behavior. This concern should be overcome by rebuilding the list of image names and charts on each call to GetImageNames(), for example:

// GetImageNames - retrieve the images
func (r *HelmAdapter) GetImageNames() ([]string, error) {
        var imageNames []string

        r.Charts = map[string][]*repo.ChartVersion{}

Then, the subsequent call to FetchSpecs(image_names) will be operating on the newly built list of image names and charts.

the Chart object. However, in order to retrieve the default values we will use
[Helm's Chartutil
pkg](https://github.com/kubernetes/helm/blob/master/pkg/chartutil/load.go) to
load the archive specified at `Chart.URLs[0]` and read the values.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate on this process a bit more? What sort of archive is it? Are we downloading something and cracking it open? Where is it being stored? etc.


Helm Chart Repositories can be authenticated, [this
issue](https://github.com/kubernetes/helm/issues/1038) provides more
information. The broker should support authenticated chart repositories.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we support all of the authentication formats? How will we accomplish this? Or would we do another proposal for handling phase 2 at a later date?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm making it clear that a separate proposal should be made for this work. Handling basic repos is a sufficient first step and the work required to support authenticated repos would require investigation.

In phase 1, only the latest chart version will be used. The broker should
support all versions of a chart and allow the consumer to specify which version
of a chart they wish to install. The base image would need to be updated to
handle specifying a specific version at provision time.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the version information stored? What does a versioned chart url look like? Or more specifically how would someone get the specific version of a chart? What changes do you anticipate being done to the base image? Or is this another proposal for when we do phase 3?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went ahead and made this part of the initial proposal, it's easy to get all of the chart's versions.

@jmrodri
Copy link
Contributor

jmrodri commented Mar 12, 2018

@eriknelson this is waiting on your review.

@djzager
Copy link
Member Author

djzager commented Mar 13, 2018


- Add the ability to read the `base_image` from the broker config.
- Pass the URL and BaseImage to the registry adapter.
- Instantiate a Helm registry adapter to handle Helm Chart registries in the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Language-wise, helm seems to use the word "repository" instead of "registry" to refer to a collection of charts. It may be a good idea to reflect that here and elsewhere.

repository
structure](https://github.com/kubernetes/helm/blob/master/docs/chart_repository.md#the-chart-repository-structure).
The broker will create an entry in the `Charts` field to hold a list of
`ChartVersion` objects and add the chart name to the list of `imageNames`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

two spaces between "and" and "add".


```
// Use the latest chart for creating the bundle
chart := charts[0]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume in the real implementation there would be a more data-driven way of determining the latest version.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what would that look like? https://github.com/kubernetes/helm/blob/master/pkg/repo/index.go#L141 sorts so we can reliably grab the latest version.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, nice! That'll do then if they're making the guarantee.

"displayName": fmt.Sprintf("%s (Helm)", chart.Name),
"documentationUrl": chart.Home,
"dependencies": chart.Sources,
"imageUrl": chart.Icon,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still haven't been able to get this to work. Is there documentation somewhere that we can cite as the authority that this is the right key to use?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is strange. I have had no issues getting this to work.

Description: "Default plan for running helm charts",
Parameters: []apb.ParameterDescriptor{
apb.ParameterDescriptor{
Name: "repo",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the use case for changing this at provision time?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There isn't one, but there is not currently a good way to hide it. That's why I use the Pattern to prevent you from changing it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to just strip these from the ParameterDescriptor list in some post-processing if there's no reason to have them there?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no case where a user should be changing these. However, at runtime we need the repo url. We can't hide these and still provide them at runtime. My solution was to make it the default and set the pattern to the exact string to prevent the user from changing it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, so they have to be passed through somehow and we can't take a helm specific approach. I wonder if the UI could mark these fields as immutable somehow?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha! Maybe we need an RFE for the broker to provide a way for a registry adapter to add hidden metadata that gets passed through to the executor and into the running bundle? It would be interesting to brainstorm about other possible use cases for that.

Required: false,
},
apb.ParameterDescriptor{
Name: "chart",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the use case for changing this at provision time? Hasn't the user already selected a chart by name through the catalog at this point?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

Copy link
Contributor

@eriknelson eriknelson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty cool stuff, just have some requests for clarification and questions.


## Creating a Base Image for Executing Helm Charts

Ansible Playbook Bundles (APBs) have already been described as an instance of
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the lanuage I would use here is:"Ansible Playbook Bundles (APBs) have served as an initial implementation of the more generic Service Bundle Specification"

Service Bundle, Helm Bundles, that respect the Service Bundle contract but use
Helm as the runtime. We already have a [Helm Bundle
Base](https://github.com/ansibleplaybookbundle/helm-bundle-base) and this
[PR](https://github.com/ansibleplaybookbundle/helm-bundle-base/pull/2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking this project is maybe more appropriate in the automationbroker org once we're ready to merge it. No need for that to block this proposal.

```
registry:
- type: helm
name: stable
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does stable signify something in the helm world? Is an unstable variant that would live at another url?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The unstable variant is called incubator and the public URL is https://kubernetes-charts-incubator.storage.googleapis.com/.

1. Type: refers to the registry adapter to handle this registry
1. Name: gives a name to this registry item
1. URL: the URL for the Helm chart repository
1. Base Image: the container image to use when provisioning/deprovisioning a
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused with the term "Base Image" here. In the APB world, we called it apb-base because it was literally the base layer of the image that APBs then layered on top of. Is the helm-bundle-base here a generic runner that I execute directly with differing arguments? That feels like more of a "runner" or a "runtime" to me, than a "base", if I'm not expected to layer anything on top of it and instead call run on it directly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are correct. It is not really a base image. Should probably make the project name and config item reflect that. runner or runner_image better reflects intent.

1. URL: the URL for the Helm chart repository
1. Base Image: the container image to use when provisioning/deprovisioning a
Helm chart
1. White List/Black List: allows the Admin to filter out Helm charts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for the base_image, would this be a const in the HelmAdapter? Would we have a different one for a downstream broker?

+1, do we need to allow users to change this? Regardless of the answer, I don't think it's a good idea to bake this into the broker as a const. That would require rebuilds and releases to change.

```

The addition of the `Charts` field makes it possible to save our work and only
read the registries' index file once.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if we're caching the index file in-memory once, how do we expect folks to be able to refresh this cache if the chart repository is updated? Would it require a complete broker restart (not ideal)? How often do we expect repositories to change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are rebuilding this cache every time GetImageNames() is called. I'm not totally familiar with how often the registry adapters are loaded and GetImageNames() and then FetchSpecs(imageNames) are called.

`index.yaml` found at the Helm Chart Repository URL based on the [chart
repository
structure](https://github.com/kubernetes/helm/blob/master/docs/chart_repository.md#the-chart-repository-structure).
The broker will create an entry in the `Charts` field to hold a list of
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just want to make sure "The broker" here isn't referring to the registry. We definitely don't want generic registry code doing helm specific stuff like writing to the chart cache, that would break the adapter abstraction. I'm thinking it should be the adapter before returning the image name list to the registry.

Also, these adapter methods are going to be called on every bootstrap. What's the condition that we're checking to prevent doing all the "work" involved with each bootstrap to load the cache? i.e.

if cacheNotLoaded() { // What's this?
    adapter.loadCache()
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, does the value of the chart's entry start out as an empty list prior to the FetchSpecs call?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating to make it clear that the "the broker" is actually the registry. The Charts field will be on the HelmAdapter struct. Calls to GetImageNames() will create the Charts map and FetchSpecs will use that map to create the Specs.

}
defer resp.Body.Close()

helmChart, err := chartutil.LoadArchive(resp.Body)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 this is pretty cool

Description: "Default plan for running helm charts",
Parameters: []apb.ParameterDescriptor{
apb.ParameterDescriptor{
Name: "repo",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to just strip these from the ParameterDescriptor list in some post-processing if there's no reason to have them there?

Required: false,
},
apb.ParameterDescriptor{
Name: "chart",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

@eriknelson
Copy link
Contributor

LGTM!

@djzager djzager merged commit 68c3072 into openshift:master Mar 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature needs-review size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants