1"use strict";(self.webpackChunkhelm_www=self.webpackChunkhelm_www||[]).push([["12671"],{88617(e,n,a){a.r(n),a.d(n,{metadata:()=>t,default:()=>d,frontMatter:()=>l,contentTitle:()=>s,toc:()=>c,assets:()=>o});var t=JSON.parse('{"id":"topics/library_charts","title":"Library Charts","description":"Explains library charts and examples of usage","source":"@site/versioned_docs/version-3/topics/library_charts.md","sourceDirName":"topics","slug":"/topics/library_charts","permalink":"/docs/v3/topics/library_charts","draft":false,"unlisted":false,"editUrl":"https://github.com/helm/helm-www/blob/main/versioned_docs/version-3/topics/library_charts.md","tags":[],"version":"3","sidebarPosition":4,"frontMatter":{"title":"Library Charts","description":"Explains library charts and examples of usage","sidebar_position":4},"sidebar":"tutorialSidebar","previous":{"title":"Chart Tests","permalink":"/docs/v3/topics/chart_tests"},"next":{"title":"Helm Provenance and Integrity","permalink":"/docs/v3/topics/provenance"}}'),r=a(74848),i=a(28453);let l={title:"Library Charts",description:"Explains library charts and examples of usage",sidebar_position:4},s,o={},c=[{value:"Create a Simple Library Chart",id:"create-a-simple-library-chart",level:2},{value:"Use the Simple Library Chart",id:"use-the-simple-library-chart",level:2},{value:"Library Chart Benefits",id:"library-chart-benefits",level:2},{value:"The Common Helm Helper Chart",id:"the-common-helm-helper-chart",level:2}];function h(e){let n={a:"a",code:"code",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)(n.p,{children:["A library chart is a type of ",(0,r.jsx)(n.a,{href:"/docs/v3/topics/charts",children:"Helm chart"}),"\nthat defines chart primitives or definitions which can be shared by Helm\ntemplates in other charts. This allows users to share snippets of code that can\nbe re-used across charts, avoiding repetition and keeping charts\n",(0,r.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/Don%27t_repeat_yourself",children:"DRY"}),"."]}),"\n",(0,r.jsx)(n.p,{children:"The library chart was introduced in Helm 3 to formally recognize common or\nhelper charts that have been used by chart maintainers since Helm 2. By\nincluding it as a chart type, it provides:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"A means to explicitly distinguish between common and application charts"}),"\n",(0,r.jsx)(n.li,{children:"Logic to prevent installation of a common chart"}),"\n",(0,r.jsx)(n.li,{children:"No rendering of templates in a common chart which may contain release\nartifacts"}),"\n",(0,r.jsx)(n.li,{children:"Allow for dependent charts to use the importer's context"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"A chart maintainer can define a common chart as a library chart and now be\nconfident that Helm will handle the chart in a standard consistent fashion. It\nalso means that definitions in an application chart can be shared by changing\nthe chart type."}),"\n",(0,r.jsx)(n.h2,{id:"create-a-simple-library-chart",children:"Create a Simple Library Chart"}),"\n",(0,r.jsxs)(n.p,{children:["As mentioned previously, a library chart is a type of ",(0,r.jsx)(n.a,{href:"/docs/v3/topics/charts",children:"Helm chart"}),". This means that you can start off by creating a\nscaffold chart:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-console",children:"$ helm create mylibchart\nCreating mylibchart\n"})}),"\n",(0,r.jsxs)(n.p,{children:["You will first remove all the files in ",(0,r.jsx)(n.code,{children:"templates"})," directory as we will create\nour own templates definitions in this example."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-console",children:"$ rm -rf mylibchart/templates/*\n"})}),"\n",(0,r.jsx)(n.p,{children:"The values file will not be required either."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-console",children:"$ rm -f mylibchart/values.yaml\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Before we jump into creating common code, lets do a quick review of some\nrelevant Helm concepts. A ",(0,r.jsx)(n.a,{href:"/docs/v3/chart_template_guide/named_templates",children:"named template"})," (sometimes called a partial\nor a subtemplate) is simply a template defined inside of a file, and given a\nname. In the ",(0,r.jsx)(n.code,{children:"templates/"})," directory, any file that begins with an underscore(_)\nis not expected to output a Kubernetes manifest file. So by convention, helper\ntemplates and partials are placed in a ",(0,r.jsx)(n.code,{children:"_*.tpl"})," or ",(0,r.jsx)(n.code,{children:"_*.yaml"})," files."]}
1),"\n",(0,r.jsxs)(n.p,{children:["In this example, we will code a common ConfigMap which creates an empty\nConfigMap resource. We will define the common ConfigMap in file\n",(0,r.jsx)(n.code,{children:"mylibchart/templates/_configmap.yaml"})," as follows:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'{{- define "mylibchart.configmap.tpl" -}}\napiVersion: v1\nkind: ConfigMap\nmetadata:\n name: {{ .Release.Name | printf "%s-%s" .Chart.Name }}\ndata: {}\n{{- end -}}\n{{- define "mylibchart.configmap" -}}\n{{- include "mylibchart.util.merge" (append . "mylibchart.configmap.tpl") -}}\n{{- end -}}\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The ConfigMap construct is defined in named template ",(0,r.jsx)(n.code,{children:"mylibchart.configmap.tpl"}),".\nIt is a simple ConfigMap with an empty resource, ",(0,r.jsx)(n.code,{children:"data"}),". Within this file there\nis another named template called ",(0,r.jsx)(n.code,{children:"mylibchart.configmap"}),". This named template\nincludes another named template ",(0,r.jsx)(n.code,{children:"mylibchart.util.merge"})," which will take 2 named\ntemplates as arguments, the template calling ",(0,r.jsx)(n.code,{children:"mylibchart.configmap"})," and\n",(0,r.jsx)(n.code,{children:"mylibchart.configmap.tpl"}),"."]}),"\n",(0,r.jsxs)(n.p,{children:["The helper function ",(0,r.jsx)(n.code,{children:"mylibchart.util.merge"})," is a named template in\n",(0,r.jsx)(n.code,{children:"mylibchart/templates/_util.yaml"}),". It is a handy util from ",(0,r.jsx)(n.a,{href:"#the-common-helm-helper-chart",children:"The Common Helm\nHelper Chart"})," because it merges the 2 templates\nand overrides any common parts in both:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'{{- /*\nmylibchart.util.merge will merge two YAML templates and output the result.\nThis takes an array of three values:\n- the top context\n- the template name of the overrides (destination)\n- the template name of the base (source)\n*/}}\n{{- define "mylibchart.util.merge" -}}\n{{- $top := first . -}}\n{{- $overrides := fromYaml (include (index . 1) $top) | default (dict ) -}}\n{{- $tpl := fromYaml (include (index . 2) $top) | default (dict ) -}}\n{{- toYaml (merge $overrides $tpl) -}}\n{{- end -}}\n'})}),"\n",(0,r.jsx)(n.p,{children:"This is important when a chart wants to use common code that it needs to\ncustomize with its configuration."}),"\n",(0,r.jsxs)(n.p,{children:["Finally, lets change the chart type to ",(0,r.jsx)(n.code,{children:"library"}),". This requires editing\n",(0,r.jsx)(n.code,{children:"mylibchart/Chart.yaml"})," as follows:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"apiVersion: v2\nname: mylibchart\ndescription: A Helm chart for Kubernetes\n\n# A chart can be either an 'application' or a 'library' chart.\n#\n# Application charts are a collection of templates that can be packaged into versioned archives\n# to be deployed.\n#\n# Library charts provide useful utilities or functions for the chart developer. They're included as\n# a dependency of application charts to inject those utilities and functions into the rendering\n# pipeline. Library charts do not define any templates and therefore cannot be deployed.\n# type: application\ntype: library\n\n# This is the chart version. This version number should be incremented each time you make changes\n# to the chart and its templates, including the app version.\nversion: 0.1.0\n\n# This is the version number of the application being deployed. This version number should be\n# incremented each time you make changes to the application and it is recommended to use it with quotes.\nappVersion: \"1.16.0\"\n"})}),"\n",(0,r.jsx)(n.p,{children:"The library chart is now ready to be shared and its ConfigMap definition to be\nre-used."}),"\n",(0,r.jsx)(n.p,{children:"Before moving on, it is worth checking if Helm recognizes the chart as a library\nchart:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-console",children:"$ helm install mylibchart mylibchart/\nError: library charts are not installable\n"})}),"\n",(0,r.jsx)(n.h2,{id:"use-the-simple-library-chart",children:"Use the Simple Library Chart"}
1),"\n",(0,r.jsx)(n.p,{children:"It is time to use the library chart. This means creating a scaffold chart again:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-console",children:"$ helm create mychart\nCreating mychart\n"})}),"\n",(0,r.jsx)(n.p,{children:"Lets clean out the template files again as we want to create a ConfigMap only:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-console",children:"$ rm -rf mychart/templates/*\n"})}),"\n",(0,r.jsx)(n.p,{children:"When we want to create a simple ConfigMap in a Helm template, it could look\nsimilar to the following:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: {{ .Release.Name | printf "%s-%s" .Chart.Name }}\ndata:\n myvalue: "Hello World"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["We are however going to re-use the common code already created in ",(0,r.jsx)(n.code,{children:"mylibchart"}),".\nThe ConfigMap can be created in the file ",(0,r.jsx)(n.code,{children:"mychart/templates/configmap.yaml"})," as\nfollows:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'{{- include "mylibchart.configmap" (list . "mychart.configmap") -}}\n{{- define "mychart.configmap" -}}\ndata:\n myvalue: "Hello World"\n{{- end -}}\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You can see that it simplifies the work we have to do by inheriting the common\nConfigMap definition which adds standard properties for ConfigMap. In our\ntemplate we add the configuration, in this case the data key ",(0,r.jsx)(n.code,{children:"myvalue"})," and its\nvalue. The configuration override the empty resource of the common ConfigMap.\nThis is feasible because of the helper function ",(0,r.jsx)(n.code,{children:"mylibchart.util.merge"})," we\nmentioned in the previous section."]}),"\n",(0,r.jsxs)(n.p,{children:["To be able to use the common code, we need to add ",(0,r.jsx)(n.code,{children:"mylibchart"})," as a dependency.\nAdd the following to the end of the file ",(0,r.jsx)(n.code,{children:"mychart/Chart.yaml"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"# My common code in my library chart\ndependencies:\n- name: mylibchart\n version: 0.1.0\n repository: file://../mylibchart\n"})}),"\n",(0,r.jsxs)(n.p,{children:["This includes the library chart as a dynamic dependency from the filesystem\nwhich is at the same parent path as our application chart. As we are including\nthe library chart as a dynamic dependency, we need to run ",(0,r.jsx)(n.code,{children:"helm dependency update"}),". It will copy the library chart into your ",(0,r.jsx)(n.code,{children:"charts/"})," directory."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-console",children:'$ helm dependency update mychart/\nHang tight while we grab the latest from your chart repositories...\n...Successfully got an update from the "stable" chart repository\nUpdate Complete. \u2388Happy Helming!\u2388\nSaving 1 charts\nDeleting outdated charts\n'})}),"\n",(0,r.jsx)(n.p,{children:"We are now ready to deploy our chart. Before installing, it is worth checking\nthe rendered template first."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-console",children:'$ helm install mydemo mychart/ --debug --dry-run\ninstall.go:159: [debug] Original chart version: ""\ninstall.go:176: [debug] CHART PATH: /root/test/helm-charts/mychart\n\nNAME: mydemo\nLAST DEPLOYED: Tue Mar 3 17:48:47 2020\nNAMESPACE: default\nSTATUS: pending-install\nREVISION: 1\nTEST SUITE: None\nUSER-SUPPLIED VALUES:\n{}\n\nCOMPUTED VALUES:\naffinity: {}\nfullnameOverride: ""\nimage:\n pullPolicy: IfNotPresent\n repository: nginx\nimagePullSecrets: []\ningress:\n annotations: {}\n enabled: false\n hosts:\n - host: chart-example.local\n paths: []\n tls: []\nmylibchart:\n global: {}\nnameOverride: ""\nnodeSelector: {}\npodSecurityContext: {}\nreplicaCount: 1\nresources: {}\nsecurityContext: {}\nservice:\n port: 80\n type: ClusterIP\nserviceAccount:\n annotations: {}\n create: true\n name: null\ntolerations: []\n\nHOOKS:\nMANIFEST:\n---\n# Source: mychart/templates/configmap.yaml\napiVersion: v1\ndata:\n myvalue: Hello World\nkind: ConfigMap\nmetadata:\n labels:\n app: mychart\n chart: mychart-0.1.0\n release: mydemo\n name: mychart-mydemo\n'})}),"\n",(0,r.jsxs)(n.p,{children:["This looks like the ConfigMap we want with data override of ",(0,r.jsx)(n.code,{children:"myvalue: Hello World"}),". Lets install it:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-console",children:"$ helm install mydemo mychart/\nNAME: mydemo\nLAST DEPLOYED: Tue Mar 3 17:52:40 2020\nNAMESPACE: default\nSTATUS: deployed\nREVISION: 1\nTEST SUITE: None\n"})}),"\n",(0,r.jsx)(n.p,{children:"We can retrieve the release and see that the actual template was loaded."}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-console",children:"$ helm get manifest mydemo\n---\n# Source: mychart/templates/configmap.yaml\napiVersion: v1\ndata:\n myvalue: Hello World\nkind: ConfigMap\nmetadata:\n labels:\n app: mychart\n chart: mychart-0.1.0\n release: mydemo\n name: mychart-mydemo\n"})}),"\n",(0,r.jsx)(n.h2,{id:"library-chart-benefits",children:"Library Chart Benefits"}),"\n",(0,r.jsx)(n.p,{children:"Because of their inability to act as standalone charts, library charts can leverage the following functionality:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["The ",(0,r.jsx)(n.code,{children:".Files"})," object references the file paths on the parent chart, rather than the path local to the library chart"]}),"\n",(0,r.jsxs)(n.li,{children:["The ",(0,r.jsx)(n.code,{children:".Values"})," object is the same as the parent chart, in contrast to application ",(0,r.jsx)(n.a,{href:"/docs/v3/chart_template_guide/subcharts_and_globals",children:"subcharts"})," which receive the section of values configured under their header in the parent."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"the-common-helm-helper-chart",children:"The Common Helm Helper Chart"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-markdown",children:"Note: The Common Helm Helper Chart repo on Github is no longer actively maintained, and the repo has been deprecated and archived.\n"})}),"\n",(0,r.jsxs)(n.p,{children:["This ",(0,r.jsx)(n.a,{href:"https://github.com/helm/charts/tree/master/incubator/common",children:"chart"})," was\nthe original pattern for common charts. It provides utilities that reflect best\npractices of Kubernetes chart development. Best of all it can be used off the\nbat by you when developing your charts to give you handy shared code."]}),"\n",(0,r.jsxs)(n.p,{children:["Here is a quick way to use it. For more details, have a look at the\n",(0,r.jsx)(n.a,{href:"https://github.com/helm/charts/blob/master/incubator/common/README.md",children:"README"}),"."]}),"\n",(0,r.jsx)(n.p,{children:"Create a scaffold chart again:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-console",children:"$ helm create demo\nCreating demo\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Lets use the common code from the helper chart. First, edit deployment\n",(0,r.jsx)(n.code,{children:"demo/templates/deployment.yaml"})," as follows:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'{{- template "common.deployment" (list . "demo.deployment") -}}\n{{- define "demo.deployment" -}}\n## Define overrides for your Deployment resource here, e.g.\napiVersion: apps/v1\nspec:\n replicas: {{ .Values.replicaCount }}\n selector:\n matchLabels:\n {{- include "demo.selectorLabels" . | nindent 6 }}\n template:\n metadata:\n labels:\n {{- include "demo.selectorLabels" . | nindent 8 }}\n\n{{- end -}}\n'})}),"\n",(0,r.jsxs)(n.p,{children:["And now the service file, ",(0,r.jsx)(n.code,{children:"demo/templates/service.yaml"})," as follows:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'{{- template "common.service" (list . "demo.service") -}}\n{{- define "demo.service" -}}\n## Define overrides for your Service resource here, e.g.\n# metadata:\n# labels:\n# custom: label\n# spec:\n# ports:\n# - port: 8080\n{{- end -}}\n'})}),"\n",(0,r.jsx)(n.p,{children:"These templates show how inheriting the common code from the helper chart\nsimplifies your coding down to your configuration or customization of the\nresources."}),"\n",(0,r.jsxs)(n.p,{children:["To be able to use the common code, we need to add ",(0,r.jsx)(n.code,{children:"common"})," as a dependency. Add\nthe following to the end of the file ",(0,r.jsx)(n.code,{children:"demo/Chart.yaml"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:'dependencies:\n- name: common\n version: "^0.0.5"\n repository: "https://charts.helm.sh/incubator/"\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Note: You will need to add the ",(0,r.jsx)(n.code,{children:"incubator"})," repo to the Helm repository list\n(",(0,r.jsx)(n.code,{children:"helm repo add"}),")."]}),"\n",(0,r.jsxs)(n.p,{children:["As we are including the chart as a dynamic dependency, we need to run ",(0,r.jsx)(n.code,{children:"helm dependency update"}),". It will copy the helper chart into your ",(0,r.jsx)(n.code,{children:"charts/"})," directory."]}),"\n",(0,r.jsxs)(n.p,{children:["As helper chart is using some Helm 2 constructs, you will need to add the\nfollowing to ",(0,r.jsx)(n.code,{children:"demo/values.yaml"})," to enable the ",(0,r.jsx)(n.code,{children:"nginx"})," image to be loaded as this\nwas updated in Helm 3 scaffold chart:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"image:\n tag: 1.16.0\n"})}),"\n",(0,r.jsxs)(n.p,{children:["You can test that the chart templates are correct prior to deploying using the ",(0,r.jsx)(n.code,{children:"helm lint"})," and ",(0,r.jsx)(n.code,{children:"helm template"})," commands."]}),"\n",(0,r.jsxs)(n.p,{children:["If it's good to go, deploy away using ",(0,r.jsx)(n.code,{children:"helm install"}),"!"]})]})}function d(e={}){let{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},28453(e,n,a){a.d(n,{R:()=>l,x:()=>s});var t=a(96540);let r={},i=t.createContext(r);function l(e){let n=t.useContext(i);return t.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function s(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:l(e.components),t.createElement(i.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.