<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sunny Bhambhani</title>
    <description>The latest articles on DEV Community by Sunny Bhambhani (@sunnybhambhani).</description>
    <link>https://dev.to/sunnybhambhani</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1005168%2Fe3697725-f1bf-4345-883a-30d23e3446f2.jpeg</url>
      <title>DEV Community: Sunny Bhambhani</title>
      <link>https://dev.to/sunnybhambhani</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sunnybhambhani"/>
    <language>en</language>
    <item>
      <title>Python - Stop storing passwords in plain text! A guide to werkzeug.security</title>
      <dc:creator>Sunny Bhambhani</dc:creator>
      <pubDate>Mon, 05 Jan 2026 18:27:12 +0000</pubDate>
      <link>https://dev.to/aws-builders/python-stop-storing-passwords-in-plain-text-a-guide-to-werkzeugsecurity-179i</link>
      <guid>https://dev.to/aws-builders/python-stop-storing-passwords-in-plain-text-a-guide-to-werkzeugsecurity-179i</guid>
      <description>&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;Storing passwords in plain text presents numerous dangers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What happens if your database is compromised? &lt;/li&gt;
&lt;li&gt;What if you accidentally reveal the wrong window while demonstrating and sharing your screen? &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Such mistakes can result in serious issues, including losing the trust of customers, damaging brand value, financial repercussions, legal penalties, etc. These kinds of incidents are not rare; news reports about data breaches frequently appear worldwide. &lt;/p&gt;

&lt;p&gt;Refer to &lt;a href="https://databreaches.net/" rel="noopener noreferrer"&gt;https://databreaches.net/&lt;/a&gt; for more details around data breaches worldwide.&lt;/p&gt;

&lt;p&gt;Therefore, we should consider security in each aspect of application development, starting from planning, coding, building, deployment, etc. &lt;/p&gt;

&lt;p&gt;And in this article, we will be talking about hashing passwords, but how do we actually do that? What options are available, etc.?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There are numerous options available, out of which some of the famous ones are werkzeug.security, argon2, bcrypt, etc.&lt;/li&gt;
&lt;li&gt;Here we will see what werkzeug.security is and its practical implementation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Working Python setup.&lt;/li&gt;
&lt;li&gt;Werkzeug Library installed.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install werkzeug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Basics
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How does this work?&lt;/strong&gt;&lt;br&gt;
werkzeug.security provides helper functions for secure password storage and verification, and the two most commonly used functions are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generate_password_hash(password, method=XXX, salt_length=XXX)&lt;/li&gt;
&lt;li&gt;check_password_hash(PASSWORD_HASH, ACTUAL_PASSWORD)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More details around this can be found in its official documentation, refer: &lt;a href="https://werkzeug.palletsprojects.com/en/stable/utils/" rel="noopener noreferrer"&gt;https://werkzeug.palletsprojects.com/en/stable/utils/&lt;/a&gt; for more details.&lt;/p&gt;

&lt;p&gt;The basic principle behind it is, &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;generate_password_hash&lt;/strong&gt; takes the actual plain-text password as an input. &lt;/li&gt;
&lt;li&gt;Further generates a salt of specified length. &lt;/li&gt;
&lt;li&gt;The password + salt is processed through the chosen algorithm.

&lt;ul&gt;
&lt;li&gt;scrypt(default)&lt;/li&gt;
&lt;li&gt;pbkdf2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Finally, it generates the output as a structured, hashed string.&lt;/li&gt;
&lt;li&gt;Then &lt;strong&gt;check_password_hash&lt;/strong&gt; comes into the picture, it securely checks if the given password and the stored password hash match or not.&lt;/li&gt;
&lt;li&gt;Once that is evaluated, it produces a Boolean result, either true or false.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  HOWTO
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;generate_password_hash&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Import generate_password_hash
from werkzeug.security import generate_password_hash

# Plain text password, if using Flask, it can come from any web form
plain_password = "SHH_SECRET"

# Generate a hashed string using default parameters
hashed = generate_password_hash(plain_password)

# Printing a hashed string
print("Hashed String: ", hashed)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Output
Hashed String:  scrypt:32768:8:1$A2qi9GPp8Ut3cESv$31e31ffc4d21251396b391c31f09f6637e9169d4c5541a790cf0d9fcae3d58d2ba8a2df51e13f2601ba77fabe2e68d517fe845c63b489418309791ae1e350d3b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you observe, the hashed string contains multiple sections&lt;br&gt;
scrypt:N:r:p(METHOD_and_PARAMETERS)$salt(RANDOM_SALT)$derived_hash(ACTUAL_HASHED_PASSWORD)&lt;/p&gt;

&lt;p&gt;In the above example, we just used the default values to generate the password hash.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Method: scrypt
N: 32768
r: 8
p: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Quick note about the parameters: Based on my understanding, the parameters N, r, and p in scrypt directly control how much compute and memory are required to derive a single password hash. The larger the numbers, the harder and more computationally intensive it is to break the password.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you want to use custom parameters, this is how we can use them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;generate_password_hash(plain_password, method="scrypt:32768:16:1", salt_length=32)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will produce the output as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scrypt:32768:16:1$0hkax1LolbhqTyEN9rMSi8MC2MoF5B8w$85a7175deab3795db17898d17f03e3164df0ae1d158081ca3ed1680f9f940ff9cac76df18a71595160fd39963f4b4811c82348354e0c4a67a328104c56900230
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;if you want to use another method, this is how we can use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;generate_password_hash(plain_password, method="pbkdf2:sha256")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The execution of generate_password_hash function generates a string that needs to be stored and checked for verification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;check_password_hash&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Import generate_password_hash and check_password_hash
from werkzeug.security import generate_password_hash, check_password_hash

# Plain text password, if using Flask, it can come from any web form
plain_password = "SHH_SECRET"
# Generate a hashed string using default parameters
hashed = generate_password_hash(plain_password)

# Login attempt 1 with wrong password
# If using Flask, it can come from any web form, like a login screen
login_attempt_1 = "SHH_WRONG_SECRET"
is_valid = check_password_hash(hashed, login_attempt_1)
print("Password correct?", is_valid)

# Login attempt 2 with correct password
# If using Flask, it can come from any web form, like a login screen
login_attempt_2 = "SHH_SECRET"
is_valid = check_password_hash(hashed, login_attempt_2)
print("Password correct?", is_valid)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Output
# This is the first attempt in which we used the wrong password, and it concluded that it was incorrect, hence it gave the output as false
Password correct? False
# This is the second attempt in which we used the correct password, and it concluded that it was correct, hence it gave the output as true
Password correct? True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Never store plaintext passwords; store only the hash strings.&lt;/li&gt;
&lt;li&gt;Do not re-invent the wheel; we can easily rely on vetted libraries and generate hash strings.&lt;/li&gt;
&lt;li&gt;Keep your dependencies up-to-date.&lt;/li&gt;
&lt;li&gt;Don’t compare strings manually; we can easily leverage functions like check_password_hash, which handle secure comparison.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Soon, I will be adding details about other libraries and functions as well. I hope this will be helpful.&lt;/p&gt;

&lt;p&gt;Feel free to add your thoughts and experiences. Also, since I am still learning, correct me if I am wrong or have misinterpreted anything. Happy Learning! 😄&lt;/p&gt;

</description>
      <category>python</category>
      <category>devops</category>
      <category>beginners</category>
      <category>linux</category>
    </item>
    <item>
      <title>A smarter way to use imagePullSecrets in Kubernetes Cluster using ServiceAccounts</title>
      <dc:creator>Sunny Bhambhani</dc:creator>
      <pubDate>Mon, 12 May 2025 12:16:05 +0000</pubDate>
      <link>https://dev.to/aws-builders/simplify-imagepullsecrets-with-serviceaccounts-in-kubernetes-2oc8</link>
      <guid>https://dev.to/aws-builders/simplify-imagepullsecrets-with-serviceaccounts-in-kubernetes-2oc8</guid>
      <description>&lt;p&gt;Kubernetes is everywhere now a days, so does the container images and fetching the images from a private registry is a norm because of N number of reasons including security, that being the topmost.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpnxr04e9itg09k18evir.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpnxr04e9itg09k18evir.webp" alt=" " width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;Just to give you a heads up before we dive further, let's assume I fire &lt;code&gt;kubectl create deployment nginx --image nginx&lt;/code&gt; what do you think happens?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using &lt;code&gt;kubeconfig&lt;/code&gt;, &lt;code&gt;kubectl&lt;/code&gt; first authenticates with the API server. &lt;/li&gt;
&lt;li&gt;It then constructs a &lt;code&gt;deployment object&lt;/code&gt; using the values which we provided like deployment name as &lt;code&gt;nginx&lt;/code&gt;, image to be used as &lt;code&gt;nginx&lt;/code&gt; and some default values and then sends a request to the API server.&lt;/li&gt;
&lt;li&gt;API server then validates the request and the object definition.&lt;/li&gt;
&lt;li&gt;This is further stored in &lt;code&gt;etcd&lt;/code&gt; datastore.&lt;/li&gt;
&lt;li&gt;Then the &lt;code&gt;controller manager&lt;/code&gt; specifically &lt;code&gt;deployment controller&lt;/code&gt; comes into the picture which creates a &lt;code&gt;replica set&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Then the &lt;code&gt;replica set&lt;/code&gt; creates a pod (this is where our nginx image will be used).&lt;/li&gt;
&lt;li&gt;Then the &lt;code&gt;schedular&lt;/code&gt; assigns the pod to a node, where it will run based on multiple conditions. If interested please check out my previous article on what all things happens in the background: &lt;a href="https://kubernetes.io/blog/2023/01/12/protect-mission-critical-pods-priorityclass/#resource-management-in-kubernetes" rel="noopener noreferrer"&gt;Resource management in Kubernetes&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Once the node is identified, the &lt;code&gt;kubelet&lt;/code&gt; running on the node is responsible for the management of the pod.&lt;/li&gt;
&lt;li&gt;Once the pod is scheduled on a specific node, the &lt;code&gt;kubelet&lt;/code&gt; looks for the image to be used and if it is already present.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;if that is present locally, it will use it.&lt;/p&gt;

&lt;p&gt;If not, it pulls the image from the registry.&lt;/p&gt;

&lt;p&gt;If the registry is public, there are no issues, it just pulls the image, runs the pods, and we are done.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  When imagePullSecrets are used?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Assume the registry is private, this is where &lt;code&gt;imagePullSecrets&lt;/code&gt; come into play. &lt;/li&gt;
&lt;li&gt;Kubernetes will need the secrets to authenticate the registry, so that it can pull the image.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How it works?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Firstly, we need to create a &lt;code&gt;secret&lt;/code&gt; which contains the credentials and some details of our docker registry like server-name, username, password, email, etc.&lt;/li&gt;
&lt;li&gt;It can be &lt;em&gt;created both imperative as well as declarative way&lt;/em&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ k get secrets  -o yaml dockersec
apiVersion: v1
data:
  .dockerconfigjson: ENCODED JSON OBJECT
kind: Secret
metadata:
  name: dockersec
  namespace: default
type: kubernetes.io/dockerconfigjson 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ k create secret docker-registry dockersec --docker-server=DOCKER_REGISTRY --docker-username=USERNAME --docker-password=PASSWORD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quick note:&lt;/strong&gt; The secret must be of a type &lt;strong&gt;kubernetes.io/dockerconfigjson&lt;/strong&gt; or &lt;strong&gt;docker-registry&lt;/strong&gt; based on the way you choose to create the secret.&lt;/li&gt;
&lt;li&gt;Once the &lt;code&gt;secret&lt;/code&gt; is created, it must be &lt;code&gt;attached to a pod&lt;/code&gt; so that it can use it.&lt;/li&gt;
&lt;li&gt;Just add below content in your pod/deployment/statefulset yaml files, the name of the secret for me is dockersec but you can change based on your requirements.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spec:
  imagePullSecrets:
    - name: dockersec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Before pulling the image, the &lt;code&gt;kubelet&lt;/code&gt; checks if the image is from a private registry. If so, it looks for &lt;code&gt;imagePullSecrets&lt;/code&gt; in the spec.&lt;/li&gt;
&lt;li&gt;Without proper &lt;code&gt;imagePullSecrets&lt;/code&gt;, the image pull will fail with &lt;code&gt;ImagePullBackOff&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Now assume you have hundreds of &lt;code&gt;YAML&lt;/code&gt; files and hundreds of Kubernetes Object where we have to use this &lt;code&gt;imagePullSecrets&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Just for the sake of doing once, you thought to do it manually but just imagine there was a change in the name of the Kubernetes secret.&lt;/li&gt;
&lt;li&gt;Maybe because the organization now decides to streamline the naming convention of all the Kubernetes objects based on environments like prod/preprod/staging/etc.

&lt;ul&gt;
&lt;li&gt;Or your org is now moving to a different registry or a different provider.&lt;/li&gt;
&lt;li&gt;Or the application is getting re-factored based on different namespaces or functions.&lt;/li&gt;
&lt;li&gt;There can be N number of reasons and doing all these changes again is a tricky and tiresome task.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;One way to look at it is, use of &lt;code&gt;helm&lt;/code&gt; charts which can help us to manage all the Kubernetes objects and this kind of a change can be pretty straight forward provided the helm charts are structured correctly and using values file we can just update the name of the secret and then can upgrade the chart, and we are done.&lt;/p&gt;

&lt;p&gt;But if in case we are not using and package manager like &lt;code&gt;helm&lt;/code&gt; and we are just working with vanilla &lt;code&gt;YAML&lt;/code&gt; files then for that as well there is a neat way to do it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The NEAT way!
&lt;/h2&gt;

