{"id":1033,"date":"2020-09-14T18:07:54","date_gmt":"2020-09-14T18:07:54","guid":{"rendered":"https:\/\/blog.samarthya.me\/wps\/?p=1033"},"modified":"2020-09-15T06:53:41","modified_gmt":"2020-09-15T06:53:41","slug":"writing-charts","status":"publish","type":"post","link":"https:\/\/blog.samarthya.me\/wps\/2020\/09\/14\/writing-charts\/","title":{"rendered":"Writing Helm Charts"},"content":{"rendered":"\n<figure class=\"wp-block-pullquote is-style-solid-color\"><blockquote><p>Helm is a dedicated package manager for Kubernetes.<\/p><\/blockquote><\/figure>\n\n\n\n<p class=\"has-drop-cap\">Although the <code>Kubernetes<\/code> objects are deployed in YAML&#8217;s there was a need to package and club them together and customise the deployment (not the K8S deployment).<\/p>\n\n\n\n<p>Helm uses <code>Go templates<\/code>. <\/p>\n\n\n\n<figure class=\"wp-block-pullquote has-background has-pale-cyan-blue-background-color is-style-solid-color\"><blockquote class=\"has-text-color has-black-color\"><p>Please refer to official go documentation on template package for details. You can also look at examples in my <a href=\"https:\/\/github.com\/samarthya\/gotemplates.git\" target=\"_blank\" rel=\"noreferrer noopener\">repo here.<\/a><\/p><\/blockquote><\/figure>\n\n\n\n<p>Actions from the official documentation<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{{\/* a comment *\/}}\n{{- \/* a comment with white space trimmed from preceding and following text *\/ -}}\n\tA comment; discarded. May contain newlines.\n\tComments do not nest and must start and end at the\n\tdelimiters, as shown here.\n\n{{pipeline}}\n\tThe default textual representation (the same as would be\n\tprinted by fmt.Print) of the value of the pipeline is copied\n\tto the output.\n\n{{if pipeline}} T1 {{end}}\n\tIf the value of the pipeline is empty, no output is generated;\n\totherwise, T1 is executed. The empty values are false, 0, any\n\tnil pointer or interface value, and any array, slice, map, or\n\tstring of length zero.\n\tDot is unaffected.\n\n{{if pipeline}} T1 {{else}} T0 {{end}}\n\tIf the value of the pipeline is empty, T0 is executed;\n\totherwise, T1 is executed. Dot is unaffected.\n\n{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}\n\tTo simplify the appearance of if-else chains, the else action\n\tof an if may include another if directly; the effect is exactly\n\tthe same as writing\n\t\t{{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}}\n\n{{range pipeline}} T1 {{end}}\n\tThe value of the pipeline must be an array, slice, map, or channel.\n\tIf the value of the pipeline has length zero, nothing is output;\n\totherwise, dot is set to the successive elements of the array,\n\tslice, or map and T1 is executed. If the value is a map and the\n\tkeys are of basic type with a defined order, the elements will be\n\tvisited in sorted key order.\n\n{{range pipeline}} T1 {{else}} T0 {{end}}\n\tThe value of the pipeline must be an array, slice, map, or channel.\n\tIf the value of the pipeline has length zero, dot is unaffected and\n\tT0 is executed; otherwise, dot is set to the successive elements\n\tof the array, slice, or map and T1 is executed.\n\n{{template \"name\"}}\n\tThe template with the specified name is executed with nil data.\n\n{{template \"name\" pipeline}}\n\tThe template with the specified name is executed with dot set\n\tto the value of the pipeline.\n\n{{block \"name\" pipeline}} T1 {{end}}\n\tA block is shorthand for defining a template\n\t\t{{define \"name\"}} T1 {{end}}\n\tand then executing it in place\n\t\t{{template \"name\" pipeline}}\n\tThe typical use is to define a set of root templates that are\n\tthen customized by redefining the block templates within.\n\n{{with pipeline}} T1 {{end}}\n\tIf the value of the pipeline is empty, no output is generated;\n\totherwise, dot is set to the value of the pipeline and T1 is\n\texecuted.\n\n{{with pipeline}} T1 {{else}} T0 {{end}}\n\tIf the value of the pipeline is empty, dot is unaffected and T0\n\tis executed; otherwise, dot is set to the value of the pipeline\n\tand T1 is executed.<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Example<\/h2>\n\n\n\n<p>Let&#8217;s show a go template example before we move to the <code>Helm<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Letter a template for the automatic reply.\nconst Letter = `\nDear {{.Name}},\n{{\/* Check if the person identified by .Name attended the event. *\/}}\n{{if .Attended}}\nIt was a pleasure to meet you at the wedding.\n{{- else}}\n{{\/* Person identified by .Name did not attended the event. *\/}}\nIt is a shame you couldn't make it to the wedding.\n{{- end}}\n{{with .Gift -}}\nThank you for the lovely {{.}}.\n{{end}}\nBest wishes,\nJosie\n`\n\n\/\/ Recipient Identifies the recipient\ntype Recipient struct {\n\tName, Gift string\n\tAttended   bool\n}<\/code><\/pre>\n\n\n\n<p>If I need to evaluate this template which is nothing just a letter template that works on some values provided.<\/p>\n\n\n\n<p>Will use sample values for the struct Recipient as under<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>var recipients = &#91;]two.Recipient{\n\t\t{\"Aunt Mildred\", \"bone china tea set\", true},\n\t\t{\"Uncle John\", \"moleskin pants\", false},\n\t\t{\"Cousin Rodney\", \"\", false},\n\t}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ exampleTwo - Uses the actions and pipelines\nfunc exampleTwo() {\n\tt := template.Must(template.New(\"letter\").Parse(two.Letter))\n\n\t\/\/ Execute the template for each recipient.\n\tfor _, r := range recipients {\n\t\terr := t.Execute(os.Stdout, r)\n\t\tif err != nil {\n\t\t\tlog.Println(\"executing template:\", err)\n\t\t}\n\t}\n}<\/code><\/pre>\n\n\n\n<p>Once invoked it will print on the console.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Dear Aunt Mildred,\n\nIt was a pleasure to meet you at the wedding.\nThank you for the lovely bone china tea set.\n\nBest wishes,\nJosie\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>Dear Uncle John,\n\nIt is a shame you couldn't make it to the wedding.\nThank you for the lovely moleskin pants.\n\nBest wishes,\nJosie\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>Dear Cousin Rodney,\n\nIt is a shame you couldn't make it to the wedding.\n\nBest wishes,\nJosie\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Local &#8211; <code>helm<\/code> version<\/h2>\n\n\n\n<p>The local helm version I am using on my box &#8211; <code>helm version<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>version.BuildInfo{Version:\"v3.3.1\", GitCommit:\"249e5215cde0c3fa72e27eb7a30e8d55c9696144\", GitTreeState:\"dirty\", GoVersion:\"go1.15\"}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>helm version --short\nv3.3.1+g249e521<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Creating my chart<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>helm create epserver<\/code><\/pre>\n\n\n\n<p>It creates some files as mentioned below<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.\n\u251c\u2500\u2500 Chart.yaml\n\u251c\u2500\u2500 charts\n\u251c\u2500\u2500 templates\n\u2502   \u251c\u2500\u2500 NOTES.txt\n\u2502   \u251c\u2500\u2500 _helpers.tpl\n\u2502   \u251c\u2500\u2500 deployment.yaml\n\u2502   \u251c\u2500\u2500 hpa.yaml\n\u2502   \u251c\u2500\u2500 ingress.yaml\n\u2502   \u251c\u2500\u2500 service.yaml\n\u2502   \u251c\u2500\u2500 serviceaccount.yaml\n\u2502   \u2514\u2500\u2500 tests\n\u2502       \u2514\u2500\u2500 test-connection.yaml\n\u2514\u2500\u2500 values.yaml<\/code><\/pre>\n\n\n\n<p>I will give a brief about most of the file I edit, but you read more anytime from the official Helm documentation<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Chart.yaml<\/h4>\n\n\n\n<figure class=\"wp-block-pullquote has-background has-cyan-bluish-gray-background-color is-style-solid-color\"><blockquote class=\"has-text-color has-black-color\"><p>A YAML file containing information about the chart<\/p><\/blockquote><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">templates\/                                       [DIRECTORY]<\/h4>\n\n\n\n<figure class=\"wp-block-pullquote has-background has-cyan-bluish-gray-background-color is-style-solid-color\"><blockquote class=\"has-text-color has-black-color\"><p>A directory of templates that, when combined with values, will generate valid Kubernetes manifest files.<\/p><\/blockquote><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">values.yaml<\/h4>\n\n\n\n<figure class=\"wp-block-pullquote has-background has-cyan-bluish-gray-background-color is-style-solid-color\"><blockquote class=\"has-text-color has-black-color\"><p>The default configuration values for this chart<\/p><\/blockquote><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">charts\/                                 [DIRECTORY]<\/h4>\n\n\n\n<figure class=\"wp-block-pullquote is-style-solid-color\"><blockquote><p>A directory containing any charts upon which this chart depends.<\/p><\/blockquote><\/figure>\n\n\n\n<p>Added some details in the <code>Chart.yaml<\/code>, which are self explanatory<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Minimum Version 3 required so v2\napiVersion: v2\nname: epserver\ndescription: A sample go server that exposes few endpoints.\ntype: application\nversion: 2.0.0\nkubeVersion: ~1.18.x\nappVersion: 3.0.0<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">serviceaccount.yaml<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>{{- if .Values.serviceAccount.create -}}\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: {{ include \"epserver.serviceAccountName\" . }}\n  labels:\n    {{- include \"epserver.labels\" . | nindent 4 }}\n  {{- with .Values.serviceAccount.annotations }}\n  annotations:\n    {{- toYaml . | nindent 4 }}\n  {{- end }}\n{{- end }}<\/code><\/pre>\n\n\n\n<p>I will use my application <code><a href=\"https:\/\/blog.samarthya.me\/wps\/2020\/08\/24\/deployments-k8s\/\">epserver<\/a><\/code> and create a chart for it just to check if simple modifications work. <\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>All, code is available in <a href=\"https:\/\/github.com\/samarthya\/epserver.git\">my github repo<\/a>.<\/p><\/blockquote>\n\n\n\n<h4 class=\"wp-block-heading\">Values.yaml<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code># Replica count\nreplicaCount: 1\n# Only 1 replica required\n\n# Labels for container\nappname: epserver\n\n# define the environment variable.\nenv:\n  defined: true\n  vars:\n    - name: SERVERPORT\n      value: \"9090\"\n\nimage:\n  repository: samarthya\/epserver\n  pullPolicy: Always\n  # Overrides the image tag whose default is the chart appVersion.\n  tag: \"2.0\"\n\nimagePullSecrets: &#91;]\nnameOverride: \"samarthya\"\nfullnameOverride: \"eps\"\n\n# Samarthya: Added v1\nenvironment: \"test\"\n\nserviceAccount:\n  # Specifies whether a service account should be created\n  create: true\n  # Annotations to add to the service account\n  annotations: {}\n  # The name of the service account to use.\n  # If not set and create is true, a name is generated using the fullname template\n  name: sa-epserver\n\npodAnnotations: {}\n\npodSecurityContext: {}\n  # fsGroup: 2000\n\nsecurityContext: {}\n  # capabilities:\n  #   drop:\n  #   - ALL\n  # readOnlyRootFilesystem: true\n  # runAsNonRoot: true\n  # runAsUser: 1000\n\nservice:\n  type: ClusterIP\n  port: 9090\n\ningress:\n  enabled: false\n  annotations: {}\n    # kubernetes.io\/ingress.class: nginx\n    # kubernetes.io\/tls-acme: \"true\"\n  hosts:\n    - host: chart-example.local\n      paths: &#91;]\n  tls: &#91;]\n  #  - secretName: chart-example-tls\n  #    hosts:\n  #      - chart-example.local\n\nresources:\n# define limits\n  limits:\n    memory: \"250Mi\"\n    cpu: \"2000m\"\n\nautoscaling:\n  enabled: false\n  minReplicas: 1\n  maxReplicas: 100\n  targetCPUUtilizationPercentage: 80\n  # targetMemoryUtilizationPercentage: 80\n\nnodeSelector: {}\n\ntolerations: &#91;]\n\naffinity: {}<\/code><\/pre>\n\n\n\n<p>Can you spot the changes done?<\/p>\n\n\n\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow\">\n<ul class=\"wp-block-list\"><li>I have added <code>resources, limits, memory<\/code><\/li><li>Have added <code>service<\/code> port<\/li><li>Added Image<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>image:\n  repository: samarthya\/epserver\n  pullPolicy: Always\n  # Overrides the image tag whose default is the chart appVersion.\n  tag: \"2.0\"<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li>Added a network policy for allow all traffic to the pods.<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>---\napiVersion: networking.k8s.io\/v1\nkind: NetworkPolicy\nmetadata:\n  name: allow-all-ingress\nspec:\n  podSelector:\n    matchLabels:\n      app: {{ .Values.appname }}\n  ingress:\n  - {}\n  policyTypes:\n  - Ingress\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Publishing Chart<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>helm package .<\/code><\/pre>\n\n\n\n<p>This should generate the chart packaging like<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>epserver-2.0.0.tgz<\/code><\/pre>\n\n\n\n<p>You can update the local repo or publish to your own <a href=\"https:\/\/github.com\/samarthya\/hlmepserver.git\">helm-git-repo<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Command that come in handy<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>helm repo search samarthya<\/code><\/pre>\n\n\n\n<p>Where samarthya is my local repo<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>helm repo list<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>NAME     \tURL                                                           \nbitnami  \thttps:\/\/charts.bitnami.com\/bitnami                            \nsamarthya\thttps:\/\/raw.githubusercontent.com\/samarthya\/hlmepserver\/master<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>helm repo index .<\/code><\/pre>\n\n\n\n<p>This you can run in the local directory where the <code>tgz<\/code> was generated.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>helm install eps samarthya\/epserver<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>NAME: eps\nLAST DEPLOYED: Mon Sep 14 17:48:05 2020\nNAMESPACE: default\nSTATUS: deployed\nREVISION: 1\nNOTES:\n1. Get the application URL by running these commands:\n  export POD_NAME=$(kubectl get pods --namespace default -l \"app.kubernetes.io\/name=samarthya,app.kubernetes.io\/instance=eps\" -o jsonpath=\"{.items&#91;0].metadata.name}\")\n  echo \"Visit http:\/\/127.0.0.1:8080 to use your application\"\n  kubectl --namespace default port-forward $POD_NAME 8080:80<\/code><\/pre>\n\n\n\n<p>You can check all the objects created<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>k get all\nNAME                       READY   STATUS              RESTARTS   AGE\npod\/eps-58fbc9cfb4-2jbdz   0\/1     ContainerCreating   0          3s\n\nNAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE\nservice\/eps          ClusterIP   10.111.254.111   &lt;none>        9090\/TCP   3s\nservice\/kubernetes   ClusterIP   10.96.0.1        &lt;none>        443\/TCP    28d\n\nNAME                  READY   UP-TO-DATE   AVAILABLE   AGE\ndeployment.apps\/eps   0\/1     1            0           3s\n\nNAME                             DESIRED   CURRENT   READY   AGE\nreplicaset.apps\/eps-58fbc9cfb4   1         1         0       3s<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>curl -m 2 http:\/\/10.111.254.111:9090\/hello?msg=My_message_my_rule<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>{\"message\":\"My_message_my_rule\",\"timestamp\":\"2020-09-14T18:00:27.929269256Z\"}<\/code><\/pre>\n\n\n\n<p>You can see the output will reflect the message is working.<\/p>\n<\/div><\/div>\n\n\n\n<pre class=\"wp-block-code\"><code>k logs service\/eps\n2020\/09\/14 17:48:12  DBG: Accepting traffic for \/hello\n2020\/09\/14 17:48:12  DBG: Accepting traffic for \/health\n -------- Welcome to my server ------- \n2020\/09\/14 17:48:12  DBG: Accepting for \/any.html\n2020\/09\/14 17:48:12  DBG: Port  :9090\n2020\/09\/14 17:48:12 My Simple Http Server\n2020\/09\/14 17:48:14  DBG: Method -  GET\n2020\/09\/14 17:48:14  DBG: Body -  {}\n2020\/09\/14 17:48:14  DBG: URL -  \/health\n2020\/09\/14 17:48:14     { \n2020\/09\/14 17:48:14      DBG: Server is Healthy!\n2020\/09\/14 17:48:14      DBG: 2020-09-14 17:48:14.594181453 +0000 UTC\n2020\/09\/14 17:48:14     } <\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">References<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>https:\/\/masterminds.github.io\/sprig\/<\/li><li>https:\/\/helm.sh\/docs\/chart_template_guide\/builtin_objects\/<\/li><li><a href=\"https:\/\/kubernetes.io\/docs\/tasks\/configure-pod-container\/configure-service-account\/\">ServiceAccountName<\/a><\/li><li>https:\/\/kubernetes.io\/docs\/reference\/generated\/kubernetes-api\/v1.18\/#serviceaccount-v1-core<\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Helm is a dedicated package manager for Kubernetes. Although the Kubernetes objects are deployed in YAML&#8217;s there was a need to package and club them together and customise the deployment (not the K8S deployment). Helm uses Go templates. Please refer to official go documentation on template package for details. You can also look at examples [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":1041,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"image","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"footnotes":""},"categories":[34],"tags":[107,108,106,18],"class_list":["post-1033","post","type-post","status-publish","format-image","has-post-thumbnail","hentry","category-technical","tag-charts","tag-example","tag-helm","tag-k8s","post_format-post-format-image"],"_links":{"self":[{"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/posts\/1033","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/comments?post=1033"}],"version-history":[{"count":0,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/posts\/1033\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/media\/1041"}],"wp:attachment":[{"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/media?parent=1033"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/categories?post=1033"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/tags?post=1033"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}