API

Helm Chart Repository

  • GET /index.yaml - retrieved when you run helm repo add chartmuseum http://localhost:8080/
  • GET /charts/mychart-0.1.0.tgz - retrieved when you run helm install chartmuseum/mychart
  • GET /charts/mychart-0.1.0.tgz.prov - retrieved when you run helm install with the --verify flag

Chart Manipulation

  • POST /api/charts - upload a new chart version
  • POST /api/prov - upload a new provenance file
  • DELETE /api/charts/<name>/<version> - delete a chart version (and corresponding provenance file)
  • GET /api/charts - list all charts
  • GET /api/charts/<name> - list all versions of a chart
  • GET /api/charts/<name>/<version> - describe a chart version
  • HEAD /api/charts/<name> - check if chart exists (any versions)
  • HEAD /api/charts/<name>/<version> - check if chart version exists

Pagination

For large chart repositories, you may wish to paginate the results from the GET /api/charts route.

To do so, add the offset and limit query params to the request. For example, to retrieve a list of 5 charts total, skipping the first 5 charts, you could use the following:

GET /api/charts?offset=5&limit=5

Server Info

  • GET / - HTML welcome page
  • GET /info - returns current ChartMuseum version
  • GET /health - returns 200 OK

Uploading a Chart Package

Follow “How to Run” section below to get ChartMuseum up and running at http://localhost:8080

First create mychart-0.1.0.tgz using the Helm CLI:

cd mychart/
helm package .

Upload mychart-0.1.0.tgz:

curl --data-binary "@mychart-0.1.0.tgz" http://localhost:8080/api/charts

If you’ve signed your package and generated a provenance file, upload it with:

curl --data-binary "@mychart-0.1.0.tgz.prov" http://localhost:8080/api/prov

Both files can also be uploaded at once (or one at a time) on the /api/charts route using the multipart/form-data format:

curl -F "chart=@mychart-0.1.0.tgz" -F "prov=@mychart-0.1.0.tgz.prov" http://localhost:8080/api/charts

You can also use the helm-push plugin:

helm push mychart/ chartmuseum

Installing Charts into Kubernetes

Add the URL to your ChartMuseum installation to the local repository list:

helm repo add chartmuseum http://localhost:8080

Search for charts:

helm search repo chartmuseum/

Install chart:

helm install chartmuseum/mychart --generate-name

How to Run

Installation

CLI

Install binary using GoFish:

gofish install chartmuseum
==> Installing chartmuseum...
🐠  chartmuseum 0.14.0: installed in 95.431145ms

or you can use the installer script:

curl https://raw.githubusercontent.com/helm/chartmuseum/main/scripts/get-chartmuseum | bash

or download manually from the releases page, which also contains all package checksums and signatures.

Determine your version with chartmuseum --version.

Configuration

Show all CLI options with chartmuseum --help. Common configurations can be seen below.

All command-line options can be specified as environment variables, which are defined by the command-line option, capitalized, with all -’s replaced with _’s.

For example, the env var STORAGE_AMAZON_BUCKET can be used in place of --storage-amazon-bucket.

Using a configuration file

Use chartmuseum --config config.yaml to read configuration from a file.

When using file-based configuration, the corresponding option name can be looked up in pkg/config/vars.go. It would be the key of configVars entry corresponding to the command line option / environment variable. For example, --storage corresponds to storage.backend in the configuration file.

Here’s a complete example of a config.yaml:

debug: true
port: 8080
storage.backend: local
storage.local.rootdir: <storage_path>
bearerauth: 1
authrealm: <authorization server url>
authservice: <authorization server service name>
authcertpath: <path to authorization server public pem file>
authactionssearchpath: <optional: JMESPath to find allowed actions in a jwt token>
depth: 2

Using with Amazon S3 or Compatible services like MinIO or DigitalOcean

Make sure your environment is properly setup to access my-s3-bucket

For Amazon S3, endpoint is automatically inferred.

chartmuseum --debug --port=8080 \
  --storage="amazon" \
  --storage-amazon-bucket="my-s3-bucket" \
  --storage-amazon-prefix="" \
  --storage-amazon-region="us-east-1"