&lt;p&gt;We can attach the &lt;code&gt;imagePullSecrets&lt;/code&gt; with the &lt;code&gt;serviceaccounts&lt;/code&gt; and where-ever the &lt;code&gt;serviceaccount&lt;/code&gt; is used, it will automatically populate the &lt;code&gt;imagePullSecrets&lt;/code&gt; in the respective object like Pods.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Below is the current status of my Kubernetes objects, no secrets, a default serviceaccount and no imagePullSecrets updated in the pod.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ k get secrets
No resources found in default namespace.
$ k get sa
NAME      SECRETS   AGE
default   0         33m
$ k get pods
NAME                     READY   STATUS             RESTARTS   AGE
nginx-65fd88fc88-8xjc9   0/1     ImagePullBackOff   0          32m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create the &lt;code&gt;docker-registry&lt;/code&gt; secret
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ k create secret docker-registry dockersec --docker-server=DOCKER_REGISTRY --docker-username=USERNAME --docker-password=PASSWORD
secret/dockersec created
$ k get secret
NAME        TYPE                             DATA   AGE
dockersec   kubernetes.io/dockerconfigjson   1      3s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Patch the default &lt;code&gt;serviceaccount&lt;/code&gt; to have the &lt;code&gt;imagePullSecrets&lt;/code&gt;. It can be any serviceaccount based on your requirements.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "dockersec"}]}'
serviceaccount/default patched
$ k get sa
NAME      SECRETS   AGE
default   0         35m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Or you can manually edit the &lt;code&gt;serviceaccount&lt;/code&gt; as well and add below content.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ k get sa default -o yaml
apiVersion: v1
imagePullSecrets:   # ADD
- name: dockersec   # ADD
kind: ServiceAccount
metadata:
  name: default
  namespace: default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;To see this in action now, delete the pod which is in failed state.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ k delete pod nginx-65fd88fc88-8xjc9 --force
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Check the events of the pod, now it was successfully able to pull the image from the private registry.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Events:
  Type     Reason     Age                From               Message
  ----     ------     ----               ----               -------
  Normal   Scheduled  65s                default-scheduler  Successfully assigned default/nginx-65fd88fc88-w8mph to minikube
  Normal   Pulling    64s                kubelet            Pulling image "sunnybhambhani/test:v1"
  Normal   Pulled     37s                kubelet            Successfully pulled image "sunnybhambhani/test:v1" in 30.288s (30.288s including waiting). Image size: 567185619 bytes.
  Normal   Created    21s (x3 over 36s)  kubelet            Created container: test
  Normal   Started    21s (x3 over 36s)  kubelet            Started container test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Interesting bit is &lt;code&gt;imagePullSecrets&lt;/code&gt; are automatically added to the object.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ k get pods nginx-65fd88fc88-w8mph -o yaml | grep -i serviceaccountname
serviceAccountName: default
$ k get pods nginx-65fd88fc88-w8mph -o yaml | grep -i imagepullse -A 1
  imagePullSecrets:
  - name: dockersec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bonus Tip
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;In case the pod is not in running status, it can be due to multiple reasons.&lt;/li&gt;
&lt;li&gt;Just describe the pod to see what is happening in the background.&lt;/li&gt;
&lt;li&gt; &lt;code&gt;kubectl describe pod POD_NAME | awk '/^Events:/ {found=1; next} found'&lt;/code&gt;, it looks for the line starting with Events, once found prints the remaining lines.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl describe pod nginx-65fd88fc88-8xjc9 | awk '/^Events:/ {found=1; next} found'
  Type     Reason     Age                     From               Message
  ----     ------     ----                    ----               -------
  Normal   Scheduled  7m21s                   default-scheduler  Successfully assigned default/nginx-65fd88fc88-8xjc9 to minikube
  Normal   Pulling    4m17s (x5 over 7m20s)   kubelet            Pulling image "REGISTRY/test:v1"
  Warning  Failed     4m14s (x5 over 7m17s)   kubelet            Failed to pull image "REGISTRY/test:v1": Error response from daemon: pull access denied for REGISTRY/test, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
  Warning  Failed     4m14s (x5 over 7m17s)   kubelet            Error: ErrImagePull
  Warning  Failed     2m41s (x19 over 7m16s)  kubelet            Error: ImagePullBackOff
  Normal   BackOff    2m20s (x21 over 7m16s)  kubelet            Back-off pulling image "REGISTRY/test:v1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Here the logs clearly state, &lt;strong&gt;requested access to the resource is denied&lt;/strong&gt; and in-turn the status of the pod is &lt;code&gt;ImagePullBackOff&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ k get pods
