DEV Community

vAIber
vAIber

Posted on

πŸš€ From Zero to Hero: Running Kubernetes Locally with ArgoCD, Helm, and Deploying a Fullstack Todo App (React + Express)

Welcome to the ultimate beginner-friendly guide. Whether you're just starting out or want to level up your DevOps game, this tutorial will take you from installing Kubernetes locally all the way to deploying a fullstack Todo app using GitOps via ArgoCD and Helm.


🏠 Why This Guide Matters

Modern development relies on container orchestration, CI/CD, and scalable deployments. Kubernetes and ArgoCD form a powerful duo for achieving that. This tutorial teaches you the basics and advanced steps while deploying a practical project: a fullstack Todo app.

You'll learn:

  • How to run Kubernetes locally using k3d
  • How to install and use ArgoCD for GitOps workflows
  • How to containerize apps with Docker
  • How to create Helm charts for deployments
  • How to deploy React and Express in a Kubernetes cluster

Let’s begin!


πŸ› οΈ Prerequisites

Make sure you have these installed on your machine:


βœ… Step 1: Set Up Kubernetes Locally with k3d

k3d lets you spin up a lightweight Kubernetes cluster inside Docker containers.

✨ Create a Cluster

k3d cluster create todo-cluster --servers 1 --agents 2 -p "8080:80@loadbalancer" -p "30080:30080@loadbalancer"
Enter fullscreen mode Exit fullscreen mode

This command:

  • Creates a cluster named todo-cluster
  • Sets up 1 server and 2 agents (worker nodes)
  • Forwards port 8080 (for app ingress) and 30080 (for ArgoCD)

βœ… Verify the Cluster

kubectl get nodes
Enter fullscreen mode Exit fullscreen mode

You should see 3 nodes listed: 1 control plane and 2 workers.


πŸŽ“ Step 2: Install ArgoCD (GitOps Engine)

ArgoCD enables continuous delivery into Kubernetes using Git repositories as the source of truth.

🏒 Install ArgoCD

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
Enter fullscreen mode Exit fullscreen mode

This installs ArgoCD into its own namespace.

πŸ“’ Expose the UI

kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "NodePort"}}'
kubectl get svc argocd-server -n argocd
Enter fullscreen mode Exit fullscreen mode

Use the listed NodePort (e.g., 30080) to access the UI at:

http://localhost:30080
Enter fullscreen mode Exit fullscreen mode

πŸ” Get the Admin Password

kubectl get secret argocd-initial-admin-secret -n argocd -o jsonpath="{.data.password}" | base64 -d
Enter fullscreen mode Exit fullscreen mode

Use username admin and this password to log in.


🎑 Step 3: Build the Todo App (React + Express)

We’ll create two folders:

  • backend/: Express server
  • frontend/: React app

🐞 Backend API

mkdir backend && cd backend
npm init -y
npm install express cors
Enter fullscreen mode Exit fullscreen mode

Create index.js:

const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.use(express.json());
let todos = [];
app.get('/api/todos', (req, res) => res.json(todos));
app.post('/api/todos', (req, res) => {
  const todo = req.body;
  todos.push(todo);
  res.status(201).json(todo);
});
app.listen(5000, () => console.log('API running on port 5000'));
Enter fullscreen mode Exit fullscreen mode

Add to package.json:

"scripts": {
  "start": "node index.js"
}
Enter fullscreen mode Exit fullscreen mode

πŸ”– Frontend (React)

cd ../
npx create-react-app frontend
cd frontend
Enter fullscreen mode Exit fullscreen mode

Modify src/App.js:

import React, { useEffect, useState } from 'react';
function App() {
  const [todos, setTodos] = useState([]);
  const [text, setText] = useState('');
  useEffect(() => {
    fetch('/api/todos').then(res => res.json()).then(setTodos);
  }, []);
  const addTodo = () => {
    fetch('/api/todos', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ text })
    }).then(res => res.json()).then(todo => setTodos([...todos, todo]));
  };
  return (
    <div>
      <h1>Todo App</h1>
      <input value={text} onChange={e => setText(e.target.value)} />
      <button onClick={addTodo}>Add</button>
      <ul>{todos.map((t, i) => <li key={i}>{t.text}</li>)}</ul>
    </div>
  );
}
export default App;
Enter fullscreen mode Exit fullscreen mode

Add this to frontend/package.json:

"proxy": "http://localhost:5000"
Enter fullscreen mode Exit fullscreen mode

πŸ“¦ Step 4: Dockerize Both Apps

Backend Dockerfile

FROM node:18
WORKDIR /app
COPY . .
RUN npm install
CMD ["npm", "start"]
Enter fullscreen mode Exit fullscreen mode

Frontend Dockerfile

FROM node:18 as builder
WORKDIR /app
COPY . .
RUN npm install && npm run build
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
Enter fullscreen mode Exit fullscreen mode

πŸš„ Step 5: Create Helm Chart

helm create todo-chart
Enter fullscreen mode Exit fullscreen mode

This scaffolds a Helm chart with template files.

Modify values.yaml to include image info:

backend:
  image:
    repository: your-dockerhub-user/todo-backend
    tag: latest
frontend:
  image:
    repository: your-dockerhub-user/todo-frontend
    tag: latest
Enter fullscreen mode Exit fullscreen mode

In templates/, create separate deployment & service files for both frontend and backend.


πŸš— Step 6: Ingress and Push Images

Build and Push Docker Images

docker build -t your-dockerhub-user/todo-backend ./backend
docker build -t your-dockerhub-user/todo-frontend ./frontend
docker push your-dockerhub-user/todo-backend
docker push your-dockerhub-user/todo-frontend
Enter fullscreen mode Exit fullscreen mode

Install Ingress Controller

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.1/deploy/static/provider/k3d/deploy.yaml
Enter fullscreen mode Exit fullscreen mode

Ingress YAML (todo-ingress.yaml)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: todo-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: todo.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend
            port:
              number: 80
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: backend
            port:
              number: 5000
Enter fullscreen mode Exit fullscreen mode

Add to /etc/hosts:

127.0.0.1 todo.local
Enter fullscreen mode Exit fullscreen mode

πŸ§™β€β™‚οΈ Step 7: Deploy with ArgoCD

Push the repo to GitHub.
Then create an ArgoCD Application:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: todo-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/YOUR_USERNAME/todo-app
    targetRevision: HEAD
    path: todo-chart
  destination:
    server: https://kubernetes.default.svc
    namespace: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
Enter fullscreen mode Exit fullscreen mode

Apply:

kubectl apply -f argocd-app.yaml
Enter fullscreen mode Exit fullscreen mode

πŸŽ‰ Step 8: Access the App

Open:

http://todo.local
Enter fullscreen mode Exit fullscreen mode

You should see your live, GitOps-powered, fully deployed React + Express Todo app!


πŸ“Š Next Steps

  • Add persistent storage for todos
  • Add authentication
  • Add CI workflow (GitHub Actions)
  • Configure TLS for Ingress
  • Split Helm chart into subcharts

✨ You Did It!

You:

  • Ran Kubernetes locally
  • Installed and used ArgoCD
  • Built and containerized a fullstack app
  • Used Helm to manage Kubernetes manifests
  • Automated everything via GitOps

High five ✌️ and happy hacking!

Top comments (0)