forked from gitea_admin/simple-node
backend files
This commit is contained in:
20
backend/Dockerfile
Normal file
20
backend/Dockerfile
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Use Node.js LTS as the base image
|
||||||
|
FROM node:18-slim
|
||||||
|
|
||||||
|
# Create and change to the app directory
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
# Copy package.json and package-lock.json
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN npm install --production
|
||||||
|
|
||||||
|
# Copy the rest of the application code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Expose the port the app runs on
|
||||||
|
EXPOSE 3001
|
||||||
|
|
||||||
|
# Command to run the application
|
||||||
|
CMD [ "node", "index.js" ]
|
||||||
67
backend/Jenkinsfile
vendored
Normal file
67
backend/Jenkinsfile
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
pipeline {
|
||||||
|
agent any
|
||||||
|
|
||||||
|
environment {
|
||||||
|
// --- Harbor Configuration ---
|
||||||
|
HARBOR_URL = 'harbor.example.com'
|
||||||
|
HARBOR_PROJECT = 'my-todo-app'
|
||||||
|
IMAGE_NAME = 'todo-backend'
|
||||||
|
HARBOR_CREDS = 'harbor-credentials-id'
|
||||||
|
|
||||||
|
// --- Kubernetes Configuration ---
|
||||||
|
K8S_CREDENTIALS_ID = 'k8s-kubeconfig' // Jenkins ID for kubeconfig file
|
||||||
|
// ----------------------------
|
||||||
|
|
||||||
|
IMAGE_TAG = "${env.BUILD_ID}"
|
||||||
|
FULL_IMAGE_PATH = "${HARBOR_URL}/${HARBOR_PROJECT}/${IMAGE_NAME}:${IMAGE_TAG}"
|
||||||
|
}
|
||||||
|
|
||||||
|
stages {
|
||||||
|
stage('Install & Test') {
|
||||||
|
steps {
|
||||||
|
sh 'npm install'
|
||||||
|
sh 'npm test || true'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Build & Push to Harbor') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
sh "docker build -t ${FULL_IMAGE_PATH} ."
|
||||||
|
withCredentials([usernamePassword(credentialsId: "${HARBOR_CREDS}", usernameVariable: 'USER', passwordVariable: 'PASS')]) {
|
||||||
|
sh "docker login ${HARBOR_URL} -u ${USER} -p ${PASS}"
|
||||||
|
sh "docker push ${FULL_IMAGE_PATH}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Deploy to Kubernetes') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
// Assuming kubectl is available on the agent and configured
|
||||||
|
// or use withKubeConfig if plugin is available:
|
||||||
|
// configFileProvider([configFile(fileId: "${K8S_CREDENTIALS_ID}", variable: 'KUBECONFIG')]) {
|
||||||
|
|
||||||
|
// 1. Replace placeholder in YAML with the actual image path
|
||||||
|
// We use a temporary file to avoid modifying the original repo file permanently in a way that breaks next builds
|
||||||
|
sh "sed 's|IMAGE_PATH_PLACEHOLDER|${FULL_IMAGE_PATH}|g' k8s-deployment.yaml > backend-k8s-applied.yaml"
|
||||||
|
|
||||||
|
// 2. Apply the manifest
|
||||||
|
sh "kubectl apply -f backend-k8s-applied.yaml"
|
||||||
|
|
||||||
|
// 3. Verify rollout
|
||||||
|
sh "kubectl rollout status deployment/todo-backend"
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
sh "docker logout ${HARBOR_URL}"
|
||||||
|
sh "rm -f backend-k8s-applied.yaml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
backend/app.test.js
Normal file
35
backend/app.test.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
const request = require('supertest');
|
||||||
|
const app = require('./index');
|
||||||
|
|
||||||
|
describe('Backend API', () => {
|
||||||
|
it('should return health check message on /', async () => {
|
||||||
|
const res = await request(app).get('/');
|
||||||
|
expect(res.statusCode).toEqual(200);
|
||||||
|
expect(res.text).toContain('Todo API is running');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fetch all todos', async () => {
|
||||||
|
const res = await request(app).get('/api/todos');
|
||||||
|
expect(res.statusCode).toEqual(200);
|
||||||
|
expect(Array.isArray(res.body)).toBeTruthy();
|
||||||
|
expect(res.body.length).toBeGreaterThanOrEqual(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add a new todo', async () => {
|
||||||
|
const newTodo = { task: 'Test task' };
|
||||||
|
const res = await request(app)
|
||||||
|
.post('/api/todos')
|
||||||
|
.send(newTodo);
|
||||||
|
expect(res.statusCode).toEqual(201);
|
||||||
|
expect(res.body.task).toEqual('Test task');
|
||||||
|
expect(res.body).toHaveProperty('id');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail to add a todo without a task', async () => {
|
||||||
|
const res = await request(app)
|
||||||
|
.post('/api/todos')
|
||||||
|
.send({});
|
||||||
|
expect(res.statusCode).toEqual(400);
|
||||||
|
expect(res.body.error).toEqual('Task is required');
|
||||||
|
});
|
||||||
|
});
|
||||||
41
backend/index.js
Normal file
41
backend/index.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const cors = require('cors');
|
||||||
|
const app = express();
|
||||||
|
const port = process.env.PORT || 3001;
|
||||||
|
|
||||||
|
app.use(cors());
|
||||||
|
app.use(express.json());
|
||||||
|
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
res.send('Todo API is running. Access todos at /api/todos');
|
||||||
|
});
|
||||||
|
|
||||||
|
let todos = [
|
||||||
|
{ id: 1, task: 'Learn Node.js', completed: false },
|
||||||
|
{ id: 2, task: 'Build a microservice app', completed: false }
|
||||||
|
];
|
||||||
|
|
||||||
|
app.get('/api/todos', (req, res) => {
|
||||||
|
res.json(todos);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/api/todos', (req, res) => {
|
||||||
|
if (!req.body.task) {
|
||||||
|
return res.status(400).json({ error: 'Task is required' });
|
||||||
|
}
|
||||||
|
const newTodo = {
|
||||||
|
id: Date.now(),
|
||||||
|
task: req.body.task,
|
||||||
|
completed: false
|
||||||
|
};
|
||||||
|
todos.push(newTodo);
|
||||||
|
res.status(201).json(newTodo);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`Backend service listening at http://localhost:${port}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = app;
|
||||||
38
backend/k8s-deployment.yaml
Normal file
38
backend/k8s-deployment.yaml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: todo-backend
|
||||||
|
labels:
|
||||||
|
app: todo-backend
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: todo-backend
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: todo-backend
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: todo-backend
|
||||||
|
image: IMAGE_PATH_PLACEHOLDER
|
||||||
|
ports:
|
||||||
|
- containerPort: 3001
|
||||||
|
env:
|
||||||
|
- name: PORT
|
||||||
|
value: "3001"
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: todo-backend-service
|
||||||
|
spec:
|
||||||
|
type: NodePort
|
||||||
|
selector:
|
||||||
|
app: todo-backend
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 3001
|
||||||
|
targetPort: 3001
|
||||||
|
nodePort: 30001
|
||||||
Reference in New Issue
Block a user