NAME                     READY   STATUS             RESTARTS   AGE
nginx-65fd88fc88-8xjc9   0/1     ImagePullBackOff   0          76s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;References:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Google.&lt;/li&gt;
&lt;li&gt;Kubernetes docs (&lt;a href="https://kubernetes.io/docs/home/" rel="noopener noreferrer"&gt;https://kubernetes.io/docs/home/&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;kubectl explain.&lt;/li&gt;
&lt;li&gt;Linux man pages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PS: This works with any flavor of Kubernetes: minikube, Elastic Kubernetes Service(EKS), Azure Kubernetes Service(AKS), Google Kubernetes Engine(GKE), etc.&lt;/p&gt;

&lt;p&gt;I hope this will be helpful, feel free to add your thoughts and experiences, Happy Learning! 😄&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>linux</category>
      <category>security</category>
    </item>
    <item>
      <title>Kubernetes hardening made easy: Running CIS Benchmarks with kube-bench</title>
      <dc:creator>Sunny Bhambhani</dc:creator>
      <pubDate>Mon, 03 Mar 2025 04:41:17 +0000</pubDate>
      <link>https://dev.to/aws-builders/kubernetes-hardening-made-easy-running-cis-benchmarks-with-kube-bench-38ne</link>
      <guid>https://dev.to/aws-builders/kubernetes-hardening-made-easy-running-cis-benchmarks-with-kube-bench-38ne</guid>
      <description>&lt;p&gt;In today's world, where security risks and breaches are growing daily, it is crucial to maintain our applications and infrastructure's compliance with security standards and that is where CIS benchmarks from CIS (Center for Internet Security) comes in. And with kube-bench, running these checks becomes straightforward, helping you strengthen your Kubernetes clusters with confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  CIS Benchmarks
&lt;/h2&gt;

&lt;p&gt;Here is the mission statement from CIS's website.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Our mission is to make the connected world a safer place by developing, validating, and promoting timely best practice solutions that help people, businesses, and governments protect themselves against pervasive cyber threats.&lt;/p&gt;

&lt;p&gt;Ref. &lt;a href="https://www.cisecurity.org/" rel="noopener noreferrer"&gt;https://www.cisecurity.org/&lt;/a&gt; for more details.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It basically helps us to jot down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What all best practices/guidelines to use?&lt;/li&gt;
&lt;li&gt;Which tools are available to assist us in scanning our application or infrastructure?&lt;/li&gt;
&lt;li&gt;Making sure the best practices are updated on timely manner.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The benchmarks are basically available for multiple platforms including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All the public cloud providers.&lt;/li&gt;
&lt;li&gt;Softwares&lt;/li&gt;
&lt;li&gt;DevSecOps tools&lt;/li&gt;
&lt;li&gt;Mobile devices&lt;/li&gt;
&lt;li&gt;Operating Systems&lt;/li&gt;
&lt;li&gt;and much more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find their extensive list here: &lt;a href="https://learn.cisecurity.org/benchmarks" rel="noopener noreferrer"&gt;https://learn.cisecurity.org/benchmarks&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  CIS Benchmarks: Download PDF for your platform
&lt;/h2&gt;

&lt;p&gt;For downloading the PDF files you just need to provide some general details about yourself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmskcp6rf6ry4s7dj71da.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmskcp6rf6ry4s7dj71da.png" alt="https://learn.cisecurity.org/benchmarks" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once done, press "Submit" and you will receive an email with the link from where you can download all kinds of benchmarks.&lt;/p&gt;

&lt;p&gt;It looks something like this: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8enfz0nfm3kpua3hbtq2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8enfz0nfm3kpua3hbtq2.png" alt="Download Benchmarks" width="465" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upon pressing "Access PDFs" you will be routed to their extensive list of benchmarks which looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxx4s2921wpx53972rv9p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxx4s2921wpx53972rv9p.png" alt="Access PDFs" width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can choose whatever you want to, but since we are interested in Kubernetes as of now, we will scroll down to the Kubernetes section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feo255650byorkhxfkx3r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feo255650byorkhxfkx3r.png" alt="Kubernetes Benchmarks" width="571" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the good part here is, this is not limited to vanilla Kubernetes, we can even download benchmarks for all the Kubernetes flavours like EKS from AWS, AKS from Azure, GKE from Google, etc.&lt;/p&gt;

&lt;p&gt;Once you download a specific PDF, you will see it contains a great amount of details including recommendations, problem statement, impact, remediation, etc.&lt;/p&gt;

&lt;p&gt;Now, if you have observed the PDF contains thousands of recommendations and going thru them and applying them one by one is a time-consuming task and just imagine you have 100s of clusters. Though I would recommend you to at-least go thru it once and get an idea of what all details it contains and how we can make use of it.&lt;/p&gt;

&lt;p&gt;To make our lives easier there are couple of tools which can help us to automate this process and help us to identify where we are lacking. So that we can fix them quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  CIS Benchmarks: Tools
&lt;/h2&gt;

&lt;p&gt;There are couple of tools which are managed by CIS itself like CIS-CAT Lite/CIS-CAT Pro/etc. CIS-CAT Lite is a free version and it supports a limited options excluding Kubernetes. CIS-CAT Pro is the one which supports Kubernetes but it is just available for CIS SecureSuite Members.&lt;/p&gt;

&lt;p&gt;Ref. &lt;a href="https://www.cisecurity.org/cybersecurity-tools" rel="noopener noreferrer"&gt;https://www.cisecurity.org/cybersecurity-tools&lt;/a&gt; for more details about the tools.&lt;/p&gt;

&lt;p&gt;Now, let's talk about the good part, the community has given us couple of opensource tools which does the same 😉 the most used one is kube-bench (from Aqua Security).&lt;/p&gt;

&lt;h2&gt;
  
  
  HOWTO: kube-bench
&lt;/h2&gt;

&lt;p&gt;kube-bench is a tool that checks whether Kubernetes is deployed securely by running the checks documented in the CIS Kubernetes Benchmark.&lt;/p&gt;

&lt;h2&gt;
  
  
  There are multiple ways to run kube-bench
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Install it via a package manager&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download the latest package based on your OS from github releases page and install it.&lt;/li&gt;
&lt;li&gt;Ref: &lt;a href="https://github.com/aquasecurity/kube-bench/releases" rel="noopener noreferrer"&gt;https://github.com/aquasecurity/kube-bench/releases&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Since, I am using Ubuntu, I will use dpkg to get this package installed.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ wget https://github.com/aquasecurity/kube-bench/releases/download/v0.10.2/kube-bench_0.10.2_linux_amd64.deb
$ sudo dpkg -i kube-bench_0.10.2_linux_amd64.deb
Selecting previously unselected package kube-bench.
(Reading database ... 41333 files and directories currently installed.)
Preparing to unpack kube-bench_0.10.2_linux_amd64.deb ...
Unpacking kube-bench (0.10.2) ...
Setting up kube-bench (0.10.2) ...
$ kube-bench version
0.10.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Run as a job in the Kubernetes Cluster&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get the job.yaml from the same github link and deploy it on your cluster.&lt;/li&gt;
&lt;li&gt;Ref: &lt;a href="https://github.com/aquasecurity/kube-bench/blob/main/job.yaml" rel="noopener noreferrer"&gt;https://github.com/aquasecurity/kube-bench/blob/main/job.yaml&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Based on your platforms there are multiple job*.yaml files available like for EKS, AKS, GKE, etc.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml
job.batch/kube-bench created
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ k get pods
NAME               READY   STATUS      RESTARTS   AGE
kube-bench-n22k9   0/1     Completed   0          96s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ k logs kube-bench-n22k9 | head -n 20
[INFO] 1 Control Plane Security Configuration
[INFO] 1.1 Control Plane Node Configuration Files
[PASS] 1.1.1 Ensure that the API server pod specification file permissions are set to 600 or more restrictive (Automated)
[PASS] 1.1.2 Ensure that the API server pod specification file ownership is set to root:root (Automated)
[PASS] 1.1.3 Ensure that the controller manager pod specification file permissions are set to 600 or more restrictive (Automated)
[PASS] 1.1.4 Ensure that the controller manager pod specification file ownership is set to root:root (Automated)
[PASS] 1.1.5 Ensure that the scheduler pod specification file permissions are set to 600 or more restrictive (Automated)
[PASS] 1.1.6 Ensure that the scheduler pod specification file ownership is set to root:root (Automated)

OUTPUT TRIMMED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ k logs kube-bench-n22k9 | tail -n 20
OUTPUT TRIMMED

5.7.3 Follow the Kubernetes documentation and apply SecurityContexts to your Pods. For a
suggested list of SecurityContexts, you may refer to the CIS Security Benchmark for Docker
Containers.

5.7.4 Ensure that namespaces are created to allow for appropriate segregation of Kubernetes
resources and that all new resources are created in a specific namespace.


== Summary policies ==
0 checks PASS
6 checks FAIL
29 checks WARN
0 checks INFO

== Summary total ==
57 checks PASS
19 checks FAIL
54 checks WARN
0 checks INFO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Just check the logs of the pod for all the recommendations. These logs contain multiple sections for different-different Kubernetes components like Controlplane, ETCD, Worker nodes, etc.&lt;/li&gt;
&lt;li&gt;At the end of each section you can see statistics about the checks and at the end of the logs you will see a quick summary about the total (as mentioned above).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;== Summary node ==
14 checks PASS
2 checks FAIL
8 checks WARN
0 checks INFO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Run as a docker container&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --rm --net host --pid host --user 0 \
  -v /etc:/etc:ro \
  -v /var:/var:ro \
  -v /usr/bin:/usr/bin:ro \
  -v /usr/lib:/usr/lib:ro \
  aquasec/kube-bench:latest --benchmark cis-1.24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;You can change the version based on your requirement, 1.24 is the latest one.&lt;/li&gt;
&lt;li&gt;More details about the versions can be found here: &lt;a href="https://github.com/aquasecurity/kube-bench/tree/main/cfg" rel="noopener noreferrer"&gt;https://github.com/aquasecurity/kube-bench/tree/main/cfg&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;For this as well, just check the logs of the container you will find the same results as we described in earlier section.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is how the remediation steps look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;== Remediations master ==
1.1.9 Run the below command (based on the file location on your system) on the control plane node.
For example, chmod 600 &amp;lt;path/to/cni/files&amp;gt;

1.1.11 On the etcd server node, get the etcd data directory, passed as an argument --data-dir,
from the command 'ps -ef | grep etcd'.
Run the below command (based on the etcd data directory found above). For example,
chmod 700 /var/lib/etcd

1.1.12 On the etcd server node, get the etcd data directory, passed as an argument --data-dir,
from the command 'ps -ef | grep etcd'.
Run the below command (based on the etcd data directory found above).
For example, chown etcd:etcd /var/lib/etcd

1.1.19 Run the below command (based on the file location on your system) on the control plane node.
For example,
chown -R root:root /etc/kubernetes/pki/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;References:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.cisecurity.org/" rel="noopener noreferrer"&gt;https://www.cisecurity.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/aquasecurity/kube-bench" rel="noopener noreferrer"&gt;https://github.com/aquasecurity/kube-bench&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to add your thoughts and experiences, Happy Learning! 😄 &lt;/p&gt;

</description>
      <category>security</category>
      <category>kubernetes</category>
      <category>docker</category>
      <category>devops</category>
    </item>
    <item>
      <title>k9s - manage your Kubernetes cluster and it’s objects like a pro!</title>
      <dc:creator>Sunny Bhambhani</dc:creator>
      <pubDate>Sat, 30 Nov 2024 06:56:46 +0000</pubDate>
      <link>https://dev.to/aws-builders/k9s-manage-your-kubernetes-cluster-like-a-pro-lko</link>
      <guid>https://dev.to/aws-builders/k9s-manage-your-kubernetes-cluster-like-a-pro-lko</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
k9s is a terminal based GUI to manage any Kubernetes(k8s) cluster. Using this single utility, we can manage, traverse, watch all our Kubernetes objects.&lt;/p&gt;

&lt;p&gt;More information around k9s can be found here: &lt;a href="https://k9scli.io/" rel="noopener noreferrer"&gt;https://k9scli.io/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will dive a bit into k9s and see how it can help us in our day-to-day life, how we can get started, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Features&lt;/strong&gt;&lt;br&gt;
Before we go into the example on how it can help, what it can do for us, let's see some of its features, it has a ton of features, but we will focus on the ones which can help us in our day-to-day activities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shows a helicopter view of all the Kubernetes objects.&lt;/li&gt;
&lt;li&gt;Easily we can move from one namespace to another.&lt;/li&gt;
&lt;li&gt;Watch/observe the state of Kubernetes objects using &lt;code&gt;pulses&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Get the &lt;code&gt;tree&lt;/code&gt; kind of structure using &lt;code&gt;xrays&lt;/code&gt; to identify objects co-relation.&lt;/li&gt;
&lt;li&gt;Manage the objects directly from the CLI, operations like deleting, editing, restarting is just one button away.&lt;/li&gt;
&lt;li&gt;Interestingly using a single button, you can get shell access to the pods.&lt;/li&gt;
&lt;li&gt;Check the logs from any of the pod without actually remembering the name of the pod, just select the pod and the logs are just one button away.&lt;/li&gt;
&lt;li&gt;Sanitize/clean up all the pods which are in completed/error state. &lt;/li&gt;
&lt;li&gt;Works with any flavor of Kubernetes &lt;code&gt;minikube&lt;/code&gt;, &lt;code&gt;Elastic Kubernetes Service(EKS)&lt;/code&gt;, &lt;code&gt;Azure Kubernetes Service(AKS)&lt;/code&gt;, &lt;code&gt;Google Kubernetes Engine(GKE)&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;.... and a lot more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Its installation is straight forward and is available for almost all the platforms.&lt;/li&gt;
&lt;li&gt;Refer &lt;a href="https://k9scli.io/topics/install/" rel="noopener noreferrer"&gt;https://k9scli.io/topics/install/&lt;/a&gt; for more details.&lt;/li&gt;
&lt;li&gt;We will be doing this on Ubuntu.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Download the latest version of k9s binary, you can use the same URL/version if required or get the latest version released and update below URL accordingly. &lt;/p&gt;

&lt;p&gt;For latest version, refer: &lt;a href="https://github.com/derailed/k9s/releases" rel="noopener noreferrer"&gt;https://github.com/derailed/k9s/releases&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ wget https://github.com/derailed/k9s/releases/download/v0.32.7/k9s_linux_amd64.deb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install it using apt package manager.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo apt install ./k9s_linux_amd64.deb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once done it will get the k9s binary installed here: &lt;code&gt;/usr/bin/k9s&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HOWTO&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Launch k9s&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ k9s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once k9s is launched you will be presented with the beautiful layout with lots of options.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F87t67zev3sc44poetl0g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F87t67zev3sc44poetl0g.png" alt="k9s dashboard" width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Press 0 to view all the pods from all the namespaces.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Navigate between Kubernetes objects&lt;/strong&gt;&lt;br&gt;
Navigating is pretty easy; it is more or less like &lt;code&gt;vi&lt;/code&gt; or &lt;code&gt;vim&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For example, if you want to view deployments then press &lt;code&gt;:&lt;/code&gt; it will bring the cursor to a text area where you can write the object which you are interested in, for instance in current example deployments.&lt;/li&gt;
&lt;li&gt;The short forms too are accepted i.e. deploy in case of deployment, svc in case of service, etc.&lt;/li&gt;
&lt;li&gt;This also supports crds :)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsbafx2ouy13s02h1a1zk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsbafx2ouy13s02h1a1zk.png" alt="k9s textarea" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pods management&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Press &lt;code&gt;:&lt;/code&gt; and type in pods, it will show you all the pods in selected namespace, if you want to see the &lt;strong&gt;pods from all namespaces press &lt;code&gt;0&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs4qdyvbrg2v0k51jdi4i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs4qdyvbrg2v0k51jdi4i.png" alt="k9s pods management" width="800" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There are times where we have to &lt;strong&gt;delete the pods on the fly&lt;/strong&gt;. Just select the pod and press &lt;code&gt;ctrl+d&lt;/code&gt; and you are done.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgz8qqw4ls8bsslxrcz63.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgz8qqw4ls8bsslxrcz63.png" alt="k9s delete pods" width="800" height="46"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There are times when you have to &lt;strong&gt;login to a pod&lt;/strong&gt;. Just select the pod and press &lt;code&gt;s&lt;/code&gt; and you are done. If you want to exit, press &lt;code&gt;ctrl+d&lt;/code&gt; or type in &lt;code&gt;exit&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjougf9ja81y1tc8s63er.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjougf9ja81y1tc8s63er.png" alt="k9s shell" width="766" height="64"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Want to &lt;strong&gt;describe the pod details&lt;/strong&gt;, press &lt;code&gt;d&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq550ybix1w77jlgfkfdg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq550ybix1w77jlgfkfdg.png" alt="k9s describe pod" width="592" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Want to get the yaml output of the Kubernetes objects, just select the object and press &lt;code&gt;y&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fntqmcug89ovtm58559wi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fntqmcug89ovtm58559wi.png" alt="k9s get yaml manifest" width="534" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Want to see the logs of a specific pod, select the pod and press &lt;code&gt;l&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdlnbgnqx5sb8wr6k4ox.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdlnbgnqx5sb8wr6k4ox.png" alt="k9s logs" width="800" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can even do port-forward from the same UI, isn't it cool :), Just press &lt;code&gt;shift+f&lt;/code&gt; and if you want to see any existing port-forward are present or not, press &lt;code&gt;f&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frvbhsdcrysrq0qizkwqt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frvbhsdcrysrq0qizkwqt.png" alt="k9s portforward1" width="660" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0m6jq8ee7ql4d4l0i61.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0m6jq8ee7ql4d4l0i61.png" alt="k9s portforward2" width="800" height="29"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sanitize/Clean up pods: For instance in below screen dump we can see there are 2 pods which are in &lt;code&gt;Completed&lt;/code&gt; and we want to clean them up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftu6dfjbfo1hcuclqqwrn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftu6dfjbfo1hcuclqqwrn.png" alt="k9s sanitize1" width="800" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just press &lt;code&gt;z&lt;/code&gt;, you will be asked "if you are sure", type in "Yes Please!" and the job is done.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnox4xwih44tw3zq3yxrx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnox4xwih44tw3zq3yxrx.png" alt="k9s sanitize2" width="666" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;XRAY&lt;/strong&gt;&lt;br&gt;
Xray gives you a great detail in terms of co-relation between k8s objects, it basically provides a &lt;code&gt;tree&lt;/code&gt; like structure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl4djaywt649akums1i4z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl4djaywt649akums1i4z.png" alt="k8s xray" width="800" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pulses&lt;/strong&gt;&lt;br&gt;
Pulses give a great dashboard to see what exactly is happening in your cluster, what all objects are there, health of your objects, etc?&lt;/p&gt;

&lt;p&gt;NOTE: Make sure metrics-server is installed and running in the cluster otherwise you won't see proper results. In my case it was not installed, therefore it was just stating blank results.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs8wcch0wl97dbwqa6c91.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs8wcch0wl97dbwqa6c91.png" alt="k9s pulses1" width="800" height="110"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After installing metrics-server and launching &lt;code&gt;pulses&lt;/code&gt; it shows an awesome dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1cx0wkk46i3s38kgs1o8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1cx0wkk46i3s38kgs1o8.png" alt="k9s pulses2" width="800" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The great part about it is, it shows the current status of your cluster.&lt;/li&gt;
&lt;li&gt;It even shows what all objects are healthy and what all objects are unhealthy.&lt;/li&gt;
&lt;li&gt;Legend: GREEN/HEALTHY &amp;amp; YELLOW/UNHEALTHY&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;References: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://k9scli.io/" rel="noopener noreferrer"&gt;https://k9scli.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/derailed/k9s" rel="noopener noreferrer"&gt;https://github.com/derailed/k9s&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free add your thoughts, Happy learning :)&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>linux</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Helmister: Updated the logic to allow custom path</title>
      <dc:creator>Sunny Bhambhani</dc:creator>
      <pubDate>Thu, 28 Nov 2024 07:53:31 +0000</pubDate>
      <link>https://dev.to/aws-builders/helmister-updated-the-logic-to-allow-custom-path-lfn</link>
      <guid>https://dev.to/aws-builders/helmister-updated-the-logic-to-allow-custom-path-lfn</guid>
      <description>&lt;p&gt;Its a follow-up post on &lt;code&gt;helmister&lt;/code&gt;, refer here for more details: &lt;a href="https://dev.to/aws-builders/installing-multiple-helm-charts-in-one-go-approach-3-using-simple-bash-utility-2795"&gt;https://dev.to/aws-builders/installing-multiple-helm-charts-in-one-go-approach-3-using-simple-bash-utility-2795&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Updated the logic allowing users to specify a custom path for config.yaml. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Log entry: [2024-11-27 12:30:06] [INFO] Generic/common values based on /home/sunny/config.yaml file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;-f | --file&lt;br&gt;
Helps you to mention explicit/specific config.yaml. If not provided it will consider the default one which is placed in the base folder.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Example: ./helmister install -f /opt/app/config-dev.yaml&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/aws-builders" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F2794%2F88da75b6-aadd-4ea1-8083-ae2dfca8be94.png" alt="AWS Community Builders " width="350" height="350"&gt;
      &lt;div class="ltag__link__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1005168%2Fe3697725-f1bf-4345-883a-30d23e3446f2.jpeg" alt="" width="468" height="476"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/aws-builders/installing-multiple-helm-charts-in-one-go-approach-3-using-simple-bash-utility-2795" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Installing multiple helm charts in one go [Approach 3 - using simple bash utility]&lt;/h2&gt;
      &lt;h3&gt;Sunny Bhambhani for AWS Community Builders  ・ Jul 23 '24&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#helm&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#kubernetes&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#devops&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#eks&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>helm</category>
      <category>linux</category>
      <category>devops</category>
      <category>automation</category>
    </item>
    <item>
      <title>sftp refresher - 101</title>
      <dc:creator>Sunny Bhambhani</dc:creator>
      <pubDate>Tue, 29 Oct 2024 11:34:22 +0000</pubDate>
      <link>https://dev.to/aws-builders/sftp-refresher-101-4ni9</link>
      <guid>https://dev.to/aws-builders/sftp-refresher-101-4ni9</guid>
      <description>&lt;p&gt;This is just a very basic refresher around sftp server, I know there are lots of other and on-cloud solutions available for file transfer and sftp server is &lt;strong&gt;&lt;em&gt;rarely&lt;/em&gt;&lt;/strong&gt; used.&lt;/p&gt;

