chore(deps): remove conflicting Flask pin from requirements #32
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # CI/CD Pipeline: Build, Push to ECR, Deploy to EC2 | |
| # Triggers on push to main and pull requests | |
| # Jobs: CI (test) → Build & Push to ECR → Deploy to EC2 instance | |
| name: CI/CD - Deploy to EC2 | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| env: | |
| AWS_REGION: ${{ secrets.AWS_REGION }} | |
| ECR_REGISTRY: ${{ secrets.ECR_REGISTRY }} | |
| ECR_REPOSITORY: ${{ secrets.ECR_REPOSITORY }} | |
| permissions: | |
| contents: read | |
| jobs: | |
| # ===== CI: Run tests and validation ===== | |
| ci: | |
| name: Continuous Integration | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Set up Python 3.10 | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.10" | |
| cache: "pip" | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -r requirements.txt | |
| - name: Lint with flake8 (optional) | |
| continue-on-error: true | |
| run: | | |
| pip install flake8 | |
| flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics || true | |
| - name: Run tests (if present) | |
| continue-on-error: true | |
| run: | | |
| if [ -d "tests" ] || ls *test*.py 2>/dev/null; then | |
| pip install pytest | |
| pytest -v || true | |
| else | |
| echo "No tests found, skipping test step" | |
| fi | |
| # ===== BUILD: Build Docker image and push to ECR ===== | |
| build-and-push: | |
| name: Build and Push to ECR | |
| runs-on: ubuntu-latest | |
| needs: ci | |
| # Only build and push on direct push to main (not PRs) | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| outputs: | |
| image: ${{ steps.build-image.outputs.image }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@v4 | |
| with: | |
| aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
| aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
| aws-region: ${{ env.AWS_REGION }} | |
| - name: Login to Amazon ECR | |
| id: login-ecr | |
| uses: aws-actions/amazon-ecr-login@v2 | |
| - name: Build, tag, and push image to Amazon ECR | |
| id: build-image | |
| env: | |
| IMAGE_TAG: ${{ github.sha }} | |
| run: | | |
| # Build Docker image | |
| docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . | |
| docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:latest | |
| # Push both tags to ECR | |
| docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG | |
| docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest | |
| echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT | |
| echo "✅ Image pushed: $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" | |
| # ===== DEPLOY: Deploy to EC2 instance ===== | |
| deploy: | |
| name: Deploy to EC2 | |
| runs-on: ubuntu-latest | |
| needs: build-and-push | |
| steps: | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@v4 | |
| with: | |
| aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
| aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
| aws-region: ${{ env.AWS_REGION }} | |
| - name: Deploy to EC2 via SSH | |
| uses: appleboy/ssh-action@v1.0.3 | |
| env: | |
| IMAGE_TAG: ${{ github.sha }} | |
| with: | |
| host: ${{ secrets.EC2_HOST }} | |
| username: ${{ secrets.EC2_USER }} | |
| key: ${{ secrets.EC2_SSH_KEY }} | |
| envs: ECR_REGISTRY,ECR_REPOSITORY,IMAGE_TAG,AWS_REGION | |
| script: | | |
| set -e | |
| echo "🚀 Starting deployment on EC2..." | |
| # Install AWS CLI if not present | |
| if ! command -v aws &> /dev/null; then | |
| echo "Installing AWS CLI..." | |
| curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" | |
| unzip -q awscliv2.zip | |
| sudo ./aws/install | |
| fi | |
| # Login to ECR | |
| echo "🔐 Logging into Amazon ECR..." | |
| aws ecr get-login-password --region ${{ secrets.AWS_REGION }} | docker login --username AWS --password-stdin ${{ secrets.ECR_REGISTRY }} | |
| # Pull latest image | |
| echo "📦 Pulling Docker image..." | |
| docker pull ${{ secrets.ECR_REGISTRY }}/${{ secrets.ECR_REPOSITORY }}:$IMAGE_TAG | |
| # Stop and remove old container (if exists) | |
| echo "🛑 Stopping old container..." | |
| docker stop mlproject 2>/dev/null || true | |
| docker rm mlproject 2>/dev/null || true | |
| # Run new container | |
| echo "▶️ Starting new container..." | |
| docker run -d \ | |
| --name mlproject \ | |
| --restart unless-stopped \ | |
| -p 80:8080 \ | |
| ${{ secrets.ECR_REGISTRY }}/${{ secrets.ECR_REPOSITORY }}:$IMAGE_TAG | |
| # Wait for container to be healthy | |
| echo "⏳ Waiting for container to start..." | |
| sleep 5 | |
| # Check container status | |
| if docker ps | grep -q mlproject; then | |
| echo "✅ Deployment successful!" | |
| docker ps | grep mlproject | |
| else | |
| echo "❌ Container failed to start" | |
| docker logs mlproject | |
| exit 1 | |
| fi | |
| # Cleanup old images (keep last 3) | |
| echo "🧹 Cleaning up old images..." | |
| docker image prune -af --filter "until=72h" || true | |
| echo "🎉 Deployment completed successfully!" |