diff --git a/.github/workflows/cd-production.yml b/.github/workflows/cd-production.yml new file mode 100644 index 0000000..c53d39e --- /dev/null +++ b/.github/workflows/cd-production.yml @@ -0,0 +1,96 @@ +name: Deploy Kaapi Guardrails to EC2 Production + +on: + push: + tags: + - "v*" # Deploy only when tags like v1.0.0, v2.1.0, etc., are created + +concurrency: + group: guardrail-production-ec2-deploy + cancel-in-progress: false + +jobs: + deploy: + runs-on: ubuntu-latest + environment: AWS_ENV_SECRETS + + permissions: + id-token: write + contents: read + + steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v6 + with: + role-to-assume: ${{ secrets.EC2_DEPLOY_ROLE_ARN }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Trigger deploy on EC2 via SSM + id: ssm + env: + INSTANCE_ID: ${{ secrets.EC2_INSTANCE_ID }} + BUILD_DIRECTORY: ${{ secrets.BUILD_DIRECTORY }} + run: | + DEPLOY_CMD="cd ${BUILD_DIRECTORY} && git fetch --tags origin && git checkout --force ${{ github.sha }} && docker compose build && docker compose run --rm --entrypoint '' backend uv run alembic upgrade head && docker compose up -d --remove-orphans && docker image prune -f" + + CMD_ID=$(aws ssm send-command \ + --instance-ids "$INSTANCE_ID" \ + --document-name "AWS-RunShellScript" \ + --comment "Deploy kaapi-guardrails production" \ + --parameters "commands=[\"set -eux\", \"sudo chown -R ec2-user:ec2-user ${BUILD_DIRECTORY}\", \"sudo -iu ec2-user bash -lc \\\"${DEPLOY_CMD}\\\"\"]" \ + --query "Command.CommandId" \ + --output text) + + echo "cmd_id=$CMD_ID" >> "$GITHUB_OUTPUT" + echo "Sent SSM command: $CMD_ID" + + - name: Wait for SSM command to finish + env: + INSTANCE_ID: ${{ secrets.EC2_INSTANCE_ID }} + CMD_ID: ${{ steps.ssm.outputs.cmd_id }} + run: | + for i in {1..20}; do + STATUS=$(aws ssm get-command-invocation \ + --command-id "$CMD_ID" \ + --instance-id "$INSTANCE_ID" \ + --query "Status" \ + --output text) + + echo "Current Status: $STATUS" + + if [ "$STATUS" = "Success" ]; then + echo "Deployment completed successfully." + + aws ssm get-command-invocation \ + --command-id "$CMD_ID" \ + --instance-id "$INSTANCE_ID" \ + --query '{Status:Status,Stdout:StandardOutputContent,Stderr:StandardErrorContent}' \ + --output json + + exit 0 + fi + + if [ "$STATUS" = "Failed" ] || [ "$STATUS" = "Cancelled" ] || [ "$STATUS" = "TimedOut" ]; then + echo "Deployment failed." + + aws ssm get-command-invocation \ + --command-id "$CMD_ID" \ + --instance-id "$INSTANCE_ID" \ + --query '{Status:Status,Stdout:StandardOutputContent,Stderr:StandardErrorContent}' \ + --output json + + exit 1 + fi + + sleep 15 + done + + echo "Deployment timed out after waiting too long." + + aws ssm get-command-invocation \ + --command-id "$CMD_ID" \ + --instance-id "$INSTANCE_ID" \ + --query '{Status:Status,Stdout:StandardOutputContent,Stderr:StandardErrorContent}' \ + --output json + + exit 1 \ No newline at end of file