{"id":27075856,"url":"https://github.com/bhanreddy1973/kubernetes-fullstack-todoweb","last_synced_at":"2026-04-10T11:02:25.628Z","repository":{"id":286346873,"uuid":"961127767","full_name":"bhanreddy1973/kubernetes-fullstack-Todoweb","owner":"bhanreddy1973","description":"This project is a full-stack web application designed to manage tasks, built using React for the frontend, Node.js for the backend, and MySQL as the database. The application is containerized using Docker and deployed on Kubernetes using Minikube.","archived":false,"fork":false,"pushed_at":"2025-04-05T20:56:42.000Z","size":1498,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-09T20:05:32.382Z","etag":null,"topics":["axios","docker","express","kubernetes","minikube","mysql","nginx","nodejs","reactjs"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bhanreddy1973.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-04-05T20:12:40.000Z","updated_at":"2025-04-05T20:58:53.000Z","dependencies_parsed_at":"2025-04-05T21:39:37.230Z","dependency_job_id":null,"html_url":"https://github.com/bhanreddy1973/kubernetes-fullstack-Todoweb","commit_stats":null,"previous_names":["bhanreddy1973/kubernetes-fullstack-todoweb"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhanreddy1973%2Fkubernetes-fullstack-Todoweb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhanreddy1973%2Fkubernetes-fullstack-Todoweb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhanreddy1973%2Fkubernetes-fullstack-Todoweb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhanreddy1973%2Fkubernetes-fullstack-Todoweb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bhanreddy1973","download_url":"https://codeload.github.com/bhanreddy1973/kubernetes-fullstack-Todoweb/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248103872,"owners_count":21048245,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["axios","docker","express","kubernetes","minikube","mysql","nginx","nodejs","reactjs"],"created_at":"2025-04-06T00:18:11.485Z","updated_at":"2026-04-10T11:02:25.611Z","avatar_url":"https://github.com/bhanreddy1973.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Full-Stack Web Application Kubernetes Deployment\n\n**Author:** Bhanu Reddy  \n**Roll No:** 2022bcd0026\n\nThis repository contains all the necessary files to containerize and deploy a full-stack web application (React frontend, Node.js backend, MySQL database) using Minikube.\n## Key Features\n-Frontend: A React-based user interface for managing tasks (CRUD operations).\n- Backend: A Node.js Express API that connects to the MySQL database and handles business logic.\n- Database: MySQL database for storing tasks with persistent storage.\n- Containerization: Dockerized services for consistent deployment.\n- Orchestration: Kubernetes manifests for deploying and managing the application components.\n\n## Technologies Used\n- Frontend: React, Axios, Nginx\n- Backend: Node.js, Express\n- Database: MySQL\n- Containerization: Docker\n- Orchestration: Kubernetes (Minikube)\n\n## Deployment\nThe application is deployed on Kubernetes with the following components:\n\n- MySQL: Configured with PersistentVolume and initialized with a script.\n- Backend: Exposed as a ClusterIP service.\n- Frontend: Exposed as a NodePort service for external access\n\n## Table of Contents\n- [Project Overview](#project-overview)\n- [Prerequisites](#prerequisites)\n- [Project Structure](#project-structure)\n- [Step 1: Setting Up the Application](#step-1-setting-up-the-application)\n  - [Backend Setup](#backend-setup)\n  - [Frontend Setup](#frontend-setup)\n  - [Database Setup](#database-setup)\n- [Step 2: Containerization](#step-2-containerization)\n  - [Backend Dockerfile](#backend-dockerfile)\n  - [Frontend Dockerfile](#frontend-dockerfile)\n  - [Building Images](#building-images)\n- [Step 3: Kubernetes Configuration](#step-3-kubernetes-configuration)\n  - [MySQL Deployment](#mysql-deployment)\n  - [Backend Deployment](#backend-deployment)\n  - [Frontend Deployment](#frontend-deployment)\n  - [ConfigMaps and Secrets](#configmaps-and-secrets)\n  - [Persistent Volumes](#persistent-volumes)\n  - [Services](#services)\n- [Step 4: Deploying to Minikube](#step-4-deploying-to-minikube)\n- [Step 5: Testing the Application](#step-5-testing-the-application)\n- [Troubleshooting](#troubleshooting)\n- [Cleaning Up](#cleaning-up)\n\n## Project Overview\n\nThis project demonstrates how to:\n1. Create a simple full-stack application with React, Node.js, and MySQL\n2. Containerize each component with Docker\n3. Configure and deploy the application on Kubernetes using Minikube\n4. Set up proper communication between components using Kubernetes Services\n5. Manage configuration and secrets using Kubernetes ConfigMaps and Secrets\n6. Create persistent storage for database data\n\n## Prerequisites\n\nEnsure you have the following installed on your system:\n- Docker\n- Minikube\n- kubectl\n- Node.js and npm\n- Git\n\n## Project Structure\n\n```\nkubernetes-fullstack-app/\n├── backend/                     # Node.js backend\n│   ├── src/\n│   │   ├── controllers/\n│   │   ├── models/\n│   │   ├── routes/\n│   │   └── app.js\n│   ├── package.json\n│   ├── Dockerfile\n│   └── .env\n├── frontend/                    # React frontend\n│   ├── public/\n│   ├── src/\n│   ├── package.json\n│   ├── Dockerfile\n│   └── .env\n├── k8s/                         # Kubernetes configuration files\n│   ├── mysql/\n│   │   ├── mysql-configmap.yaml\n│   │   ├── mysql-secret.yaml\n│   │   ├── mysql-pv.yaml\n│   │   ├── mysql-pvc.yaml\n│   │   ├── mysql-deployment.yaml\n│   │   └── mysql-service.yaml\n│   ├── backend/\n│   │   ├── backend-configmap.yaml\n│   │   ├── backend-deployment.yaml\n│   │   └── backend-service.yaml\n│   └── frontend/\n│       ├── frontend-configmap.yaml\n│       ├── frontend-deployment.yaml\n│       └── frontend-service.yaml\n├── docker-compose.yaml          # Docker Compose configuration\n└── README.md                    # This file\n```\n![alt text](image-32.png)\n\n## Step 1: Setting Up the Application\n\n### Backend Setup\n\n1. Create a Node.js Express application:\n\n```bash\nmkdir -p backend/src\ncd backend\nnpm init -y\nnpm install express mysql2 cors dotenv\ntouch src/app.js\n```\n\n2. Create a simple CRUD API in `src/app.js`:\n\n```javascript\nconst express = require('express');\nconst mysql = require('mysql2/promise');\nconst cors = require('cors');\nrequire('dotenv').config();\n\nconst app = express();\napp.use(cors());\napp.use(express.json());\n\n// MySQL connection pool\nconst pool = mysql.createPool({\n  host: process.env.DB_HOST || 'mysql',\n  user: process.env.DB_USER || 'root',\n  password: process.env.DB_PASSWORD || 'password',\n  database: process.env.DB_NAME || 'tasksdb',\n  waitForConnections: true,\n  connectionLimit: 10,\n  queueLimit: 0\n});\n\n// Health check endpoint\napp.get('/api/health', (req, res) =\u003e {\n  res.status(200).json({ status: 'healthy' });\n});\n\n// Get all tasks\napp.get('/api/tasks', async (req, res) =\u003e {\n  try {\n    const [rows] = await pool.query('SELECT * FROM tasks');\n    res.json(rows);\n  } catch (error) {\n    console.error('Error fetching tasks:', error);\n    res.status(500).json({ error: 'Failed to fetch tasks' });\n  }\n});\n\n// Get a specific task\napp.get('/api/tasks/:id', async (req, res) =\u003e {\n  try {\n    const [rows] = await pool.query('SELECT * FROM tasks WHERE id = ?', [req.params.id]);\n    if (rows.length === 0) {\n      return res.status(404).json({ error: 'Task not found' });\n    }\n    res.json(rows[0]);\n  } catch (error) {\n    console.error('Error fetching task:', error);\n    res.status(500).json({ error: 'Failed to fetch task' });\n  }\n});\n\n// Create a new task\napp.post('/api/tasks', async (req, res) =\u003e {\n  const { title, description } = req.body;\n  \n  if (!title) {\n    return res.status(400).json({ error: 'Title is required' });\n  }\n  \n  try {\n    const [result] = await pool.query(\n      'INSERT INTO tasks (title, description) VALUES (?, ?)',\n      [title, description || '']\n    );\n    \n    res.status(201).json({\n      id: result.insertId,\n      title,\n      description: description || ''\n    });\n  } catch (error) {\n    console.error('Error creating task:', error);\n    res.status(500).json({ error: 'Failed to create task' });\n  }\n});\n\n// Update a task\napp.put('/api/tasks/:id', async (req, res) =\u003e {\n  const { title, description } = req.body;\n  \n  try {\n    const [result] = await pool.query(\n      'UPDATE tasks SET title = ?, description = ? WHERE id = ?',\n      [title, description || '', req.params.id]\n    );\n    \n    if (result.affectedRows === 0) {\n      return res.status(404).json({ error: 'Task not found' });\n    }\n    \n    res.json({ id: req.params.id, title, description });\n  } catch (error) {\n    console.error('Error updating task:', error);\n    res.status(500).json({ error: 'Failed to update task' });\n  }\n});\n\n// Delete a task\napp.delete('/api/tasks/:id', async (req, res) =\u003e {\n  try {\n    const [result] = await pool.query('DELETE FROM tasks WHERE id = ?', [req.params.id]);\n    \n    if (result.affectedRows === 0) {\n      return res.status(404).json({ error: 'Task not found' });\n    }\n    \n    res.status(204).end();\n  } catch (error) {\n    console.error('Error deleting task:', error);\n    res.status(500).json({ error: 'Failed to delete task' });\n  }\n});\n\n// Initialize database function\nasync function initDb() {\n  try {\n    // Create connection to MySQL server (without database selection)\n    const tempPool = mysql.createPool({\n      host: process.env.DB_HOST || 'mysql',\n      user: process.env.DB_USER || 'root',\n      password: process.env.DB_PASSWORD || 'password',\n      waitForConnections: true,\n      connectionLimit: 10,\n      queueLimit: 0\n    });\n    \n    // Create database if it doesn't exist\n    await tempPool.query(`CREATE DATABASE IF NOT EXISTS ${process.env.DB_NAME || 'tasksdb'}`);\n    \n    // Connect to the database\n    await pool.query(`\n      CREATE TABLE IF NOT EXISTS tasks (\n        id INT AUTO_INCREMENT PRIMARY KEY,\n        title VARCHAR(255) NOT NULL,\n        description TEXT,\n        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n      )\n    `);\n    \n    console.log('Database and tables initialized successfully');\n  } catch (error) {\n    console.error('Error initializing database:', error);\n    // Retry after delay\n    setTimeout(initDb, 5000);\n  }\n}\n\nconst PORT = process.env.PORT || 5000;\napp.listen(PORT, () =\u003e {\n  console.log(`Server running on port ${PORT}`);\n  // Initialize database\n  initDb();\n});\n```\n\n3. Create a `package.json` file:\n\n```json\n{\n  \"name\": \"backend-2022bcd0026-bhanu-reddy\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Backend API for task management\",\n  \"main\": \"src/app.js\",\n  \"scripts\": {\n    \"start\": \"node src/app.js\",\n    \"dev\": \"nodemon src/app.js\"\n  },\n  \"dependencies\": {\n    \"cors\": \"^2.8.5\",\n    \"dotenv\": \"^16.0.3\",\n    \"express\": \"^4.18.2\",\n    \"mysql2\": \"^3.2.0\"\n  },\n  \"devDependencies\": {\n    \"nodemon\": \"^2.0.22\"\n  }\n}\n```\n\n### Frontend Setup\n\n1. Create a React application:\n\n```bash\nnpx create-react-app frontend\ncd frontend\nnpm install axios\n```\n\n2. Replace the content of `src/App.js` with:\n\n```jsx\nimport React, { useState, useEffect } from 'react';\nimport axios from 'axios';\nimport './App.css';\n\nconst API_URL = process.env.REACT_APP_API_URL || 'http://localhost:5000/api';\n\nfunction App() {\n  const [tasks, setTasks] = useState([]);\n  const [newTask, setNewTask] = useState({ title: '', description: '' });\n  const [editingTask, setEditingTask] = useState(null);\n  const [loading, setLoading] = useState(true);\n  const [error, setError] = useState(null);\n\n  // Fetch tasks on component mount\n  useEffect(() =\u003e {\n    fetchTasks();\n  }, []);\n\n  const fetchTasks = async () =\u003e {\n    try {\n      setLoading(true);\n      const response = await axios.get(`${API_URL}/tasks`);\n      setTasks(response.data);\n      setError(null);\n    } catch (err) {\n      console.error('Error fetching tasks:', err);\n      setError('Failed to fetch tasks. Please try again later.');\n    } finally {\n      setLoading(false);\n    }\n  };\n\n  const handleInputChange = (e) =\u003e {\n    const { name, value } = e.target;\n    setNewTask({ ...newTask, [name]: value });\n  };\n\n  const handleEditChange = (e) =\u003e {\n    const { name, value } = e.target;\n    setEditingTask({ ...editingTask, [name]: value });\n  };\n\n  const createTask = async (e) =\u003e {\n    e.preventDefault();\n    if (!newTask.title.trim()) return;\n\n    try {\n      await axios.post(`${API_URL}/tasks`, newTask);\n      setNewTask({ title: '', description: '' });\n      fetchTasks();\n    } catch (err) {\n      console.error('Error creating task:', err);\n      setError('Failed to create task. Please try again.');\n    }\n  };\n\n  const startEditing = (task) =\u003e {\n    setEditingTask({ ...task });\n  };\n\n  const cancelEditing = () =\u003e {\n    setEditingTask(null);\n  };\n\n  const updateTask = async (e) =\u003e {\n    e.preventDefault();\n    if (!editingTask.title.trim()) return;\n\n    try {\n      await axios.put(`${API_URL}/tasks/${editingTask.id}`, {\n        title: editingTask.title,\n        description: editingTask.description\n      });\n      setEditingTask(null);\n      fetchTasks();\n    } catch (err) {\n      console.error('Error updating task:', err);\n      setError('Failed to update task. Please try again.');\n    }\n  };\n\n  const deleteTask = async (id) =\u003e {\n    if (!window.confirm('Are you sure you want to delete this task?')) return;\n\n    try {\n      await axios.delete(`${API_URL}/tasks/${id}`);\n      fetchTasks();\n    } catch (err) {\n      console.error('Error deleting task:', err);\n      setError('Failed to delete task. Please try again.');\n    }\n  };\n\n  return (\n    \u003cdiv className=\"App\"\u003e\n      \u003cheader className=\"App-header\"\u003e\n        \u003ch1\u003eTask Manager\u003c/h1\u003e\n        \u003ch2\u003eby Bhanu Reddy (2022bcd0026)\u003c/h2\u003e\n      \u003c/header\u003e\n\n      \u003cdiv className=\"container\"\u003e\n        {error \u0026\u0026 \u003cdiv className=\"error-message\"\u003e{error}\u003c/div\u003e}\n\n        \u003cdiv className=\"form-container\"\u003e\n          \u003ch2\u003eAdd New Task\u003c/h2\u003e\n          \u003cform onSubmit={createTask}\u003e\n            \u003cdiv className=\"form-group\"\u003e\n              \u003clabel htmlFor=\"title\"\u003eTitle:\u003c/label\u003e\n              \u003cinput\n                type=\"text\"\n                id=\"title\"\n                name=\"title\"\n                value={newTask.title}\n                onChange={handleInputChange}\n                required\n              /\u003e\n            \u003c/div\u003e\n            \u003cdiv className=\"form-group\"\u003e\n              \u003clabel htmlFor=\"description\"\u003eDescription:\u003c/label\u003e\n              \u003ctextarea\n                id=\"description\"\n                name=\"description\"\n                value={newTask.description}\n                onChange={handleInputChange}\n              /\u003e\n            \u003c/div\u003e\n            \u003cbutton type=\"submit\" className=\"btn\"\u003eAdd Task\u003c/button\u003e\n          \u003c/form\u003e\n        \u003c/div\u003e\n\n        \u003cdiv className=\"tasks-container\"\u003e\n          \u003ch2\u003eTasks\u003c/h2\u003e\n          {loading ? (\n            \u003cp\u003eLoading tasks...\u003c/p\u003e\n          ) : tasks.length === 0 ? (\n            \u003cp\u003eNo tasks found. Add a new task to get started.\u003c/p\u003e\n          ) : (\n            \u003cul className=\"tasks-list\"\u003e\n              {tasks.map((task) =\u003e (\n                \u003cli key={task.id} className=\"task-item\"\u003e\n                  {editingTask \u0026\u0026 editingTask.id === task.id ? (\n                    \u003cform onSubmit={updateTask} className=\"edit-form\"\u003e\n                      \u003cdiv className=\"form-group\"\u003e\n                        \u003clabel htmlFor={`edit-title-${task.id}`}\u003eTitle:\u003c/label\u003e\n                        \u003cinput\n                          type=\"text\"\n                          id={`edit-title-${task.id}`}\n                          name=\"title\"\n                          value={editingTask.title}\n                          onChange={handleEditChange}\n                          required\n                        /\u003e\n                      \u003c/div\u003e\n                      \u003cdiv className=\"form-group\"\u003e\n                        \u003clabel htmlFor={`edit-description-${task.id}`}\u003eDescription:\u003c/label\u003e\n                        \u003ctextarea\n                          id={`edit-description-${task.id}`}\n                          name=\"description\"\n                          value={editingTask.description}\n                          onChange={handleEditChange}\n                        /\u003e\n                      \u003c/div\u003e\n                      \u003cdiv className=\"button-group\"\u003e\n                        \u003cbutton type=\"submit\" className=\"btn save\"\u003eSave\u003c/button\u003e\n                        \u003cbutton type=\"button\" className=\"btn cancel\" onClick={cancelEditing}\u003eCancel\u003c/button\u003e\n                      \u003c/div\u003e\n                    \u003c/form\u003e\n                  ) : (\n                    \u003c\u003e\n                      \u003cdiv className=\"task-content\"\u003e\n                        \u003ch3\u003e{task.title}\u003c/h3\u003e\n                        \u003cp\u003e{task.description}\u003c/p\u003e\n                        \u003csmall\u003eCreated: {new Date(task.created_at).toLocaleString()}\u003c/small\u003e\n                      \u003c/div\u003e\n                      \u003cdiv className=\"task-actions\"\u003e\n                        \u003cbutton onClick={() =\u003e startEditing(task)} className=\"btn edit\"\u003eEdit\u003c/button\u003e\n                        \u003cbutton onClick={() =\u003e deleteTask(task.id)} className=\"btn delete\"\u003eDelete\u003c/button\u003e\n                      \u003c/div\u003e\n                    \u003c/\u003e\n                  )}\n                \u003c/li\u003e\n              ))}\n            \u003c/ul\u003e\n          )}\n        \u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n\nexport default App;\n```\n\n3. Add some basic styling in `src/App.css`:\n\n```css\n.App {\n  text-align: center;\n  font-family: Arial, sans-serif;\n}\n\n.App-header {\n  background-color: #282c34;\n  padding: 20px;\n  color: white;\n}\n\n.container {\n  max-width: 1200px;\n  margin: 0 auto;\n  padding: 20px;\n}\n\n.form-container {\n  background-color: #f5f5f5;\n  padding: 20px;\n  border-radius: 8px;\n  margin-bottom: 20px;\n}\n\n.form-group {\n  margin-bottom: 15px;\n  text-align: left;\n}\n\n.form-group label {\n  display: block;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\n\n.form-group input,\n.form-group textarea {\n  width: 100%;\n  padding: 8px;\n  border: 1px solid #ddd;\n  border-radius: 4px;\n}\n\n.btn {\n  background-color: #4CAF50;\n  color: white;\n  border: none;\n  padding: 10px 15px;\n  cursor: pointer;\n  border-radius: 4px;\n  font-size: 16px;\n}\n\n.btn:hover {\n  background-color: #45a049;\n}\n\n.tasks-list {\n  list-style: none;\n  padding: 0;\n}\n\n.task-item {\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 8px;\n  margin-bottom: 15px;\n  padding: 15px;\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n}\n\n.task-content {\n  text-align: left;\n  flex-grow: 1;\n}\n\n.task-content h3 {\n  margin-top: 0;\n}\n\n.task-content p {\n  color: #666;\n}\n\n.task-actions {\n  display: flex;\n  gap: 10px;\n}\n\n.edit {\n  background-color: #2196F3;\n}\n\n.edit:hover {\n  background-color: #0b7dda;\n}\n\n.delete {\n  background-color: #f44336;\n}\n\n.delete:hover {\n  background-color: #d32f2f;\n}\n\n.save {\n  background-color: #4CAF50;\n}\n\n.cancel {\n  background-color: #9e9e9e;\n}\n\n.edit-form {\n  width: 100%;\n}\n\n.button-group {\n  display: flex;\n  gap: 10px;\n  justify-content: flex-end;\n}\n\n.error-message {\n  background-color: #ffebee;\n  color: #c62828;\n  padding: 10px;\n  border-radius: 4px;\n  margin-bottom: 20px;\n}\n```\n\n### Database Setup\n\nWe'll be using MySQL as our database. The database initialization will be handled by our backend application, but we need to prepare the Kubernetes files for it.\n\n## Step 2: Containerization\n\n### Backend Dockerfile\n\nCreate a `Dockerfile` in the backend directory:\n\n```Dockerfile\nFROM node:18-alpine\n\nWORKDIR /app\n\nCOPY package*.json ./\n\nRUN npm install --production\n\nCOPY . .\n\nEXPOSE 5000\n\nCMD [\"node\", \"src/app.js\"]\n```\n\n### Frontend Dockerfile\n\nCreate a `Dockerfile` in the frontend directory:\n\n```Dockerfile\n# Stage 1: Build the React application\nFROM node:18-alpine AS build\n\nWORKDIR /app\n\nCOPY package*.json ./\n\nRUN npm install\n\nCOPY . .\n\n# Pass the correct backend API URL as a build argument\nARG REACT_APP_API_URL=http://192.168.58.2:30001/api\nENV REACT_APP_API_URL=${REACT_APP_API_URL}\n\nRUN npm run build\n\n# Stage 2: Serve the React application using Nginx\nFROM nginx:alpine\n\nCOPY --from=build /app/build /usr/share/nginx/html\n\n# Expose port 80\nEXPOSE 80\n\nCMD [\"nginx\", \"-g\", \"daemon off;\"]\n```\n\n### Building Images\n\n```bash\n# Build backend image\ncd backend\ndocker build -t bhanureddy1973/backend-2022bcd0026:latest .\n```\n### Push the image to a container registry (if necessary):\n```bash\ndocker push bhanureddy1973/backend-2022bcd0026:latest\n```\n![alt text](image.png)\n```bash\n# Build frontend image\ncd ../frontend\ndocker build -t bhanureddy1973/frontend-2022bcd0026-bhanu-reddy:latest .\n```\n### Push the image to a container registry (if necessary):\n```bash\ndocker push bhanureddy1973/frontend-2022bcd0026-bhanu-reddy:latest\n```\n![alt text](image-1.png)\n\n## Step 3: Kubernetes Configuration\n\n### Create Kubernetes Configuration Files\n\nLet's create the necessary Kubernetes configuration files.\n\n#### MySQL ConfigMap, Secret, and PV/PVC\n\n`k8s/mysql/mysql-configmap.yaml`:\n\n```yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: db-config-2022bcd0026\ndata:\n  DB_HOST: mysql\n  DB_NAME: tasksdb\n```\n\n`k8s/mysql/mysql-secret.yaml`:\n\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n  name: mysql-secret-2022bcd0026\ntype: Opaque\ndata:\n  mysql-root-password: cGFzc3dvcmQ=  # 'password' encoded in base64\n  mysql-user: cm9vdA==  # 'root' encoded in base64\n  mysql-password: cGFzc3dvcmQ=  # 'password' encoded in base64\n```\n\n`k8s/mysql/mysql-pv.yaml`:\n\n```yaml\napiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: mysql-pv-2022bcd0026\n  labels:\n    type: local\nspec:\n  storageClassName: manual\n  capacity:\n    storage: 1Gi\n  accessModes:\n    - ReadWriteOnce\n  hostPath:\n    path: \"/mnt/data\"\n```\n\n`k8s/mysql/mysql-pvc.yaml`:\n\n```yaml\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: mysql-pvc-2022bcd0026\nspec:\n  storageClassName: manual\n  accessModes:\n    - ReadWriteOnce\n  resources:\n    requests:\n      storage: 1Gi\n```\n\n`k8s/mysql/mysql-deployment.yaml`:\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: mysql-2022bcd0026\nspec:\n  selector:\n    matchLabels:\n      app: mysql\n      owner: 2022bcd0026\n  strategy:\n    type: Recreate\n  template:\n    metadata:\n      labels:\n        app: mysql\n        owner: 2022bcd0026\n    spec:\n      containers:\n      - image: mysql:8.0\n        name: mysql\n        env:\n        - name: MYSQL_ROOT_PASSWORD\n          valueFrom:\n            secretKeyRef:\n              name: mysql-secret-2022bcd0026\n              key: mysql-root-password\n        - name: MYSQL_DATABASE\n          valueFrom:\n            configMapKeyRef:\n              name: db-config-2022bcd0026\n              key: DB_NAME\n        ports:\n        - containerPort: 3306\n          name: mysql\n        volumeMounts:\n        - name: mysql-persistent-storage\n          mountPath: /var/lib/mysql\n          - name: init-script\n          mountPath: /docker-entrypoint-initdb.d/\n        resources:\n          requests:\n            memory: \"256Mi\"\n            cpu: \"250m\"\n      volumes:\n      - name: mysql-persistent-storage\n        persistentVolumeClaim:\n          claimName: mysql-pvc-2022bcd0026\n       - name: init-script\n        configMap:\n          name: mysql-init-script\n```\n\n`k8s/mysql/mysql-service.yaml`:\n\n```yaml\napiVersion: v1\nkind: Service\nmetadata:\n  name: mysql-2022bcd0026\nspec:\n  selector:\n    app: mysql\n    owner: 2022bcd0026\n  ports:\n    - protocol: TCP\n      port: 3306\n      targetPort: 3306\n  clusterIP: None\n\n```\n\n#### Backend ConfigMap and Deployment\n\n`k8s/backend/backend-configmap.yaml`:\n\n```yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: backend-config\ndata:\n  PORT: \"5000\"\n  DB_HOST: \"mysql-2022bcd0026.default.svc.cluster.local\"\n  DB_USER: \"root\"\n  DB_PASSWORD: \"password\"\n  DB_NAME: \"tasks\"\n  NODE_ENV: \"production\"\n\n```\n\n`k8s/backend/backend-deployment.yaml`:\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: backend-deploy-2022bcd0026\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: backend\n      owner: 2022bcd0026\n  template:\n    metadata:\n      labels:\n        app: backend\n        owner: 2022bcd0026\n    spec:\n      containers:\n      - name: backend\n        image: bhanureddy1973/2022bcd0026-bhanu-reddy:latest\n        imagePullPolicy: Always\n        ports:\n        - containerPort: 5000\n        env:\n        - name: PORT\n          valueFrom:\n            configMapKeyRef:\n              name: backend-config\n              key: PORT\n        - name: DB_HOST\n          valueFrom:\n            configMapKeyRef:\n              name: backend-config\n              key: DB_HOST\n        - name: DB_NAME\n          valueFrom:\n            configMapKeyRef:\n              name: backend-config\n              key: DB_NAME\n        - name: DB_USER\n          valueFrom:\n            configMapKeyRef:\n              name: backend-config\n              key: DB_USER\n        - name: DB_PASSWORD\n          valueFrom:\n            configMapKeyRef:\n              name: backend-config\n              key: DB_PASSWORD\n              ```\n\n`k8s/backend/backend-service.yaml`:\n\n```yaml\napiVersion: v1\nkind: Service\nmetadata:\n  name: backend-service-2022bcd0026\nspec:\n  selector:\n    app: backend\n    owner: 2022bcd0026\n  ports:\n  - port: 5000\n    targetPort: 5000\n    nodePort:  3001\n  type: NodePort\n```\n\n#### Frontend Deployment and Service\n\n`k8s/frontend/frontend-deployment.yaml`:\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: frontend-deploy-2022bcd0026\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: frontend\n      owner: 2022bcd0026\n  template:\n    metadata:\n      labels:\n        app: frontend\n        owner: 2022bcd0026\n    spec:\n      containers:\n      - name: frontend\n        image: bhanureddy1973/frontend-2022bcd0026-bhanu-reddy:latest\n        imagePullPolicy: Always\n        ports:\n        - containerPort: 80\n        env:\n        - name: REACT_APP_API_URL\n          valueFrom:\n            configMapKeyRef:\n              name: frontend-config\n              key: REACT_APP_API_URL\n              ```\n\n`k8s/frontend/frontend-service.yaml`:\n\n```yaml\napiVersion: v1\nkind: Service\nmetadata:\n  name: frontend-service-2022bcd0026\n  labels:\n    app: frontend\nspec:\n  selector:\n    app: frontend\n    \n  ports:\n  - port: 80\n    protocol: TCP\n    targetPort: 80\n  type: NodePort\n```\n`k8s/frontend/frontend-config.yaml`:\n\n```yaml\n\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: frontend-config\ndata:\n  REACT_APP_API_URL: \"http://$(minikube ip):30001/api\"\n  APP_ENV: \"production\"\n```\n\n## Step 4: Deploying to Minikube\n\nNow we'll deploy our application to Minikube:\n\n1. Start Minikube:\n\n```bash\nminikube start\n```\n![alt text](image-2.png)\n\n2. Set your Docker environment to use Minikube's Docker daemon:\n\n```bash\neval $(minikube docker-env)\n```\n\n3. Build the Docker images:\n\n```bash\ncd backend\ndocker build -t 2022bcd0026-bhanu-reddy .```\n![alt text](image-8.png)\n![alt text](image-9.png)\n\n\n```bash\ncd ../frontend\ndocker build -t frontend-2022bcd0026-bhanu-reddy .\n```\n![alt text](image-3.png)\n\n```bash\ndocker-compose.yml\nversion: '3.8'\n\nservices:\n  # MySQL Database\n  mysql:\n    image: mysql:8.0\n    container_name: mysql-2022bcd0026\n    restart: unless-stopped\n    environment:\n      MYSQL_ROOT_PASSWORD: password\n      MYSQL_DATABASE: tasksdb\n    ports:\n      - \"3306:3306\"\n    volumes:\n      - mysql-data:/var/lib/mysql\n    networks:\n      - app-network\n    healthcheck:\n      test: [\"CMD\", \"mysqladmin\", \"ping\", \"-h\", \"localhost\"]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n\n  # Node.js Backend\n  backend:\n    build:\n      context: ./backend\n      dockerfile: Dockerfile\n    image: 2022bcd0026-bhanu-reddy:latest\n    container_name: backend-2022bcd0026\n    restart: unless-stopped\n    environment:\n      PORT: 5000\n      DB_HOST: mysql\n      DB_USER: root\n      DB_PASSWORD: password\n      DB_NAME: tasksdb\n    ports:\n      - \"5000:5000\"\n    depends_on:\n      - mysql\n    networks:\n      - app-network\n\n  # React Frontend\n  frontend:\n    build:\n      context: ./frontend\n      dockerfile: Dockerfile\n      args:\n        - REACT_APP_API_URL=http://localhost:5000/api\n    image: frontend-2022bcd0026-bhanu-reddy:latest\n    container_name: frontend-2022bcd0026\n    restart: unless-stopped\n    ports:\n      - \"80:80\"\n    depends_on:\n      - backend\n    networks:\n      - app-network\n\nnetworks:\n  app-network:\n    driver: bridge\n\nvolumes:\n  mysql-data:\n    driver: local\n\n```\n![alt text](image-19.png)\n![alt text](image-20.png)\n\n4. Deploy MySQL:\n\n```bash\n#move to the k8s/mysql directory \nkubectl apply -f mysql-pv.yaml\nkubectl apply -f mysql-pvc.yaml\nkubectl apply -f mysql-configmap.yaml\nkubectl apply -f mysql-secret.yaml\nkubectl apply -f mysql-deployment.yaml\nkubectl apply -f mysql-service.yaml\n```\n![alt text](image-4.png)\n![alt text](image-15.png)\n![alt text](image-16.png)\n![alt text](image-17.png)\n\n5. Deploy the backend:\n\n```bash\nkubectl apply -f k8s/backend/backend-configmap.yaml\nkubectl apply -f k8s/backend/backend-deployment.yaml\nkubectl apply -f k8s/backend/backend-service.yaml\n```\n![alt text](image-5.png)\n\n6. Deploy the frontend:\n\n```bash\nkubectl apply -f k8s/frontend/frontend-deployment.yaml\nkubectl apply -f k8s/frontend/frontend-service.yaml\nkubectl apply -f k8s/frontend/frontend-configmap.yaml\n```\n![alt text](image-6.png)\n\n7. Check that everything is running:\n\n### Verify Services:\n```bash\n#FRONTEND SERVICE:\nkubectl get svc -l app=frontend\n#BACKEND SERVIICE:\nkubectl get svc -l app=backend\n#MYSQL SERVICE:\nkubectl get svc -l app=backend\n```\n\n```bash\n#TO GET ALL PODS AND SERVICES\nkubectl get pods\nkubectl get services\n```\n![alt text](image-12.png)\n![alt text](image-13.png)\n\n```bash\n#Delete all existing pods :-\nDelete all existing pods \n```\n\n\n\n# MySQL Tasks Database Setup\n\n## Access MySQL\n```bash\nkubectl exec -it $(kubectl get pod -l app=mysql -o jsonpath='{.items[0].metadata.name}') -- /bin/bash\n\n# Inside the pod\nmysql -u root -p\n\n```\n###Enter the password (password) when prompted. mentioned in the secret.yaml file\n\n\n## Steps to Set Up the Tasks Database\n\n### 1. Use the `tasksdb` Database\n\nSwitch to the `tasksdb` database:\n```sql\nUSE tasksdb;\n```\n\n### 2. Create a Table for Tasks\n\nCreate a table named `tasks` with columns for task ID, name, status, and creation date:\n```sql\nCREATE TABLE tasks (\n    id INT AUTO_INCREMENT PRIMARY KEY,\n    task_name VARCHAR(255) NOT NULL,\n    status VARCHAR(50) DEFAULT 'Pending',\n    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n```\n\n### 3. Insert Sample Tasks\n\nInsert a few tasks into the `tasks` table:\n```sql\nINSERT INTO tasks (task_name, status) VALUES\n('Complete Kubernetes setup', 'Pending'),\n('Test MySQL connectivity', 'Done'),\n('Deploy backend service', 'In Progress'),\n('Configure frontend application', 'Pending');\n```\n\n### 4. Verify the Inserted Tasks\n\nRetrieve all tasks from the `tasks` table:\n```sql\nSELECT * FROM tasks;\n```\n\nYou should see output similar to this:\n```\n+----+----------------------------+-------------+---------------------+\n| id | task_name                  | status      | created_at          |\n+----+----------------------------+-------------+---------------------+\n|  1 | Complete Kubernetes setup  | Pending     | 2025-04-05 11:00:00 |\n|  2 | Test MySQL connectivity    | Done        | 2025-04-05 11:05:00 |\n|  3 | Deploy backend service     | In Progress | 2025-04-05 11:10:00 |\n|  4 | Configure frontend application | Pending | 2025-04-05 11:15:00 |\n+----+----------------------------+-------------+---------------------+\n```\n\n### 5. Exit MySQL\n\nOnce done, exit the MySQL shell:\n```sql\nEXIT;\n```\n![alt text](image-18.png)\n\n## Troubleshooting\n\n- Ensure that MySQL is running and accessible.\n- Verify that the `tasksdb` database exists or create it if necessary.\n- Check for any syntax errors in SQL commands.\n\n\n\n## Step 5: Testing the Application\n\n### Let's test our deployed application:\n```bash\n# Get Minikube IP\nMINIKUBE_IP=$(minikube ip)\necho \"Minikube IP: $MINIKUBE_IP\"\n\n# Get service NodePorts\nBACKEND_PORT=$(kubectl get svc backend-service-YOUR_REGISTER_NUMBER -o jsonpath='{.spec.ports[0].nodePort}')\nFRONTEND_PORT=$(kubectl get svc frontend-service-YOUR_REGISTER_NUMBER -o jsonpath='{.spec.ports[0].nodePort}')\n\necho \"Backend available at: http://$MINIKUBE_IP:$BACKEND_PORT\"\necho \"Frontend available at: http://$MINIKUBE_IP:$FRONTEND_PORT\"\n\n# Test backend API using curl\ncurl http://$MINIKUBE_IP:$BACKEND_PORT/api/health\ncurl http://$MINIKUBE_IP:$BACKEND_PORT/api/tasks\n\n# For testing POST requests\ncurl -X POST -H \"Content-Type: application/json\" \\\n  -d '{\"title\":\"Task from curl\",\"description\":\"Created using curl command\"}' \\\n  http://$MINIKUBE_IP:$BACKEND_PORT/api/tasks\n\n```\n\n1. Get the URL of the frontend service:\n\n```bash\nminikube service frontend-service-2022bcd0026 --url\n```\n![alt text](image-14.png)\n\n2. Test the backend API using curl:\n\n```bash\n# Port-forward the backend service to localhost\nkubectl port-forward svc/backend-service-2022bcd0026 5000:5000\n```\n![alt text](image-10.png)\n```bash\n# In another terminal, test the API\ncurl http://localhost:5000/api/health\ncurl http://localhost:5000/api/tasks\ncurl -X POST -H \"Content-Type: application/json\" -d '{\"title\":\"Test Task\",\"description\":\"This is a test task\"}' http://localhost:5000/api/tasks\n```\n![alt text](image-11.png)\n\n3. Access the frontend in your browser using the URL provided by Minikube.\n###GET THE MINIKUBE IP:-\n```bash\nminikube ip\n```\n###Access the Frontend: Use the Minikube IP and the frontend service's NodePort to access the application:\n\n```bash\nhttp://\u003cminikube-ip\u003e:\u003cfrontend-nodeport\u003e\n```\n###Verify API Requests: Open the browser's developer tools (Network tab) and confirm that the API requests are being sent to the correct backend URL (http://\u003cminikube-ip\u003e:30001/api/tasks).\n\n## Troubleshooting\n\nIf you encounter issues with your deployment, here are some common troubleshooting steps:\n\n1. Check pod status:\n\n```bash\n# Get all pods\nkubectl get pods\n\n# Get detailed information about a pod\nkubectl describe pod \u003cpod-name\u003e\n\n# Check pod logs\nkubectl logs \u003cpod-name\u003e\n\n# For previous container logs (if container crashed)\nkubectl logs \u003cpod-name\u003e --previous\n\n# Check specific container logs in a multi-container pod\nkubectl logs \u003cpod-name\u003e -c \u003ccontainer-name\u003e\n```\n\n2. Check service status:\n\n```bash\n# List all services\nkubectl get services\n\n# Get details about a specific service\nkubectl describe service \u003cservice-name\u003e\n\n# Test a service's endpoint directly\nkubectl run -i --tty --rm debug --image=busybox -- wget -O- \u003cservice-name\u003e:\u003cport\u003e\n```\n![alt text](image-21.png)\n\n3. Check ConfigMaps and Secrets:\n\n```bash\n# List all ConfigMaps\nkubectl get configmaps\n\n# Get details about a specific ConfigMap\nkubectl describe configmap \u003cconfigmap-name\u003e\n\n# List all secrets\nkubectl get secrets\n\n# Get details about a specific secret\nkubectl describe secret \u003csecret-name\u003e\n\n# Decode a secret value\nkubectl get secret \u003csecret-name\u003e -o jsonpath=\"{.data.\u003ckey\u003e}\" | base64 --decode\n```\n![alt text](image-22.png)\n\n4. Check Network Policies\n```bash\n# If you're using Network Policies, check them\nkubectl get networkpolicies\nkubectl describe networkpolicy \u003cpolicy-name\u003e\n```\n\n5. Common issues:\n   - Images not found: Make sure you've built the images in the Minikube Docker environment\n   ```bash\n   eval $(minikube docker-env)\n  docker images | grep YOUR_REGISTER_NUMBER\n```\n   - Database connection issues: Check the logs of your backend pod for connection errors\n   ```bash\n   kubectl logs $(kubectl get pod -l app=backend,owner=YOUR_REGISTER_NUMBER -o jsonpath='{.items[0].metadata.name}')\n   ```\n   - Services not accessible: Use `kubectl port-forward` to debug connectivity\n   ```bash\n   kubectl port-forward svc/backend-service-YOUR_REGISTER_NUMBER 5000:5000\n# In another terminal\ncurl http://localhost:5000/api/health\n```\n    - Check for imagePullBackOff errors:\n    ```bash\n    kubectl get pods\n# If you see ImagePullBackOff, switch to minikube's docker daemon\neval $(minikube docker-env)\ndocker images # Check if your image exists\n```\n  - Restart a deployment after making changes:\n  ```bash\n  kubectl rollout restart deployment/backend-deploy-YOUR_REGISTER_NUMBER\n  ```\n\n\n\n\n\n#OUTPUT\n\n##CRUD OPERATIONS\n\n###INTIALLY FETCHED DATA , DATA ADDED IN TERMINAL - GET ()\n![alt text](image-18.png)\n![alt text](image-23.png)\n\n![alt text](image-24.png)\n\n###NEW TASK IS ADDED\n![alt text](image-25.png)\n\n###TASK 1 IS DELETED\n![alt text](image-26.png)\n\n###TASK 5 (ASSIGNMENT 3 ) IS UPDATED \n![alt text](image-27.png)\n\n\n###AFTER CHANGES \n####FRONTEND\n![alt text](image-29.png)\n####BACKEND\n![alt text](image-28.png)\n![alt text](image-30.png)\n\n####MYSQL\n![alt text](image-31.png)\n\n\n\n## Cleaning Up\n\nTo clean up all the resources:\n\n```bash\n# Delete frontend resources\nkubectl delete -f k8s/frontend/\n\n# Delete backend resources\nkubectl delete -f k8s/backend/\n\n# Delete MySQL resources\nkubectl delete -f k8s/mysql/\n\n# Delete PersistentVolumeClaims and PersistentVolumes if needed\nkubectl delete pvc mysql-pvc-YOUR_REGISTER_NUMBER\nkubectl delete pv mysql-pv-YOUR_REGISTER_NUMBER\n\n# Stop Minikube\nminikube stop\n\n# Optional: Delete the Minikube cluster\nminikube delete\n```\n\n## Additional Commands\n```bash\n# Get all resources in the namespace\nkubectl get all\n\n# View Pod details in YAML format\nkubectl get pod \u003cpod-name\u003e -o yaml\n\n# Open a shell in a running pod\nkubectl exec -it \u003cpod-name\u003e -- /bin/bash\n# or for containers that don't have bash\nkubectl exec -it \u003cpod-name\u003e -- /bin/sh\n\n# View real-time logs of a pod\nkubectl logs -f \u003cpod-name\u003e\n\n# Check Minikube status\nminikube status\n\n# Access Minikube dashboard\nminikube dashboard\n\n# Check resource usage\nkubectl top nodes\nkubectl top pods\n\n# Generate YAML manifests for debugging\nkubectl create deployment test --image=nginx --dry-run=client -o yaml\n\n# Check all events in the cluster\nkubectl get events --sort-by='.metadata.creationTimestamp'\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbhanreddy1973%2Fkubernetes-fullstack-todoweb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbhanreddy1973%2Fkubernetes-fullstack-todoweb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbhanreddy1973%2Fkubernetes-fullstack-todoweb/lists"}