ChartMuseum is an open-source Helm Chart Repository server written in Go (Golang), with support for cloud storage backends, including Google Cloud Storage, Amazon S3, Microsoft Azure Blob Storage, Alibaba Cloud OSS Storage, Openstack Object Storage, Oracle Cloud Infrastructure Object Storage, and Baidu Cloud BOS Storage.
Works as a valid Helm Chart Repository, and also provides an API for uploading charts.
Powered by some great Go technology:
- helm/helm - for working with charts
- gin-gonic/gin - for HTTP routing
- urfave/cli - for command line option parsing
- spf13/viper - for configuration
- uber-go/zap - for logging
- chartmuseum/auth - for auth
- chartmuseum/storage - for multi-cloud storage
GET /index.yaml
- retrieved when you runhelm repo add chartmuseum http://localhost:8080/
GET /charts/mychart-0.1.0.tgz
- retrieved when you runhelm install chartmuseum/mychart
GET /charts/mychart-0.1.0.tgz.prov
- retrieved when you runhelm install
with the--verify
flag
POST /api/charts
- upload a new chart versionPOST /api/prov
- upload a new provenance fileDELETE /api/charts/<name>/<version>
- delete a chart version (and corresponding provenance file)GET /api/charts
- list all chartsGET /api/charts/<name>
- list all versions of a chartGET /api/charts/<name>/<version>
- describe a chart version
GET /
- HTML welcome pageGET /health
- returns 200 OK
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
Add the URL to your ChartMuseum installation to the local repository list:
helm repo add chartmuseum http://localhost:8080
Search for charts:
helm search chartmuseum/
Install chart:
helm install chartmuseum/mychart
Install binary using GoFish:
gofish install chartmuseum
==> Installing chartmuseum...
๐ chartmuseum 0.8.2: installed in 95.431145ms
or manually:
# on Linux
curl -LO https://s3.amazonaws.com/chartmuseum/release/latest/bin/linux/amd64/chartmuseum
# on macOS
curl -LO https://s3.amazonaws.com/chartmuseum/release/latest/bin/darwin/amd64/chartmuseum
# on Windows
curl -LO https://s3.amazonaws.com/chartmuseum/release/latest/bin/windows/amd64/chartmuseum
chmod +x ./chartmuseum
mv ./chartmuseum /usr/local/bin
Using latest
in URLs above will get the latest binary (built from master branch).
Replace latest
with $(curl -s https://s3.amazonaws.com/chartmuseum/release/stable.txt)
to automatically determine the latest stable release (e.g. v0.8.2
). The stable checksums can be found here.
Determine your version with chartmuseum --version
.
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
.
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"
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"
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/*"
}
]
}
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=""
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=""
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"
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
orOS_TENANT_NAME
orOS_PROJECT_ID
orOS_TENANT_ID
- either
OS_DOMAIN_NAME
orOS_DOMAIN_ID
- either
OS_USERNAME
orOS_USERID
OS_PASSWORD
chartmuseum --debug --port=8080 \
--storage="openstack" \
--storage-openstack-container="mycontainer" \
--storage-openstack-prefix="" \
--storage-openstack-region="myregion"
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"
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"
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"
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
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
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.
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).
For more information about how this works, please see chartmuseum/auth-server-example.
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
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
You can specify the --gen-index
option if you only wish to use ChartMuseum to generate your index.yaml file. Note that this will only work with --depth=0
.
The contents of index.yaml will be printed to stdout and the program will exit. This is useful if you are satisfied with your current Helm CI/CD process and/or don't want to monitor another webservice.
--log-json
- output structured logs as json--log-health
- log incoming /health requests--disable-api
- disable all routes prefixed with /api--disable-statefiles
- disable use of index-cache.yaml--allow-overwrite
- allow chart versions to be re-uploaded without ?force querystring--disable-force-overwrite
- do not allow chart versions to be re-uploaded, even with ?force querystring--chart-url=<url>
- absolute url for .tgzs in index.yaml--storage-amazon-endpoint=<endpoint>
- alternative s3 endpoint--storage-amazon-sse=<algorithm>
- s3 server side encryption algorithm--storage-openstack-cacert=<path>
- path to a custom ca certificates bundle for openstack--chart-post-form-field-name=<field>
- form field which will be queried for the chart file content--prov-post-form-field-name=<field>
- form field which will be queried for the provenance file content--index-limit=<number>
- limit the number of parallel indexers--context-path=<path>
- base context path (new root for application routes)--depth=<number>
- levels of nested repos for multitenancy
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 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:/home/chartmuseum/.aws:ro \
chartmuseum/chartmuseum:latest
There is a Helm chart for ChartMuseum itself which can be found in the official Helm charts repository.
You can also view it on Helm Hub.
To install:
helm repo add stable https://kubernetes-charts.storage.googleapis.com
helm install stable/chartmuseum
If interested in making changes, please submit a PR to helm/charts. Before doing any work, please check for any currently open pull requests. Thanks!
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 o