diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 4b0a877..0000000 --- a/.dockerignore +++ /dev/null @@ -1,18 +0,0 @@ -__pycache__ -*.pyc -*.pyo -*.pyd -.Python -env/ -venv/ -.venv/ -*.log -.git -.gitignore -README.md -.env -.vscode/ -.idea/ -*.db -*.sqlite -.DS_Store \ No newline at end of file diff --git a/.forgejo/workflows/deploy.yml b/.forgejo/workflows/deploy.yml deleted file mode 100644 index 5b99e90..0000000 --- a/.forgejo/workflows/deploy.yml +++ /dev/null @@ -1,171 +0,0 @@ -name: Build and Deploy Flask App - -on: - push: - branches: - - master - - main - pull_request: - branches: - - master - - main - -env: - REGISTRY: ${{ secrets.REGISTRY_URL || 'forgejo.example.com' }} - IMAGE_NAME: ${{ secrets.IMAGE_NAME || 'flask-app' }} - DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} - DEPLOY_USER: ${{ secrets.DEPLOY_USER }} - DEPLOY_PORT: ${{ secrets.DEPLOY_PORT || '22' }} - -jobs: - test: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v4 - with: - python-version: '3.14' - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install pytest flake8 - - - name: Lint with flake8 - run: | - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - - name: Test with pytest (опционально) - run: | - # Добавьте тесты если есть - echo "Tests passed!" - - build-and-push: - needs: test - runs-on: ubuntu-latest - if: github.event_name == 'push' - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ secrets.REGISTRY_USERNAME }} - password: ${{ secrets.REGISTRY_PASSWORD }} - - - name: Get commit hash - id: vars - run: | - echo "COMMIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - echo "BUILD_TIME=$(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_OUTPUT - echo "IMAGE_TAG=${GITHUB_SHA::8}" >> $GITHUB_OUTPUT - - - name: Build and push Docker image - uses: docker/build-push-action@v5 - with: - context: . - push: true - tags: | - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.vars.outputs.IMAGE_TAG }} - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.run_number }} - cache-from: type=gha - cache-to: type=gha,mode=max - build-args: | - COMMIT_HASH=${{ steps.vars.outputs.COMMIT_HASH }} - BUILD_TIME=${{ steps.vars.outputs.BUILD_TIME }} - - deploy: - needs: build-and-push - runs-on: ubuntu-latest - if: github.event_name == 'push' && github.ref == 'refs/heads/master' - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup SSH - uses: webfactory/ssh-agent@v0.9.0 - with: - ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} - - - name: Add host to known_hosts - run: | - ssh-keyscan -p ${{ env.DEPLOY_PORT }} -H ${{ env.DEPLOY_HOST }} >> ~/.ssh/known_hosts - - - name: Deploy to VPS - run: | - ssh -p ${{ env.DEPLOY_PORT }} ${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} << 'DEPLOY_SCRIPT' - set -e - - # Переменные для деплоя - APP_NAME="flask-app" - REGISTRY="${{ env.REGISTRY }}" - IMAGE_NAME="${{ env.IMAGE_NAME }}" - CONTAINER_NAME="flask-app" - PORT=5000 - DEPLOY_DIR="/opt/flask-app" - - echo "🚀 Начинаем деплой на сервер..." - - # Создаем директорию для приложения если её нет - mkdir -p $DEPLOY_DIR - cd $DEPLOY_DIR - - # Загружаем последний образ - echo "📦 Загружаем Docker образ..." - docker pull $REGISTRY/$IMAGE_NAME:latest - - # Останавливаем и удаляем старый контейнер - echo "🔄 Перезапускаем контейнер..." - docker stop $CONTAINER_NAME 2>/dev/null || true - docker rm $CONTAINER_NAME 2>/dev/null || true - - # Запускаем новый контейнер - echo "🚀 Запускаем новый контейнер..." - docker run -d \ - --name $CONTAINER_NAME \ - --restart unless-stopped \ - -p $PORT:5000 \ - -e APP_VERSION="${{ github.run_number }}" \ - -e COMMIT_HASH="${{ github.sha }}" \ - -e FLASK_ENV=production \ - -e SECRET_KEY="${{ secrets.APP_SECRET_KEY }}" \ - $REGISTRY/$IMAGE_NAME:latest - - # Проверяем здоровье - sleep 5 - if curl -f http://localhost:$PORT/health; then - echo "✅ Деплой успешно завершен!" - echo "🌐 Приложение доступно на порту $PORT" - else - echo "❌ Ошибка: приложение не отвечает!" - docker logs $CONTAINER_NAME --tail 50 - exit 1 - fi - - # Очищаем старые образы - echo "🧹 Очищаем старые Docker образы..." - docker image prune -f - DEPLOY_SCRIPT - - - name: Notify about deployment - if: always() - run: | - if [ ${{ job.status }} == 'success' ]; then - echo "✅ Деплой прошел успешно!" - else - echo "❌ Деплой завершился с ошибкой!" - exit 1 - fi \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 862816e..831f799 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,34 +1,26 @@ -# Многоступенчатая сборка для оптимизации -FROM python:3.14-slim as builder +FROM python:3.12-slim + +# Установка curl для healthcheck +RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* WORKDIR /app -# Устанавливаем зависимости COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt -# Финальный образ -FROM python:3.14-slim - -WORKDIR /app - -# Копируем зависимости из builder -COPY --from=builder /usr/local/lib/python3.9/site-packages /usr/local/lib/python3.9/site-packages -COPY --from=builder /usr/local/bin /usr/local/bin - -# Копируем код приложения COPY . . -# Создаем пользователя для запуска -RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app +# Создаем non-root пользователя +RUN groupadd -r appuser && useradd -r -g appuser appuser USER appuser -# Экспортируем порт EXPOSE 5000 -# Health check -HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ - CMD python -c "import requests; requests.get('http://localhost:5000/health')" || exit 1 +HEALTHCHECK --interval=30s --timeout=3s --retries=3 \ + CMD curl -f http://localhost:5000/health || exit 1 -# Запускаем через gunicorn -CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "4", "run:app"] \ No newline at end of file +# Вариант 1: Запуск через Python +CMD ["python", "-c", "from main import app; app.run(host='0.0.0.0', port=5000)"] + +# Вариант 2: Если используете gunicorn +# CMD ["gunicorn", "--bind", "0.0.0.0:5000", "main:app"] \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py deleted file mode 100644 index fda8dd8..0000000 --- a/app/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -from flask import Flask -import os - - -def create_app(): - app = Flask(__name__) - app.config.from_object('config.Config') - - from app.routes import main - app.register_blueprint(main) - - return app \ No newline at end of file diff --git a/app/routes.py b/app/routes.py deleted file mode 100644 index 3a482d7..0000000 --- a/app/routes.py +++ /dev/null @@ -1,27 +0,0 @@ -from flask import Blueprint, render_template, jsonify -import os -import datetime - -main = Blueprint('main', __name__) - -@main.route('/') -def index(): - return render_template('index.html', - title='Flask CI/CD Demo', - version=os.environ.get('APP_VERSION', '1.0.0')) - -@main.route('/health') -def health(): - return jsonify({ - 'status': 'healthy', - 'timestamp': datetime.datetime.now().isoformat(), - 'environment': os.environ.get('FLASK_ENV', 'production') - }) - -@main.route('/api/info') -def info(): - return jsonify({ - 'app': 'Flask CI/CD Demo', - 'version': os.environ.get('APP_VERSION', '1.0.0'), - 'commit': os.environ.get('COMMIT_HASH', 'unknown') - }) \ No newline at end of file diff --git a/app/static/css/style.css b/app/static/css/style.css deleted file mode 100644 index 65a0a5e..0000000 --- a/app/static/css/style.css +++ /dev/null @@ -1,124 +0,0 @@ -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -body { - font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - min-height: 100vh; - display: flex; - flex-direction: column; -} - -nav { - background: rgba(255, 255, 255, 0.95); - box-shadow: 0 2px 10px rgba(0,0,0,0.1); - padding: 1rem 2rem; -} - -.nav-container { - max-width: 1200px; - margin: 0 auto; - display: flex; - justify-content: space-between; - align-items: center; -} - -.nav-container h1 { - color: #333; - font-size: 1.5rem; -} - -.nav-links a { - color: #555; - text-decoration: none; - margin-left: 2rem; - padding: 0.5rem 1rem; - border-radius: 4px; - transition: all 0.3s; -} - -.nav-links a:hover { - background: #667eea; - color: white; -} - -main { - flex: 1; - max-width: 1200px; - margin: 2rem auto; - padding: 0 2rem; - width: 100%; -} - -.container { - background: white; - border-radius: 12px; - padding: 2rem; - box-shadow: 0 4px 20px rgba(0,0,0,0.1); -} - -h2 { - color: #333; - margin-bottom: 1.5rem; -} - -.status-card { - background: #f8f9fa; - border-radius: 8px; - padding: 1.5rem; - margin: 1.5rem 0; -} - -.status-item { - display: flex; - justify-content: space-between; - padding: 0.5rem 0; - border-bottom: 1px solid #e9ecef; -} - -.status-item:last-child { - border-bottom: none; -} - -.label { - color: #666; - font-weight: 500; -} - -.value { - color: #333; - font-weight: 600; -} - -.green { - color: #28a745; -} - -.info-box { - background: #e8f4fd; - border-left: 4px solid #667eea; - padding: 1.5rem; - border-radius: 4px; - margin-top: 2rem; -} - -.info-box ol { - margin-left: 1.5rem; - margin-top: 0.5rem; -} - -.info-box li { - padding: 0.3rem 0; - color: #333; -} - -footer { - background: rgba(255, 255, 255, 0.9); - text-align: center; - padding: 1rem; - color: #666; - font-size: 0.9rem; -} \ No newline at end of file diff --git a/app/static/js/main.js b/app/static/js/main.js deleted file mode 100644 index ddcf4bf..0000000 --- a/app/static/js/main.js +++ /dev/null @@ -1,10 +0,0 @@ -document.addEventListener('DOMContentLoaded', function() { - console.log('Flask CI/CD App загружен!'); - - // Добавляем время сборки если есть - const footer = document.querySelector('footer p'); - if (footer) { - const buildTime = new Date().toLocaleString('ru-RU'); - footer.textContent += ` | Собрано: ${buildTime}`; - } -}); \ No newline at end of file diff --git a/app/templates/base.html b/app/templates/base.html deleted file mode 100644 index 456c32d..0000000 --- a/app/templates/base.html +++ /dev/null @@ -1,31 +0,0 @@ - - -
- - -