# EN: Build & Deploy GoodGo Platform to K8s staging via Gitea Actions # VI: Build & Deploy GoodGo Platform len K8s staging qua Gitea Actions # # Flow: Push → detect changes → batch Kaniko builds (parallel) → Harbor → kubectl deploy # Runner: act_runner (host mode, in-cluster kubectl) # Build: Kaniko Jobs clone from Gitea, build Dockerfiles, push to Harbor name: Build & Deploy to K8s on: push: branches: [master, main] jobs: build-and-deploy: runs-on: ubuntu-latest steps: - name: Clone source run: | git clone --depth 2 --branch ${{ github.ref_name }} \ https://admin:${{ secrets.REPO_PASSWORD }}@gitea.techbi.org/admin/pos-system.git . - name: Detect changed services run: | IMAGE_TAG=$(echo "${{ github.sha }}" | cut -c1-7) echo "IMAGE_TAG=${IMAGE_TAG}" >> $GITHUB_ENV CHANGED=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || echo "ALL") SERVICES="" check_change() { if echo "$CHANGED" | grep -q "^${1}/" || echo "$CHANGED" | grep -q "ALL"; then SERVICES="${SERVICES} ${2}" fi } check_change "services/iam-service-net" "iam-service" check_change "services/merchant-service-net" "merchant-service" check_change "services/order-service-net" "order-service" check_change "services/fnb-engine-net" "fnb-engine" check_change "services/catalog-service-net" "catalog-service" check_change "services/inventory-service-net" "inventory-service" check_change "services/wallet-service-net" "wallet-service" check_change "services/storage-service-net" "storage-service" check_change "services/booking-service-net" "booking-service" check_change "services/chat-service-net" "chat-service" check_change "services/social-service-net" "social-service" check_change "services/promotion-service-net" "promotion-service" check_change "services/membership-service-net" "membership-service" check_change "services/mining-service-net" "mining-service" check_change "services/mission-service-net" "mission-service" check_change "services/ads-manager-service-net" "ads-manager-service" check_change "services/ads-serving-service-net" "ads-serving-service" check_change "services/ads-billing-service-net" "ads-billing-service" check_change "services/ads-tracking-service-net" "ads-tracking-service" check_change "services/ads-analytics-service-net" "ads-analytics-service" check_change "services/mkt-facebook-service-net" "mkt-facebook-service" check_change "services/mkt-whatsapp-service-net" "mkt-whatsapp-service" check_change "services/mkt-x-service-net" "mkt-x-service" check_change "services/mkt-zalo-service-net" "mkt-zalo-service" check_change "apps/web-client-tpos-net" "pos-web" K8S_CONFIG="" if echo "$CHANGED" | grep -q "^deployments/staging/"; then K8S_CONFIG="yes" fi echo "CHANGED_SERVICES=${SERVICES}" >> $GITHUB_ENV echo "K8S_CONFIG=${K8S_CONFIG}" >> $GITHUB_ENV echo "Changed services:${SERVICES:-none}" echo "K8s config changed: ${K8S_CONFIG:-no}" - name: Setup Kaniko registry secret run: | BUILD_SERVICES="" for svc in $CHANGED_SERVICES; do BUILD_SERVICES="${BUILD_SERVICES} ${svc}"; done if [ -z "$BUILD_SERVICES" ]; then echo "No services to build"; exit 0; fi kubectl create secret docker-registry kaniko-harbor-secret -n staging \ --docker-server=harbor.techbi.org \ --docker-username=${{ secrets.HARBOR_USERNAME }} \ --docker-password=${{ secrets.HARBOR_PASSWORD }} \ --docker-email=admin@techbi.org \ --dry-run=client -o yaml | kubectl apply -f - - name: Build services via Kaniko (batched parallel) run: | if [ -z "$CHANGED_SERVICES" ]; then echo "No services to build"; exit 0; fi HARBOR="harbor.techbi.org" PROJECT="goodgo" GITEA_URL="https://admin:${{ secrets.REPO_PASSWORD }}@gitea.techbi.org/admin/pos-system.git" BRANCH="${{ github.ref_name }}" NS="staging" get_context() { case "$1" in iam-service) echo "services/iam-service-net" ;; merchant-service) echo "services/merchant-service-net" ;; order-service) echo "services/order-service-net" ;; fnb-engine) echo "services/fnb-engine-net" ;; catalog-service) echo "services/catalog-service-net" ;; inventory-service) echo "services/inventory-service-net" ;; wallet-service) echo "services/wallet-service-net" ;; storage-service) echo "services/storage-service-net" ;; booking-service) echo "services/booking-service-net" ;; chat-service) echo "services/chat-service-net" ;; social-service) echo "services/social-service-net" ;; promotion-service) echo "services/promotion-service-net" ;; membership-service) echo "services/membership-service-net" ;; mining-service) echo "services/mining-service-net" ;; mission-service) echo "services/mission-service-net" ;; ads-manager-service) echo "services/ads-manager-service-net" ;; ads-serving-service) echo "services/ads-serving-service-net" ;; ads-billing-service) echo "services/ads-billing-service-net" ;; ads-tracking-service) echo "services/ads-tracking-service-net" ;; ads-analytics-service) echo "services/ads-analytics-service-net" ;; mkt-facebook-service) echo "services/mkt-facebook-service-net" ;; mkt-whatsapp-service) echo "services/mkt-whatsapp-service-net" ;; mkt-x-service) echo "services/mkt-x-service-net" ;; mkt-zalo-service) echo "services/mkt-zalo-service-net" ;; pos-web) echo "apps/web-client-tpos-net" ;; esac } get_image() { case "$1" in pos-web) echo "web-client-tpos-net" ;; *) echo "${1}-net" ;; esac } create_kaniko_job() { local svc="$1" local ctx=$(get_context "$svc") local img=$(get_image "$svc") local full="${HARBOR}/${PROJECT}/${img}" local job="kaniko-${svc}-${IMAGE_TAG}" cat </dev/null; then echo " ✅ ${job} succeeded" else echo " ❌ ${job} FAILED" kubectl logs "job/${job}" -n ${NS} --tail=20 2>/dev/null TOTAL_FAILED=$((TOTAL_FAILED + 1)) fi done done echo "" echo "=== Build Summary ===" echo "Total batches: ${BATCH}" echo "Failed: ${TOTAL_FAILED}" if [ $TOTAL_FAILED -gt 0 ]; then echo "ERROR: ${TOTAL_FAILED} builds failed" exit 1 fi - name: Apply K8s configs run: | if [ -n "$K8S_CONFIG" ]; then echo "=== Applying K8s configs ===" kubectl apply -f deployments/staging/kubernetes/configmap.yaml kubectl apply -f deployments/staging/kubernetes/redis.yaml kubectl apply -f deployments/staging/kubernetes/rabbitmq.yaml kubectl apply -f deployments/staging/kubernetes/minio.yaml kubectl apply -f deployments/staging/kubernetes/ingress.yaml kubectl apply -f deployments/staging/kubernetes/network-policy.yaml fi - name: Deploy services run: | if [ -z "$CHANGED_SERVICES" ] && [ -z "$K8S_CONFIG" ]; then echo "Nothing to deploy" exit 0 fi HARBOR="harbor.techbi.org" PROJECT="goodgo" NS="staging" deploy_svc() { local name="$1" img="$2" manifest="$3" echo "=== Deploying ${name} ===" kubectl apply -f "deployments/staging/kubernetes/${manifest}" kubectl set image "deployment/${name}" "${name}=${HARBOR}/${PROJECT}/${img}:${IMAGE_TAG}" -n "${NS}" 2>/dev/null kubectl patch deployment "${name}" -n "${NS}" \ -p '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"harbor-pull-secret"}],"containers":[{"name":"'"${name}"'","imagePullPolicy":"Always"}]}}}}' 2>/dev/null } for svc in $CHANGED_SERVICES; do case "$svc" in iam-service) deploy_svc "iam-service" "iam-service-net" "iam-service.yaml" ;; merchant-service) deploy_svc "merchant-service" "merchant-service-net" "merchant-service.yaml" ;; order-service) deploy_svc "order-service" "order-service-net" "order-service.yaml" ;; fnb-engine) deploy_svc "fnb-engine" "fnb-engine-net" "fnb-engine.yaml" ;; catalog-service) deploy_svc "catalog-service" "catalog-service-net" "catalog-service.yaml" ;; inventory-service) deploy_svc "inventory-service" "inventory-service-net" "inventory-service.yaml" ;; wallet-service) deploy_svc "wallet-service" "wallet-service-net" "wallet-service.yaml" ;; storage-service) deploy_svc "storage-service" "storage-service-net" "storage-service.yaml" ;; booking-service) deploy_svc "booking-service" "booking-service-net" "booking-service.yaml" ;; chat-service) deploy_svc "chat-service" "chat-service-net" "chat-service.yaml" ;; social-service) deploy_svc "social-service" "social-service-net" "social-service.yaml" ;; promotion-service) deploy_svc "promotion-service" "promotion-service-net" "promotion-service.yaml" ;; membership-service) deploy_svc "membership-service" "membership-service-net" "membership-service.yaml" ;; mining-service) deploy_svc "mining-service" "mining-service-net" "mining-service.yaml" ;; mission-service) deploy_svc "mission-service" "mission-service-net" "mission-service.yaml" ;; ads-manager-service) deploy_svc "ads-manager-service" "ads-manager-service-net" "ads-manager-service.yaml" ;; ads-serving-service) deploy_svc "ads-serving-service" "ads-serving-service-net" "ads-serving-service.yaml" ;; ads-billing-service) deploy_svc "ads-billing-service" "ads-billing-service-net" "ads-billing-service.yaml" ;; ads-tracking-service) deploy_svc "ads-tracking-service" "ads-tracking-service-net" "ads-tracking-service.yaml" ;; ads-analytics-service) deploy_svc "ads-analytics-service" "ads-analytics-service-net" "ads-analytics-service.yaml" ;; mkt-facebook-service) deploy_svc "mkt-facebook-service" "mkt-facebook-service-net" "mkt-facebook-service.yaml" ;; mkt-whatsapp-service) deploy_svc "mkt-whatsapp-service" "mkt-whatsapp-service-net" "mkt-whatsapp-service.yaml" ;; mkt-x-service) deploy_svc "mkt-x-service" "mkt-x-service-net" "mkt-x-service.yaml" ;; mkt-zalo-service) deploy_svc "mkt-zalo-service" "mkt-zalo-service-net" "mkt-zalo-service.yaml" ;; pos-web) deploy_svc "pos-web" "web-client-tpos-net" "pos-web.yaml" ;; esac done echo "" echo "=== Waiting for rollouts ===" FAILED=0 for svc in $CHANGED_SERVICES; do if ! kubectl rollout status "deployment/${svc}" -n "${NS}" --timeout=180s 2>/dev/null; then echo "⚠️ ${svc} rollout incomplete" FAILED=$((FAILED + 1)) fi done echo "" echo "=== Final Status ===" kubectl get pods -n "${NS}" --sort-by=.metadata.name echo "" kubectl get svc -n "${NS}" | grep -v cm-acme if [ $FAILED -gt 0 ]; then echo "⚠️ ${FAILED} service(s) did not complete rollout" fi # Fri 10 Apr 2026 21:48:29 +07