name: Build, Push and Deploy Florale Emotion Website on: push: branches: [ 'feature/*', 'main', 'master' ] pull_request: branches: [ main, master ] env: HARBOR_REGISTRY: registry.julianvollmer.de PROJECT_NAME: florale-emotion jobs: feature-branch: runs-on: ubuntu-latest timeout-minutes: 60 if: startsWith(github.ref, 'refs/heads/feature/') steps: - name: Checkout code uses: actions/checkout@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 with: driver-opts: | image=moby/buildkit:v0.12.0 buildkitd-flags: --debug - name: Extract metadata id: meta run: | BRANCH_CLEAN=$(echo "${{ github.ref_name }}" | sed 's/[^a-zA-Z0-9._-]/-/g') SHORT_SHA="${{ github.sha }}" SHORT_SHA="${SHORT_SHA:0:8}" TAG="${BRANCH_CLEAN}-${SHORT_SHA}" echo "tag=${TAG}" >> $GITHUB_OUTPUT echo "frontend_image=${{ env.HARBOR_REGISTRY }}/${{ env.PROJECT_NAME }}/florale-emotion-frontend:${TAG}" >> $GITHUB_OUTPUT echo "backend_image=${{ env.HARBOR_REGISTRY }}/${{ env.PROJECT_NAME }}/florale-emotion-backend:${TAG}" >> $GITHUB_OUTPUT echo "bot_image=${{ env.HARBOR_REGISTRY }}/${{ env.PROJECT_NAME }}/florale-emotion-bot:${TAG}" >> $GITHUB_OUTPUT - name: Login to Harbor Registry run: | echo "Harbor12345" | docker login ${{ env.HARBOR_REGISTRY }} -u admin --password-stdin - name: Build and Push Frontend (Feature) working-directory: ./website run: | IMAGE_NAME=${{ steps.meta.outputs.frontend_image }} for attempt in 1 2 3; do echo "Build attempt $attempt for feature frontend..." docker build --no-cache --progress=plain -t "${IMAGE_NAME}" . || { echo "Build failed on attempt $attempt" if [ $attempt -eq 3 ]; then echo "All build attempts failed" exit 1 fi sleep 10 continue } for push_attempt in 1 2 3; do echo "Push attempt $push_attempt for feature frontend..." docker push "${IMAGE_NAME}" && { echo "Feature frontend push successful on attempt $push_attempt" break } || { echo "Push failed on attempt $push_attempt" if [ $push_attempt -eq 3 ]; then echo "All push attempts failed" exit 1 fi sleep 30 } done break done echo "โœ… Feature frontend build and push completed successfully!" echo "๐Ÿท๏ธ Tag: ${TAG}" echo "๐Ÿ“ฆ Image: ${IMAGE_NAME}" - name: Build and Push Backend (Feature) working-directory: ./website/backend env: IMAGE_NAME: ${{ steps.meta.outputs.backend_image }} TAG: ${{ steps.meta.outputs.tag }} run: | echo "Building backend image: ${IMAGE_NAME}" docker build --no-cache --progress=plain -t "${IMAGE_NAME}" . echo "Pushing backend image: ${IMAGE_NAME}" docker push "${IMAGE_NAME}" echo "โœ… Feature backend build and push completed successfully!" echo "๐Ÿท๏ธ Tag: ${TAG}" echo "๐Ÿ“ฆ Image: ${IMAGE_NAME}" - name: Build and Push Social Media Bot (Feature) working-directory: ./website/social-media-bot env: IMAGE_NAME: ${{ steps.meta.outputs.bot_image }} TAG: ${{ steps.meta.outputs.tag }} run: | echo "Building social media bot image: ${IMAGE_NAME}" docker build --no-cache --progress=plain -t "${IMAGE_NAME}" . echo "Pushing social media bot image: ${IMAGE_NAME}" docker push "${IMAGE_NAME}" echo "โœ… Feature social media bot build and push completed successfully!" echo "๐Ÿท๏ธ Tag: ${TAG}" echo "๐Ÿ“ฆ Image: ${IMAGE_NAME}" - name: Setup kubectl run: | # Install kubectl directly to avoid permission issues echo "Installing kubectl..." curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" chmod +x kubectl sudo mv kubectl /usr/local/bin/ kubectl version --client - name: Configure kubectl run: | mkdir -p ~/.kube echo "๐Ÿ” Debugging KUBECTLSECRET..." echo "Secret length: ${#KUBECTLSECRET}" # Try to decode as base64 first, if that fails, use as plain text if echo "${{ secrets.KUBECTLSECRET }}" | base64 -d > ~/.kube/config 2>/dev/null; then echo "โœ… KUBECTLSECRET decoded as base64" else echo "โš ๏ธ KUBECTLSECRET is not base64, using as plain text" echo "${{ secrets.KUBECTLSECRET }}" > ~/.kube/config fi echo "๐Ÿ“ kubeconfig created at ~/.kube/config" chmod 600 ~/.kube/config - name: Test kubectl connection run: | kubectl version --client kubectl get nodes - name: Deploy Feature Branch env: FRONTEND_IMAGE: ${{ steps.meta.outputs.frontend_image }} BACKEND_IMAGE: ${{ steps.meta.outputs.backend_image }} BOT_IMAGE: ${{ steps.meta.outputs.bot_image }} BRANCH_NAME: ${{ github.ref_name }} run: | echo "๐Ÿš€ Deploying feature branch: $BRANCH_NAME" echo "Frontend image: $FRONTEND_IMAGE" echo "Backend image: $BACKEND_IMAGE" echo "Bot image: $BOT_IMAGE" # Ensure namespace exists kubectl create namespace florale-emotion --dry-run=client -o yaml | kubectl apply -f - # Ensure Harbor registry secret exists kubectl create secret docker-registry harbor-registry-secret \ --docker-server=${{ env.HARBOR_REGISTRY }} \ --docker-username=admin \ --docker-password=Harbor12345 \ --namespace=florale-emotion \ --dry-run=client -o yaml | kubectl apply -f - # Apply frontend deployment und ersetze das Image-Tag dynamisch (kein latest in Features) sed "s|__IMAGE_TAG__|${{ steps.meta.outputs.tag }}|g" website/k8s/frontend.yaml | kubectl apply -n florale-emotion -f - # Apply backend deployment mit Tag-Ersetzung sed "s|__IMAGE_TAG__|${{ steps.meta.outputs.tag }}|g" website/k8s/backend.yaml | kubectl apply -n florale-emotion -f - # Apply social media bot deployment mit Tag-Ersetzung sed "s|__IMAGE_TAG__|${{ steps.meta.outputs.tag }}|g" website/k8s/bot.yaml | kubectl apply -n florale-emotion -f - # Apply feature branch ingress (using dev subdomain) kubectl apply -f website/k8s/ingress-dev.yaml -n florale-emotion # Wait for rollout echo "โณ Waiting for rollout to finish..." kubectl rollout status deployment/florale-emotion-frontend -n florale-emotion --timeout=300s echo "โœ… Feature branch deployment complete!" echo "๐ŸŒ Dev URL: https://dev.florale-emotion.de" echo "๐Ÿ“ฆ Harbor Registry: https://registry.julianvollmer.de" production-branch: runs-on: ubuntu-latest timeout-minutes: 60 if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' steps: - name: Checkout code uses: actions/checkout@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 with: driver-opts: | image=moby/buildkit:v0.12.0 buildkitd-flags: --debug - name: Extract metadata id: meta run: | BRANCH_CLEAN=$(echo "${{ github.ref_name }}" | sed 's/[^a-zA-Z0-9._-]/-/g') SHORT_SHA="${{ github.sha }}" SHORT_SHA="${SHORT_SHA:0:8}" TAG="${BRANCH_CLEAN}-${SHORT_SHA}" # Fรผr Master-Branches zusรคtzlich latest Tag erstellen echo "Master branch detected, will create latest tags" echo "tag=${TAG}" >> $GITHUB_OUTPUT echo "frontend_image=${{ env.HARBOR_REGISTRY }}/${{ env.PROJECT_NAME }}/florale-emotion-frontend:${TAG}" >> $GITHUB_OUTPUT echo "backend_image=${{ env.HARBOR_REGISTRY }}/${{ env.PROJECT_NAME }}/florale-emotion-backend:${TAG}" >> $GITHUB_OUTPUT echo "bot_image=${{ env.HARBOR_REGISTRY }}/${{ env.PROJECT_NAME }}/florale-emotion-bot:${TAG}" >> $GITHUB_OUTPUT - name: Login to Harbor Registry run: | echo "Harbor12345" | docker login ${{ env.HARBOR_REGISTRY }} -u admin --password-stdin - name: Build and Push Frontend (Production + Latest) working-directory: ./website run: | IMAGE_NAME=${{ steps.meta.outputs.frontend_image }} LATEST_IMAGE="${{ env.HARBOR_REGISTRY }}/${{ env.PROJECT_NAME }}/florale-emotion-frontend:latest" for attempt in 1 2 3; do echo "Build attempt $attempt for production frontend..." docker build --no-cache --progress=plain -t "${IMAGE_NAME}" . || { echo "Build failed on attempt $attempt" if [ $attempt -eq 3 ]; then echo "All build attempts failed" exit 1 fi sleep 10 continue } # Push versioned image for push_attempt in 1 2 3; do echo "Push attempt $push_attempt for production frontend..." docker push "${IMAGE_NAME}" && { echo "Production frontend push successful on attempt $push_attempt" break } || { echo "Push failed on attempt $push_attempt" if [ $push_attempt -eq 3 ]; then echo "All push attempts failed" exit 1 fi sleep 30 } done # Create and push latest tag echo "Creating latest tag for production..." docker tag "${IMAGE_NAME}" "${LATEST_IMAGE}" for push_attempt in 1 2 3; do echo "Push attempt $push_attempt for latest tag..." docker push "${LATEST_IMAGE}" && { echo "Latest tag push successful on attempt $push_attempt" break } || { echo "Latest push failed on attempt $push_attempt" if [ $push_attempt -eq 3 ]; then echo "Latest push attempts failed" exit 1 fi sleep 30 } done break done echo "โœ… Production frontend build and push completed successfully!" echo "๐Ÿท๏ธ Tag: ${TAG}" echo "๐Ÿ“ฆ Image: ${IMAGE_NAME}" echo "๐Ÿ“ฆ Latest: ${LATEST_IMAGE}" - name: Build and Push Backend (Production + Latest) working-directory: ./website/backend env: IMAGE_NAME: ${{ steps.meta.outputs.backend_image }} TAG: ${{ steps.meta.outputs.tag }} run: | echo "Building backend image: ${IMAGE_NAME}" docker build --no-cache --progress=plain -t "${IMAGE_NAME}" . echo "Pushing backend image: ${IMAGE_NAME}" docker push "${IMAGE_NAME}" LATEST_IMAGE="${IMAGE_NAME%:*}:latest" echo "Tagging backend as latest: ${LATEST_IMAGE}" docker tag "${IMAGE_NAME}" "${LATEST_IMAGE}" docker push "${LATEST_IMAGE}" echo "โœ… Production backend build and push completed successfully!" echo "๐Ÿท๏ธ Tag: ${TAG}" echo "๐Ÿ“ฆ Image: ${IMAGE_NAME}" echo "๐Ÿ“ฆ Latest: ${LATEST_IMAGE}" - name: Build and Push Social Media Bot (Production + Latest) working-directory: ./website/social-media-bot env: IMAGE_NAME: ${{ steps.meta.outputs.bot_image }} TAG: ${{ steps.meta.outputs.tag }} run: | echo "Building social media bot image: ${IMAGE_NAME}" docker build --no-cache --progress=plain -t "${IMAGE_NAME}" . echo "Pushing social media bot image: ${IMAGE_NAME}" docker push "${IMAGE_NAME}" LATEST_IMAGE="${IMAGE_NAME%:*}:latest" echo "Tagging social media bot as latest: ${LATEST_IMAGE}" docker tag "${IMAGE_NAME}" "${LATEST_IMAGE}" docker push "${LATEST_IMAGE}" echo "โœ… Production social media bot build and push completed successfully!" echo "๐Ÿท๏ธ Tag: ${TAG}" echo "๐Ÿ“ฆ Image: ${IMAGE_NAME}" echo "๐Ÿ“ฆ Latest: ${LATEST_IMAGE}" - name: Setup kubectl run: | # Install kubectl directly to avoid permission issues echo "Installing kubectl..." curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" chmod +x kubectl sudo mv kubectl /usr/local/bin/ kubectl version --client - name: Configure kubectl run: | mkdir -p ~/.kube echo "๐Ÿ” Debugging KUBECTLSECRET..." echo "Secret length: ${#KUBECTLSECRET}" # Try to decode as base64 first, if that fails, use as plain text if echo "${{ secrets.KUBECTLSECRET }}" | base64 -d > ~/.kube/config 2>/dev/null; then echo "โœ… KUBECTLSECRET decoded as base64" else echo "โš ๏ธ KUBECTLSECRET is not base64, using as plain text" echo "${{ secrets.KUBECTLSECRET }}" > ~/.kube/config fi echo "๐Ÿ“ kubeconfig created at ~/.kube/config" chmod 600 ~/.kube/config - name: Test kubectl connection run: | kubectl version --client kubectl get nodes - name: Deploy to Production env: FRONTEND_IMAGE: ${{ steps.meta.outputs.frontend_image }} BACKEND_IMAGE: ${{ steps.meta.outputs.backend_image }} BOT_IMAGE: ${{ steps.meta.outputs.bot_image }} run: | echo "๐Ÿš€ Deploying to production..." echo "Frontend image: $FRONTEND_IMAGE" echo "Backend image: $BACKEND_IMAGE" echo "Bot image: $BOT_IMAGE" # Ensure namespace exists kubectl create namespace florale-emotion --dry-run=client -o yaml | kubectl apply -f - # Ensure Harbor registry secret exists kubectl create secret docker-registry harbor-registry-secret \ --docker-server=${{ env.HARBOR_REGISTRY }} \ --docker-username=admin \ --docker-password=Harbor12345 \ --namespace=florale-emotion \ --dry-run=client -o yaml | kubectl apply -f - # Apply frontend deployment und ersetze das Image-Tag mit latest sed "s|__IMAGE_TAG__|latest|g" website/k8s/frontend.yaml | kubectl apply -n florale-emotion -f - # Apply backend deployment mit latest Tag sed "s|__IMAGE_TAG__|latest|g" website/k8s/backend.yaml | kubectl apply -n florale-emotion -f - # Apply social media bot deployment mit latest Tag sed "s|__IMAGE_TAG__|latest|g" website/k8s/bot.yaml | kubectl apply -n florale-emotion -f - # Apply production ingress kubectl apply -f website/k8s/ingress.yaml -n florale-emotion # Wait for rollout echo "โณ Waiting for rollout to finish..." kubectl rollout status deployment/florale-emotion-frontend -n florale-emotion --timeout=300s echo "โœ… Production deployment complete!" echo "๐ŸŒ Website: https://florale-emotion.de" echo "๐ŸŒ WWW: https://www.florale-emotion.de" echo "๐Ÿ”ง Backend API: https://api.florale-emotion.de" # Hinweise: # - Angepasst fรผr florale-emotion Projekt # - Namespace: florale-emotion # - Dev-Deployment unter dev.florale-emotion.de # - Production unter florale-emotion.de # - Unterstรผtzt Frontend, Backend und Social Media Bot # - Robuste Retry-Mechanismen fรผr Build und Push # - Eindeutige Tags fรผr bessere Nachverfolgung # - Timeout-Schutz fรผr alle Deployments