name: Deploy Production on: push: branches: - main env: REGISTRY_URL: ${{ vars.REGISTRY_URL }} IMAGE_NAME: ${{ vars.IMAGE_NAME }} APP_ENV: production jobs: build-and-push: name: Build and Push runs-on: ubuntu-latest outputs: image_tag: ${{ steps.meta.outputs.image_tag }} app_version: ${{ steps.meta.outputs.app_version }} environment: name: production url: https://practicas.prod.kubistudio.cloud steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Gitea Registry run: | set -euo pipefail echo "${{ secrets.TOKEN }}" | docker login $REGISTRY_URL -u ${{ gitea.actor }} --password-stdin - name: Build and push id: meta run: | set -euo pipefail SHA_TAG="${{ gitea.sha }}" PROD_TAG="production-latest" STABLE_TAG="stable" BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") APP_VERSION="release-${{ gitea.sha }}" docker buildx build \ --push \ --build-arg APP_VERSION=${APP_VERSION} \ --build-arg BUILD_DATE=${BUILD_DATE} \ --build-arg GIT_COMMIT=${SHA_TAG} \ --build-arg GIT_BRANCH=main \ -t ${REGISTRY_URL}/${IMAGE_NAME}:${PROD_TAG} \ -t ${REGISTRY_URL}/${IMAGE_NAME}:${STABLE_TAG} \ -t ${REGISTRY_URL}/${IMAGE_NAME}:sha-${SHA_TAG} \ . echo "image_tag=${PROD_TAG}" >> $GITEA_OUTPUT echo "app_version=${APP_VERSION}" >> $GITEA_OUTPUT echo "::notice::Image pushed: ${REGISTRY_URL}/${IMAGE_NAME}:${PROD_TAG}" deploy: name: Deploy to Production runs-on: ubuntu-latest needs: build-and-push environment: name: production url: https://practicas.prod.kubistudio.cloud steps: - name: Deploy via SSH run: | set -euo pipefail IMAGE_TAG="${{ needs.build-and-push.outputs.image_tag }}" APP_VERSION="${{ needs.build-and-push.outputs.app_version }}" eval $(ssh-agent -s) echo "${{ secrets.DEPLOY_SSH_KEY }}" | ssh-add - mkdir -p ~/.ssh ssh-keyscan -H ${{ secrets.DEPLOY_HOST }} >> ~/.ssh/known_hosts 2>/dev/null # 1. Pasamos las variables como argumentos en el mismo orden ssh ${{ secrets.DEPLOY_USERNAME }}@${{ secrets.DEPLOY_HOST }} bash -s \ "${{ env.REGISTRY_URL }}" \ "${{ env.IMAGE_NAME }}" \ "${IMAGE_TAG}" \ "${APP_VERSION}" \ "${{ gitea.actor }}" \ "${{ secrets.TOKEN }}" << 'EOF' set -euo pipefail # 2. Las recibimos dentro de la sesión remota REGISTRY_URL=$1 IMAGE_NAME=$2 IMAGE_TAG=$3 APP_VERSION=$4 GITEA_ACTOR=$5 TOKEN=$6 echo "Saving current image tag for rollback..." CURRENT_IMAGE=$(docker inspect cicd-prod --format '{{.Config.Image}}' 2>/dev/null || echo "") echo "Pulling image..." echo "$TOKEN" | docker login $REGISTRY_URL -u $GITEA_ACTOR --password-stdin docker pull $REGISTRY_URL/$IMAGE_NAME:$IMAGE_TAG echo "Stopping existing container..." docker stop cicd-prod 2>/dev/null || true docker rm cicd-prod 2>/dev/null || true echo "Starting new container..." docker run -d --name cicd-prod --restart unless-stopped -p 8083:80 \ -e APP_ENV=production \ -e APP_VERSION=${APP_VERSION} \ -e DEPLOY_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \ $REGISTRY_URL/$IMAGE_NAME:$IMAGE_TAG echo "Waiting for health check..." HEALTHY=false for i in $(seq 1 12); do if curl -sf http://localhost:8083/health > /dev/null 2>&1; then HEALTHY=true echo "::notice::Production health check passed" break fi sleep 5 done if [ "$HEALTHY" = false ]; then echo "::error::Health check failed - rolling back" docker stop cicd-prod 2>/dev/null || true docker rm cicd-prod 2>/dev/null || true if [ -n "$CURRENT_IMAGE" ]; then docker run -d \ --name cicd-prod \ --restart unless-stopped \ -p 8083:80 \ -e APP_ENV=production \ -e APP_VERSION=rollback \ -e DEPLOY_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \ "$CURRENT_IMAGE" echo "::warning::Rollback completed to previous image: $CURRENT_IMAGE" else echo "::error::No previous image available for rollback" fi exit 1 fi EOF release-notes: name: Release Notes runs-on: ubuntu-latest needs: [build-and-push, deploy] if: success() steps: - name: Generate release notes run: | set -euo pipefail COMMITS_SINCE_LAST=$(git log --oneline --no-decorate ${{ gitea.sha }} -n 20 2>/dev/null || echo "No commit history available") cat << 'SUMMARY' >> $GITEA_HOME/workflow/summary ## Production Deployment Successful :rocket: **Version:** ${{ needs.build-and-push.outputs.app_version }} **Commit:** ${{ gitea.sha }} **Image:** ${{ vars.REGISTRY_URL }}/${{ vars.IMAGE_NAME }}:production-latest **URL:** https://practicas.prod.kubistudio.cloud ### Recent Commits ``` SUMMARY git log --oneline --no-decorate -n 20 ${{ gitea.sha }} 2>/dev/null >> $GITEA_HOME/workflow/summary || true cat << 'SUMMARY' >> $GITEA_HOME/workflow/summary ``` ### Rollback If needed, rollback with: ```bash docker stop cicd-prod && docker rm cicd-prod docker run -d --name cicd-prod --restart unless-stopped -p 8083:80 \${{ vars.REGISTRY_URL }}/\${{ vars.IMAGE_NAME }}:stable ``` SUMMARY