&lt;p&gt;But since I got a query yesterday about it, I thought to create a small write-up :)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;sftp server&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There was a time when sftp was widely used for secure file transfers, though now there are many options available, but this used to be a hero service then and was commonly asked during interviews.&lt;/li&gt;
&lt;li&gt;The name itself expands to 'Secure File Transfer Protocol'.&lt;/li&gt;
&lt;li&gt;This allows for a secure file transfer over SSH (On port 22).&lt;/li&gt;
&lt;li&gt;It is quite fast and efficient.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pre-requisites&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Any linux machine with internet access (here I am using Ubuntu).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;HOWTO&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update the package lists on your Ubuntu(debian based) machine.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ apt update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install ssh/openssh-sftp-server/vim(if not present).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ apt install ssh openssh-sftp-server vim -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Edit the sshd config file and append below details
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ vim /etc/ssh/sshd_config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Match group sftp
ChrootDirectory /home
X11Forwarding no
AllowTcpForwarding no
ForceCommand internal-sftp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Match group sftp&lt;/strong&gt;&lt;/em&gt;: This statement states below settings will be applicable to all the users who belong to sftp group.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;ChrootDirectory&lt;/em&gt;&lt;/strong&gt;: This basically changes the root directory to mentioned path.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;X11Forwarding&lt;/em&gt;&lt;/strong&gt;: This disables X11 forwarding (this is enabled in some GUI use-cases) and for sftp this is not required. &lt;br&gt;
&lt;strong&gt;&lt;em&gt;AllowTcpForwarding&lt;/em&gt;&lt;/strong&gt;: Disables TCP forwarding.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;ForceCommand&lt;/em&gt;&lt;/strong&gt;: This forcefully mandates that the used of this group should be only allowed to use sftp and nothing else.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Restart the service, you can use this way or use systemctl based on your distribution.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ /etc/init.d/ssh restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add a new group called sftp to the system.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ addgroup sftp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create a new user with sftp group attached to it.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ useradd -m sunny -g sftp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Change the password of the newly created user.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ passwd sunny
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Change the permission of the directory to USER/OWNER only.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ chmod 700 /home/sunny/ -R
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Try connecting to sftp server
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sftp sunny@HOST_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Enter the password and try using get and put commands.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;*&lt;em&gt;Feel free to add any details which I might have missed, happy learning :) *&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>beginners</category>
      <category>bash</category>
    </item>
    <item>
      <title>Quick guide to install minikube, kubectl, helm and enable ingress controller on Ubuntu</title>
      <dc:creator>Sunny Bhambhani</dc:creator>
      <pubDate>Mon, 21 Oct 2024 12:39:29 +0000</pubDate>
      <link>https://dev.to/aws-builders/quick-guide-to-install-minikube-and-enable-ingress-controller-on-ubuntu-3g1p</link>
      <guid>https://dev.to/aws-builders/quick-guide-to-install-minikube-and-enable-ingress-controller-on-ubuntu-3g1p</guid>
      <description>&lt;p&gt;This is just a quick guide to install minikube and enable ingress controller on Ubuntu.&lt;/p&gt;

&lt;p&gt;The purpose of this post is to consolidate all the commands in one place for quick reference.&lt;/p&gt;

&lt;p&gt;Minikube is a lightweight Kubernetes cluster that enables you to run Kubernetes clusters locally. It's ideal for learning Kubernetes while developing and testing on a single machine.&lt;/p&gt;

