In this article we are going to cover Deploy NodeJS App Helm Chart on Minikube using GitHub Actions and ArgoCD
Table of Contents
Prerequisites:
- AWS Account(Ubuntu EC2 configured)
- Install Git
- Install NodeJS and NPM
- Install Docker
- Install Minikube
- Install kubectl
- Install Helm
- Install ArgoCD
Step #1:Install ArgoCD on Minikube
Follow these steps to install Argo CD
We are using driver as docker
minikube start --driver=docker
Just like other Kubernetes tools, ArgoCD requires a namespace with its name. Therefore, we will create a namespace for argocd.
kubectl create ns argocd
ArgoCD can be installed using its manifests. First, you’ll need to download these manifests and apply them to your Minikube cluster.
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
Step #2:Install Helm on Minikube
Helm simplifies deploying and managing applications on Kubernetes. Let’s configure Helm and add the necessary repositories:
Install Helm
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
Add the official Helm repository:
helm repo add stable https://charts.helm.sh/stable
Update the Helm repositories:
helm repo update
Step #3:Create NodeJS application
Now that we have Argo CD and Helm configured, let’s set up our application using the provided code. We will package it into a Docker container and define the necessary configuration files.
Create a file named service.js
and copy the following code into it
const express = require('express');
const app = express();
const port = 3000;
app.listen(port);
console.log(`App running at http://localhost:${port}`);
app.get('/health', (req, res) => {
res.send('OK');
res.status(200);
});
app.get('/', (req, res) => {
const name = process.env.NAME || 'World';
res.send(`Hello ${name}!`);
});
Create a file named package.json
and copy the following code into it:
{
"name": "app",
"version": "1.0.0",
"main": "service.js",
"repository": "",
"scripts": {
"start": "node service.js"
},
"dependencies": {
"express": "^4.16.2"
}
}
Step #4:Create Dockerfile, Docker Image and Container for NodeJS Application
Create a file named Dockerfile
and copy the following code into it:
FROM node:16-alpine
WORKDIR /src
COPY . .
RUN npm install --quiet
EXPOSE 3000
CMD npm start
Build the Docker image:
docker build -t node-app:latest .
Test the application locally:
docker run -p 3000:3000 node-app:latest
Step #5:Create Helm Chart for NodeJS application and modify helm chart file
Initialize a new Helm chart:
helm create nodeapp
This will create a new directory named nodeapp with the basic structure of a Helm chart.
Modify the Helm chart files according to our application’s requirements.
Update nodeapp/templates/deployment.yaml
: Replace the content of the file with the following code:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "helm.fullname" . }}
labels:
{{- include "helm.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "helm.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "helm.labels" . | nindent 8 }}
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "helm.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.env.APP_VERSION | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.port }}
protocol: TCP
livenessProbe:
{{- toYaml .Values.livenessProbe | nindent 12 }}
readinessProbe:
{{- toYaml .Values.readinessProbe | nindent 12 }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.volumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
Update nodeapp/templates/service.yaml
: Replace the content of the file with the following code:
apiVersion: v1
kind: Service
metadata:
name: {{ include "helm.fullname" . }}
labels:
{{- include "helm.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "helm.selectorLabels" . | nindent 4 }}
Update the values.yaml
file located in nodeapp
directory:
# Default values for helm.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: devopshint/node-app
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
# Specifies whether a service account should be created
create: true
# Automatically mount a ServiceAccount's API credentials?
automount: true
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
podAnnotations: {}
podLabels: {}
env:
APP_VERSION: 6994f1633e5cd2f29b845046507e606df9cc247b
podSecurityContext: {}
# fsGroup: 2000
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
type: NodePort
port: 3000
targetPort: 3000
protocol: TCP
ingress:
enabled: false
className: ""
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: chart-example.local
paths:
- path: /
pathType: ImplementationSpecific
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80
# Additional volumes on the output Deployment definition.
volumes: []
# - name: foo
# secret:
# secretName: mysecret
# optional: false
# Additional volumeMounts on the output Deployment definition.
volumeMounts: []
# - name: foo
# mountPath: "/etc/foo"
# readOnly: true
nodeSelector: {}
tolerations: []
affinity: {}
Step #6:Push NodeJS code and Dockerfile to GitHub Repo
- Create new repo in GitHub
- Click on the “New” button to create a new repository.
- Provide a name for your repository.
- Optionally, add a description and choose the repository visibility settings.
- Click on the “Create repository” button to create the repository.
Initialize Git and link the repository:
- Open a terminal or command prompt.
- Navigate to the root directory of your application.
- Commit and push the application code
Stage the changes by running the following command:
git add .
Commit the changes with a meaningful message by running the following command:
git commit -m "Initial commit"
Push the code to the remote repository by running the following command:
git push -u origin main
Step #7:Access the Argo CD UI
Run the following command to port forward the Argo CD UI to your local machine:
kubectl port-forward svc/argocd-server -n argocd --address 0.0.0.0 8080:443
Open your browser and navigate to http://localhost:8080 to access the Argo CD UI.
Retrieve the Argo CD admin password by running the following command:
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
Step #8:Deploy NodeJS Application on Minikube using GitHub Actions and ArgoCD
- In your GitHub repository, create the directory
.github/workflows
- Create a new file named
cd.yaml
and open it for editing.
name: CD
on:
push:
branches:
- main
env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKERHUB_KEY: ${{ secrets.DOCKER_KEY }}
IMAGE_NAME: node-app
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ env.DOCKERHUB_USERNAME }}
password: ${{ env.DOCKERHUB_KEY }}
- name: Build Docker image
run: docker build -t ${{ env.DOCKERHUB_USERNAME }}/${{ env.IMAGE_NAME }}:${{ github.sha }} .
- name: Push Docker image
run: docker push ${{ env.DOCKERHUB_USERNAME }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
- name: Update values.yaml
run: |
cd helm
sed -i 's|APP_VERSION:.*|APP_VERSION: '${{ github.sha }}'|' values.yaml
git config --global user.name 'devopshint'
git config --global user.email '[email protected]'
git add values.yaml
git commit -m "Update values.yaml"
git push
Configure Docker Hub and GitHub secrets
- In your GitHub repository, go to the “Settings” tab.
- In the left sidebar, click on “Secrets”.
- Click on the “New repository secret” button.
- Add the following secrets:
- Name:
DOCKER_USERNAME
, Value: [Your Docker Hub username] - Name:
DOCKER_KEY
, Value: [Your Docker Hub access token or password] - Click on the “Add secret” button to save the secrets.
Update GitHub Actions permissions:
- In your GitHub repository, go to the “Settings” tab.
- In the left sidebar, click on “Actions”.
- Under the “Permissions” section, make sure that the following permissions are enabled:
- Write, Read, Run workflows, Manage workflows
- If any permissions are not enabled, click on the “Enable” button next to each permission to grant access.
Step #9:Deploy NodeJS Application on Minikube using ArgoCD
- Click on the “Applications” tab in the top navigation bar.
- Click on the “New Application” button.
- Configure the following settings:
- Application Name: Enter a name for your application (e.g., “my-app”).
- Project: Choose the default project or create a new project.
- Repository: Enter the URL of your GitHub repository.
- Path: Enter the path to the Helm chart directory (e.g.,
helm/
). - Cluster URL: Select the target Kubernetes cluster.
- Namespace: Enter the target namespace for deployment (e.g.,
default
). - Values Files: Specify the path to your
values.yaml
file if you have custom values.
Lets Forward the port to access our image in browser
kubectl port-forward svc/nodeapp-helm --address 0.0.0.0 3000:3000
ubuntu@ip-172-31-41-16:~$ kubectl port-forward svc/test-nodeapp --address 0.0.0.0 3000:3000
Forwarding from 0.0.0.0:3000 -> 3000
Handling connection for 3000
Handling connection for 3000
Handling connection for 3000
Access NodeJS application on browser using Minikube IP and port Number
Conclusion:
In this article we have covered Deploy NodeJS App Helm Chart on Minikube using GitHub Actions and ArgoCD
Related Articles:
It will best not to create monorepo which means helm chart should be in different repository.
Yes, this is simple project, we should keep helm chart in different repo. Thanks
And also this subject:
Step #2:Install Helm on Minikube
its confusing. Helm is not installed on Minikube but on localhost who is running the helm cli