diff --git a/.forgejo/workflows/deploy.yml b/.forgejo/workflows/deploy.yml index 5b99e90..ab4221a 100644 --- a/.forgejo/workflows/deploy.yml +++ b/.forgejo/workflows/deploy.yml @@ -11,56 +11,81 @@ on: - main env: - REGISTRY: ${{ secrets.REGISTRY_URL || 'forgejo.example.com' }} - IMAGE_NAME: ${{ secrets.IMAGE_NAME || 'flask-app' }} + IMAGE_NAME: ${{ secrets.IMAGE_NAME || 'vsdiscoveries/flask-app' }} DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} DEPLOY_USER: ${{ secrets.DEPLOY_USER }} DEPLOY_PORT: ${{ secrets.DEPLOY_PORT || '22' }} jobs: - test: - runs-on: ubuntu-latest + setup: + runs-on: docker steps: - - name: Checkout code - uses: actions/checkout@v4 + - name: Clone repository + run: | + git config --global http.sslVerify false + git clone https://vicsergeev.ru/forgejo/Vic/DummyApp.git . + git checkout ${{ github.sha }} + ls -la + - name: Setup complete + run: echo "✅ Setup complete, starting pipeline..." - - name: Setup Python - uses: actions/setup-python@v4 - with: - python-version: '3.14' + test: + needs: setup + runs-on: docker + steps: + - name: Clone repository + run: | + git config --global http.sslVerify false + git clone https://vicsergeev.ru/forgejo/Vic/DummyApp.git . + git checkout ${{ github.sha }} + + - name: Install Python + run: | + apt-get update + apt-get install -y python3 python3-pip python3-venv + python3 --version - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install pytest flake8 + python3 -m pip install --upgrade pip + pip3 install -r requirements.txt + pip3 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!" + - name: Test with pytest + run: echo "✅ Tests passed!" build-and-push: needs: test - runs-on: ubuntu-latest + runs-on: docker if: github.event_name == 'push' steps: - - name: Checkout code - uses: actions/checkout@v4 + - name: Clone repository + run: | + git config --global http.sslVerify false + git clone https://vicsergeev.ru/forgejo/Vic/DummyApp.git . + git checkout ${{ github.sha }} + + - name: Install Docker CLI + run: | + apt-get update + apt-get install -y ca-certificates curl + curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-26.1.4.tgz -o docker.tgz + tar xzf docker.tgz --strip-components=1 -C /usr/bin docker/docker + rm docker.tgz + docker --version - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Log in to registry + - name: Log in to Docker Hub uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} username: ${{ secrets.REGISTRY_USERNAME }} password: ${{ secrets.REGISTRY_PASSWORD }} @@ -77,28 +102,35 @@ jobs: 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 + ${{ env.IMAGE_NAME }}:latest + ${{ env.IMAGE_NAME }}:${{ steps.vars.outputs.IMAGE_TAG }} + ${{ env.IMAGE_NAME }}:${{ github.run_number }} 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 + runs-on: docker if: github.event_name == 'push' && github.ref == 'refs/heads/master' steps: - - name: Checkout code - uses: actions/checkout@v4 + - name: Clone repository + run: | + git config --global http.sslVerify false + git clone https://vicsergeev.ru/forgejo/Vic/DummyApp.git . + git checkout ${{ github.sha }} - name: Setup SSH - uses: webfactory/ssh-agent@v0.9.0 - with: - ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + run: | + apt-get update && apt-get install -y openssh-client + mkdir -p /root/.ssh + chmod 700 /root/.ssh + + echo "${{ secrets.SSH_PRIVATE_KEY }}" | sed 's/\r$//' > /root/.ssh/deploy_key + chmod 600 /root/.ssh/deploy_key + + ssh-keyscan -p ${{ env.DEPLOY_PORT }} -H ${{ env.DEPLOY_HOST }} > /root/.ssh/known_hosts 2>/dev/null || true - name: Add host to known_hosts run: | @@ -106,12 +138,10 @@ jobs: - name: Deploy to VPS run: | - ssh -p ${{ env.DEPLOY_PORT }} ${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} << 'DEPLOY_SCRIPT' + ssh -p ${{ env.DEPLOY_PORT }} -i /root/.ssh/deploy_key -o StrictHostKeyChecking=no -o BatchMode=yes ${{ 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 @@ -119,20 +149,16 @@ jobs: echo "🚀 Начинаем деплой на сервер..." - # Создаем директорию для приложения если её нет mkdir -p $DEPLOY_DIR cd $DEPLOY_DIR - # Загружаем последний образ - echo "📦 Загружаем Docker образ..." - docker pull $REGISTRY/$IMAGE_NAME:latest + echo "📦 Загружаем Docker образ с Docker Hub..." + docker pull $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 \ @@ -142,10 +168,9 @@ jobs: -e COMMIT_HASH="${{ github.sha }}" \ -e FLASK_ENV=production \ -e SECRET_KEY="${{ secrets.APP_SECRET_KEY }}" \ - $REGISTRY/$IMAGE_NAME:latest + $IMAGE_NAME:latest - # Проверяем здоровье - sleep 5 + sleep 15 if curl -f http://localhost:$PORT/health; then echo "✅ Деплой успешно завершен!" echo "🌐 Приложение доступно на порту $PORT" @@ -155,7 +180,6 @@ jobs: exit 1 fi - # Очищаем старые образы echo "🧹 Очищаем старые Docker образы..." docker image prune -f DEPLOY_SCRIPT diff --git a/Dockerfile b/Dockerfile index 862816e..ec2efcd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,34 +1,21 @@ -# Многоступенчатая сборка для оптимизации -FROM python:3.14-slim as builder +FROM python:3.12-slim 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 . . -# Создаем пользователя для запуска +# Создаём пользователя и даём права на /app RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app 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 + CMD python -c "import urllib.request; urllib.request.urlopen('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 diff --git a/README.md b/README.md index 40e8b06..9d84cce 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ -# DummyApp - -Dummy app for dockerfile training +# DummyApp for dockerfile training & Forgejo CI/CD +My first time ### Dockerfile -is created with AI, used as best practices example \ No newline at end of file +is created with AI, used as best practices example + +### Success +I started with very difficult one - Forgejo has to be setup manualy, runner install seperatly +All secerest also done manually. "How to" doc is going to be created in nearest future \ No newline at end of file diff --git a/run.py b/run.py index 7425f4c..d365871 100644 --- a/run.py +++ b/run.py @@ -3,4 +3,5 @@ from app import create_app app = create_app() if __name__ == '__main__': + print("Starting server...") app.run(host='0.0.0.0', port=5000, debug=True) \ No newline at end of file