&lt;p&gt;More information about minikube can be found here: &lt;a href="https://minikube.sigs.k8s.io/docs/" rel="noopener noreferrer"&gt;https://minikube.sigs.k8s.io/docs/&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install minikube (Ref: &lt;a href="https://minikube.sigs.k8s.io/docs/start" rel="noopener noreferrer"&gt;https://minikube.sigs.k8s.io/docs/start&lt;/a&gt;)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube &amp;amp;&amp;amp; rm minikube-linux-amd64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install docker (Ref: &lt;a href="https://docs.docker.com/engine/install/ubuntu/" rel="noopener noreferrer"&gt;https://docs.docker.com/engine/install/ubuntu/&lt;/a&gt;)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release &amp;amp;&amp;amp; echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null
sudo apt-get update

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add current user to docker group
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo usermod -aG docker $USER &amp;amp;&amp;amp; newgrp docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install kubectl (Ref: &lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/" rel="noopener noreferrer"&gt;https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/&lt;/a&gt;)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
sudo chmod +x kubectl
sudo mv kubectl /usr/local/bin
alias k=kubectl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install helm (Ref: &lt;a href="https://helm.sh/docs/intro/install/" rel="noopener noreferrer"&gt;https://helm.sh/docs/intro/install/&lt;/a&gt;)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Start minikube
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube start
# Once started
k get nodes
# To get a list of underlying nodes
k get pods -A
# To get a list of all the pods from all namespaces
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Get minikube's IP and enable ingress controller
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube ip
minikube addons enable ingress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>kubernetes</category>
      <category>linux</category>
      <category>beginners</category>
      <category>bash</category>
    </item>
    <item>
      <title>Installing multiple helm charts in one go [Approach 3 - using simple bash utility]</title>
      <dc:creator>Sunny Bhambhani</dc:creator>
      <pubDate>Tue, 23 Jul 2024 10:34:55 +0000</pubDate>
      <link>https://dev.to/aws-builders/installing-multiple-helm-charts-in-one-go-approach-3-using-simple-bash-utility-2795</link>
      <guid>https://dev.to/aws-builders/installing-multiple-helm-charts-in-one-go-approach-3-using-simple-bash-utility-2795</guid>
      <description>&lt;p&gt;In this article, we will be talking about Approach 3 i.e. how to get multiple helm charts installed using a simple bash utility.&lt;/p&gt;

&lt;p&gt;If you haven't read the previous article where I discussed other approaches, feel free to read it over.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ref: &lt;a href="https://dev.to/aws-builders/installing-multiple-helm-charts-in-one-go-approach-1-5d1p"&gt;Installing multiple helm charts in one go [Approach 1 - using parent/child charts]&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Ref: &lt;a href="https://dev.to/aws-builders/installing-multiple-helm-charts-in-one-go-approach-2-using-helmfile-4e4h"&gt;Installing multiple helm charts in one go [Approach 2 - using helmfile]&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Motive&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Why I thought of a simple bash utility?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In some of the air-gapped environments it is sometimes a bit difficult to use the tools/utilities available because moving things inside an air-gapped environment is a challenge.&lt;/li&gt;
&lt;li&gt;Some of the environments are so secure that one may need to follow a whole process of getting all the security clearances and approval before using a tool/utility, which altogether is a nightmare.&lt;/li&gt;
&lt;li&gt;I chose bash, the reason being it is pretty common among engineers and it is easily understandable.&lt;/li&gt;
&lt;li&gt;The source code can be found here: &lt;a href="https://github.com/sunnybhambhani/helmister" rel="noopener noreferrer"&gt;https://github.com/sunnybhambhani/helmister&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;You can copy it, and tweak it based on your requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PS: I chose a name for this utility as well &lt;code&gt;helmister&lt;/code&gt; or &lt;code&gt;helm-minister&lt;/code&gt;  but you can call it whatever you want 🙂&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A running Kubernetes cluster with proper permissions, it can be any  flavor of Kubernetes &lt;code&gt;minikube&lt;/code&gt;, &lt;code&gt;Elastic Kubernetes Service(EKS)&lt;/code&gt;, &lt;code&gt;Azure Kubernetes Service(AKS)&lt;/code&gt;, &lt;code&gt;Google Kubernetes Engine(GKE)&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl&lt;/code&gt; and &lt;code&gt;helm&lt;/code&gt; installed on your machine to interact with the Kubernetes cluster.

&lt;ul&gt;
&lt;li&gt;Ref: &lt;a href="https://kubernetes.io/docs/tasks/tools/" rel="noopener noreferrer"&gt;https://kubernetes.io/docs/tasks/tools/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Ref: &lt;a href="https://helm.sh/docs/intro/install/" rel="noopener noreferrer"&gt;https://helm.sh/docs/intro/install/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;A clone of helmister repository.&lt;/li&gt;

&lt;li&gt;yq(required) and cowsay(optional) packages installed on your machine.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Helmister&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is a small bash utility that can help to install and uninstall multiple helm charts in one go. The idea is inspired by &lt;code&gt;helmfile&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Its usage is quite simple, just run the utility followed by the option like install or uninstall i.e. &lt;code&gt;./helmister [install/uninstall]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Under the hood, it calls &lt;code&gt;helm&lt;/code&gt; binary. Therefore it is kind of a wrapper around &lt;code&gt;helm&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It consumes a &lt;code&gt;config.yaml&lt;/code&gt; file which contains all the necessary details about the releases, and common parameters.&lt;/li&gt;
&lt;li&gt;This supports both &lt;code&gt;oci://&lt;/code&gt; and &lt;code&gt;https://&lt;/code&gt; helm registries.&lt;/li&gt;
&lt;li&gt;PS: In the future, I am planning to add some more options/functionalities to this.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Directory structure&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── config.yaml
├── helmister
├── logs
│   ├── archive
│   │   └── helmister_20240227_170201.tar.gz
│   └── helmister.log
├── README.md
└── values
    ├── argo-cd.yaml
    └── nginx-values.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;helmister&lt;/em&gt;, this is the script written in bash you can just cat and see what all things it contains.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;config.yaml&lt;/em&gt;, this is the main configuration file or you can call the state file which contains the list of all releases you want to install in a cluster, plus it also contains some additional key:value pairs that are generic and common across all the releases. I first kept this configuration file in csv format, but later decided to convert it to yaml because it is more readable.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;logs&lt;/em&gt;, this is a directory that holds the logs of this utility, it contains the information about the execution of the last iteration, plus any archived/past logs (if required for reference).&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;README.md&lt;/em&gt;, contains bit of a documentation about this utility, and what options are present.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;values&lt;/em&gt;, this is the directory where all the values files are placed (it can be anywhere in your system but for simplicity, I have placed them in the same directory).&lt;/li&gt;
&lt;li&gt;Now let's talk about &lt;code&gt;config.yaml&lt;/code&gt; which is the main ingredient.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;config.yaml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dry_run: false
create_namespace: true
wait: false
timeout: false # If true, defaults to 20 mins
charts:
  - release_name: nginx
    chart_name: nginx
    chart_repo: oci://registry-1.docker.io/bitnamicharts
    values_file: values/nginx-values.yaml
  - release_name: argocd
    chart_name: argo-cd
    chart_repo: https://argoproj.github.io/argo-helm
    values_file: values/argo-cd.yaml
    version: 6.4.0
    namespace: argo-cd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The initial key:value pairs are common across all the releases.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;charts&lt;/em&gt;, is an array that contains a list of what all releases need to be installed in a Kubernetes cluster.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;dry_run&lt;/em&gt;, it is a boolean [true or false], and if true, none of the Kubernetes resources will be created it will just do a dry_run.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;create_namespace&lt;/em&gt;, it is a boolean [true or false], and if true it will automatically create a namespace for the release specified in the charts array.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;wait&lt;/em&gt;, it is a boolean [true or false], and if true it acts similar to &lt;code&gt;helm --wait&lt;/code&gt; wherein the shell will be kept occupied until all the Kubernetes resources are created.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;timeout&lt;/em&gt;, it is a boolean [true or false], and if true it acts similar to &lt;code&gt;helm --timeout=20m&lt;/code&gt; i.e. if all the resources are not created within 20 mins the execution will fail. By default, I have kept the timeout as 20 minutes which is more than enough.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;charts&lt;/em&gt;, it is an array that contains details around individual releases. Except for version and namespace all the key:value pairs are mandatory.

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;release_name&lt;/em&gt;, this is the name of the release.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;chart_name&lt;/em&gt;, this is the name of the chart that needs to be installed.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;chart_repo&lt;/em&gt;, this is the helm registry where the chart is located. It can be any &lt;code&gt;oci://&lt;/code&gt; or &lt;code&gt;https://&lt;/code&gt; registry.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;values_file&lt;/em&gt;, which contains the path of the values file for individual releases.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;version&lt;/em&gt;, this is the version of the chart that needs to be installed. This is optional and if not provided, It will consider the &lt;code&gt;latest&lt;/code&gt; chart version.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;namespace&lt;/em&gt;, this is where the chart will be installed. This is optional as well and if not provided it will be installed in the &lt;code&gt;default&lt;/code&gt; namespace.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Let's see this in action&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I will use the same &lt;code&gt;config.yaml&lt;/code&gt; which will install one helm release from an &lt;code&gt;oci://&lt;/code&gt; registry in &lt;code&gt;default&lt;/code&gt; namespace (since I haven't specified any namespace for that release) and another one from &lt;code&gt;https://&lt;/code&gt; registry in &lt;code&gt;argo-cd&lt;/code&gt; namespace. Note the version as well for nginx, there as well I haven't specified any version, it will pick the latest available one automatically.&lt;/li&gt;
&lt;li&gt;This is my cluster's current status.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ k get ns
NAME              STATUS   AGE
default           Active   28s
kube-node-lease   Active   28s
kube-public       Active   29s
kube-system       Active   29s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ helm list -A
NAME    NAMESPACE       REVISION        UPDATED STATUS  CHART   APP VERSION
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./helmister install
[2024-07-23 15:02:47] [INFO] Using file: config.yaml
 ____________________________
&amp;lt; Helmister, Install charts! &amp;gt;
 ----------------------------
   \
    \
        .--.
       |o_o |
       |:_/ |
      //   \ \
     (|     | )
    /'\_   _/`\
    \___)=(___/

[2024-07-23 15:02:47] [INFO] Generic/common values based on config.yaml file
[2024-07-23 15:02:48] [INFO] Dry Run: false
[2024-07-23 15:02:48] [INFO] Create Namespace: true
[2024-07-23 15:02:48] [INFO] Wait: false
[2024-07-23 15:02:48] [INFO] Timeout: false
[2024-07-23 15:02:48] [INFO] ****************************
[2024-07-23 15:02:48] [INFO] Chart specific values based on config.yaml file
[2024-07-23 15:02:48] [INFO] Release Name: nginx
[2024-07-23 15:02:48] [INFO] Chart Name: nginx
[2024-07-23 15:02:48] [INFO] Chart Repo: oci://registry-1.docker.io/bitnamicharts
[2024-07-23 15:02:48] [INFO] Values File: values/nginx-values.yaml
[2024-07-23 15:02:48] [INFO] Version: null
[2024-07-23 15:02:48] [INFO] Namespace: null
[2024-07-23 15:02:48] [INFO] ****************************
[2024-07-23 15:02:48] [INFO] Installing nginx with release name nginx from oci://registry-1.docker.io/bitnamicharts with version null using values file: values/nginx-values.yaml in default namespace
...
...
OUTPUT TRIMMED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Actual stdout output can be &lt;a href="https://github.com/sunnybhambhani/helmister/blob/main/artifacts/sample_logs/during_installation_on_stdout.log" rel="noopener noreferrer"&gt;found here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Here you will see that it provides all the minute details of what exactly it is doing.&lt;/li&gt;
&lt;li&gt;For example: Generic values

&lt;ul&gt;
&lt;li&gt;Here I have marked create_namespace as true because I don't already have argo-cd namespace wherein I want to install argocd release.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[2024-07-23 15:02:47] [INFO] Generic/common values based on config.yaml file
[2024-07-23 15:02:48] [INFO] Dry Run: false
[2024-07-23 15:02:48] [INFO] Create Namespace: true
[2024-07-23 15:02:48] [INFO] Wait: false
[2024-07-23 15:02:48] [INFO] Timeout: false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Next, you will see, chart/release specific values of all the items in charts array one by one:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[2024-07-23 15:03:31] [INFO] Chart specific values based on config.yaml file
[2024-07-23 15:03:31] [INFO] Release Name: argocd
[2024-07-23 15:03:31] [INFO] Chart Name: argo-cd
[2024-07-23 15:03:31] [INFO] Chart Repo: https://argoproj.github.io/argo-helm
[2024-07-23 15:03:31] [INFO] Values File: values/argo-cd.yaml
[2024-07-23 15:03:31] [INFO] Version: 6.4.0
[2024-07-23 15:03:31] [INFO] Namespace: argo-cd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Here I have explicitly added an additional check that will check if the pods are up and healthy (this is just specific to pods it won't consider any other k8s objects).&lt;/li&gt;
&lt;li&gt;It will continuously check for next 20mins and will check every 5 secs. If the pods are still in non-running state it will terminate the process.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[2024-07-23 15:03:47] [WARN] Pods for release argocd are not yet in Running state, checking again in 5 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Once all the pods are in running state and it has deployed all the releases it will show a successful message.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[2024-07-23 15:05:20] [INFO] All actions completed successfully
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Once this is done, if required you can see the logs as well from the logs directory. A sample can be &lt;a href="https://github.com/sunnybhambhani/helmister/blob/main/artifacts/sample_logs/actual_log_file.log" rel="noopener noreferrer"&gt;found here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;And here is my cluster's current status now:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ helm list -A
NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
argocd  argo-cd         1               2024-07-23 15:03:34.46715742 +0530 IST  deployed        argo-cd-6.4.0   v2.10.1
nginx   default         1               2024-07-23 15:02:53.590367521 +0530 IST deployed        nginx-18.1.5    1.27.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ k get ns
NAME              STATUS   AGE
argo-cd           Active   58m
default           Active   62m
kube-node-lease   Active   62m
kube-public       Active   62m
kube-system       Active   62m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ k get pods -n argo-cd
NAME                                                READY   STATUS    RESTARTS   AGE
argocd-application-controller-0                     1/1     Running   0          58m
argocd-applicationset-controller-68cd75bc89-d4q8x   1/1     Running   0          58m
argocd-dex-server-84b5bbdcbf-c4qv2                  1/1     Running   0          58m
argocd-notifications-controller-7bc55c495d-xz6gt    1/1     Running   0          58m
argocd-redis-5d5cdcfd54-2rx26                       1/1     Running   0          58m
argocd-repo-server-756ff4cd7d-rpvh7                 1/1     Running   0          58m
argocd-server-7587d49b7b-9h47l                      1/1     Running   0          58m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ k get pods -n default
NAME                     READY   STATUS    RESTARTS   AGE
nginx-569b6bc698-48qqt   1/1     Running   0          59m
nginx-569b6bc698-9qzpv   1/1     Running   0          59m
nginx-569b6bc698-wflrj   1/1     Running   0          59m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;If you want to uninstall it, simply do:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./helmister uninstall
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;It will get everything cleaned for all the releases that are specified in &lt;code&gt;config.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The sample log can be &lt;a href="https://github.com/sunnybhambhani/helmister/blob/main/artifacts/sample_logs/during_uninstallation_on_stdout.log" rel="noopener noreferrer"&gt;found here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to use it, and tweak it based on your requirements.&lt;/p&gt;

&lt;p&gt;I will soon add some more functionalities to it.&lt;/p&gt;

&lt;p&gt;Happy learning!&lt;/p&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Google/Stackoverflow/Linux man pages/etc&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>helm</category>
      <category>kubernetes</category>
      <category>devops</category>
      <category>eks</category>
    </item>
    <item>
      <title>Update multiple Kubernetes objects/configmaps in one go!</title>
      <dc:creator>Sunny Bhambhani</dc:creator>
      <pubDate>Wed, 22 May 2024 12:54:25 +0000</pubDate>
      <link>https://dev.to/aws-builders/update-multiple-kubernetes-objectsconfigmaps-in-one-go-5417</link>
      <guid>https://dev.to/aws-builders/update-multiple-kubernetes-objectsconfigmaps-in-one-go-5417</guid>
      <description>&lt;p&gt;There may be cases wherein we just need to update a Kubernetes configmap or any other Kubernetes object based on our requirements.&lt;/p&gt;

&lt;p&gt;And let's say it's just one or two configmaps(here we will be talking about configmaps just for simplicity but its applicable for other Kubernetes objects as well) then that's fine, right? We can simply do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl edit -n NAMESPACE_NAME configmap CONFIGMAP_NAME&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Update it based on our requirements.&lt;/li&gt;
&lt;li&gt;Save it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But think about a scenario, wherein we need to update +100 configmaps with the same values how to do it?&lt;/p&gt;

&lt;p&gt;We cannot update or edit each and every object since that would be a bit tedious and will be error-prone as well. Plus there might be chances we might skip some of them.&lt;/p&gt;

&lt;p&gt;So, the best way to do it is by using &lt;code&gt;patch&lt;/code&gt; command in an automated way.&lt;/p&gt;

&lt;p&gt;Refer: &lt;a href="https://kubernetes.io/docs/reference/kubectl/generated/kubectl_patch/" rel="noopener noreferrer"&gt;https://kubernetes.io/docs/reference/kubectl/generated/kubectl_patch/&lt;/a&gt; for more details about it.&lt;/p&gt;

&lt;p&gt;Let's see this in action:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I have a very minimal configmap which contains some DATABASE details.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
data:
  DATABASE_HOST: "api01.ybdb.io"
  DATABASE_NAME: "api01"
  DATABASE_PORT: "5433"
kind: ConfigMap
metadata:
  name: api01-configmap
  namespace: default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now, let's assume there is an update instead of port number 5433. Our database now listens on port 5444.&lt;/li&gt;
&lt;li&gt;We can easily accomplish this using &lt;code&gt;kubectl edit&lt;/code&gt; but let's see &lt;code&gt;patch&lt;/code&gt; in action:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl patch configmap api01-configmap -n default -p '{"data":{"DATABASE_PORT":"5444"}}'
configmap/api01-configmap patched
$ kubectl get cm -n default -o yaml api01-configmap
apiVersion: v1
data:
  DATABASE_HOST: api01.ybdb.io
  DATABASE_NAME: api01
  DATABASE_PORT: "5444"
kind: ConfigMap
metadata:
  creationTimestamp: "2024-05-22T10:06:39Z"
  name: api01-configmap
  namespace: default
  resourceVersion: "67651"
  uid: 2d49a0ea-6910-420c-b2bf-00e42e6c08d7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The command is pretty straight forward &lt;code&gt;kubectl patch configmap api01-configmap -n default -p '{"data":{"DATABASE_PORT":"5444"}}'&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;-n is to specify the namespace name where the configmap resides.&lt;/li&gt;
&lt;li&gt;-p is to specify what patch/update we want in the Kubernetes object.&lt;/li&gt;
&lt;li&gt;Here, under &lt;code&gt;data:&lt;/code&gt; we are updating a key called &lt;code&gt;DATABASE_PORT:&lt;/code&gt; to &lt;code&gt;5444&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Note: If in case &lt;code&gt;DATABASE_PORT:&lt;/code&gt; key doesn't exist, it will create that key for us.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Assume you want to see the output as well in the same command then add -o or --output flag with the type [json,name,yaml,etc].&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl patch configmap api01-configmap -n default -p '{"data":{"DATABASE_PORT":"5444"}}' -o yaml
apiVersion: v1
data:
  DATABASE_HOST: api01.ybdb.io
  DATABASE_NAME: api01
  DATABASE_PORT: "5444"
kind: ConfigMap
metadata:
  creationTimestamp: "2024-05-22T10:47:41Z"
  name: api01-configmap
  namespace: default
  resourceVersion: "69416"
  uid: a303bd0e-7f61-49c0-b671-06649ecdf999
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But there is another catch, you can also not run the patch command +100 times, I mean definitely you can but again that might be error-prone too.&lt;/p&gt;

&lt;p&gt;So, in that case we can write a simple reusable bash script that can do the job for us and can help us to update +100 configmaps in one go.&lt;/p&gt;

&lt;p&gt;It can be in any language but I have chosen &lt;code&gt;bash&lt;/code&gt;, since it's pretty common.&lt;/p&gt;

&lt;p&gt;Quick rundown of the script:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Here I have three variables, NAMESPACE (where the object resides), CONFIGMAP_FILE (input file which contains a list of all the configmaps that need to be updated), DATA (a set of key:value pair which needs to be replaced/added).&lt;/li&gt;
&lt;li&gt;Here I am creating log files as well (update_cm.log - contains generic readable information, patch.log - contains output of patch command).&lt;/li&gt;
&lt;li&gt;As of now, I just have added action as add but we can have other actions as well like replace or remove (based on our requirements).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash

NAMESPACE="default"
CONFIGMAP_FILE="configmaps"
DATA='{"data":{"DATABASE_PORT":"5444"}}'

rm patch.log update_cm.log

if [ ! -f "$CONFIGMAP_FILE" ]; then
  echo "File $CONFIGMAP_FILE not found."
  exit 1
fi

echo `date` &amp;gt;&amp;gt; update_cm.log
echo "----------------------------" &amp;gt;&amp;gt; update_cm.log

action=$1

if [ "$action" == "add" ]; then
  echo "Action: $action"
  echo "Action: $action" &amp;gt;&amp;gt; update_cm.log
  while IFS= read -r cm; do
    echo "Updating ConfigMap: $cm"
    echo "Updating ConfigMap: $cm" &amp;gt;&amp;gt; update_cm.log
    kubectl patch configmap "$cm" -n "$NAMESPACE" -p $DATA &amp;gt;&amp;gt; patch.log 2&amp;gt;&amp;amp;1
  done &amp;lt; "$CONFIGMAP_FILE"

else
  echo "Invalid action, please specify add".
  exit 1
fi

echo "----------------------------" &amp;gt;&amp;gt; update_cm.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feel free to use it, tweak it, based on your requirements. This script is for configmaps but similar logic we can write for other objects as well if required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy learning :)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Google.&lt;/li&gt;
&lt;li&gt;Kubernetes docs (&lt;a href="https://kubernetes.io/docs/home/" rel="noopener noreferrer"&gt;https://kubernetes.io/docs/home/&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl explain&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We should not manually update/patch the Kubernetes objects, this should be done when absolutely necessary or needed on the fly.&lt;/li&gt;
&lt;li&gt;Ideally these all values should come from the version control system wherein the values files are maintained.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PS: This works with any flavor of Kubernetes &lt;code&gt;minikube&lt;/code&gt;, &lt;code&gt;Elastic Kubernetes Service(EKS)&lt;/code&gt;, &lt;code&gt;Azure Kubernetes Service(AKS)&lt;/code&gt;, &lt;code&gt;Google Kubernetes Engine(GKE)&lt;/code&gt;, etc.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>linux</category>
      <category>devops</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Installing multiple helm charts in one go [Approach 2 - using helmfile]</title>
      <dc:creator>Sunny Bhambhani</dc:creator>
      <pubDate>Tue, 26 Dec 2023 13:09:52 +0000</pubDate>
      <link>https://dev.to/aws-builders/installing-multiple-helm-charts-in-one-go-approach-2-using-helmfile-4e4h</link>
      <guid>https://dev.to/aws-builders/installing-multiple-helm-charts-in-one-go-approach-2-using-helmfile-4e4h</guid>
      <description>&lt;p&gt;In this article we will be talking about &lt;code&gt;Approach 2&lt;/code&gt; i.e. how to get multiple helm charts installed using helmfile.&lt;/p&gt;

&lt;p&gt;If you haven't read the previous article where I discussed about &lt;code&gt;Approach 1&lt;/code&gt;, feel free to read it over.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ref: &lt;a href="https://dev.to/aws-builders/installing-multiple-helm-charts-in-one-go-approach-1-5d1p"&gt;https://dev.to/aws-builders/installing-multiple-helm-charts-in-one-go-approach-1-5d1p&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Prerequisites:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A running Kubernetes cluster with proper permissions, here I have used minikube.&lt;/li&gt;
&lt;li&gt;kubectl, helm, and helmfile installed on your machine to interact with the Kubernetes cluster.

&lt;ul&gt;
&lt;li&gt;Ref: &lt;a href="https://kubernetes.io/docs/tasks/tools/" rel="noopener noreferrer"&gt;https://kubernetes.io/docs/tasks/tools/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Ref: &lt;a href="https://helm.sh/docs/intro/install/" rel="noopener noreferrer"&gt;https://helm.sh/docs/intro/install/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Ref: &lt;a href="https://github.com/helmfile/helmfile" rel="noopener noreferrer"&gt;https://github.com/helmfile/helmfile&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Installation of helmfile is pretty straight forward, we just need to grab its binary and put that in /usr/local/bin and we are done (Ref: &lt;a href="https://helmfile.readthedocs.io/en/latest/#installation" rel="noopener noreferrer"&gt;https://helmfile.readthedocs.io/en/latest/#installation&lt;/a&gt; for operating system other than linux).&lt;/p&gt;

&lt;p&gt;Grab the latest one from the assets section from here: &lt;a href="https://github.com/helmfile/helmfile/releases" rel="noopener noreferrer"&gt;https://github.com/helmfile/helmfile/releases&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;wget https://github.com/helmfile/helmfile/releases/download/v0.159.0/helmfile_0.159.0_linux_amd64.tar.gz
&lt;span class="nb"&gt;sudo tar&lt;/span&gt; &lt;span class="nt"&gt;-xxf&lt;/span&gt; helmfile_0.159.0_linux_amd64.tar.gz
&lt;span class="nb"&gt;sudo rm &lt;/span&gt;helmfile_0.159.0_linux_amd64.tar.gz
&lt;span class="nb"&gt;sudo mv &lt;/span&gt;helmfile /usr/local/bin/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once helmfile is installed, we need to initialize it so that it can download necessary helm plugins.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helmfile init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to list it out what all plugins init installs, it can be found using below command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helm plugin list
NAME            VERSION DESCRIPTION
diff            3.8.1   Preview helm upgrade changes as a diff
helm-git        0.12.0  Get non-packaged Charts directly from Git.
s3              0.14.0  Provides AWS S3 protocol support &lt;span class="k"&gt;for &lt;/span&gt;charts and repos. https://github.com/hypnoglow/helm-s3
secrets         4.1.1   This plugin provides secrets values encryption &lt;span class="k"&gt;for &lt;/span&gt;Helm charts secure storing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: A notice to upgrade helm may appear if the helm version is 3.10 or lower.&lt;/p&gt;

&lt;p&gt;helm version is too low, the current version is 3.10.1+g9f88ccb, the required version is 3.12.3&lt;br&gt;
use: '&lt;a href="https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3" rel="noopener noreferrer"&gt;https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3&lt;/a&gt;' [y/n]: y&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Approach 2:
&lt;/h3&gt;

&lt;p&gt;helmfile is pretty intresting and a very useful utility when it comes to get multiple helm charts installed. Using a single file &lt;code&gt;helmfile.yaml&lt;/code&gt; we can manage N number of charts.&lt;/p&gt;

&lt;p&gt;When it comes to installing mutiple helm charts, helmfile is a really helpful and interesting tool. The &lt;code&gt;helmfile.yaml&lt;/code&gt; values file and helmfile binary is all that is needed to manage N number of charts. Internally helmfile invokes helm command to manage Kubernetes objects/charts. Also you can think of helmfile as a wrapper around helm together with some helm plugins.&lt;/p&gt;

&lt;p&gt;Below is a quick example, wherein I have a 3-Tier application comprising of a frontend, backend, and database and for all of them I have 3 individual charts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;tree
&lt;span class="nb"&gt;.&lt;/span&gt;
├── backend
│   ├── Chart.yaml
│   ├── templates
│   │   ├── _helpers.tpl
│   │   ├── deployment.yaml
│   │   ├── hpa.yaml
│   │   ├── ingress.yaml
│   │   ├── service.yaml
│   │   └── serviceaccount.yaml
│   └── values.yaml
├── database
│   ├── Chart.yaml
│   ├── templates
│   │   ├── _helpers.tpl
│   │   ├── deployment.yaml
│   │   ├── hpa.yaml
│   │   ├── ingress.yaml
│   │   ├── service.yaml
│   │   └── serviceaccount.yaml
│   └── values.yaml
└── webapp
    ├── Chart.yaml
    ├── templates
    │   ├── _helpers.tpl
    │   ├── deployment.yaml
    │   ├── hpa.yaml
    │   ├── ingress.yaml
    │   ├── service.yaml
    │   └── serviceaccount.yaml
    └── values.yaml

6 directories, 24 files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we will use helmfile (that too a single command to get these charts installed).&lt;/p&gt;

&lt;p&gt;In the same directory where my charts are there, lets create a new file called &lt;code&gt;helmfile.yaml&lt;/code&gt;. Just to add here we are referring local charts now, but we will refer charts from helm repositories in next examples.&lt;/p&gt;

&lt;h4&gt;
  
  
  Location: Local helm charts
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;$ cat helmfile.yaml&lt;/span&gt;
&lt;span class="na"&gt;releases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;webapp&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
    &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./webapp&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.1.0"&lt;/span&gt;
    &lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;installed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
    &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./backend&lt;/span&gt;
    &lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;database&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
    &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./database&lt;/span&gt;
    &lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lets break this file now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There can be multiple sections in this &lt;code&gt;YAML&lt;/code&gt; file, but majorly we will focus on &lt;code&gt;.releases&lt;/code&gt; and &lt;code&gt;.repositories&lt;/code&gt; sections.&lt;/li&gt;
&lt;li&gt;For more details around what all things we can have in a helmfile.yaml, ref: &lt;a href="https://helmfile.readthedocs.io/en/latest/#configuration" rel="noopener noreferrer"&gt;https://helmfile.readthedocs.io/en/latest/#configuration&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.releases&lt;/code&gt; is an array which basically signifies what all helm releases we need to deploy in a Kubernetes cluster. 

&lt;ul&gt;
&lt;li&gt;Important KV pairs in each item are &lt;code&gt;.releases[].name&lt;/code&gt; which refers to the name of the release.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.releases[].namespace&lt;/code&gt;, it refers to the name of the namespace where we need to install the chart.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.releases[].chart&lt;/code&gt;, it refers to the location of the chart from where helm needs to pull it. In this example its in my local machine and in the current directory.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.releases[].version&lt;/code&gt;, it refers to the version of chart which needs to be installed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.releases[].installed&lt;/code&gt;, it is a boolean key which referes if we want to get specific chart installed or not (by default the value is true).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.releases[].wait&lt;/code&gt;, it is same as &lt;code&gt;--wait&lt;/code&gt; flag of helm, which means the operation will wait untill all the components are ready/healthy. Ref: &lt;a href="https://helm.sh/docs/intro/using_helm/" rel="noopener noreferrer"&gt;https://helm.sh/docs/intro/using_helm/&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Now, lets see helmfile in action:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As of now nothing is installed.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helm list &lt;span class="nt"&gt;-A&lt;/span&gt;
NAME    NAMESPACE       REVISION        UPDATED STATUS  CHART   APP VERSION
&lt;span class="err"&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We will first initialize helm to gather all the dependencies.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helmfile init
helmfile initialization completed!
&lt;span class="err"&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Lets list out what all releases are defined in our release file?
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helmfile list
NAME            NAMESPACE       ENABLED INSTALLED       LABELS  CHART           VERSION
webapp          default         &lt;span class="nb"&gt;true    true&lt;/span&gt;                    ./webapp        0.1.0
backend         default         &lt;span class="nb"&gt;true    true&lt;/span&gt;                    ./backend
database        default         &lt;span class="nb"&gt;true    true&lt;/span&gt;                    ./database
&lt;span class="err"&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;All, looks good, lets apply the state file using &lt;code&gt;helmfile apply&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helmfile apply
Building dependency &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;webapp, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;webapp
Building dependency &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backend, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backend
Building dependency &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;database, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;database
Comparing &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;webapp, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;webapp
&lt;span class="k"&gt;********************&lt;/span&gt;

        Release was not present &lt;span class="k"&gt;in &lt;/span&gt;Helm.  Diff will show entire contents as new.

&lt;span class="k"&gt;********************&lt;/span&gt;
default, webapp, Deployment &lt;span class="o"&gt;(&lt;/span&gt;apps&lt;span class="o"&gt;)&lt;/span&gt; has been added:
-
+ &lt;span class="c"&gt;# Source: webapp/templates/deployment.yaml&lt;/span&gt;
+ apiVersion: apps/v1

&lt;span class="c"&gt;#.........&lt;/span&gt;
&lt;span class="c"&gt;#.........&lt;/span&gt;
&lt;span class="c"&gt;# OUTPUT TRIMMED&lt;/span&gt;

UPDATED RELEASES:
NAME       CHART        VERSION   DURATION
webapp     ./webapp     0.1.0           3s
database   ./database   0.1.0           3s
backend    ./backend    0.1.0           3s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;If you will see here, using a single command it instructed helm to build the dependency of all the charts specified in the state file then it used &lt;code&gt;helm diff&lt;/code&gt; to list out actual k8s yaml files, then it installs all the releases.&lt;/li&gt;
&lt;li&gt;If you will fire &lt;code&gt;helm list&lt;/code&gt; or &lt;code&gt;kubectl get pods&lt;/code&gt; now, you will see all the intended resources.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helm list &lt;span class="nt"&gt;-A&lt;/span&gt;
NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
backend         default         1               2023-12-11 16:13:24.769966852 +0530 IST deployed        backend-0.1.0   1.16.0
database        default         1               2023-12-11 16:13:24.771955874 +0530 IST deployed        database-0.1.0  1.16.0
webapp          default         1               2023-12-11 16:13:24.771767015 +0530 IST deployed        webapp-0.1.0    1.16.0
&lt;span class="nv"&gt;$ &lt;/span&gt;k get pods
NAME                       READY   STATUS    RESTARTS   AGE
backend-7f458d4566-zwcz2   1/1     Running   0          3m47s
database-b4f679788-z6r84   1/1     Running   0          3m47s
webapp-7f6ffdc676-g5w7j    1/1     Running   0          3m47s
&lt;span class="err"&gt;$&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Get the status using &lt;code&gt;helmfile status&lt;/code&gt; if required.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helmfile status
Getting status backend
Getting status webapp
Getting status database
NAME: backend
LAST DEPLOYED: Mon Dec 11 16:13:24 2023
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

NAME: webapp
LAST DEPLOYED: Mon Dec 11 16:13:24 2023
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

NAME: database
LAST DEPLOYED: Mon Dec 11 16:13:24 2023
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now, lets assume you just need to update the database release and that too just the replicaCount, 

&lt;ul&gt;
&lt;li&gt;How to update that using &lt;code&gt;values&lt;/code&gt; file or using &lt;code&gt;set&lt;/code&gt; key?&lt;/li&gt;
&lt;li&gt;What helmfile will do?&lt;/li&gt;
&lt;li&gt;How to check what all changes helmfile will make?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;By default, similar to &lt;code&gt;helm&lt;/code&gt;, this will also use helm chart's default values.yaml file which is a part of helm chart itself. So either you can update that and fulfill your requirement (which idelly is not a good practice, since in real world scenario that is most unlikely to happen and ideally we should to override intended keys).&lt;/p&gt;

&lt;p&gt;To cater this need we have something called &lt;code&gt;values&lt;/code&gt; and &lt;code&gt;set&lt;/code&gt; which we can specify in the state file and helmfile will consider those values and will override them.&lt;/p&gt;

&lt;p&gt;Lets use the same example, but now I have added few additional line for backend as well as for the database item in our releases array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;releases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;webapp&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
    &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./webapp&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.1.0"&lt;/span&gt;
    &lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;installed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
    &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./backend&lt;/span&gt;
    &lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;replicaCount&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;database&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
    &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./database&lt;/span&gt;
    &lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./db-values.yaml"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;$ cat db-values.yaml&lt;/span&gt;
&lt;span class="na"&gt;replicaCount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Just to cut short, &lt;code&gt;values&lt;/code&gt; is same as &lt;code&gt;--values&lt;/code&gt; and &lt;code&gt;set&lt;/code&gt; is same as &lt;code&gt;--set&lt;/code&gt; in helm.&lt;/li&gt;
&lt;li&gt;Here if you will see, for &lt;code&gt;backend&lt;/code&gt; I have used &lt;code&gt;set&lt;/code&gt; and I am overwriding &lt;code&gt;relicaCount&lt;/code&gt; to &lt;code&gt;2&lt;/code&gt; and for &lt;code&gt;database&lt;/code&gt; I have used 'values' and there I have passed a path where my values file resides which contains again the &lt;code&gt;replicaCount&lt;/code&gt; as &lt;code&gt;2&lt;/code&gt; but for database release.&lt;/li&gt;
&lt;li&gt;Now, comes the 2nd question, how to see what all differences will helmfile make, simply fire &lt;code&gt;helmfile diff&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helmfile diff
Building dependency &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;webapp, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;webapp
Building dependency &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backend, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backend
Building dependency &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;database, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;database
Comparing &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;webapp, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;webapp
Comparing &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backend, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backend
default, backend, Deployment &lt;span class="o"&gt;(&lt;/span&gt;apps&lt;span class="o"&gt;)&lt;/span&gt; has changed:
  &lt;span class="c"&gt;# Source: backend/templates/deployment.yaml&lt;/span&gt;
  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: backend
&lt;span class="c"&gt;# ......&lt;/span&gt;
&lt;span class="c"&gt;# OUTPUT TRIMMED&lt;/span&gt;

-   replicas: 1
+   replicas: 2
&lt;span class="c"&gt;# ......&lt;/span&gt;
&lt;span class="c"&gt;# OUTPUT TRIMMED&lt;/span&gt;

Comparing &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;database, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;database
default, database, Deployment &lt;span class="o"&gt;(&lt;/span&gt;apps&lt;span class="o"&gt;)&lt;/span&gt; has changed:
  &lt;span class="c"&gt;# Source: database/templates/deployment.yaml&lt;/span&gt;
  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: database
&lt;span class="c"&gt;# ......&lt;/span&gt;
&lt;span class="c"&gt;# OUTPUT TRIMMED&lt;/span&gt;

-   replicas: 1
+   replicas: 2
&lt;span class="c"&gt;# ......&lt;/span&gt;
&lt;span class="c"&gt;# OUTPUT TRIMMED&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Here, if you will observe, firstly it compared the release webapp (wherein it didn't found any differences then it compared backend where it found that the replicaCount was updated to &lt;code&gt;2&lt;/code&gt;) then it compared database where it again found that the replicaCount was updated to &lt;code&gt;2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;helmfile apply&lt;/code&gt;, we will apply the changes now.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: &lt;code&gt;helmfile apply&lt;/code&gt; basically calls two operations &lt;code&gt;helmfile diff&lt;/code&gt; and &lt;code&gt;helmfilesync&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Again it will show you what all changes it will bring then will apply the changes.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helmfile apply
Building dependency &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;webapp, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;webapp
Building dependency &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backend, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backend
Building dependency &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;database, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;database
Comparing &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;webapp, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;webapp
default, backend, Deployment &lt;span class="o"&gt;(&lt;/span&gt;apps&lt;span class="o"&gt;)&lt;/span&gt; has changed:
&lt;span class="c"&gt;# ..........&lt;/span&gt;
&lt;span class="c"&gt;# OUTPUT TRIMMED&lt;/span&gt;

-   replicas: 1
+   replicas: 2

default, database, Deployment &lt;span class="o"&gt;(&lt;/span&gt;apps&lt;span class="o"&gt;)&lt;/span&gt; has changed:
&lt;span class="c"&gt;# ..........&lt;/span&gt;
&lt;span class="c"&gt;# OUTPUT TRIMMED&lt;/span&gt;

-   replicas: 1
+   replicas: 2

Upgrading &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;database, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;database
Upgrading &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backend, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backend
Release &lt;span class="s2"&gt;"backend"&lt;/span&gt; has been upgraded. Happy Helming!
NAME: backend
LAST DEPLOYED: Mon Dec 11 16:37:27 2023
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None

Listing releases matching ^backend&lt;span class="err"&gt;$&lt;/span&gt;
Release &lt;span class="s2"&gt;"database"&lt;/span&gt; has been upgraded. Happy Helming!
NAME: database
LAST DEPLOYED: Mon Dec 11 16:37:27 2023
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None

UPDATED RELEASES:
NAME       CHART        VERSION   DURATION
backend    ./backend    0.1.0           3s
database   ./database   0.1.0           3s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helm list
NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
backend         default         2               2023-12-11 16:37:27.366097438 +0530 IST deployed        backend-0.1.0   1.16.0
database        default         2               2023-12-11 16:37:27.366586959 +0530 IST deployed        database-0.1.0  1.16.0
webapp          default         1               2023-12-11 16:13:24.771767015 +0530 IST deployed        webapp-0.1.0    1.16.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Revision got incremented by &lt;code&gt;1&lt;/code&gt;, and now I have &lt;code&gt;2&lt;/code&gt; new pods running +1 for backend and +1 for database.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;k get pods
NAME                       READY   STATUS    RESTARTS   AGE
backend-7f458d4566-6jgxk   1/1     Running   0          12s
backend-7f458d4566-zwcz2   1/1     Running   0          24m
database-b4f679788-9kxhl   1/1     Running   0          12s
database-b4f679788-z6r84   1/1     Running   0          24m
webapp-7f6ffdc676-g5w7j    1/1     Running   0          24m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example we referred the helm charts which were placed locally, now lets see how to consume the helm charts which are a part of OCI or HTTPS repositories.&lt;/p&gt;

&lt;h4&gt;
  
  
  Location: helm charts from OCI repositories
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Let's now install a helm chart from an opensource oci repository (ref: &lt;a href="https://artifacthub.io/" rel="noopener noreferrer"&gt;https://artifacthub.io/&lt;/a&gt;); Just for an example we will install nginx chart.&lt;/li&gt;
&lt;li&gt;Again, I have a new helmfile.yaml and the only difference here is in the chart key.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;releases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
    &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oci://registry-1.docker.io/bitnamicharts/nginx&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;15.4.4"&lt;/span&gt;
    &lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service.type&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterIP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Here, if you will observe firstly helmfile is pulling the helmchart then will list out the difference i.e. what all things it will create and then will get the k8s resources created.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helmfile apply
Pulling registry-1.docker.io/bitnamicharts/nginx:15.4.4
Comparing &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/helmfile976774944/default/nginx/nginx/15.4.4/nginx
&lt;span class="k"&gt;********************&lt;/span&gt;

        Release was not present &lt;span class="k"&gt;in &lt;/span&gt;Helm.  Diff will show entire contents as new.

&lt;span class="k"&gt;********************&lt;/span&gt;
default, nginx, Deployment &lt;span class="o"&gt;(&lt;/span&gt;apps&lt;span class="o"&gt;)&lt;/span&gt; has been added:
&lt;span class="c"&gt;# ......&lt;/span&gt;
&lt;span class="c"&gt;# ......&lt;/span&gt;
&lt;span class="c"&gt;# OUTPUT TRIMMED&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Location: helm charts from HTTPS repositories
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Let's now install a helm chart from an opensource HTTPS repository and here I have taken an example from the official helmfile documentation (ref: &lt;a href="https://helmfile.readthedocs.io/en/latest/#getting-started" rel="noopener noreferrer"&gt;https://helmfile.readthedocs.io/en/latest/#getting-started&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Here is the new helmfile.yaml and now the difference here is &lt;code&gt;.repositories&lt;/code&gt; and &lt;code&gt;.releases[].chart&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;repositories&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prometheus-community&lt;/span&gt;
   &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://prometheus-community.github.io/helm-charts&lt;/span&gt;

&lt;span class="na"&gt;releases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prom-norbac-ubuntu&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prometheus&lt;/span&gt;
  &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prometheus-community/prometheus&lt;/span&gt;
  &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.create&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Here, if you will observe in this helmfile we have a new section called &lt;code&gt;.repositories&lt;/code&gt; which again is an array and can contain multiple repositories with a human friendly name which can be referred in the &lt;code&gt;.releases&lt;/code&gt; section. For instance here the repo is &lt;code&gt;https://prometheus-community.github.io/helm-charts&lt;/code&gt; and it can be referred in the releases section as &lt;code&gt;prometheus-community&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;And in-turn &lt;code&gt;.releases[].chart&lt;/code&gt; now is &lt;code&gt;prometheus-community/prometheus&lt;/code&gt; where &lt;code&gt;prometheus&lt;/code&gt; is the chart name. When installing many charts from the same source, this eliminates duplication, and if we only need to change the repository, the update would only be needed at one place and we are done.&lt;/li&gt;
&lt;li&gt;Another point to note here is, adding &lt;code&gt;.repositories&lt;/code&gt; is similar to running &lt;code&gt;helm repo add prometheus-communit https://prometheus-community.github.io/helm-charts&lt;/code&gt; this command.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helmfile apply
Adding repo prometheus-community https://prometheus-community.github.io/helm-charts
&lt;span class="s2"&gt;"prometheus-community"&lt;/span&gt; has been added to your repositories

Comparing &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;prom-norbac-ubuntu, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;prometheus-community/prometheus
&lt;span class="k"&gt;********************&lt;/span&gt;

        Release was not present &lt;span class="k"&gt;in &lt;/span&gt;Helm.  Diff will show entire contents as new.

&lt;span class="k"&gt;********************&lt;/span&gt;
prometheus, prom-norbac-ubuntu-alertmanager, ConfigMap &lt;span class="o"&gt;(&lt;/span&gt;v1&lt;span class="o"&gt;)&lt;/span&gt; has been added:
&lt;span class="c"&gt;# ......&lt;/span&gt;
&lt;span class="c"&gt;# ......&lt;/span&gt;
&lt;span class="c"&gt;# OUTPUT TRIMMED&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Repositories
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;We already touched upon this topic but just for completeness sake similar to above example we can have &lt;code&gt;OCI&lt;/code&gt; repositories as well defined under &lt;code&gt;.repositories&lt;/code&gt; section.&lt;/li&gt;
&lt;li&gt;Here is an example for the same:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;repositories&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ocirepo&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry-1.docker.io/bitnamicharts&lt;/span&gt;
    &lt;span class="na"&gt;oci&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;releases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
    &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ocirepo/nginx&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;15.4.4&lt;/span&gt;
    &lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service.type&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterIP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;If you are referring an &lt;code&gt;oci&lt;/code&gt; repository make sure to use &lt;code&gt;repositories[].oci&lt;/code&gt; as true.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helmfile apply
Pulling registry-1.docker.io/bitnamicharts/nginx:15.4.4
Comparing &lt;span class="nv"&gt;release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx, &lt;span class="nv"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/helmfile4237214626/default/nginx/nginx/15.4.4/nginx
&lt;span class="k"&gt;********************&lt;/span&gt;

        Release was not present &lt;span class="k"&gt;in &lt;/span&gt;Helm.  Diff will show entire contents as new.

&lt;span class="k"&gt;********************&lt;/span&gt;
default, nginx, Deployment &lt;span class="o"&gt;(&lt;/span&gt;apps&lt;span class="o"&gt;)&lt;/span&gt; has been added:
&lt;span class="c"&gt;# ......&lt;/span&gt;
&lt;span class="c"&gt;# ......&lt;/span&gt;
&lt;span class="c"&gt;# OUTPUT TRIMMED&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feel free to read it over and share your thoughts and comments.&lt;/p&gt;

&lt;p&gt;Merry Christmas and a prosperous New Year to everyone! :)&lt;/p&gt;

&lt;p&gt;Happy Learning!&lt;/p&gt;

&lt;p&gt;PS: The cover image is created using &lt;a href="https://www.canva.com/" rel="noopener noreferrer"&gt;canva&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://helmfile.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;https://helmfile.readthedocs.io/en/latest/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>kubernetes</category>
      <category>devops</category>
      <category>helm</category>
    </item>
    <item>
      <title>Installing multiple helm charts in one go [Approach 1 - using parent/child charts]</title>
      <dc:creator>Sunny Bhambhani</dc:creator>
      <pubDate>Fri, 01 Dec 2023 20:42:32 +0000</pubDate>
      <link>https://dev.to/aws-builders/installing-multiple-helm-charts-in-one-go-approach-1-5d1p</link>
      <guid>https://dev.to/aws-builders/installing-multiple-helm-charts-in-one-go-approach-1-5d1p</guid>
      <description>&lt;p&gt;Helm is really a very powerful tool for managing &lt;code&gt;Kubernetes&lt;/code&gt; objects and is widely adopted across various organizations. It is truly a game changer on how Kubernetes objects are being managed. &lt;/p&gt;

&lt;p&gt;With a single command, we can install or upgrade multiple related Kubernetes entities together, we need not to worry about how the resources will be created, Helm will do all the heavy lifting for us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;RELEASE_NAME] &lt;span class="o"&gt;[&lt;/span&gt;REPO]/[CHART]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the below post is not about the basics of helm or how to install or upgrade a chart, etc. It's about some new ways of getting charts deployed.&lt;/p&gt;

&lt;p&gt;Let's say you have a requirement for getting more than 100 charts installed on a specific Kubernetes cluster, what would you do in this scenario?&lt;/p&gt;

&lt;p&gt;On top of my head, I can think of a couple of approaches:&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A running Kubernetes cluster with proper permissions, here I have used minikube.&lt;/li&gt;
&lt;li&gt;kubectl and helm installed on your machine to interact with the Kubernetes cluster.

&lt;ul&gt;
&lt;li&gt;Ref: &lt;a href="https://kubernetes.io/docs/tasks/tools/" rel="noopener noreferrer"&gt;https://kubernetes.io/docs/tasks/tools/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Ref: &lt;a href="https://helm.sh/docs/intro/install/" rel="noopener noreferrer"&gt;https://helm.sh/docs/intro/install/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Approach 1:
&lt;/h3&gt;

&lt;p&gt;Club inter-related charts into one, as in getting a parent/wrapper chart created which will in turn have the related child charts as dependency. Which mean if we install the parent/wrapper chart it will get all the Kubernetes resources of all the child charts deployed (provided they are marked as enabled in Chart.yaml).&lt;/p&gt;

&lt;p&gt;Below is a quick example, wherein I have a 3-Tier application named app01.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you notice the output of both the commands in the parent's Chart.yaml I have all three charts listed as dependencies and in the other one, individual charts have their own Kubernetes resources.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;Chart.yaml
apiVersion: v2
name: app01
description: A Helm chart &lt;span class="k"&gt;for &lt;/span&gt;app01 which contains FE, BE, DB.
version: 0.1.0
appVersion: 1.0.0
dependencies:
  - name: webapp
    version: &lt;span class="s2"&gt;"0.1.0"&lt;/span&gt;
    repository: &lt;span class="s2"&gt;"file://./charts/webapp"&lt;/span&gt;
    enabled: &lt;span class="nb"&gt;true&lt;/span&gt;
  - name: backend
    version: &lt;span class="s2"&gt;"0.1.0"&lt;/span&gt;
    repository: &lt;span class="s2"&gt;"file://./charts/backend"&lt;/span&gt;
    enabled: &lt;span class="nb"&gt;true&lt;/span&gt;
  - name: database
    version: &lt;span class="s2"&gt;"0.1.0"&lt;/span&gt;
    repository: &lt;span class="s2"&gt;"file://./charts/database"&lt;/span&gt;
    enabled: &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;tree
&lt;span class="nb"&gt;.&lt;/span&gt;
├── Chart.yaml
├── charts
│   ├── backend
│   │   ├── Chart.yaml
│   │   ├── charts
│   │   ├── templates
│   │   │   ├── _helpers.tpl
│   │   │   ├── deployment.yaml
│   │   │   ├── hpa.yaml
│   │   │   ├── ingress.yaml
│   │   │   ├── service.yaml
│   │   │   └── serviceaccount.yaml
│   │   └── values.yaml
│   ├── database
│   │   ├── Chart.yaml
│   │   ├── charts
│   │   ├── templates
│   │   │   ├── _helpers.tpl
│   │   │   ├── deployment.yaml
│   │   │   ├── hpa.yaml
│   │   │   ├── ingress.yaml
│   │   │   ├── service.yaml
│   │   │   └── serviceaccount.yaml
│   │   └── values.yaml
│   └── webapp
│       ├── Chart.yaml
│       ├── charts
│       ├── templates
│       │   ├── _helpers.tpl
│       │   ├── deployment.yaml
│       │   ├── hpa.yaml
│       │   ├── ingress.yaml
│       │   ├── service.yaml
│       │   └── serviceaccount.yaml
│       └── values.yaml
└── values.yaml

10 directories, 26 files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;When we install the parent chart it will get all the Kubernetes resources deployed.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helm &lt;span class="nb"&gt;install &lt;/span&gt;app01 ./app01/
NAME: app01
LAST DEPLOYED: Sat Dec  2 00:14:50 2023
NAMESPACE: default
STATUS: deployed
REVISION: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helm list &lt;span class="nt"&gt;-A&lt;/span&gt;
NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
app01   default         1               2023-12-02 00:14:50.075444065 +0530 IST deployed        app01-0.1.0     1.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;k get all
NAME                                  READY   STATUS    RESTARTS   AGE
pod/app01-backend-965cb9b5b-q7gqv     1/1     Running   0          17m
pod/app01-database-56bdbcd49c-bh4s2   1/1     Running   0          17m
pod/app01-webapp-5b67db8bdf-m6psg     1/1     Running   0          17m

NAME                     TYPE        CLUSTER-IP       EXTERNAL-IP   PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;   AGE
service/app01-backend    ClusterIP   10.107.53.8      &amp;lt;none&amp;gt;        8080/TCP  17m
service/app01-database   ClusterIP   10.104.173.124   &amp;lt;none&amp;gt;        3306/TCP  17m
service/app01-webapp     ClusterIP   10.111.168.18    &amp;lt;none&amp;gt;        80/TCP    17m
service/kubernetes       ClusterIP   10.96.0.1        &amp;lt;none&amp;gt;        443/TCP   8d

NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/app01-backend    1/1     1            1           17m
deployment.apps/app01-database   1/1     1            1           17m
deployment.apps/app01-webapp     1/1     1            1           17m

NAME                                        DESIRED   CURRENT   READY   AGE
replicaset.apps/app01-backend-965cb9b5b     1         1         1       17m
replicaset.apps/app01-database-56bdbcd49c   1         1         1       17m
replicaset.apps/app01-webapp-5b67db8bdf     1         1         1       17m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Another thing to note here is now we have 4 values.yaml files (one for each child chart and one for the parent helm chart).&lt;/li&gt;
&lt;li&gt;And the good part here is using just one parent's values.yaml file we can manage all 3 of them.&lt;/li&gt;
&lt;li&gt;Make sure in parent's values.yaml, the child chart's values are indented correctly, and they are indented under specific chart name as mentioned in Chart.yaml under &lt;code&gt;.dependencies[*].name&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;values.yaml
webapp:
  replicaCount: 2

database:
  replicaCount: 1

backend:
  replicaCount: 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Here we are just updating the replicaCount of all child charts and are upgrading the release.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;helm upgrade &lt;span class="nt"&gt;--install&lt;/span&gt; app01 ./app01/
Release &lt;span class="s2"&gt;"app01"&lt;/span&gt; has been upgraded. Happy Helming!
NAME: app01
LAST DEPLOYED: Sat Dec  2 01:21:56 2023
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;As specified in parent chart values.yaml, the replicaCount is now increased to 2,3 respectively.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;k get deploy&lt;span class="p"&gt;;&lt;/span&gt; k get pods
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
app01-backend    3/3     3            3           105m
app01-database   1/1     1            1           105m
app01-webapp     2/2     2            2           105m
NAME                              READY   STATUS    RESTARTS   AGE
app01-backend-965cb9b5b-dg6gq     1/1     Running   0          38m
app01-backend-965cb9b5b-q7gqv     1/1     Running   0          105m
app01-backend-965cb9b5b-z92c8     1/1     Running   0          38m
app01-database-56bdbcd49c-bh4s2   1/1     Running   0          105m
app01-webapp-5b67db8bdf-c25kc     1/1     Running   0          38m
app01-webapp-5b67db8bdf-m6psg     1/1     Running   0          105m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;As you see here with a single command, we deployed multiple helm charts and using a single values.yaml file we have the ability to manage all of them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Approach 2:
&lt;/h3&gt;

&lt;p&gt;Using helmfile.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach 3:
&lt;/h3&gt;

&lt;p&gt;Using bash or any other scripting language (I am planning to write a simple utility to accomplish this).&lt;/p&gt;

&lt;p&gt;Further, I am in the process of writing another article around Approach 2 and 3, plus there can be multiple other approaches for getting this accomplished (feel free to share your thoughts and comments).&lt;/p&gt;

&lt;p&gt;Happy learning :)&lt;/p&gt;

