{"id":6143,"date":"2021-03-23T15:44:28","date_gmt":"2021-03-23T10:14:28","guid":{"rendered":"https:\/\/opstree.com\/blog\/\/?p=6143"},"modified":"2021-03-23T18:26:55","modified_gmt":"2021-03-23T12:56:55","slug":"create-your-first-helm-chart-part-03","status":"publish","type":"post","link":"https:\/\/opstree.com\/blog\/2021\/03\/23\/create-your-first-helm-chart-part-03\/","title":{"rendered":"Create Your First Helm Chart (Part 03)"},"content":{"rendered":"\r\n<p class=\"has-text-align-justify\">Bonjour! So we&#8217;ve had our <a href=\"https:\/\/www.bogotobogo.com\/DevOps\/Docker\/Docker-Kubernetes-Minikube-install-on-AWS-EC2.php\" target=\"_blank\" rel=\"noopener\">minikube cluster up and running<\/a> and tried setting up MySQL application onto our cluster using publicly available Helm Charts in our <a href=\"https:\/\/opstree.com\/blog\/\/2021\/02\/09\/helm-hands-on-get-started-with-helm-part-02\/\">previous blog<\/a>. In case, you haven\u2019t, I suggest you go through the link before reading this blog.<\/p>\r\n\r\n\r\n\r\n<p class=\"has-text-align-justify\">This guide walks us through the process of creating our first-ever chart, explaining what goes inside these packages and the tools we use to develop them. By the end of it we should have an understanding of the advantages of using and creating our Helm Charts to deliver our own applications to the K8s cluster.<\/p>\r\n\r\n\r\n\r\n<div class=\"wp-block-image\">\r\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"350\" height=\"265\" class=\"wp-image-6157\" src=\"https:\/\/opstree.com\/blog\/\/wp-content\/uploads\/2021\/03\/lets_do_this_5.gif?w=350\" alt=\"\" \/><\/figure>\r\n<p>&nbsp;<\/p>\r\n<\/div>\r\n<p><!--more--><\/p>\r\n\r\n\r\n\r\n<h5 class=\"wp-block-heading\">Case: Deploying a Golang Application using our own Helm Charts<\/h5>\r\n\r\n\r\n\r\n<p class=\"has-text-align-justify\">The best way to get started with a new chart is to use the <code>helm create<\/code> command, which helps to understand the directory structure of a Chart in Helm. It is nothing but a packaged version of your application that follows some specifications for describing the resources to be installed into K8s.<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-syntaxhighlighter-code\">$ helm create gowebapp<\/pre>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"693\" height=\"325\" class=\"wp-image-6155\" src=\"https:\/\/opstree.com\/blog\/\/wp-content\/uploads\/2021\/03\/helm1.png?w=693\" alt=\"\" \/><\/figure>\r\n\r\n\r\n\r\n<p class=\"has-text-align-justify\"><strong>Chart.yaml : <\/strong>It provides the information about the chart version, name, description, etc. or, in another words, the metadata of our chart.<\/p>\r\n\r\n\r\n\r\n<p class=\"has-text-align-justify\"><strong>Templates :<\/strong> The most important piece in the puzzle of Helm is the <code>templates\/<\/code> directory. This is where Helm finds the YAML definitions for our Services, Deployments, and other K8s objects.<\/p>\r\n\r\n\r\n\r\n<p class=\"has-text-align-justify\"><strong>values.yaml :<\/strong> This file can&#8217;t be shrugged off as it contains the default values for the chart. These values may be overridden by us to manage our K8s objects.<\/p>\r\n\r\n\r\n\r\n<div class=\"wp-block-group\">\r\n<div class=\"wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow\">\r\n<h6 class=\"wp-block-heading\">Building a Helm Chart<\/h6>\r\n\r\n\r\n\r\n<p class=\"has-text-align-justify\">As we have already created the default structure for our application as shown above, we&#8217;ll proceed with building our resource files under <code>gowebapp\/<\/code> directory. We have some database dependencies for our application which helps to bring up the UI. To resolve those dependencies, we mention it under <code>Chart.yaml<\/code> as shown below<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-syntaxhighlighter-code\">apiVersion: v2\r\nname: gowebapp\r\ndescription: A Helm chart for GoWebApp\r\ntype: application\r\nversion: 0.1.0\r\nappVersion: 1.16.0\r\ndependencies:\r\n- name: mysql\r\n  version: \"1.6.9\"\r\n  repository: \"https:\/\/charts.helm.sh\/stable\"\r\n- name: redis\r\n  version: \"10.5.7\"\r\n  repository: \"https:\/\/charts.helm.sh\/stable\"<\/pre>\r\n\r\n\r\n\r\n<p class=\"has-text-align-justify\">Before, updating the dependencies we can list out to check do we have any or not, as shown :<\/p>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"765\" height=\"85\" class=\"wp-image-6197\" src=\"https:\/\/opstree.com\/blog\/\/wp-content\/uploads\/2021\/03\/helm6.png?w=765\" alt=\"\" \/><\/figure>\r\n<\/div>\r\n<\/div>\r\n\r\n\r\n\r\n<p class=\"has-text-align-justify\">Now, to update the application dependencies we have to follow some steps keeping ourselves under the <code>gowebapp<\/code> directory :<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-syntaxhighlighter-code\">$ helm dependency list\r\n$ helm dependency update<\/pre>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"816\" height=\"338\" class=\"wp-image-6166\" src=\"https:\/\/opstree.com\/blog\/\/wp-content\/uploads\/2021\/03\/helm4.png?w=816\" alt=\"\" \/><\/figure>\r\n\r\n\r\n\r\n<p class=\"has-text-align-justify\">As the dependencies are downloaded, it&#8217;s time for adding resource files. For our Golang Application all we need is deployment, service, and ingress resources. The other resources created by default like, service account, _helpers.tpl, etc. can be deleted.<\/p>\r\n\r\n\r\n\r\n<p class=\"has-text-align-justify\">Here, we passed some default values of database, labels, matchlabels, and containers specs to the Chart with the help of values.yaml file as below :<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-syntaxhighlighter-code\">mysql:\r\n  mysqlDatabase: employeedb\r\n  mysqlRootPassword: password\r\n  persistence:\r\n    enabled: false\r\n\r\nredis:\r\n  usePassword: false\r\n  cluster:\r\n    enabled: false\r\n  master:\r\n    persistence:\r\n      enabled: false\r\n\r\nlabels:\r\n  app.kubernetes.io\/name: app\r\n  app.kubernetes.io\/instance: goweb-app\r\n  app.kubernetes.io\/version: \"1.16.0\"\r\n\r\nmatchLabels:\r\n  app.kubernetes.io\/name: app\r\n  app.kubernetes.io\/instance: goweb-app\r\n\r\ncontainers:\r\n  name: goweb-app\r\n  image: opstreedevops\/ot-go-webapp\r\n  tag: \"v1\"<\/pre>\r\n\r\n\r\n\r\n<p>Now, we can start adding the resource file values under the <code>template\/<\/code> directory in the deployment, service, and ingress resource files as below :<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-syntaxhighlighter-code\">apiVersion: apps\/v1\r\nkind: Deployment\r\nmetadata:\r\n  name: goweb-app\r\n  {{- if .Values.labels }}\r\n  labels:\r\n    {{- toYaml .Values.labels | nindent 4 }}\r\n  {{- end }}\r\nspec:\r\n  replicas: 1\r\n  selector:\r\n    matchLabels:\r\n      {{- toYaml .Values.matchLabels | nindent 6 }}\r\n  template:\r\n    metadata:\r\n      {{- if .Values.matchLabels }}\r\n      labels:\r\n        {{- toYaml .Values.matchLabels| nindent 8 }}\r\n      {{- end }}\r\n    spec:\r\n      containers:\r\n        - name: {{ .Values.containers.name }}\r\n          image: \"{{ .Values.containers.image }}:{{ .Values.containers.tag }}\"\r\n          imagePullPolicy: IfNotPresent\r\n          ports:\r\n          - name: http\r\n            containerPort: 8080\r\n            protocol: TCP\r\n          env:\r\n          - name: DB_URL\r\n            value: goweb-app-mysql\r\n          - name: DB_PORT\r\n            value: \"3306\"\r\n          - name: DB_USER\r\n            value: \"root\"\r\n          - name: DB_PASSWORD\r\n            value: password\r\n          - name: REDIS_HOST\r\n            value: \"goweb-app-redis-headless\"\r\n          - name: REDIS_PORT\r\n            value: \"6379\"<\/pre>\r\n\r\n\r\n\r\n<pre class=\"wp-block-syntaxhighlighter-code\">apiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: goweb-app\r\n  {{- if .Values.labels }}\r\n  labels:\r\n    {{- toYaml .Values.labels | nindent 4 }}\r\n  {{- end }}\r\nspec:\r\n  type: ClusterIP\r\n  ports:\r\n    - port: 8080\r\n      targetPort: http\r\n      protocol: TCP\r\n      name: http\r\n{{- if .Values.matchLabels }}\r\n  selector:\r\n        {{- toYaml .Values.matchLabels| nindent 4 }}\r\n      {{- end }}<\/pre>\r\n\r\n\r\n\r\n<pre class=\"wp-block-syntaxhighlighter-code\">apiVersion: networking.k8s.io\/v1beta1\r\nkind: Ingress\r\nmetadata:\r\n  name: goweb-app\r\n  {{- if .Values.labels }}\r\n  labels:\r\n    {{- toYaml .Values.labels | nindent 4 }}\r\n  {{- end }}\r\nspec:\r\n  rules:\r\n    - host: \"ethanhunt.com\"\r\n      http:\r\n        paths:\r\n          - path: \/\r\n            backend:\r\n              serviceName: goweb-app\r\n              servicePort: 8080<\/pre>\r\n\r\n\r\n\r\n<p class=\"has-text-align-justify\">Let\u2019s validate the manifest content by running <code>helm template<\/code> command, which will list out all the resource files with the configured values which will be needed to install our application using Helm Chart onto our K8s cluster.<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-syntaxhighlighter-code\">$ helm template gowebapp\/<\/pre>\r\n\r\n\r\n\r\n<p class=\"has-text-align-justify\">To make it more clear let&#8217;s understand the flow when Helm Chart is installed into Kubernetes :<\/p>\r\n\r\n\r\n\r\n<ul>\r\n<li>Helm reads the chart.<\/li>\r\n<li>It reads the configuration values from the values.yml and generates the manifest files with these values.<\/li>\r\n<li>Helm sends these generated manifests to the Kubernetes API server.<\/li>\r\n<li>K8 takes these manifest files and creates desired resources in the cluster.<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n<div class=\"wp-block-image\">\r\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/media.giphy.com\/media\/3FQxaJJkQR8U4gdzr0\/giphy.gif\" alt=\"\" \/><\/figure>\r\n<\/div>\r\n\r\n\r\n\r\n<h6 class=\"wp-block-heading\">Installing a Local Helm Chart of our Application<\/h6>\r\n\r\n\r\n\r\n<p class=\"has-text-align-justify\">We can deploy and verify the locally created helm chart of our application using<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-syntaxhighlighter-code\">$ helm install go-web-app gowebapp\/\r\n$ helm ls\r\n$ kubectl get pods <\/pre>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-6175\" src=\"https:\/\/opstree.com\/blog\/\/wp-content\/uploads\/2021\/03\/helm-5.png?w=1024\" alt=\"\" width=\"629\" height=\"187\" \/><\/figure>\r\n\r\n\r\n\r\n<p class=\"has-text-align-justify\">And finally, we can check our application up and running with the help of hostname given in our Ingress resource file.<\/p>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/raw.githubusercontent.com\/OT-CONTAINER-KIT\/Working-with-Helm\/dee\/Images\/11.PNG\" alt=\"\" width=\"629\" height=\"493\" \/><\/figure>\r\n\r\n\r\n\r\n<p class=\"has-text-align-justify\">With the above steps, it should not be difficult to get a pod up and running with our own chart. The journey so far brought us from understanding the basics of Helm to creating our, very own, first chart. Until now, we went with somewhat hardcoded approach to understand the functioning of Helm Charts. In the next blog, we&#8217;ll go further in automating by templating the chart and populating the variables as per requirement.<\/p>\r\n<p class=\"has-text-align-justify\">Till then, Happy Helming!<\/p>\r\n<p>References &#8211; <a href=\"https:\/\/encrypted-tbn0.gstatic.com\/images?q=tbn:ANd9GcQVy0MHDwOWAyF-TXEHR7onfmkLEVwu1NuGw5knI6-6oc9WrelI4I_kCGmFiiAIX1dwxWE&amp;usqp=CAU\" target=\"_blank\" rel=\"noopener\">GIF 1<\/a>, <a href=\"https:\/\/sciencefiction.com\/wp-content\/uploads\/2019\/01\/doctor-strange-we-are-in-the-endgame-now.gif\" target=\"_blank\" rel=\"noopener\">GIF 2<\/a><\/p>\r\n<p>&nbsp;<\/p>\r\n<p><strong>Blog Pundit: <\/strong><strong><a href=\"https:\/\/opstree.com\/blog\/\/author\/adeel109\/\" target=\"_blank\" rel=\"noreferrer noopener\">Adeel Ahmad\u00a0<\/a><\/strong><\/p>\r\n<p>Opstree is an End to End DevOps solution provider<\/p>\r\n<p><a href=\"https:\/\/www.opstree.com\/contact-us\" target=\"_blank\" rel=\"noreferrer noopener\">CONTACT US<\/a><\/p>\r\n","protected":false},"excerpt":{"rendered":"<p>Bonjour! So we&#8217;ve had our minikube cluster up and running and tried setting up MySQL application onto our cluster using publicly available Helm Charts in our previous blog. In case, you haven\u2019t, I suggest you go through the link before reading this blog. This guide walks us through the process of creating our first-ever chart, &hellip; <a href=\"https:\/\/opstree.com\/blog\/2021\/03\/23\/create-your-first-helm-chart-part-03\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Create Your First Helm Chart (Part 03)&#8221;<\/span><\/a><\/p>\n","protected":false},"author":198919067,"featured_media":29900,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[28070474],"tags":[498519,712305460,768739309,2704],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/opstree.com\/blog\/wp-content\/uploads\/2025\/11\/DevSecOps-1.jpg","jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pfDBOm-1B5","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/6143"}],"collection":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/users\/198919067"}],"replies":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/comments?post=6143"}],"version-history":[{"count":23,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/6143\/revisions"}],"predecessor-version":[{"id":6208,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/6143\/revisions\/6208"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/media\/29900"}],"wp:attachment":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/media?parent=6143"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/categories?post=6143"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/tags?post=6143"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}