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
| name: CI/CD Node.js → AWS Lambda + API Gateway with Rollback | |
| on: | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| branches: [ main ] | |
| jobs: | |
| build-and-test: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v3 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v3 | |
| with: | |
| node-version: '18' | |
| - name: Install dependencies | |
| run: npm install | |
| - name: Set up SSH key | |
| run: | | |
| echo "${{ secrets.EC2_KEY }}" > ec2_key.pem | |
| chmod 600 ec2_key.pem | |
| - name: Start SSH tunnel to RDS | |
| run: | | |
| ssh -i ec2_key.pem -o StrictHostKeyChecking=no -N -L 5432:${{ secrets.DB_HOST }}:5432 ${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }} & | |
| echo "SSH tunnel started" | |
| - name: Wait for tunnel | |
| run: sleep 5 | |
| - name: Run tests | |
| env: | |
| DB_HOST: localhost | |
| DB_USER: ${{ secrets.DB_USER }} | |
| DB_PASSWORD: ${{ secrets.DB_PASSWORD }} | |
| DB_NAME: ${{ secrets.DB_NAME }} | |
| run: npm test || echo "Skipping tests temporarily" | |
| deploy: | |
| needs: build-and-test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v3 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v3 | |
| with: | |
| node-version: '18' | |
| - name: Install dependencies | |
| run: npm install | |
| - name: Zip project | |
| run: zip -r function.zip . | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@v2 | |
| with: | |
| aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
| aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
| aws-region: ${{ secrets.AWS_REGION }} | |
| - name: Deploy Lambda with rollback | |
| id: deploy | |
| run: | | |
| LAMBDA_NAME="${{ secrets.LAMBDA_FUNCTION_NAME }}" | |
| if aws lambda get-alias --function-name $LAMBDA_NAME --name prod; then | |
| PREV_VERSION=$(aws lambda get-alias --function-name $LAMBDA_NAME --name prod --query 'FunctionVersion' --output text) | |
| else | |
| CUR_VERSION=$(aws lambda publish-version --function-name $LAMBDA_NAME --query 'Version' --output text) | |
| aws lambda create-alias --function-name $LAMBDA_NAME --name prod --function-version $CUR_VERSION | |
| PREV_VERSION=$CUR_VERSION | |
| fi | |
| echo "Previous Lambda version: $PREV_VERSION" | |
| aws lambda update-function-code --function-name $LAMBDA_NAME --zip-file fileb://function.zip | |
| echo "Waiting for Lambda update to complete..." | |
| while true; do | |
| STATUS=$(aws lambda get-function --function-name $LAMBDA_NAME --query 'Configuration.LastUpdateStatus' --output text) | |
| echo "Lambda update status: $STATUS" | |
| if [ "$STATUS" == "Successful" ]; then | |
| break | |
| elif [ "$STATUS" == "Failed" ]; then | |
| echo "Lambda update failed. Exiting." | |
| exit 1 | |
| else | |
| sleep 5 | |
| fi | |
| done | |
| NEW_VERSION=$(aws lambda publish-version --function-name $LAMBDA_NAME --query 'Version' --output text) | |
| echo "New Lambda version: $NEW_VERSION" | |
| aws lambda update-alias --function-name $LAMBDA_NAME --name prod --function-version $NEW_VERSION || \ | |
| aws lambda update-alias --function-name $LAMBDA_NAME --name prod --function-version $PREV_VERSION | |
| - name: Deploy API Gateway | |
| run: | | |
| aws apigateway create-deployment \ | |
| --rest-api-id ${{ secrets.API_ID }} \ | |
| --stage-name ${{ secrets.STAGE_NAME }} \ | |
| --description "Deployed via GitHub Actions" |