&lt;p&gt;PS: The cover image is created using &lt;a href="https://www.canva.com/" rel="noopener noreferrer"&gt;canva&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>helm</category>
      <category>kubernetes</category>
      <category>linux</category>
      <category>devops</category>
    </item>
    <item>
      <title>Bridging the Gap: Leveraging Secret Store CSI Drivers to Access Secrets from Google Secret Manager in GKE Cluster</title>
      <dc:creator>Sunny Bhambhani</dc:creator>
      <pubDate>Thu, 08 Jun 2023 04:00:03 +0000</pubDate>
      <link>https://dev.to/sunnybhambhani/bridging-the-gap-leveraging-secret-store-csi-drivers-to-access-secrets-from-google-secret-manager-in-gke-cluster-po7</link>
      <guid>https://dev.to/sunnybhambhani/bridging-the-gap-leveraging-secret-store-csi-drivers-to-access-secrets-from-google-secret-manager-in-gke-cluster-po7</guid>
      <description>&lt;p&gt;Today, preserving and securely storing secrets like API keys, passwords, and certificates is an essential part of creating and deploying applications. &lt;/p&gt;

&lt;p&gt;Google Secret Manager provides a powerful and centralized solution for secret management, as well as a secure vault to store and access sensitive information.&lt;/p&gt;

&lt;p&gt;However, getting these secrets and seamlessly integrating them into applications might be difficult. This post will detail this process and demonstrate how simple it is to consume secrets from Google Secret Manager into a GKE cluster.&lt;/p&gt;

&lt;p&gt;Before we get started there are couple of pre-requisites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make sure the GKE cluster which you are creating should have WORKLOAD_IDENTITY enabled.&lt;/li&gt;
&lt;li&gt;Make sure you have a IAM SERVICE_ACCOUNT created with proper permissions.&lt;/li&gt;
&lt;li&gt;One which we are most interested in is "Secret Manager Secret Accessor(roles/secretmanager.secretAccessor). Refer &lt;a href="https://cloud.google.com/secret-manager/docs/access-control" rel="noopener noreferrer"&gt;this&lt;/a&gt; for more details.&lt;/li&gt;
&lt;li&gt;gcloud command line gives a great way to quickly create and destroy resources on GCP.&lt;/li&gt;
&lt;li&gt;In below command, replace &lt;code&gt;CLUSTER_NAME&lt;/code&gt; with the name of the GKE cluster, &lt;code&gt;PROJECT_ID&lt;/code&gt; with the name of the project where you want to create the GKE cluster, &lt;code&gt;SERVICE_ACCOUNT&lt;/code&gt; with the name of the service account which contains the necessary permissions to interact with GCP resources (for example in this case it would be Google Secret Manager), &lt;code&gt;MACHINE_TYPE&lt;/code&gt; with the size of machine to deploy your workloads since we would be installing couple of resources make sure you choose a medium machine, &lt;code&gt;ZONE&lt;/code&gt; with the name of the zone, &lt;code&gt;NUMBER_OF_NODES&lt;/code&gt; with an integer value stating minimum number of nodes per zone, &lt;code&gt;CLUSTER_VERSION&lt;/code&gt; with the version of the GKE cluster you want to install.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;gcloud container clusters create CLUSTER_NAME --workload-pool=PROJECT_ID.svc.id.goog --service-account=&lt;a href="mailto:SERVICE_ACCOUNT@PROJECT_ID.iam.gserviceaccount.com"&gt;SERVICE_ACCOUNT@PROJECT_ID.iam.gserviceaccount.com&lt;/a&gt; --zone ZONE --machine-type MACHINE_TYPE --num-nodes=NUMBER_OF_NODES --cluster-version=CLUSTER_VERSION&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcloud container clusters create test-k8s \
    --workload-pool=proj-101.svc.id.goog \
    --service-account=test-k8s@proj-101.iam.gserviceaccount.com \
    --zone us-central1-a \
    --machine-type e2-standard-4 \
    --num-nodes=1 \
    --cluster-version=1.23.17-gke.5600
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install the Secret Store CSI Drivers, the simplest way is to get them installed via &lt;code&gt;helm&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Additionally, if you want to create secret k8s resource as well make sure to enable syncSecret flag.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm repo add secrets-store-csi-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts

