Загрузить файлы в «sk1»

This commit is contained in:
Vladyslav Korzun 2025-04-13 21:00:58 +00:00
parent 8aa3fa139d
commit 5b381d2391
9 changed files with 442 additions and 0 deletions

16
sk1/Dockerfile Normal file
View File

@ -0,0 +1,16 @@
FROM python:3.9-slim
WORKDIR /app
# Установка зависимостей
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt gunicorn
# Копируем все файлы приложения
COPY . .
# Открываем порт для приложения
EXPOSE 5000
# Запуск приложения через Gunicorn
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "app:app"]

72
sk1/README.md Normal file
View File

@ -0,0 +1,72 @@
# **Správa Používateľov - Docker Aplikácia**
## **1. Podmienky na nasadenie a spustenie aplikácie**
Aby ste mohli aplikáciu spustiť, musíte mať nainštalované:
- **Linux** (napr. Ubuntu vo WSL, alebo iná distribúcia)
- **Docker** (https://docs.docker.com/get-docker/)
- **Docker Compose** (https://docs.docker.com/compose/install/)
## **2. Opis aplikácie**
Aplikácia poskytuje jednoduché webové rozhranie na správu používateľov. Používateľlia sú uložení v databáze PostgreSQL a aplikácia ich dokáže pridávať alebo mazať cez jednoduché API a webové rozhranie.
## **3. Opis virtuálnych sietí a pomenovaných zväzkov**
- **Virtuálna sieť `app_network`** - Umožňuje komunikáciu medzi kontajnermi (web, db, pgAdmin).
- **Pomenovaný zväzok `pgdata`** - Používa sa na trvalé uloženie databázových údajov PostgreSQL, aby sa nestratili pri reštarte kontajnerov.
## **4. Opis konfigurácie kontajnerov**
Aplikácia používa **Docker Compose**, kde sú definované tri kontajnery:
- **Web** (Flask aplikácia)
- Počúva na porte **5000**
- Komunikuje s databázou `db`
- **DB** (PostgreSQL)
- Používa volume `pgdata` na trvalé uloženie údajov
- Počúva na porte **5432**
- **pgAdmin** (Grafické rozhranie na správu PostgreSQL)
- Počúva na porte **8080**
## **5. Zoznam použitých kontajnerov**
- **Web (Flask)** - Používa Python 3.9 a Flask na poskytovanie webovej aplikácie.
- **PostgreSQL** - Používa obraz `postgres:13`, databázu `mydatabase`.
- **pgAdmin** - Používa obraz `dpage/pgadmin4`, port **8080**.
## **6. Ako pripraviť, spustiť, pozastaviť a vymazať aplikáciu**
### **Príprava aplikácie:**
```bash
./prepare-app.sh
```
Týmto príkazom sa vytvorí sieť, volume a pripraví databáza.
### **Spustenie aplikácie:**
```bash
./start-app.sh
```
Aplikácia sa spustí a bude dostupná na **http://localhost:5000**.
### **Pozastavenie aplikácie:**
```bash
./stop-app.sh
```
Pozastavenie aplikácie neodstráni údaje.
### **Vymazanie aplikácie:**
```bash
./remove-app.sh
```
Tento príkaz **vymaže všetky kontajnery, sieť a volume**, čo znamená, že **databáza bude kompletne vymazaná**.
## **7. Ako si pozrieť aplikáciu v prehliadači**
- **Hlavná aplikácia:** [http://localhost:5000](http://localhost:5000)
- **pgAdmin (správa databázy):** [http://localhost:8080](http://localhost:8080)
## **8. Príklad práce s aplikáciou**
### **Pridanie používateľa:**
1. Otvorte aplikáciu na **http://localhost:5000**
2. Zadajte meno do textového poľa.
3. Kliknite na **"Pridať"**.
4. Používateľ sa uloží do databázy a zobrazí na stránke.
### **Odstránenie používateľa:**
1. Kliknite na tlačidlo **"Odstrániť"** pri konkrétnom používateľovi.
2. Používateľ bude vymazaný z databázy.

73
sk1/app.py Normal file
View File

@ -0,0 +1,73 @@
from flask import Flask, render_template, request, jsonify
import psycopg2
import os
app = Flask(__name__, template_folder="templates", static_folder="static")
# Подключение к БД
def get_db_connection():
conn = psycopg2.connect(
host=os.getenv("DB_HOST"),
database=os.getenv("DB_NAME"),
user=os.getenv("DB_USER"),
password=os.getenv("DB_PASS"),
sslmode="require"
)
return conn
# Главная страница с HTML
@app.route("/")
def home():
conn = get_db_connection()
cur = conn.cursor()
cur.execute("SELECT id, name, created_at FROM users;")
users = cur.fetchall()
cur.close()
conn.close()
return render_template("index.html", users=users)
# API для добавления пользователя
@app.route("/add_user", methods=["POST"])
def add_user():
name = request.form.get("name")
if name:
conn = get_db_connection()
cur = conn.cursor()
cur.execute("INSERT INTO users (name) VALUES (%s) RETURNING id;", (name,))
user_id = cur.fetchone()[0]
conn.commit()
cur.close()
conn.close()
return jsonify({"id": user_id, "name": name}), 201
return jsonify({"error": "Имя не может быть пустым"}), 400
# API для удаления пользователя
@app.route("/delete_user/<int:user_id>", methods=["POST"])
def delete_user(user_id):
conn = get_db_connection()
cur = conn.cursor()
cur.execute("DELETE FROM users WHERE id = %s RETURNING id;", (user_id,))
deleted = cur.fetchone()
conn.commit()
cur.close()
conn.close()
if deleted:
return jsonify({"message": "Пользователь удален"})
return jsonify({"error": "Пользователь не найден"}), 404
# API для случайного пользователя
@app.route("/random_user")
def random_user():
conn = get_db_connection()
cur = conn.cursor()
cur.execute("SELECT id, name, created_at FROM users ORDER BY RANDOM() LIMIT 1;")
user = cur.fetchone()
cur.close()
conn.close()
if user:
return jsonify({"id": user[0], "name": user[1], "created_at": user[2].strftime('%Y-%m-%d %H:%M:%S')})
return jsonify({"error": "Нет пользователей"}), 404
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)

22
sk1/docker-compose.yml Normal file
View File

@ -0,0 +1,22 @@
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
depends_on:
- db
restart: always # Добавлено для автоматического рестарта при сбоях
db:
image: postgres:13
volumes:
- pgdata:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=mysecretpassword
- POSTGRES_DB=mydatabase
restart: always # Также добавлено здесь
volumes:
pgdata:

188
sk1/prepare-app.sh Normal file
View File

@ -0,0 +1,188 @@
#!/bin/bash
set -e
# Параметры
APP_NAME="userapp"
RESOURCE_GROUP="userapp-rg"
ENV_NAME="userapp-env"
ACR_NAME="userappvladregistry"
ACR_IMAGE="$ACR_NAME.azurecr.io/z1-web"
POSTGRES_NAME="userapp-pg-vlad4"
POSTGRES_HOST="$POSTGRES_NAME.postgres.database.azure.com"
POSTGRES_DB="flexibleserverdb"
POSTGRES_USER="postgres"
POSTGRES_PASS="MySuperSecretPass123"
LOCATION="northeurope"
# 🏗️ Создание resource group (если не существует)
echo "📁 Проверка: существует ли Resource Group $RESOURCE_GROUP..."
RG_EXISTS=$(az group exists --name $RESOURCE_GROUP)
if [[ "$RG_EXISTS" == "false" ]]; then
echo "🌟 Создаю Resource Group $RESOURCE_GROUP..."
az group create --name $RESOURCE_GROUP --location $LOCATION
else
echo "✔️ Resource Group уже существует"
fi
# 🔧 Проверка и создание ACR
ACR_EXISTS=$(az acr show --name $ACR_NAME --resource-group $RESOURCE_GROUP --query "name" -o tsv 2>/dev/null || echo "")
if [[ -z "$ACR_EXISTS" ]]; then
echo "🌟 Создаю Azure Container Registry..."
az acr create --resource-group $RESOURCE_GROUP --name $ACR_NAME --sku Basic
else
echo "✔️ ACR уже существует"
fi
# Включаем admin user
az acr update --name $ACR_NAME --admin-enabled true
# Ждем, пока ACR станет доступным
echo "⏳ Ждем пока ACR станет доступным..."
for i in {1..10}; do
if az acr repository list --name $ACR_NAME &>/dev/null; then
echo "✅ ACR готов"
break
else
echo "⏳ Ожидание... ($i/10)"
sleep 5
fi
done
# Получаем учетные данные
ACR_USERNAME=$(az acr credential show --name $ACR_NAME --query "username" -o tsv)
ACR_PASSWORD=$(az acr credential show --name $ACR_NAME --query "passwords[0].value" -o tsv)
echo "🧠 Проверка: существует ли PostgreSQL сервер..."
PG_EXISTS=$(az postgres flexible-server show \
--name $POSTGRES_NAME \
--resource-group $RESOURCE_GROUP \
--query "name" -o tsv 2>/dev/null || echo "")
if [[ -n "$PG_EXISTS" ]]; then
echo "🔐 Пробуем подключиться к PostgreSQL..."
if ! psql "host=$POSTGRES_HOST port=5432 dbname=postgres user=$POSTGRES_USER password=$POSTGRES_PASS sslmode=require" -c '\q' 2>/dev/null; then
echo "❌ Пароль не работает — удаляю и создаю заново..."
az postgres flexible-server delete --name $POSTGRES_NAME --resource-group $RESOURCE_GROUP --yes
PG_EXISTS=""
sleep 5
else
echo "✅ Успешное подключение"
fi
fi
if [[ -z "$PG_EXISTS" ]]; then
echo "🌟 Создаю PostgreSQL..."
az postgres flexible-server create \
--name $POSTGRES_NAME \
--resource-group $RESOURCE_GROUP \
--location $LOCATION \
--admin-user postgres \
--admin-password $POSTGRES_PASS \
--sku-name Standard_B1ms \
--tier Burstable \
--storage-size 32 \
--yes
echo "⏳ Ожидание готовности PostgreSQL..."
for i in {1..10}; do
STATE=$(az postgres flexible-server show --name $POSTGRES_NAME --resource-group $RESOURCE_GROUP --query "state" -o tsv 2>/dev/null || echo "")
echo "🔄 Состояние: $STATE"
if [[ "$STATE" == "Ready" ]]; then
break
fi
sleep 10
done
echo "🌐 Разрешаю IP..."
az postgres flexible-server firewall-rule create \
--name $POSTGRES_NAME \
--resource-group $RESOURCE_GROUP \
--rule-name AllowAllIps \
--start-ip-address 0.0.0.0 \
--end-ip-address 255.255.255.255
fi
echo "🔑 Сбрасываю пароль PostgreSQL..."
az postgres flexible-server update --name $POSTGRES_NAME --resource-group $RESOURCE_GROUP --admin-password $POSTGRES_PASS
echo "⏳ Ждем 10 сек..."
sleep 10
echo "📆 Логин в ACR..."
echo $ACR_PASSWORD | docker login "$ACR_NAME.azurecr.io" -u $ACR_USERNAME --password-stdin
echo "▶️ Сборка Docker образа..."
docker build -t z1-web .
echo "📦 Тегирование и пуш..."
docker tag z1-web $ACR_IMAGE
docker push $ACR_IMAGE
echo "☁️ Проверка Container App Environment..."
ENV_EXISTS=$(az containerapp env show --name $ENV_NAME --resource-group $RESOURCE_GROUP --query "name" -o tsv 2>/dev/null || echo "")
if [[ -z "$ENV_EXISTS" ]]; then
echo "🌟 Создаю Container Environment..."
az containerapp env create --name $ENV_NAME --resource-group $RESOURCE_GROUP --location $LOCATION
else
echo "✔️ Среда уже есть"
fi
echo "☁️ Проверка Container App..."
APP_EXISTS=$(az containerapp show --name $APP_NAME --resource-group $RESOURCE_GROUP --query "name" -o tsv 2>/dev/null || echo "")
if [[ -z "$APP_EXISTS" ]]; then
echo "🌟 Создаю Container App..."
az containerapp create \
--name $APP_NAME \
--resource-group $RESOURCE_GROUP \
--environment $ENV_NAME \
--image $ACR_IMAGE \
--target-port 5000 \
--ingress external \
--registry-server "$ACR_NAME.azurecr.io" \
--registry-username $ACR_USERNAME \
--registry-password $ACR_PASSWORD \
--cpu 0.5 --memory 1.0Gi \
--env-vars \
DB_HOST=$POSTGRES_HOST \
DB_NAME=$POSTGRES_DB \
DB_USER=$POSTGRES_USER \
DB_PASS=$POSTGRES_PASS
else
echo "🔁 Обновляю Container App..."
az containerapp registry set \
--name $APP_NAME \
--resource-group $RESOURCE_GROUP \
--server "$ACR_NAME.azurecr.io" \
--username $ACR_USERNAME \
--password $ACR_PASSWORD
az containerapp update \
--name $APP_NAME \
--resource-group $RESOURCE_GROUP \
--image $ACR_IMAGE \
--set-env-vars \
DB_HOST=$POSTGRES_HOST \
DB_NAME=$POSTGRES_DB \
DB_USER=$POSTGRES_USER \
DB_PASS=$POSTGRES_PASS
fi
echo "🗄️ Создание таблицы users..."
command -v psql >/dev/null 2>&1 || {
echo "❌ Установи psql: sudo apt install postgresql-client"
exit 1
}
psql "host=$POSTGRES_HOST port=5432 dbname=$POSTGRES_DB user=$POSTGRES_USER password=$POSTGRES_PASS sslmode=require" <<EOF
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
EOF
echo "✅ Готово! Всё развёрнуто."

60
sk1/remove-app.sh Normal file
View File

@ -0,0 +1,60 @@
#!/bin/bash
set -e
# Параметры
APP_NAME="userapp"
RESOURCE_GROUP="userapp-rg"
ENV_NAME="userapp-env"
ACR_NAME="userappvladregistry"
ACR_IMAGE="z1-web"
POSTGRES_NAME="userapp-pg-vlad4"
# 🚮 Container App
echo "🚮 Удаляю Container App..."
if az containerapp show --name $APP_NAME --resource-group $RESOURCE_GROUP &>/dev/null; then
az containerapp delete --name $APP_NAME --resource-group $RESOURCE_GROUP --yes
else
echo "❌ Container App $APP_NAME уже удален или не существует"
fi
# 🚮 Container Environment
echo "🚮 Удаляю Container Environment..."
if az containerapp env show --name $ENV_NAME --resource-group $RESOURCE_GROUP &>/dev/null; then
az containerapp env delete --name $ENV_NAME --resource-group $RESOURCE_GROUP --yes
else
echo "❌ Container Env $ENV_NAME уже удален или не существует"
fi
# 🚮 PostgreSQL
echo "🚮 Удаляю PostgreSQL Server..."
if az postgres flexible-server show --name $POSTGRES_NAME --resource-group $RESOURCE_GROUP &>/dev/null; then
az postgres flexible-server delete --name $POSTGRES_NAME --resource-group $RESOURCE_GROUP --yes
else
echo "❌ PostgreSQL сервер $POSTGRES_NAME уже удален или не существует"
fi
# 🚮 Docker образ
echo "🚮 Удаляю образ из ACR..."
if az acr repository show --name $ACR_NAME --repository $ACR_IMAGE &>/dev/null; then
az acr repository delete --name $ACR_NAME --repository $ACR_IMAGE --yes
else
echo "❌ Образ $ACR_IMAGE уже удален или не найден"
fi
# 🚮 Удаление реестра контейнеров (ACR)
echo "🚮 Удаляю ACR $ACR_NAME..."
if az acr show --name $ACR_NAME --resource-group $RESOURCE_GROUP &>/dev/null; then
az acr delete --name $ACR_NAME --resource-group $RESOURCE_GROUP --yes
else
echo "❌ ACR $ACR_NAME уже удален или не существует"
fi
# 🚮 Удаление группы ресурсов
echo "🚮 Удаляю группу ресурсов $RESOURCE_GROUP..."
if az group show --name $RESOURCE_GROUP &>/dev/null; then
az group delete --name $RESOURCE_GROUP --yes --no-wait
else
echo "❌ Группа ресурсов $RESOURCE_GROUP уже удалена или не существует"
fi
echo "✅ Все успешно удалено."

3
sk1/requirements.txt Normal file
View File

@ -0,0 +1,3 @@
flask
psycopg2-binary
gunicorn

4
sk1/start-app.sh Normal file
View File

@ -0,0 +1,4 @@
#!/bin/bash
set -e
docker-compose up -d
echo "http://localhost:5000 (Flask)"

4
sk1/stop-app.sh Normal file
View File

@ -0,0 +1,4 @@
#!/bin/bash
set -e
echo "Zastavujeme kontajnery..."
docker-compose down