You need at least the following permissions inside your IAM Policy

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowListObjects",
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket"
      ],
      "Resource": "arn:aws:s3:::my-s3-bucket"
    },
    {
      "Sid": "AllowObjectsCRUD",
      "Effect": "Allow",
      "Action": [
        "s3:DeleteObject",
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::my-s3-bucket/*"
    }
  ]
}

In order to work with AWS service accounts you may need to set AWS_SDK_LOAD_CONFIG=1 in your environment. For more context, please see here.

Note: With certain S3-based storage backends, the LastModified field on objects is truncated to the nearest second. For more info, please see issue #152. In order to mitigate this, you may use use the --storage-timestamp-tolerance option. For example, to round to the nearest second, you could use --storage-timestamp-tolerance=1s. For acceptable values to use for this field, please see here.

MinIO

For S3 compatible services like Minio, set the credentials using environment variables and pass the endpoint.

export AWS_ACCESS_KEY_ID=""
export AWS_SECRET_ACCESS_KEY=""
chartmuseum --debug --port=8080 \
  --storage="amazon" \
  --storage-amazon-bucket="my-s3-bucket" \
  --storage-amazon-prefix="" \
  --storage-amazon-region="us-east-1" \
  --storage-amazon-endpoint="my-s3-compatible-service-endpoint"

DigitalOcean

For DigitalOcean, set the credentials using environment variable and pass the endpoint. Note below, that the region us-east-1 needs to be set, since that is how the DigitalOcean cli implementation functions. The actual region of your spaces location is defined by the endpoint. Below we are using Frankfurt as an example.

export AWS_ACCESS_KEY_ID="spaces_access_key"
export AWS_SECRET_ACCESS_KEY="spaces_secret_key"
  chartmuseum --debug --port=8080 \
  --storage="amazon" \
  --storage-amazon-bucket="my_spaces_name" \
  --storage-amazon-prefix="my_spaces_name_subfolder" \
  --storage-amazon-region="us-east-1" \
  --storage-amazon-endpoint="https://fra1.digitaloceanspaces.com"

The access_key and secret_key can be generated from the DigitalOcean console, under the section API/Spaces_access_keys.

Using With Google Cloud Storage

Make sure your environment is properly setup to access my-gcs-bucket.

One way to do so is to set the GOOGLE_APPLICATION_CREDENTIALS var in your environment, pointing to the JSON file containing your service account key:

export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/[FILE_NAME].json"

More info on Google Cloud authentication can be found here.

chartmuseum --debug --port=8080 \
  --storage="google" \
  --storage-google-bucket="my-gcs-bucket" \
  --storage-google-prefix=""

Using With Microsoft Azure Blob Storage

Make sure your environment is properly setup to access mycontainer.

To do so, you must set the following env vars:

  • AZURE_STORAGE_ACCOUNT
  • AZURE_STORAGE_ACCESS_KEY
chartmuseum --debug --port=8080 \
  --storage="microsoft" \
  --storage-microsoft-container="mycontainer" \
  --storage-microsoft-prefix=""

Using With Alibaba Cloud Oss Storage

Make sure your environment is properly setup to access my-oss-bucket.

To do so, you must set the following env vars:

  • ALIBABA_CLOUD_ACCESS_KEY_ID
  • ALIBABA_CLOUD_ACCESS_KEY_SECRET
chartmuseum --debug --port=8080 \
  --storage="alibaba" \
  --storage-alibaba-bucket="my-oss-bucket" \
  --storage-alibaba-prefix="" \
  --storage-alibaba-endpoint="oss-cn-beijing.aliyuncs.com"

Using with Baidu Cloud BOS Storage

Make sure your environment is properly setup to access my-bos-bucket.

To do so, you must set the following env vars:

  • BAIDU_CLOUD_ACCESS_KEY_ID
  • BAIDU_CLOUD_ACCESS_KEY_SECRET
chartmuseum --debug --port=8080 \
  --storage="baidu" \
  --storage-baidu-bucket="my-bos-bucket" \
  --storage-baidu-prefix="" \
  --storage-baidu-endpoint="bj.bcebos.com"

Using with etcd

To use etcd as backend you need the CA certificate and the signed key pair. See here

chartmuseum --debug --port=8080 \
  --storage="etcd" \
  --storage-etcd-cafile="/path/to/ca.crt" \
  --storage-etcd-certfile="/path/to/server.crt" \
  --storage-etcd-keyfile="/path/to/server.key" \
  --storage-etcd-prefix="" \
  --storage-etcd-endpoint="http://localhost:2379"

Using with Netease Cloud NOS Storage

Make sure your environment is properly setup to access my-nos-bucket.

To do so, you must set the following env vars:

  • NETEASE_CLOUD_ACCESS_KEY_ID
  • NETEASE_CLOUD_ACCESS_KEY_SECRET
chartmuseum --debug --port=8080 \
  --storage="netease" \
  --storage-netease-bucket="my-nos-bucket" \
  --storage-netease-prefix="" \
  --storage-netease-endpoint="nos-eastchina1.126.net"

Using With Oracle Cloud Infratructure Object Storage

Make sure your environment is properly setup to access my-ocs-bucket.

More info on Oracle Cloud Infrastructure authentication can be found here.

chartmuseum --debug --port=8080 \
  --storage="oracle" \
  --storage-oracle-bucket="my-ocs-bucket" \
  --storage-oracle-prefix="" \
  --storage-oracle-compartmentid="ocid1.compartment.oc1..1234"

Using with Tencent Cloud COS Storage

Make sure your environment is properly setup to access my-cos-bucket.

To do so, you must set the following env vars:

  • TENCENT_CLOUD_COS_SECRET_ID
  • TENCENT_CLOUD_COS_SECRET_KEY
chartmuseum --debug --port=8080 \
  --storage="tencent" \
  --storage-tencent-bucket="my-cos-bucket" \
  --storage-tencent-prefix="" \
  --storage-tencent-endpoint="cos.ap-beijing.myqcloud.com"

Using With Openstack Object Storage

Make sure your environment is properly setup to access mycontainer.

To do so, you must set the following env vars (depending on your openstack version):

  • OS_AUTH_URL
  • either OS_PROJECT_NAME or OS_TENANT_NAME or OS_PROJECT_ID or OS_TENANT_ID
  • either OS_DOMAIN_NAME or OS_DOMAIN_ID
  • either OS_USERNAME or OS_USERID
  • OS_PASSWORD
chartmuseum --debug --port=8080 \
  --storage="openstack" \
  --storage-openstack-container="mycontainer" \
  --storage-openstack-prefix="" \
  --storage-openstack-region="myregion"

For Swift V1 Auth you must set the following env vars:

  • ST_AUTH
  • ST_USER
  • ST_KEY
chartmuseum --debug --port=8080 \
  --storage="openstack" \
  --storage-openstack-auth="v1" \
  --storage-openstack-container="mycontainer" \
  --storage-openstack-prefix=""

Using With Local Filesystem Storage

Make sure you have read-write access to ./chartstorage (will create if doesn’t exist on first upload)

chartmuseum --debug --port=8080 \
  --storage="local" \
  --storage-local-rootdir="./chartstorage"

Basic Auth

If both of the following options are provided, basic http authentication will protect all routes:

  • --basic-auth-user=<user> - username for basic http authentication
  • --basic-auth-pass=<pass> - password for basic http authentication

You may want basic auth to only be applied to operations that can change Charts, i.e. PUT, POST and DELETE. So to avoid basic auth on GET operations use

  • --auth-anonymous-get - allow anonymous GET operations

Bearer/Token Auth

If all of the following options are provided, bearer auth will protect all routes:

  • --bearer-auth - enables bearer auth
  • --auth-realm=<realm> - authorization server url
  • --auth-service=<service> - authorization server service name
  • --auth-cert-path=<path> - path to authorization server public pem file
  • --auth-actions-search-path=<JMESPath> - (optional) JMESPath to find allowed actions in a jwt token

Using options above, ChartMuseum is configured with a public key, and will accept RS256 JWT tokens signed by the associated private key, passed in the Authorization header. You can use the chartmuseum/auth Go library to generate valid JWT tokens.

JWT Token without a custom JMESPath to find actions

In order to gain access to a specific resource, the JWT token must contain an access section in the claims. This section indicates which resources the user is able to access. Here is an example token payload:

{
  "exp": 1543995770,
  "iat": 1543995470,
  "access": [
    {
      "type": "artifact-repository",
      "name": "org1/repo1",
      "actions": [
        "pull"
      ]
    }
  ]
}

The type is always “artifact-repository”, the name is the namespace/tenant (just use the string “repo” if using single-tenant server), and actions is an array of actions the user can perform (“pull” and/or “push).

If your JWT token structure is different, you can configure a JMESPath string. So you can define the way to find the allowed actions yourself.

For the type and the the name you can use following placeholder

  • name: $NAMESPACE
  • type: $ACCESS_ENTRY_TYPE

E.g.: If you want to represent the default configuration, the JMESPath looks like: access[?name=='$NAMESPACE' && type=='$ACCESS_ENTRY_TYPE'].actions[].

For more information about how this works, please see chartmuseum/auth-server-example.

HTTPS

If both of the following options are provided, the server will listen and serve HTTPS:

  • --tls-cert=<crt> - path to tls certificate chain file
  • --tls-key=<key> - path to tls key file

HTTPS with Client Certificate Authentication

If the above HTTPS values are provided in addition to below, the server will listen and serve HTTPS and authenticate client requests against the CA certificate:

  • --tls-ca-cert=<cacert> - path to tls certificate file

All CLI Options

--config value, -c value              chartmuseum configuration file [$CONFIG]
--write-timeout value                 socket timeout in seconds (default: 0) [$WRITE_TIMEOUT]
--storage-openstack-cacert value      path to a CA cert bundle for your openstack endpoint [$STORAGE_OPENSTACK_CACERT]
--storage-tencent-prefix value        prefix to store charts for --storage-tencent-cloud-bucket [$STORAGE_TENCENT_PREFIX]
--context-path value                  base context path [$CONTEXT_PATH]
--log-health                          log inbound /health requests [$LOG_HEALTH]
--log-latency-integer                 log latency as an integer (nanoseconds) instead of a string [$LOG_LATENCY_INTEGER]
--disable-delete                      disable DELETE route [$DISABLE_DELETE]
--disable-statefiles                  disable use of index-cache.yaml [$DISABLE_STATEFILES]
--disable-force-overwrite             do not allow chart versions to be re-uploaded, even with ?force querystring [$DISABLE_FORCE_OVERWRITE]
--storage-baidu-bucket value          BOS bucket to store charts for Baidu Cloud storage backend [$STORAGE_BAIDU_BUCKET]
--chart-post-form-field-name value    form field which will be queried for the chart file content [$CHART_POST_FORM_FIELD_NAME]
--bearer-auth                         enable bearer auth [$BEARER_AUTH]
--storage-etcd-keyfile value          key provided to etcd [$STORAGE_ETCD_KEYFILE]
--tls-key value                       path to tls key file [$TLS_KEY]
--storage-oracle-region value         region to store charts for --storage-oracle-bucket [$STORAGE_ORACLE_REGION]
--storage-alibaba-bucket value        OSS bucket to store charts for Alibaba Cloud storage backend [$STORAGE_ALIBABA_BUCKET]
--storage-alibaba-endpoint value      OSS endpoint [$STORAGE_ALIBABA_ENDPOINT]
--gen-index                           generate index.yaml, print to stdout and exit [$GEN_INDEX]
--log-json                            output structured logs as json [$LOG_JSON]
--basic-auth-user value               username for basic http authentication [$BASIC_AUTH_USER]
--tls-cert value                      path to tls certificate chain file [$TLS_CERT]
--enforce-semver2                     (deprecated) enforce the chart museum server only accepts the valid chart version as Helm does [$ENFORCE_SEMVER2]
--basic-auth-pass value               password for basic http authentication [$BASIC_AUTH_PASS]
--storage value                       storage backend, can be one of: local, amazon, google, oracle [$STORAGE]
--storage-openstack-region value      region of --storage-openstack-container [$STORAGE_OPENSTACK_REGION]
--cache-redis-addr value              address of Redis service (host:port) [$CACHE_REDIS_ADDR]
--storage-amazon-prefix value         prefix to store charts for --storage-amazon-bucket [$STORAGE_AMAZON_PREFIX]
--storage-alibaba-prefix value        prefix to store charts for --storage-alibaba-cloud-bucket [$STORAGE_ALIBABA_PREFIX]
--storage-etcd-prefix value           prefix used in etcd to store the charts in etcd [$STORAGE_ETCD_PREFIX]
--cache-redis-db value                Redis database to be selected after connect (default: 0) [$CACHE_REDIS_DB]
--storage-alibaba-sse value           server side encryption algorithm for Alibaba Cloud storage backend, AES256 or KMS [$STORAGE_ALIBABA_SSE]
--storage-etcd-cafile value           ca-file provided to etcd [$STORAGE_ETCD_CAFILE]
--storage-baidu-endpoint value        BOS endpoint [$STORAGE_BAIDU_ENDPOINT]
--storage-tencent-bucket value        COS bucket to store charts for Tencent Cloud storage backend [$STORAGE_TENCENT_BUCKET]
--prov-post-form-field-name value     form field which will be queried for the provenance file content [$PROV_POST_FORM_FIELD_NAME]
--depth-dynamic                       the length of repo variable [$DEPTH_DYNAMIC]
--cache value                         cache store, can be one of: redis [$CACHE]
--storage-google-prefix value         prefix to store charts for --storage-google-bucket [$STORAGE_GOOGLE_PREFIX]
--storage-oracle-compartmentid value  compartment ocid of --storage-oracle-bucket [$STORAGE_ORACLE_COMPARTMENTID]
--storage-microsoft-prefix value      prefix to store charts for --storage-microsoft-prefix [$STORAGE_MICROSOFT_PREFIX]
--cache-interval value                set the interval of delta updating the cache (default: 0s) [$CACHE_INTERVAL]
--storage-netease-bucket value        NOS bucket to store charts for Netease Cloud storage backend [$STORAGE_NETEASE_BUCKET]
--max-upload-size value               max size of post body (in bytes) (default: 20971520) [$MAX_UPLOAD_SIZE]
--chart-url value                     absolute url for .tgzs in index.yaml [$CHART_URL]
--storage-timestamp-tolerance value   timestamp drift tolerated between cached and generated index before invalidation (default: 0s) [$STORAGE_TIMESTAMP_TOLERANCE]
--max-storage-objects value           maximum number of objects allowed in storage (per tenant) (default: 0) [$MAX_STORAGE_OBJECTS]
--auth-cert-path value                path to authorization server public pem file [$AUTH_CERT_PATH]
--storage-microsoft-container value   container to store charts for microsoft storage backend [$STORAGE_MICROSOFT_CONTAINER]
--storage-openstack-container value   container to store charts for openstack storage backend [$STORAGE_OPENSTACK_CONTAINER]
--listen-host value                   specifies the host to listen on [$LISTEN_HOST]
--storage-netease-endpoint value      NOS endpoint [$STORAGE_NETEASE_ENDPOINT]
--auth-realm value                    authorization server url [$AUTH_REALM]
--cors-alloworigin value              value to set in the Access-Control-Allow-Origin HTTP header [$CORS_ALLOW_ORIGIN]
--auth-anonymous-get                  allow anonymous GET operations when auth is used [$AUTH_ANONYMOUS_GET]
--tls-ca-cert value                   path to tls ca cert file [$TLS_CA_CERT]
--storage-amazon-endpoint value       alternative s3 endpoint [$STORAGE_AMAZON_ENDPOINT]
--storage-tencent-endpoint value      COS endpoint [$STORAGE_TENCENT_ENDPOINT]
--storage-local-rootdir value         directory to store charts for local storage backend [$STORAGE_LOCAL_ROOTDIR]
--storage-amazon-sse value            server side encryption algorithm [$STORAGE_AMAZON_SSE]
--storage-oracle-bucket value         ocs bucket to store charts for oracle cloud storage [$STORAGE_ORACLE_BUCKET]
--index-limit value                   parallel scan limit for the repo indexer (default: 0) [$INDEX_LIMIT]
--debug                               show debug messages [$DEBUG]
--disable-metrics                     disable Prometheus metrics [$DISABLE_METRICS]
--read-timeout value                  socket timeout in seconds (default: 0) [$READ_TIMEOUT]
--cache-redis-password value          Redis requirepass server configuration [$CACHE_REDIS_PASSWORD]
--storage-openstack-auth value        the OpenStack auth protocol to use. Set "v1" for v1 or "auto" for v2 and v3 [$STORAGE_OPENSTACK_AUTH]
--storage-baidu-prefix value          prefix to store charts for --storage-baidu-cloud-bucket [$STORAGE_BAIDU_PREFIX]
--storage-etcd-certfile value         cert provided to etcd [$STORAGE_ETCD_CERTFILE]
--storage-netease-prefix value        prefix to store charts for --storage-netease-cloud-bucket [$STORAGE_NETEASE_PREFIX]
--disable-api                         disable all routes prefixed with /api [$DISABLE_API]
--allow-overwrite                     allow chart versions to be re-uploaded without ?force querystring [$ALLOW_OVERWRITE]
--storage-amazon-bucket value         s3 bucket to store charts for amazon storage backend [$STORAGE_AMAZON_BUCKET]
--storage-amazon-region value         region of --storage-amazon-bucket [$STORAGE_AMAZON_REGION]
--depth value                         levels of nested repos for multitenancy (default: 0) [$DEPTH]
--auth-service value                  authorization server service name [$AUTH_SERVICE]
--port value                          port to listen on (default: 0) [$PORT]
--auth-actions-search-path value      JMESPath to find allowed actions in a jwt token [$AUTH_ACTIONS_SEARCH_PATH]
--storage-google-bucket value         gcs bucket to store charts for google storage backend [$STORAGE_GOOGLE_BUCKET]
--storage-oracle-prefix value         prefix to store charts for --storage-oracle-bucket [$STORAGE_ORACLE_PREFIX]
--storage-openstack-prefix value      prefix to store charts for --storage-openstack-container [$STORAGE_OPENSTACK_PREFIX]
--storage-etcd-endpoint value         ETCD endpoint [$STORAGE_ETCD_ENDPOINT]
--help, -h                            show help
--version, -v                         print the version

Docker Image

Available via Docker Hub.

Example usage (local storage):

docker run --rm -it \
  -p 8080:8080 \
  -e DEBUG=1 \
  -e STORAGE=local \
  -e STORAGE_LOCAL_ROOTDIR=/charts \
  -v $(pwd)/charts:/charts \
  chartmuseum/chartmuseum:latest

Example usage (S3):

docker run --rm -it \
  -p 8080:8080 \
  -e PORT=8080 \
  -e DEBUG=1 \
  -e STORAGE="amazon" \
  -e STORAGE_AMAZON_BUCKET="my-s3-bucket" \
  -e STORAGE_AMAZON_PREFIX="" \
  -e STORAGE_AMAZON_REGION="us-east-1" \
  -v ~/.aws:/root/.aws:ro \
  chartmuseum/chartmuseum:latest

Helm Chart

There is a Helm chart for ChartMuseum itself which can be found in the ChartMuseum repository.

You can also view it on Artifact Hub.

To install:

helm repo add chartmuseum https://chartmuseum.github.io/charts
helm install chartmuseum/chartmuseum

If interested in making changes, please submit a PR to chartmuseum/charts. Before doing any work, please check for any currently open pull requests. Thanks!

Multitenancy

Multitenancy is supported with the --depth flag.

To begin, start with a directory structure such as

charts
├── org1
│   ├── repoa
│   │   └── nginx-ingress-0.9.3.tgz
├── org2
│   ├── repob
│   │   └── chartmuseum-0.4.0.tgz

This represents a storage layout appropriate for --depth=2. The organization level can be eliminated by using --depth=1. The default depth is 0 (singletenant server).

Start the server with --depth=2, pointing to the charts/ directory:

chartmuseum --debug --depth=2 --storage="local" --storage-local-rootdir=./charts

This example will provide two separate Helm Chart Repositories at the following locations:

  • http://localhost:8080/org1/repoa
  • http://localhost:8080/org2/repob

This should work with all supported storage backends.

To use the chart manipulation routes, simply place the name of the repo directly after “/api” in the route:

curl -F "chart=@mychart-0.1.0.tgz" http://localhost:8080/api/org1/repoa/charts

You may also experiment with the --depth-dynamic flag, which should allow for dynamic depth levels (i.e. all of /api/charts, /api/myrepo/charts, /api/org1/repoa/charts).

Cache

By default, the contents of index.yaml (per-tenant) will be stored in memory. This means that memory usage will continue to grow indefinitely as more charts are added to storage.

You may wish to offload this to an external cache store, especially for large, multitenant installations.

Cache Interval

When dealing with thousands of charts, you may experience latency with the default settings. This is because upon each request, the storage backend is scanned for changes compared to the cache.

If you are ok with index.yaml being out-of-date for a fixed period of time, you can improve performance by using the --cache-interval=<interval> option.

When this setting is enabled, the charts available for each tenant are refreshed on a timer.

For example, to only check storage every 5 minutes, you can use --cache-interval=5m.

For valid values to use for this setting, please see here.

Using Redis

Example of using Redis as an external cache store:

chartmuseum --debug --port=8080 \
  --storage="local" \
  --storage-local-rootdir="./chartstorage" \
  --cache="redis" \
  --cache-redis-addr="localhost:6379" \
  --cache-redis-password="" \
  --cache-redis-db=0

Prometheus Metrics

ChartMuseum exposes its Prometheus metrics at the /metrics route on the main port. This can be disabled with the --disable-metrics command-line flag or the DISABLE_METRICS environment variable.

Note that the Kubernetes chart currently disables metrics by default (DISABLE_METRICS=true is set in the chart).

Below are the current application metrics exposed. Note that there is a per tenant (repo) label. The repo label corresponds to the depth parameter, so a depth=2 as the example above would have repo labels named org1/repoa and org2/repob.

MetricTypeLabelsDescription
chartmuseum_charts_served_totalGauge{repo="*"}Total number of charts
chartmuseum_charts_versions_served_totalGauge{repo="*"}Total number of chart versions available

*: see above for repo label

There are other general global metrics harvested (per process, hence for all tenants). You can get the complete list by using the /metrics route.

MetricTypeLabelsDescription
chartmuseum_request_duration_secondsSummary{quantile=“0.5”}, {quantile=“0.9”}, {quantile=“0.99”}The HTTP request latencies in seconds
chartmuseum_request_duration_seconds_sum
chartmuseum_request_duration_seconds_count
chartmuseum_request_size_bytesSummary{quantile=“0.5”}, {quantile=“0.9”}, {quantile=“0.99”}The HTTP request sizes in bytes
chartmuseum_request_size_bytes_sum
chartmuseum_request_size_bytes_count
chartmuseum_response_size_bytesSummary{quantile=“0.5”}, {quantile=“0.9”}, {quantile=“0.99”}The HTTP response sizes in bytes
chartmuseum_response_size_bytes_sum
chartmuseum_response_size_bytes_count
go_goroutinesGaugeNumber of goroutines that currently exist

Notes on index.yaml

The repository index (index.yaml) is dynamically generated based on packages found in storage. If you store your own version of index.yaml, it will be completely ignored.

GET /index.yaml occurs when you run helm repo add chartmuseum http://localhost:8080 or helm repo update.

If you manually add/remove a .tgz package from storage, it will be immediately reflected in GET /index.yaml.

You are no longer required to maintain your own version of index.yaml using helm repo index --merge.

The --gen-index CLI option (described above) can be used to generate and print index.yaml to stdout.

Upon index regeneration, ChartMuseum will, however, save a statefile in storage called index-cache.yaml used for cache optimization. This file is only meant for internal use, but may be able to be used for migration to simple storage.

Mirroring the Official Kubernetes Repositories

Please see scripts/mirror_k8s_repos.sh for an example of how to download all .tgz packages from the official Kubernetes repositories (both stable and incubator).

You can then use ChartMuseum to serve up an internal mirror:

scripts/mirror_k8s_repos.sh
chartmuseum --debug --port=8080 --storage="local" --storage-local-rootdir="./mirror"

Subprojects

The following subprojects are maintained by ChartMuseum: