How do we manage k8s applications deployed in multiple k8s clusters using argoCD & Helm?
Stackademic is a learning hub for programmers, devs, coders, and engineers. Our goal is to democratize free coding education for the world.
argoCD
What is ArgoCD?¶
Argo CD is a Kubernetes-native continuous deployment (CD) tool. Unlike external CD tools that only enable push-based deployments, Argo CD can pull updated code from Git repositories and deploy it directly to Kubernetes resources.
What is GitOps?¶
GitOps is a way of implementing Continuous Deployment for cloud-native applications. It focuses on a developer-centric experience when operating infrastructure using tools developers are already familiar with, including Git and Continuous Deployment tools.
The core idea of GitOps is to have a Git repository that always contains declarative descriptions of the infrastructure currently desired in the production environment and an automated process to make the production environment match the described state in the repository. If you want to deploy a new or existing application, you only need to update the repository — the automated process handles everything else. It’s like having cruise control for managing your applications in production.
GitOps with CI/CD
If you want to learn more about argoCD and GitOps then click here.
In this tutorial, we will see how do we manage k8s application deployed in multiple k8s clusters using argoCD & Helm. I will use my portfolio application’s image to demonstrate this tutorial. I will create the application in 3 different k8s clusters i.e. prod, dev & stg.
Prerequisites:¶
- 3 running k8s clusters (for prod, dev & stg environment)
- argoCD installed in one of the k8s clusters.
- eksctl installed
- Git repository
Click here to learn how to install argoCD in the k8s cluster.
Now, let’s start configuring the project.
Step 1: Register the k8s cluster with argoCD¶
- Run the below command to log in to argoCD
argocd login 127.0.0.1:<argocd_port> - The above command will ask for the
usernameandpassword. username will beadminand you can fetch the password by running the below command.kubectl get secret -n argocd argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d - After login, run the below command to register the k8s cluster with argoCD.
argocd cluster add your_k8s_context_name - You will see the cluster under the
Settings -> Clustersin argoCD UI.
Clusters
Step 2: Create the Helm chart for the application¶
- We need to create the helm chart for our application with different values for each environment.
[dhruvinsoni@Dhruvins-MacBook-Pro charts (⎈|dhsoni@prod-cluster.us-east-2.eksctl.io:N/A)]$ tree . └── portfolio-app ├── Chart.yaml ├── templates │ ├── deployment.yaml │ └── service.yaml └── values ├── development │ └── values.yaml ├── production │ └── values.yaml └── staging └── values.yaml 7 directories, 6 files [dhruvinsoni@Dhruvins-MacBook-Pro charts (⎈|dhsoni@prod-cluster.us-east-2.eksctl.io:N/A)]$ - Above is the structure of the helm chart. Create the same structure in your machine.
- Add the below code to the
Chart.yamlfile.apiVersion: v1 name: my-web-app description: A Helm chart for my portfolio website type: application version: 1.0.0 appVersion: 1.0.0 maintainers: - name: Dhruvin Soni email: dksoni4530@gmail.com
Note: You can replace the values as per yours.
Step 3: Create the deployment & service for the application¶
- Create the
deployment.yaml&service.yamlfile in thetemplatesfolder. - Add the below code to
deployment.yamlfile.apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Chart.Name }} namespace: {{ .Values.service.nameSpace }} spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: app: {{ .Chart.Name }} template: metadata: labels: app: {{ .Chart.Name }} spec: containers: - name: {{ .Chart.Name }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - name: http containerPort: 80 - Add the below code to
service.yamlfile.apiVersion: v1 kind: Service metadata: name: {{ .Values.service.name }} namespace: {{ .Values.service.nameSpace }} spec: type: {{ .Values.service.type }} ports: - port: {{ .Values.service.port }} protocol: TCP selector: app: {{ .Chart.Name }} - The values will be rendered from the values file which we will create later in the tutorial.
Step 4: Store the code in the Git repository¶
- Now, for argoCD to apply the changes we need to store the code to the Git repository.
- Create a Git repository and store the code in it.

Code
Step 5: Create the values file¶
- Create the
production,development&stagingdirectory in thevaluesdirectory and createvalues.yamlfile in each directory. - Add the below code to development values.yaml file.
replicaCount: 1 image: repository: dhruvin30/dhsoniweb tag: v1 pullPolicy: IfNotPresent service: name: my-web-app-dev type: LoadBalancer port: 80 nameSpace: mywebapp - For the development environment, I have set the
replicaCountto 1. - Add the below code to staging values.yaml file.
replicaCount: 1 image: repository: dhruvin30/dhsoniweb tag: v1 pullPolicy: IfNotPresent service: name: my-web-app-stg type: LoadBalancer port: 80 nameSpace: mywebapp - For the development environment, I have set the
replicaCountto 1. - Add the below code to production values.yaml file.
replicaCount: 3 image: repository: dhruvin30/dhsoniweb tag: v1 pullPolicy: IfNotPresent service: name: my-web-app-prod type: LoadBalancer port: 80 nameSpace: mywebapp - For the production environment, I have set the
replicaCountto 3. - Commit all the code to the git repository
Step 6: Create the applications in argoCD¶
- Now, we need to create the 3 different applications in argoCD for each environment.
[dhruvinsoni@Dhruvins-MacBook-Pro applications (⎈|dhsoni@prod-cluster.us-east-2.eksctl.io:N/A)]$ tree . ├── pre-prod │ ├── portfolio-app-dev.yaml │ └── portfolio-app-stg.yaml └── prod └── portfolio-app-prod.yaml 3 directories, 3 files [dhruvinsoni@Dhruvins-MacBook-Pro applications (⎈|dhsoni@prod-cluster.us-east-2.eksctl.io:N/A)]$ - The above is the structure of the argoCD applications.
pre-prodfolder contains the dev & stg application code andprodfolder contains the prod application code.- Add the below code to
portfolio-app-dev.yamlapiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: portfolio-app-dev-set namespace: argocd spec: generators: - list: elements: - cluster_url: 'https://E1AD8AA23D533C4F7577F7E5490B77F3.gr7.us-east-2.eks.amazonaws.com' environment: development target_revision: HEAD namespace: mywebapp region: us-east-1 template: metadata: name: portfolio-app-{{environment}}-{{region}} spec: destination: namespace: '{{namespace}}' server: '{{cluster_url}}' source: path: 'charts/portfolio-app' repoURL: 'https://github.com/Dhruvin4530/argoCD-Helm' targetRevision: '{{target_revision}}' helm: releaseName: portfolio-app valueFiles: - ./values/{{environment}}/values.yaml project: default syncPolicy: syncOptions: - CreateNamespace=true
Note: You need to change the cluster_url, repoURL, path, namespace & region as per yours
- The above code will create the application in the
argocdnamespace because all the resources of argoCD are deployed in the same namespace. mywebappis the namespace where argoCD will create the deployment and service for our applications.- For argoCD to create the namespace automatically we need to define
CreateNamespace=true - Add the below code to
portfolio-app-stg.yamlapiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: portfolio-app-stg-set namespace: argocd spec: generators: - list: elements: - cluster_url: 'https://C97142F25F1C99374E82B9D29D8F83A7.gr7.us-east-2.eks.amazonaws.com' environment: staging target_revision: HEAD namespace: mywebapp region: us-east-1 template: metadata: name: portfolio-app-{{environment}}-{{region}} spec: destination: namespace: '{{namespace}}' server: '{{cluster_url}}' source: path: 'charts/portfolio-app' repoURL: 'https://github.com/Dhruvin4530/argoCD-Helm' targetRevision: '{{target_revision}}' helm: releaseName: portfolio-app valueFiles: - ./values/{{environment}}/values.yaml project: default syncPolicy: syncOptions: - CreateNamespace=true
Note: You need to change the cluster_url, repoURL, path, namespace & region as per yours
- Add the below code to
portfolio-app-prod.yamlapiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: portfolio-app-prod-set namespace: argocd spec: generators: - list: elements: - cluster_url: 'https://4C0CD6FC11D6F8998E30C3E96E55B8F1.gr7.us-east-2.eks.amazonaws.com' environment: production target_revision: HEAD namespace: mywebapp region: us-east-1 template: metadata: name: portfolio-app-{{environment}}-{{region}} spec: destination: namespace: '{{namespace}}' server: '{{cluster_url}}' source: path: 'charts/portfolio-app' repoURL: 'https://github.com/Dhruvin4530/argoCD-Helm' targetRevision: '{{target_revision}}' helm: releaseName: portfolio-app valueFiles: - ./values/{{environment}}/values.yaml project: default syncPolicy: syncOptions: - CreateNamespace=true
Note: You need to change the cluster_url, repoURL, path, namespace & region as per yours
Now, our application code is ready. Now run the below commands to deploy the application.
kubectl apply -f portfolio-app-prod.yaml
kubectl apply -f portfolio-app-dev.yaml
kubectl apply -f portfolio-app-stg.yaml
Applications
- You can verify the resources from the backend as well.
[dhruvinsoni@Dhruvins-MacBook-Pro applications (⎈|dhsoni@prod-cluster.us-east-2.eksctl.io:N/A)]$ kubectl get all -n mywebapp NAME READY STATUS RESTARTS AGE pod/my-web-app-56d98fbf46-67rlm 1/1 Running 0 49m pod/my-web-app-56d98fbf46-fr99w 1/1 Running 0 49m pod/my-web-app-56d98fbf46-whthf 1/1 Running 0 49m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/my-web-app-prod LoadBalancer 10.100.210.5 af90ce8fb84f44d1aba678ae8bf70ea9-479334478.us-east-2.elb.amazonaws.com 80:30412/TCP 49m NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/my-web-app 3/3 3 3 49m NAME DESIRED CURRENT READY AGE replicaset.apps/my-web-app-56d98fbf46 3 3 3 49m [dhruvinsoni@Dhruvins-MacBook-Pro applications (⎈|dhsoni@prod-cluster.us-east-2.eksctl.io:N/A)]$ - The above are the resources for the production environment.

Production
- You can see 3 pods are running from the above snippet.
Step 8: Change the target revision¶
- Now, we can also set the different target revision for each environment.
- We can create a branch or a tag in the git repository and apply the changes to them and we can define them in the argoCD application file so that it will fetch the update from them.
- Now, let’s say we want 2 replicas for our application in the development environment, So instead of making changes to
HEAD, we can create a branch or a tag & change the replica count in the values file. - I’ve created a branch called
dev-application-v0.1and applied the changes to that branch.
Branch
Changes
Changes
Sync to a different branch
Changes
- The best practice is to set the target revision to a different branch or a tag in the production environment so if we accidentally made some false changes to that branch then we can always revert the changes to the HEAD branch.
- Now you can perform different changes as per your need and argoCD will take care of the further action.
- You can find the entire code here.
- Feel free to check out my other repositories as well.
Follow me on LinkedIn
Follow for more stories like this 😁
Stackademic 🎓¶
Thank you for reading until the end. Before you go:
- Please consider clapping and following the writer! 👏
- Follow us X | LinkedIn | YouTube | Discord
- Visit our other platforms: In Plain English | CoFeed | Venture | Cubed
- More content at Stackademic.com
Stackademic is a learning hub for programmers, devs, coders, and engineers. Our goal is to democratize free coding education for the world.
Senior Cloud Infrastructure Engineer | AWS | Automation | 2x AWS | CKA | Terraform Certified | k8s | Docker | CI/CD | http://dhsoni.info/
More from Dhruvin Soni and Stackademic¶
Recommended from Medium¶
[
See more recommendations
](https://medium.com/?source=post_page---read_next_recirc--d1de7b1d36e6---------------------------------------)








