Загрузить файлы в «Z2»
This commit is contained in:
parent
ee7033edad
commit
d60c97abc1
18
Z2/Dockerfile
Normal file
18
Z2/Dockerfile
Normal file
@ -0,0 +1,18 @@
|
||||
# Используем легкий образ Python
|
||||
FROM python:3.10-slim
|
||||
|
||||
# Устанавливаем рабочую директорию
|
||||
WORKDIR /app
|
||||
|
||||
# Копируем зависимости и устанавливаем их
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Копируем код приложения
|
||||
COPY . .
|
||||
|
||||
# Открываем порт (по умолчанию Flask — 5000)
|
||||
EXPOSE 5000
|
||||
|
||||
# Команда запуска
|
||||
CMD ["python", "app.py"]
|
120
Z2/README.md
Normal file
120
Z2/README.md
Normal file
@ -0,0 +1,120 @@
|
||||
# To-Do List Application on Kubernetes
|
||||
|
||||
## Application Description
|
||||
|
||||
This is a simple To-Do List web application that allows users to:
|
||||
- Add new tasks
|
||||
- Mark tasks as completed
|
||||
- Delete tasks
|
||||
- Filter tasks by their status (All, Active, Completed)
|
||||
- Reorder tasks using drag-and-drop functionality
|
||||
|
||||
The application uses local storage to persist tasks and allows users to manage their daily tasks efficiently.
|
||||
|
||||
## Container Images Used
|
||||
|
||||
1. **todo-web-app:latest**:
|
||||
- Custom image based on nginx:alpine
|
||||
- Contains the static web files (HTML, CSS, JavaScript) for the To-Do List application
|
||||
- Serves the web interface on port 80
|
||||
|
||||
2. **redis:alpine**:
|
||||
- Official Redis image based on Alpine Linux
|
||||
- Used in the StatefulSet for data persistence
|
||||
- Stores task data on a persistent volume
|
||||
- Runs on port 6379
|
||||
|
||||
## Kubernetes Objects
|
||||
|
||||
1. **Namespace** (`todo-app-ns`):
|
||||
- Isolates all the application resources in a dedicated namespace
|
||||
|
||||
2. **Deployment** (`todo-web-app`):
|
||||
- Manages the web application containers
|
||||
- Maintains 2 replicas for high availability
|
||||
- Defines resource limits and requests
|
||||
|
||||
3. **StatefulSet** (`todo-data-manager`):
|
||||
- Manages Redis instances for data persistence
|
||||
- Uses persistent storage to maintain task data
|
||||
- Ensures data consistency during pod restarts
|
||||
|
||||
4. **PersistentVolume** (`todo-app-pv`):
|
||||
- Provides storage resources for the application
|
||||
- Uses local storage on the host at `/mnt/data/todo-app`
|
||||
- 1GB capacity for storing task data
|
||||
|
||||
5. **PersistentVolumeClaim** (`todo-app-pvc`):
|
||||
- Claims storage from the PersistentVolume
|
||||
- Used by the StatefulSet for data persistence
|
||||
|
||||
6. **Services**:
|
||||
- `todo-web-service`: NodePort service exposing the web application
|
||||
- `todo-data-service`: Headless service for the StatefulSet
|
||||
|
||||
## Network and Volume Configuration
|
||||
|
||||
### Networks
|
||||
- The application components communicate within the Kubernetes cluster using services
|
||||
- `todo-web-service` exposes the web interface externally using NodePort
|
||||
- `todo-data-service` provides internal DNS-based service discovery for the StatefulSet
|
||||
|
||||
### Volumes
|
||||
- The application uses a persistent volume mounted at `/mnt/data/todo-app` on the host
|
||||
- This volume is mounted into the Redis container at `/data` to persist task data
|
||||
- The volume uses the `manual` storage class with ReadWriteOnce access mode
|
||||
|
||||
## Container Configuration
|
||||
|
||||
### Web Application Container
|
||||
- Based on nginx:alpine
|
||||
- Configured to serve static content from `/usr/share/nginx/html`
|
||||
- Resource limits: 500m CPU, 256Mi memory
|
||||
- Resource requests: 100m CPU, 128Mi memory
|
||||
|
||||
### Redis Container
|
||||
- Based on redis:alpine
|
||||
- Data directory mounted to persistent storage
|
||||
- Resource limits: 300m CPU, 256Mi memory
|
||||
- Resource requests: 100m CPU, 128Mi memory
|
||||
|
||||
## How to Use the Application
|
||||
|
||||
### Prerequisites
|
||||
- Kubernetes cluster (Minikube or similar)
|
||||
- kubectl configured to communicate with your cluster
|
||||
- Docker for building the application image
|
||||
|
||||
### Prepare the Application
|
||||
1. Clone this repository
|
||||
2. Run the preparation script:
|
||||
```
|
||||
chmod +x prepare-app.sh
|
||||
./prepare-app.sh
|
||||
```
|
||||
|
||||
### Start the Application
|
||||
1. Run the start script:
|
||||
```
|
||||
chmod +x start-app.sh
|
||||
./start-app.sh
|
||||
```
|
||||
2. The script will display the URL to access the application
|
||||
|
||||
### Stop the Application
|
||||
1. Run the stop script:
|
||||
```
|
||||
chmod +x stop-app.sh
|
||||
./stop-app.sh
|
||||
```
|
||||
|
||||
### Accessing the Web Interface
|
||||
1. After starting the application, note the NodePort displayed in the terminal
|
||||
2. Open your web browser and navigate to `http://localhost:<NodePort>`
|
||||
3. You should see the To-Do List application interface
|
||||
4. Start adding tasks, marking them as completed, or deleting them as needed
|
||||
|
||||
## Troubleshooting
|
||||
- If pods aren't starting, check the pod status: `kubectl get pods -n todo-app-ns`
|
||||
- For detailed pod issues: `kubectl describe pod <pod-name> -n todo-app-ns`
|
||||
- To view logs: `kubectl logs <pod-name> -n todo-app-ns`
|
32
Z2/app.py
Normal file
32
Z2/app.py
Normal file
@ -0,0 +1,32 @@
|
||||
from flask import Flask, request, jsonify
|
||||
import json
|
||||
import os
|
||||
|
||||
app = Flask(__name__)
|
||||
DATA_FILE = "/data/tasks.json"
|
||||
|
||||
def read_tasks():
|
||||
if os.path.exists(DATA_FILE):
|
||||
with open(DATA_FILE, "r") as f:
|
||||
return json.load(f)
|
||||
return []
|
||||
|
||||
def write_tasks(tasks):
|
||||
with open(DATA_FILE, "w") as f:
|
||||
json.dump(tasks, f)
|
||||
|
||||
@app.route("/tasks", methods=["GET"])
|
||||
def get_tasks():
|
||||
return jsonify(read_tasks())
|
||||
|
||||
@app.route("/tasks", methods=["POST"])
|
||||
def add_task():
|
||||
tasks = read_tasks()
|
||||
new_task = request.json
|
||||
tasks.append(new_task)
|
||||
write_tasks(tasks)
|
||||
return jsonify(new_task), 201
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=5000)
|
||||
|
20
Z2/backend-deployment.yaml
Normal file
20
Z2/backend-deployment.yaml
Normal file
@ -0,0 +1,20 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: backend-deployment
|
||||
namespace: todo-app-ns-v2 # Указываем пространство имен
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: backend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: backend
|
||||
spec:
|
||||
containers:
|
||||
- name: backend
|
||||
image: jank8000/backend-image:latest
|
||||
ports:
|
||||
- containerPort: 8081
|
11
Z2/backend-service.yaml
Normal file
11
Z2/backend-service.yaml
Normal file
@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: backend-service
|
||||
namespace: todo-app-ns-v2 # Указываем пространство имен
|
||||
spec:
|
||||
ports:
|
||||
- port: 8081
|
||||
targetPort: 8081
|
||||
selector:
|
||||
app: backend
|
30
Z2/deployment.yaml
Normal file
30
Z2/deployment.yaml
Normal file
@ -0,0 +1,30 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: todo-web-app
|
||||
namespace: todo-app-ns-v2
|
||||
labels:
|
||||
app: todo-web-app
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: todo-web-app
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: todo-web-app
|
||||
spec:
|
||||
containers:
|
||||
- name: todo-web-app
|
||||
image: todo-web-app:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- containerPort: 80
|
||||
resources:
|
||||
limits:
|
||||
cpu: "500m"
|
||||
memory: "256Mi"
|
||||
requests:
|
||||
cpu: "100m"
|
||||
memory: "128Mi"
|
21
Z2/frontend-deployment.yaml
Normal file
21
Z2/frontend-deployment.yaml
Normal file
@ -0,0 +1,21 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: frontend-deployment
|
||||
namespace: todo-app-ns-v2
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: todo-web
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: todo-web
|
||||
spec:
|
||||
containers:
|
||||
- name: todo-web
|
||||
image: jank8000/todo-web:latest # Указываем Docker-образ фронтенда, который вы загрузили
|
||||
ports:
|
||||
- containerPort: 80
|
||||
|
12
Z2/frontend-service.yaml
Normal file
12
Z2/frontend-service.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: frontend-service
|
||||
namespace: todo-app-ns-v2
|
||||
spec:
|
||||
selector:
|
||||
app: todo-web
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
type: ClusterIP # Сервис будет доступен внутри кластера
|
30
Z2/index.html
Normal file
30
Z2/index.html
Normal file
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>To-Do List</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-container">
|
||||
<h1>What should i do list (Reminder)</h1>
|
||||
<p class="subtitle">What needs to be done today</p>
|
||||
|
||||
<form id="task-form">
|
||||
<input type="text" id="task-input" placeholder="Enter a new task">
|
||||
<button type="submit">Add</button>
|
||||
</form>
|
||||
|
||||
<div class="filter-buttons">
|
||||
<button class="filter active" data-filter="all">All</button>
|
||||
<button class="filter" data-filter="active">Active</button>
|
||||
<button class="filter" data-filter="completed">Completed</button>
|
||||
</div>
|
||||
|
||||
<ul id="task-list"></ul>
|
||||
</div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
18
Z2/ingress.yaml
Normal file
18
Z2/ingress.yaml
Normal file
@ -0,0 +1,18 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: todo-ingress
|
||||
namespace: todo-app-ns-v2
|
||||
spec:
|
||||
rules:
|
||||
- host: 147.232.185.30 # Указан ваш внешний IP
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: frontend-service
|
||||
port:
|
||||
number: 80
|
||||
|
4
Z2/namespace.yaml
Normal file
4
Z2/namespace.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: todo-app-ns-v2
|
684
Z2/prepare-app.sh
Normal file
684
Z2/prepare-app.sh
Normal file
@ -0,0 +1,684 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Preparing To-Do List Application for Kubernetes Deployment"
|
||||
|
||||
# Create directory for application files
|
||||
mkdir -p ./app
|
||||
|
||||
# Create index.html file
|
||||
cat > ./app/index.html << 'EOF'
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>To-Do List</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-container">
|
||||
<h1>What should i do list (Reminder)</h1>
|
||||
<p class="subtitle">What needs to be done today</p>
|
||||
|
||||
<form id="task-form">
|
||||
<input type="text" id="task-input" placeholder="Enter a new task">
|
||||
<button type="submit">Add</button>
|
||||
</form>
|
||||
|
||||
<div class="filter-buttons">
|
||||
<button class="filter active" data-filter="all">All</button>
|
||||
<button class="filter" data-filter="active">Active</button>
|
||||
<button class="filter" data-filter="completed">Completed</button>
|
||||
</div>
|
||||
|
||||
<ul id="task-list"></ul>
|
||||
</div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
|
||||
# Create style.css file
|
||||
cat > ./app/style.css << 'EOF'
|
||||
body {
|
||||
font-family: "Helvetica Neue", sans-serif;
|
||||
background: linear-gradient(to bottom, #f7f7f7, #e1e1e1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.app-container {
|
||||
background-color: #ffffff;
|
||||
padding: 40px;
|
||||
border-radius: 20px;
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
box-shadow: 0px 15px 20px rgba(0, 0, 0, 0.3);
|
||||
border: 1px solid #d9d9d9;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: "Helvetica", sans-serif;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
font-size: 30px;
|
||||
color: #4a4a4a;
|
||||
text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 16px;
|
||||
color: #6d6d72;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#task-input {
|
||||
flex-grow: 1;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #c7c7c7;
|
||||
background-color: #f0f0f0;
|
||||
font-size: 18px;
|
||||
box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
form button {
|
||||
padding: 15px 25px;
|
||||
border: none;
|
||||
background: linear-gradient(to bottom, #4da6ff, #0066cc);
|
||||
color: #ffffff;
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
text-shadow: 0px -1px 1px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 0px 5px 8px rgba(0, 0, 0, 0.2);
|
||||
transition: all 0.2s ease;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
form button:active {
|
||||
background: linear-gradient(to bottom, #0066cc, #4da6ff);
|
||||
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2);
|
||||
transform: translateY(2px);
|
||||
}
|
||||
|
||||
.filter-buttons {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.filter {
|
||||
background: linear-gradient(to bottom, #e6e6e6, #d1d1d1);
|
||||
border: 1px solid #c3c3c3;
|
||||
padding: 10px 20px;
|
||||
color: #4a4a4a;
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.6);
|
||||
box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.15);
|
||||
transition: all 0.2s ease;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.filter.active, .filter:hover {
|
||||
background: linear-gradient(to bottom, #4da6ff, #0066cc);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
#task-list {
|
||||
list-style: none;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
padding: 10px 0;
|
||||
background-color: #ffffff;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e2e2e2;
|
||||
}
|
||||
|
||||
.task-item {
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
background-color: #ffffff;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||
transition: background 0.3s ease;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.task-item:hover {
|
||||
background: linear-gradient(to bottom, #4da6ff, #0066cc);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.task-item.completed {
|
||||
text-decoration: line-through;
|
||||
color: #a09b8d;
|
||||
}
|
||||
|
||||
.task-actions {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.task-actions button {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.task-actions button.complete-btn {
|
||||
color: #60a36e;
|
||||
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.task-actions button.delete-btn {
|
||||
color: #d9534f;
|
||||
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create script.js file
|
||||
cat > ./app/script.js << 'EOF'
|
||||
// Получение элементов из HTML
|
||||
const taskForm = document.getElementById("task-form");
|
||||
const taskInput = document.getElementById("task-input");
|
||||
const taskList = document.getElementById("task-list");
|
||||
const filterButtons = document.querySelectorAll(".filter");
|
||||
|
||||
// Загрузка задач из LocalStorage
|
||||
let tasks = JSON.parse(localStorage.getItem("tasks")) || [];
|
||||
|
||||
// Переменная для отслеживания перетаскиваемой задачи
|
||||
let draggedTaskIndex = null;
|
||||
|
||||
// Функция для отображения задач
|
||||
function displayTasks(filter = "all") {
|
||||
taskList.innerHTML = "";
|
||||
const filteredTasks = tasks.filter(task =>
|
||||
filter === "all" || (filter === "active" && !task.completed) || (filter === "completed" && task.completed)
|
||||
);
|
||||
|
||||
filteredTasks.forEach((task, index) => {
|
||||
const taskItem = document.createElement("li");
|
||||
taskItem.classList.add("task-item");
|
||||
taskItem.draggable = true; // Сделать элемент перетаскиваемым
|
||||
|
||||
if (task.completed) taskItem.classList.add("completed");
|
||||
|
||||
taskItem.innerHTML = `
|
||||
<span>${task.text}</span>
|
||||
<div class="task-actions">
|
||||
<button class="complete-btn" onclick="toggleComplete('${task.id}')">✓</button>
|
||||
<button class="delete-btn" onclick="deleteTask('${task.id}')">✗</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Добавление событий для drag-and-drop
|
||||
taskItem.addEventListener("dragstart", () => handleDragStart(index));
|
||||
taskItem.addEventListener("dragover", (e) => handleDragOver(e));
|
||||
taskItem.addEventListener("drop", () => handleDrop(index));
|
||||
taskItem.addEventListener("dragend", handleDragEnd);
|
||||
|
||||
taskList.appendChild(taskItem);
|
||||
});
|
||||
}
|
||||
|
||||
// Обработчик начала перетаскивания
|
||||
function handleDragStart(index) {
|
||||
draggedTaskIndex = index;
|
||||
}
|
||||
|
||||
// Обработчик, предотвращающий действия по умолчанию (нужен для drop)
|
||||
function handleDragOver(e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
// Обработчик окончания перетаскивания
|
||||
function handleDrop(index) {
|
||||
if (draggedTaskIndex !== null && draggedTaskIndex !== index) {
|
||||
const draggedTask = tasks[draggedTaskIndex];
|
||||
tasks.splice(draggedTaskIndex, 1);
|
||||
tasks.splice(index, 0, draggedTask);
|
||||
saveTasks();
|
||||
displayTasks();
|
||||
}
|
||||
draggedTaskIndex = null;
|
||||
}
|
||||
|
||||
// Обработчик окончания перетаскивания
|
||||
function handleDragEnd() {
|
||||
draggedTaskIndex = null;
|
||||
}
|
||||
|
||||
// Добавление новой задачи
|
||||
taskForm.addEventListener("submit", (e) => {
|
||||
e.preventDefault();
|
||||
const taskText = taskInput.value.trim();
|
||||
if (!taskText) return;
|
||||
|
||||
const newTask = {
|
||||
id: Date.now().toString(),
|
||||
text: taskText,
|
||||
completed: false
|
||||
};
|
||||
tasks.push(newTask);
|
||||
saveTasks();
|
||||
displayTasks();
|
||||
taskInput.value = "";
|
||||
});
|
||||
|
||||
// Переключение статуса задачи на выполнено
|
||||
function toggleComplete(taskId) {
|
||||
tasks = tasks.map(task =>
|
||||
task.id === taskId ? { ...task, completed: !task.completed } : task
|
||||
);
|
||||
saveTasks();
|
||||
displayTasks();
|
||||
}
|
||||
|
||||
// Удаление задачи
|
||||
function deleteTask(taskId) {
|
||||
tasks = tasks.filter(task => task.id !== taskId);
|
||||
saveTasks();
|
||||
displayTasks();
|
||||
}
|
||||
|
||||
// Сохранение задач в LocalStorage
|
||||
function saveTasks() {
|
||||
localStorage.setItem("tasks", JSON.stringify(tasks));
|
||||
console.log("Tasks saved:", tasks);
|
||||
}
|
||||
|
||||
// Добавление события для фильтров
|
||||
filterButtons.forEach(button => {
|
||||
button.addEventListener("click", () => {
|
||||
filterButtons.forEach(btn => btn.classList.remove("active"));
|
||||
button.classList.add("active");
|
||||
displayTasks(button.dataset.filter);
|
||||
});
|
||||
});
|
||||
|
||||
// Инициализация
|
||||
displayTasks();
|
||||
EOF
|
||||
|
||||
# Create Dockerfile
|
||||
cat > ./Dockerfile << 'EOF'
|
||||
FROM nginx:alpine
|
||||
|
||||
# Create app directory
|
||||
WORKDIR /usr/share/nginx/html
|
||||
|
||||
# Copy application files
|
||||
COPY ./app/index.html .
|
||||
COPY ./app/style.css .
|
||||
COPY ./app/script.js .
|
||||
|
||||
# Expose port
|
||||
EXPOSE 80
|
||||
|
||||
# Start nginx server
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
EOF
|
||||
|
||||
# Create Kubernetes namespace file
|
||||
cat > ./namespace.yaml << 'EOF'
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: todo-app-ns
|
||||
labels:
|
||||
app: todo-app
|
||||
EOF
|
||||
|
||||
# Create deployment file
|
||||
cat > ./deployment.yaml << 'EOF'
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: todo-web-app
|
||||
namespace: todo-app-ns
|
||||
labels:
|
||||
app: todo-web-app
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: todo-web-app
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: todo-web-app
|
||||
spec:
|
||||
containers:
|
||||
- name: todo-web-app
|
||||
image: todo-web-app:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- containerPort: 80
|
||||
resources:
|
||||
limits:
|
||||
cpu: "500m"
|
||||
memory: "256Mi"
|
||||
requests:
|
||||
cpu: "100m"
|
||||
memory: "128Mi"
|
||||
EOF
|
||||
|
||||
# Create service file
|
||||
cat > ./service.yaml << 'EOF'
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: todo-web-service
|
||||
namespace: todo-app-ns
|
||||
spec:
|
||||
selector:
|
||||
app: todo-web-app
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
type: NodePort
|
||||
EOF
|
||||
|
||||
# Create statefulset file
|
||||
cat > ./statefulset.yaml << 'EOF'
|
||||
# PersistentVolume for storing tasks data
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: todo-app-pv
|
||||
labels:
|
||||
type: local
|
||||
spec:
|
||||
storageClassName: manual
|
||||
capacity:
|
||||
storage: 1Gi
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
hostPath:
|
||||
path: "/mnt/data/todo-app"
|
||||
---
|
||||
# PersistentVolumeClaim for the StatefulSet
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: todo-app-pvc
|
||||
namespace: todo-app-ns
|
||||
spec:
|
||||
storageClassName: manual
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
---
|
||||
# StatefulSet for task data persistence
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: todo-data-manager
|
||||
namespace: todo-app-ns
|
||||
spec:
|
||||
serviceName: "todo-data-service"
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: todo-data-manager
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: todo-data-manager
|
||||
spec:
|
||||
containers:
|
||||
- name: todo-data-manager
|
||||
image: redis:alpine
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
name: redis
|
||||
volumeMounts:
|
||||
- name: todo-data
|
||||
mountPath: /data
|
||||
resources:
|
||||
limits:
|
||||
cpu: "300m"
|
||||
memory: "256Mi"
|
||||
requests:
|
||||
cpu: "100m"
|
||||
memory: "128Mi"
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: todo-data
|
||||
spec:
|
||||
accessModes: [ "ReadWriteOnce" ]
|
||||
storageClassName: manual
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
---
|
||||
# Service for StatefulSet
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: todo-data-service
|
||||
namespace: todo-app-ns
|
||||
labels:
|
||||
app: todo-data-manager
|
||||
spec:
|
||||
ports:
|
||||
- port: 6379
|
||||
name: redis
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: todo-data-manager
|
||||
EOF
|
||||
|
||||
# Create start app script
|
||||
cat > ./start-app.sh << 'EOF'
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Starting To-Do List Application in Kubernetes"
|
||||
|
||||
# Apply namespace
|
||||
kubectl apply -f namespace.yaml
|
||||
|
||||
# Apply PV, PVC, and StatefulSet
|
||||
kubectl apply -f statefulset.yaml
|
||||
|
||||
# Apply deployment
|
||||
kubectl apply -f deployment.yaml
|
||||
|
||||
# Apply service
|
||||
kubectl apply -f service.yaml
|
||||
|
||||
echo "Waiting for the application to start..."
|
||||
sleep 5
|
||||
|
||||
# Get NodePort information
|
||||
NODE_PORT=$(kubectl get svc todo-web-service -n todo-app-ns -o jsonpath='{.spec.ports[0].nodePort}')
|
||||
echo "The To-Do List application is available at: http://localhost:$NODE_PORT"
|
||||
|
||||
echo "Application started successfully!"
|
||||
EOF
|
||||
|
||||
# Create stop app script
|
||||
cat > ./stop-app.sh << 'EOF'
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Stopping To-Do List Application in Kubernetes"
|
||||
|
||||
# Delete service
|
||||
kubectl delete -f service.yaml
|
||||
|
||||
# Delete deployment
|
||||
kubectl delete -f deployment.yaml
|
||||
|
||||
# Delete StatefulSet, PVC, and PV
|
||||
kubectl delete -f statefulset.yaml
|
||||
|
||||
# Delete namespace
|
||||
kubectl delete -f namespace.yaml
|
||||
|
||||
echo "Application stopped successfully!"
|
||||
EOF
|
||||
|
||||
# Create README.md
|
||||
cat > ./README.md << 'EOF'
|
||||
# To-Do List Application on Kubernetes
|
||||
|
||||
## Application Description
|
||||
|
||||
This is a simple To-Do List web application that allows users to:
|
||||
- Add new tasks
|
||||
- Mark tasks as completed
|
||||
- Delete tasks
|
||||
- Filter tasks by their status (All, Active, Completed)
|
||||
- Reorder tasks using drag-and-drop functionality
|
||||
|
||||
The application uses local storage to persist tasks and allows users to manage their daily tasks efficiently.
|
||||
|
||||
## Container Images Used
|
||||
|
||||
1. **todo-web-app:latest**:
|
||||
- Custom image based on nginx:alpine
|
||||
- Contains the static web files (HTML, CSS, JavaScript) for the To-Do List application
|
||||
- Serves the web interface on port 80
|
||||
|
||||
2. **redis:alpine**:
|
||||
- Official Redis image based on Alpine Linux
|
||||
- Used in the StatefulSet for data persistence
|
||||
- Stores task data on a persistent volume
|
||||
- Runs on port 6379
|
||||
|
||||
## Kubernetes Objects
|
||||
|
||||
1. **Namespace** (`todo-app-ns`):
|
||||
- Isolates all the application resources in a dedicated namespace
|
||||
|
||||
2. **Deployment** (`todo-web-app`):
|
||||
- Manages the web application containers
|
||||
- Maintains 2 replicas for high availability
|
||||
- Defines resource limits and requests
|
||||
|
||||
3. **StatefulSet** (`todo-data-manager`):
|
||||
- Manages Redis instances for data persistence
|
||||
- Uses persistent storage to maintain task data
|
||||
- Ensures data consistency during pod restarts
|
||||
|
||||
4. **PersistentVolume** (`todo-app-pv`):
|
||||
- Provides storage resources for the application
|
||||
- Uses local storage on the host at `/mnt/data/todo-app`
|
||||
- 1GB capacity for storing task data
|
||||
|
||||
5. **PersistentVolumeClaim** (`todo-app-pvc`):
|
||||
- Claims storage from the PersistentVolume
|
||||
- Used by the StatefulSet for data persistence
|
||||
|
||||
6. **Services**:
|
||||
- `todo-web-service`: NodePort service exposing the web application
|
||||
- `todo-data-service`: Headless service for the StatefulSet
|
||||
|
||||
## Network and Volume Configuration
|
||||
|
||||
### Networks
|
||||
- The application components communicate within the Kubernetes cluster using services
|
||||
- `todo-web-service` exposes the web interface externally using NodePort
|
||||
- `todo-data-service` provides internal DNS-based service discovery for the StatefulSet
|
||||
|
||||
### Volumes
|
||||
- The application uses a persistent volume mounted at `/mnt/data/todo-app` on the host
|
||||
- This volume is mounted into the Redis container at `/data` to persist task data
|
||||
- The volume uses the `manual` storage class with ReadWriteOnce access mode
|
||||
|
||||
## Container Configuration
|
||||
|
||||
### Web Application Container
|
||||
- Based on nginx:alpine
|
||||
- Configured to serve static content from `/usr/share/nginx/html`
|
||||
- Resource limits: 500m CPU, 256Mi memory
|
||||
- Resource requests: 100m CPU, 128Mi memory
|
||||
|
||||
### Redis Container
|
||||
- Based on redis:alpine
|
||||
- Data directory mounted to persistent storage
|
||||
- Resource limits: 300m CPU, 256Mi memory
|
||||
- Resource requests: 100m CPU, 128Mi memory
|
||||
|
||||
## How to Use the Application
|
||||
|
||||
### Prerequisites
|
||||
- Kubernetes cluster (Minikube or similar)
|
||||
- kubectl configured to communicate with your cluster
|
||||
- Docker for building the application image
|
||||
|
||||
### Prepare the Application
|
||||
1. Clone this repository
|
||||
2. Run the preparation script:
|
||||
```
|
||||
chmod +x prepare-app.sh
|
||||
./prepare-app.sh
|
||||
```
|
||||
|
||||
### Start the Application
|
||||
1. Run the start script:
|
||||
```
|
||||
chmod +x start-app.sh
|
||||
./start-app.sh
|
||||
```
|
||||
2. The script will display the URL to access the application
|
||||
|
||||
### Stop the Application
|
||||
1. Run the stop script:
|
||||
```
|
||||
chmod +x stop-app.sh
|
||||
./stop-app.sh
|
||||
```
|
||||
|
||||
### Accessing the Web Interface
|
||||
1. After starting the application, note the NodePort displayed in the terminal
|
||||
2. Open your web browser and navigate to `http://localhost:<NodePort>`
|
||||
3. You should see the To-Do List application interface
|
||||
4. Start adding tasks, marking them as completed, or deleting them as needed
|
||||
|
||||
## Troubleshooting
|
||||
- If pods aren't starting, check the pod status: `kubectl get pods -n todo-app-ns`
|
||||
- For detailed pod issues: `kubectl describe pod <pod-name> -n todo-app-ns`
|
||||
- To view logs: `kubectl logs <pod-name> -n todo-app-ns`
|
||||
EOF
|
||||
|
||||
# Build Docker image
|
||||
echo "Building Docker image for the web application..."
|
||||
docker build -t todo-web-app:latest .
|
||||
|
||||
# Create the host directory for PersistentVolume
|
||||
echo "Creating directory for persistent data..."
|
||||
# Use mkdir without sudo for compatibility with GitBash/Windows
|
||||
mkdir -p /mnt/data/todo-app 2>/dev/null || {
|
||||
echo "Note: Could not create /mnt/data/todo-app directory directly."
|
||||
echo "If you're using Minikube, you may need to create this directory inside the Minikube VM."
|
||||
echo "You can do this by running: minikube ssh 'sudo mkdir -p /mnt/data/todo-app && sudo chmod 777 /mnt/data/todo-app'"
|
||||
}
|
||||
|
||||
# Make scripts executable
|
||||
chmod +x start-app.sh stop-app.sh
|
||||
|
||||
echo "Application preparation completed successfully!"
|
2
Z2/requirements.txt
Normal file
2
Z2/requirements.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Flask
|
||||
|
36
Z2/script.js
Normal file
36
Z2/script.js
Normal file
@ -0,0 +1,36 @@
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const taskForm = document.getElementById("task-form");
|
||||
const taskInput = document.getElementById("task-input");
|
||||
const taskList = document.getElementById("task-list");
|
||||
|
||||
function loadTasks() {
|
||||
fetch("/api/tasks")
|
||||
.then(res => res.json())
|
||||
.then(tasks => {
|
||||
taskList.innerHTML = "";
|
||||
tasks.forEach(t => {
|
||||
const li = document.createElement("li");
|
||||
li.textContent = t.task;
|
||||
taskList.appendChild(li);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
taskForm.addEventListener("submit", e => {
|
||||
e.preventDefault();
|
||||
const task = taskInput.value.trim();
|
||||
if (!task) return;
|
||||
|
||||
fetch("/api/tasks", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ task })
|
||||
}).then(() => {
|
||||
taskInput.value = "";
|
||||
loadTasks();
|
||||
});
|
||||
});
|
||||
|
||||
loadTasks();
|
||||
});
|
||||
|
12
Z2/service.yaml
Normal file
12
Z2/service.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: todo-web-service
|
||||
namespace: todo-app-ns-v2
|
||||
spec:
|
||||
selector:
|
||||
app: todo-web-app
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
type: NodePort
|
27
Z2/start-app.sh
Normal file
27
Z2/start-app.sh
Normal file
@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Starting To-Do List Application in Kubernetes"
|
||||
|
||||
# Apply namespace
|
||||
kubectl apply -f k8s/namespace.yaml
|
||||
|
||||
# Apply PV, PVC, and StatefulSet
|
||||
kubectl apply -f k8s/statefulset.yaml
|
||||
|
||||
# Apply deployment
|
||||
kubectl apply -f k8s/deployment.yaml
|
||||
|
||||
# Apply service
|
||||
kubectl apply -f k8s/service.yaml
|
||||
|
||||
echo "Waiting for the application to start..."
|
||||
sleep 5
|
||||
|
||||
# Get NodePort information
|
||||
NODE_PORT=$(kubectl get svc todo-web-service -n todo-app-ns-v2 -o jsonpath='{.spec.ports[0].nodePort}')
|
||||
echo "The To-Do List application is available at: http://localhost:$NODE_PORT"
|
||||
|
||||
echo "Application started successfully!"
|
||||
|
||||
|
37
Z2/statefulset.yaml
Normal file
37
Z2/statefulset.yaml
Normal file
@ -0,0 +1,37 @@
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: todo-data-manager # Имя StatefulSet
|
||||
namespace: todo-app-ns-v2 # Пространство имен
|
||||
spec:
|
||||
serviceName: "todo-data-service" # Сервис для StatefulSet
|
||||
replicas: 1 # Количество реплик
|
||||
selector:
|
||||
matchLabels:
|
||||
app: todo-data # Лейбл для выборки подов
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: todo-data # Лейблы для подов
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: my-docker-secret # Секрет для загрузки образа Docker
|
||||
containers:
|
||||
- name: todo-data # Имя контейнера
|
||||
image: jank8000/todo-data-image:latest # Docker образ
|
||||
ports:
|
||||
- containerPort: 8080 # Порт контейнера
|
||||
volumeMounts:
|
||||
- name: todo-app-pvc # PVC, которое будет монтироваться
|
||||
mountPath: /data # Место, где данные будут храниться в контейнере
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: todo-app-pvc # PVC для хранения данных
|
||||
namespace: todo-app-ns-v2 # Пространство имен для PVC
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce # Режим доступа к PVC
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi # Запрос на 1Gi хранилища
|
||||
volumeMode: Filesystem # Монтирование как файловая система
|
18
Z2/stop-app.sh
Normal file
18
Z2/stop-app.sh
Normal file
@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Stopping To-Do List Application in Kubernetes"
|
||||
|
||||
# Delete service
|
||||
kubectl delete -f service.yaml
|
||||
|
||||
# Delete deployment
|
||||
kubectl delete -f deployment.yaml
|
||||
|
||||
# Delete StatefulSet, PVC, and PV
|
||||
kubectl delete -f statefulset.yaml
|
||||
|
||||
# Delete namespace
|
||||
kubectl delete -f namespace.yaml
|
||||
|
||||
echo "Application stopped successfully!"
|
150
Z2/style.css
Normal file
150
Z2/style.css
Normal file
@ -0,0 +1,150 @@
|
||||
body {
|
||||
font-family: "Helvetica Neue", sans-serif;
|
||||
background: linear-gradient(to bottom, #f7f7f7, #e1e1e1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.app-container {
|
||||
background-color: #ffffff;
|
||||
padding: 40px;
|
||||
border-radius: 20px;
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
box-shadow: 0px 15px 20px rgba(0, 0, 0, 0.3);
|
||||
border: 1px solid #d9d9d9;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: "Helvetica", sans-serif;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
font-size: 30px;
|
||||
color: #4a4a4a;
|
||||
text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 16px;
|
||||
color: #6d6d72;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#task-input {
|
||||
flex-grow: 1;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #c7c7c7;
|
||||
background-color: #f0f0f0;
|
||||
font-size: 18px;
|
||||
box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
form button {
|
||||
padding: 15px 25px;
|
||||
border: none;
|
||||
background: linear-gradient(to bottom, #4da6ff, #0066cc);
|
||||
color: #ffffff;
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
text-shadow: 0px -1px 1px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 0px 5px 8px rgba(0, 0, 0, 0.2);
|
||||
transition: all 0.2s ease;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
form button:active {
|
||||
background: linear-gradient(to bottom, #0066cc, #4da6ff);
|
||||
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2);
|
||||
transform: translateY(2px);
|
||||
}
|
||||
|
||||
.filter-buttons {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.filter {
|
||||
background: linear-gradient(to bottom, #e6e6e6, #d1d1d1);
|
||||
border: 1px solid #c3c3c3;
|
||||
padding: 10px 20px;
|
||||
color: #4a4a4a;
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.6);
|
||||
box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.15);
|
||||
transition: all 0.2s ease;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.filter.active, .filter:hover {
|
||||
background: linear-gradient(to bottom, #4da6ff, #0066cc);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
#task-list {
|
||||
list-style: none;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
padding: 10px 0;
|
||||
background-color: #ffffff;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e2e2e2;
|
||||
}
|
||||
|
||||
.task-item {
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
background-color: #ffffff;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||
transition: background 0.3s ease;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.task-item:hover {
|
||||
background: linear-gradient(to bottom, #4da6ff, #0066cc);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.task-item.completed {
|
||||
text-decoration: line-through;
|
||||
color: #a09b8d;
|
||||
}
|
||||
|
||||
.task-actions {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.task-actions button {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.task-actions button.complete-btn {
|
||||
color: #60a36e;
|
||||
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.task-actions button.delete-btn {
|
||||
color: #d9534f;
|
||||
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);
|
||||
}
|
1
Z2/tasks.json
Normal file
1
Z2/tasks.json
Normal file
@ -0,0 +1 @@
|
||||
[]
|
87
Z2/todo-app-deployment.yaml
Normal file
87
Z2/todo-app-deployment.yaml
Normal file
@ -0,0 +1,87 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: todo-app-ns-v2
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: todo-web-service
|
||||
namespace: todo-app-ns-v2
|
||||
spec:
|
||||
selector:
|
||||
app: todo-web
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 8080
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: frontend-deployment
|
||||
namespace: todo-app-ns-v2
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: todo-web
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: todo-web
|
||||
spec:
|
||||
containers:
|
||||
- name: frontend
|
||||
image: your-frontend-image:latest # Укажи свой образ для фронтенда
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: backend-deployment
|
||||
namespace: todo-app-ns-v2
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: todo-backend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: todo-backend
|
||||
spec:
|
||||
containers:
|
||||
- name: backend
|
||||
image: your-backend-image:latest # Укажи свой образ для бэкенда
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: todo-app-pv
|
||||
namespace: todo-app-ns-v2
|
||||
spec:
|
||||
capacity:
|
||||
storage: 1Gi
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
hostPath:
|
||||
path: /mnt/data
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: todo-app-pvc
|
||||
namespace: todo-app-ns-v2
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
volumeName: todo-app-pv
|
4
Z2/todo-app-ns-v2.yaml
Normal file
4
Z2/todo-app-ns-v2.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: todo-app-ns-v2
|
14
Z2/todo-app-pv.yaml
Normal file
14
Z2/todo-app-pv.yaml
Normal file
@ -0,0 +1,14 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
metadata:
|
||||
name: todo-app-pv
|
||||
namespace: todo-app-ns-v2 # Указываем пространство имен
|
||||
spec:
|
||||
capacity:
|
||||
storage: 1Gi
|
||||
volumeMode: Filesystem
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
persistentVolumeReclaimPolicy: Retain
|
||||
hostPath:
|
||||
path: "/mnt/data/todo-app"
|
12
Z2/todo-app-pvc.yaml
Normal file
12
Z2/todo-app-pvc.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: todo-app-pvc
|
||||
namespace: todo-app-ns-v2 # Указываем пространство имен
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
volumeMode: Filesystem
|
12
Z2/todo-data-service.yaml
Normal file
12
Z2/todo-data-service.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: todo-data-service
|
||||
namespace: todo-app-ns-v2 # Указываем пространство имен
|
||||
spec:
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: todo-data
|
||||
clusterIP: None # Указывает на использование StatefulSet
|
23
Z2/todo-data-statefulset.yaml
Normal file
23
Z2/todo-data-statefulset.yaml
Normal file
@ -0,0 +1,23 @@
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: todo-data-manager
|
||||
namespace: todo-app-ns-v2 # Указываем пространство имен
|
||||
spec:
|
||||
serviceName: "todo-data-service"
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: todo-data
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: todo-data
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: my-docker-secret # Имя секрета для DockerHub
|
||||
containers:
|
||||
- name: todo-data
|
||||
image: jank8000/todo-data-image:latest
|
||||
ports:
|
||||
- containerPort: 8080
|
Loading…
Reference in New Issue
Block a user