From dc367e2327aef4a243bfb882ce4a3f596237662d Mon Sep 17 00:00:00 2001 From: Damir Date: Tue, 7 Apr 2026 22:06:27 +0300 Subject: [PATCH] add docker --- .dockerignore | 17 +++++++++++++ backend/Dockerfile | 15 +++++++++++ docker-compose.yml | 27 ++++++++++++++++++++ frontend/Dockerfile | 15 +++++++++++ main.py | 53 --------------------------------------- readme.md | 18 ++++++++++++- requirements-backend.txt | 4 +++ requirements-frontend.txt | 2 ++ run.sh | 20 ++++----------- ui.py | 38 ---------------------------- 10 files changed, 102 insertions(+), 107 deletions(-) create mode 100644 .dockerignore create mode 100644 backend/Dockerfile create mode 100644 docker-compose.yml create mode 100644 frontend/Dockerfile delete mode 100644 main.py create mode 100644 requirements-backend.txt create mode 100644 requirements-frontend.txt delete mode 100644 ui.py diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d4e84c0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,17 @@ +__pycache__/ +*.pyc +*.pyo +*.pyd +.Python +*.log +.venv/ +venv/ +env/ +.env +.git/ +.gitignore +.idea/ +.vscode/ +dist/ +build/ +*.egg-info/ diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..b01d460 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,15 @@ +FROM python:3.12-slim + +WORKDIR /app + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 + +COPY requirements-backend.txt /app/requirements-backend.txt +RUN pip install --no-cache-dir -r /app/requirements-backend.txt + +COPY backend/ /app/backend/ + +EXPOSE 8000 + +CMD ["python", "-m", "uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..381e625 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,27 @@ +services: + backend: + build: + context: . + dockerfile: backend/Dockerfile + environment: + OLLAMA_API_URL: "http://10.10.10.136:11434/api/generate" + PORT: "8000" + ports: + - "8000:8000" + healthcheck: + test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health').read()"] + interval: 10s + timeout: 3s + retries: 10 + + frontend: + build: + context: . + dockerfile: frontend/Dockerfile + environment: + BACKEND_URL: "http://backend:8000/generate" + ports: + - "8501:8501" + depends_on: + backend: + condition: service_healthy diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..ed10ccc --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,15 @@ +FROM python:3.12-slim + +WORKDIR /app + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 + +COPY requirements-frontend.txt /app/requirements-frontend.txt +RUN pip install --no-cache-dir -r /app/requirements-frontend.txt + +COPY frontend/ /app/frontend/ + +EXPOSE 8501 + +CMD ["python", "-m", "streamlit", "run", "frontend/ui.py", "--server.address=0.0.0.0", "--server.port=8501"] diff --git a/main.py b/main.py deleted file mode 100644 index 8057acb..0000000 --- a/main.py +++ /dev/null @@ -1,53 +0,0 @@ -from fastapi import FastAPI, HTTPException -from pydantic import BaseModel -import requests -import yaml - -app = FastAPI(title="AI CI/CD Assistant") - -# ЗАМЕНИТЕ на IP вашего контейнера с Ollama -OLLAMA_API_URL = "http://10.10.10.136:11434/api/generate" - -class GenerationRequest(BaseModel): - description: str - platform: str = "GitHub Actions" # или GitLab CI - model: str = "codellama" - -def validate_config(config_text: str): - """Простая валидация YAML синтаксиса""" - try: - yaml.safe_load(config_text) - return True, "Success" - except Exception as e: - return False, str(e) - -@app.post("/generate") -async def generate_pipeline(req: GenerationRequest): - prompt = f"Write only a valid {req.platform} YAML configuration for: {req.description}. No explanations, just code." - - payload = { - "model": req.model, - "prompt": prompt, - "stream": False - } - - try: - response = requests.post(OLLAMA_API_URL, json=payload, timeout=60) - raw_text = response.json().get("response", "") - - # Очистка от Markdown-оберток (```yaml ... ```) - clean_code = raw_text.replace("```yaml", "").replace("```", "").strip() - - is_valid, error_msg = validate_config(clean_code) - - return { - "status": "ok" if is_valid else "error", - "config": clean_code, - "validation_error": error_msg if not is_valid else None - } - except Exception as e: - raise HTTPException(status_code=500, detail=f"Ollama error: {str(e)}") - -if __name__ == "__main__": - import uvicorn - uvicorn.run(app, host="0.0.0.0", port=8000) \ No newline at end of file diff --git a/readme.md b/readme.md index 56a6051..4779d9f 100644 --- a/readme.md +++ b/readme.md @@ -1 +1,17 @@ -1 \ No newline at end of file +## DevOps Portal (prototype) + +### Run + +```bash +docker compose up --build +``` + +### URLs + +- **Backend health**: `http://localhost:8000/health` +- **Frontend (Streamlit)**: `http://localhost:8501` + +### Configuration + +- **Ollama**: backend uses `OLLAMA_API_URL` (set in `docker-compose.yml`) +- **Frontend → backend**: frontend uses `BACKEND_URL` (defaults to `http://backend:8000/generate`) \ No newline at end of file diff --git a/requirements-backend.txt b/requirements-backend.txt new file mode 100644 index 0000000..667a987 --- /dev/null +++ b/requirements-backend.txt @@ -0,0 +1,4 @@ +fastapi +uvicorn[standard] +requests +pyyaml diff --git a/requirements-frontend.txt b/requirements-frontend.txt new file mode 100644 index 0000000..885ed68 --- /dev/null +++ b/requirements-frontend.txt @@ -0,0 +1,2 @@ +streamlit +requests diff --git a/run.sh b/run.sh index 116a437..34fb0c0 100755 --- a/run.sh +++ b/run.sh @@ -1,19 +1,9 @@ #!/bin/bash -# 1. Снимаем блокировку Git (на случай, если что-то изменилось локально) -git reset --hard HEAD -git pull origin master +set -euo pipefail -# 2. Убиваем старые процессы, чтобы освободить порты 8000 и 8501 -fuser -k 8000/tcp -fuser -k 8501/tcp +echo "Starting services with Docker Compose..." +docker compose up --build -d -# 3. Запуск Бэкенда (указываем правильный файл main.py) -echo "Starting Backend..." -nohup python3 main.py > backend.log 2>&1 & - -# 4. Запуск Фронтенда -echo "Starting Frontend..." -nohup streamlit run ui.py --server.port 8501 > frontend.log 2>&1 & - -echo "Services started!" \ No newline at end of file +echo "Backend: http://localhost:8000/health" +echo "Frontend: http://localhost:8501" \ No newline at end of file diff --git a/ui.py b/ui.py deleted file mode 100644 index d6976f6..0000000 --- a/ui.py +++ /dev/null @@ -1,38 +0,0 @@ -import streamlit as st -import requests - -st.set_page_config(page_title="DevOps AI Assistant", page_icon="🚀") - -st.title("🤖 AI CI/CD Pipeline Generator") -st.markdown("Прототип сервиса для генерации и валидации конфигураций") - -with st.sidebar: - st.header("Настройки") - api_url = st.text_input("Backend URL", "http://localhost:8000/generate") - model = st.selectbox("LLM Модель", ["deepseek-r1:1.5b", "qwen2.5-coder:1.5b", "llama3.1:8b", "Arena Model"]) - platform = st.radio("Платформа", ["GitHub Actions", "GitLab CI"]) - -user_input = st.text_area("Опишите пайплайн (например: 'Python app with pytest and docker build')", height=150) - -if st.button("Сгенерировать конфигурацию", type="primary"): - if user_input: - with st.spinner("LLM думает..."): - try: - res = requests.post(api_url, json={ - "description": user_input, - "platform": platform, - "model": model - }) - data = res.json() - - if data["status"] == "ok": - st.success("✅ Конфигурация валидна!") - st.code(data["config"], language="yaml") - st.download_button("Скачать .yml", data["config"], file_name="pipeline.yml") - else: - st.error(f"❌ Ошибка валидации: {data['validation_error']}") - st.code(data["config"], language="yaml") - except Exception as e: - st.error(f"Ошибка подключения к бекенду: {e}") - else: - st.warning("Пожалуйста, введите описание.") \ No newline at end of file