helm upgrade --install csi-secrets-store secrets-store-csi-driver/secrets-store-csi-driver --namespace kube-system 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install the GCP provider plugin.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/secrets-store-csi-driver-provider-gcp/main/deploy/provider-gcp-plugin.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Make sure your service-account is binded with IAM GCP account&lt;/li&gt;
&lt;li&gt;Use below command to add/check IAM policy binding.&lt;/li&gt;
&lt;li&gt;Make sure to follow proper naming convention for service-account i.e. [NAMESPACE/SERVICE_ACCOUNT_NAME] for instance here we have [default/app-sa].
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcloud iam service-accounts add-iam-policy-binding \
    --role roles/iam.workloadIdentityUser \
    --member "serviceAccount:$proj-101.svc.id.goog[default/app-sa]" \
    test-k8s@proj-101.iam.gserviceaccount.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once all these things are done you are ready to use the secrets from Google Secret Manager and consume them in your deployments.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the same GCP IAM service account in k8s service account annotations.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    iam.gke.io/gcp-service-account: test-k8s@proj-101.iam.gserviceaccount.com
  name: app-sa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create the k8s &lt;code&gt;SecretProviderClass&lt;/code&gt; resource and have your path of secret appended to resourceName key (this is the one which will come from Google Secret Manager).&lt;/li&gt;
&lt;li&gt;In this example, I already created a secret called testpassword in GSM.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: test-secret
spec:
  provider: gcp
  parameters:
    secrets: |
      - resourceName: "projects/proj-101/secrets/testpassword/versions/latest"
        fileName: "testpassword"
  secretObjects:
  - secretName: testpassword
    data:
    - key: testpassword
      objectName: testpassword
    type: Opaque
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create the pod/deployment and use your secrets in your application.&lt;/li&gt;
&lt;li&gt;Here we are creating a volume item which is referring secrets-store.csi.k8s.io csi drivers and using the secretProviderClass which we created in above step.&lt;/li&gt;
&lt;li&gt;Further, we are mounting this as a volume to be consumed. &lt;/li&gt;
&lt;li&gt;Note: If you are planning to use the secret as an environment variable make sure the secret (k8s resource) is present.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  serviceAccountName: app-sa
  containers:
  - image: gcr.io/google.com/cloudsdktool/cloud-sdk:slim
    name: mypod
    resources:
      requests:
        cpu: 100m
    tty: true
    volumeMounts:
      - mountPath: "/var/secrets"
        name: vol-secret
        readOnly: true
  volumes:
  - name: vol-secret
    csi:
      driver: secrets-store.csi.k8s.io
      readOnly: true
      volumeAttributes:
        secretProviderClass: "test-secret"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope you find this post useful, feel free to add your thoughts or comments.&lt;/p&gt;

&lt;p&gt;Happy learning!&lt;/p&gt;

&lt;p&gt;References: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/en/actions/deployment/deploying-to-your-cloud-provider/deploying-to-google-kubernetes-engine" rel="noopener noreferrer"&gt;https://docs.github.com/en/actions/deployment/deploying-to-your-cloud-provider/deploying-to-google-kubernetes-engine&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GoogleCloudPlatform/secrets-store-csi-driver-provider-gcp" rel="noopener noreferrer"&gt;https://github.com/GoogleCloudPlatform/secrets-store-csi-driver-provider-gcp&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>googlecloud</category>
      <category>devops</category>
      <category>security</category>
    </item>
  </channel>
</rss>
