Deploy NodeJS App Helm Chart on Minikube using GitHub Actions and ArgoCD

In this article we are going to cover Deploy NodeJS App Helm Chart on Minikube using GitHub Actions and ArgoCD

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
Deploy NodeJS App Helm Chart on Minikube using GitHub Actions and ArgoCD 1

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.
Deploy NodeJS App Helm Chart on Minikube using GitHub Actions and ArgoCD 2
Deploy NodeJS App Helm Chart on Minikube using GitHub Actions and ArgoCD 3

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

Deploy NodeJS App Helm Chart on Minikube using GitHub Actions and ArgoCD 4

Conclusion:

In this article we have covered Deploy NodeJS App Helm Chart on Minikube using GitHub Actions and ArgoCD

Related Articles:

How to Deploy Application on Minikube using ArgoCD CLI

Shweta Mamidwar

I am Shweta Mamidwar working as a Intern in Product Company. Likes to share knowledge.

3 thoughts on “Deploy NodeJS App Helm Chart on Minikube using GitHub Actions and ArgoCD”

  1. 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

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Share via
Copy link
Powered by Social Snap