diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml index 6e59c188..c0c59a0c 100644 --- a/.gitea/workflows/deploy.yaml +++ b/.gitea/workflows/deploy.yaml @@ -1,8 +1,8 @@ # 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 changed services → docker build → push Harbor → kubectl deploy -# Runner: act_runner (host mode, in-cluster kubectl) +# Flow: Push → detect changed services → Kaniko build → push Harbor → kubectl deploy +# Runner: act_runner (host mode, in-cluster kubectl + Kaniko Jobs) name: Build & Deploy to K8s @@ -14,7 +14,7 @@ jobs: build-and-deploy: runs-on: ubuntu-latest steps: - - name: Clone source from GitHub + - name: Clone source from Gitea run: | git clone --depth 2 --branch ${{ github.ref_name }} \ https://admin:Velik%402026@gitea.techbi.org/admin/pos-system.git . @@ -77,61 +77,149 @@ jobs: echo "CHANGED_SERVICES=${SERVICES}" >> $GITHUB_ENV echo "Changed services: ${SERVICES:-none}" - - name: Build and push changed services + - name: Build and push via Kaniko run: | - if [ -z "$CHANGED_SERVICES" ]; then - echo "No services changed, skipping build" + # Filter out __k8s_config__ to get only real services + BUILD_SERVICES="" + for svc in $CHANGED_SERVICES; do + if [ "$svc" != "__k8s_config__" ]; then + BUILD_SERVICES="${BUILD_SERVICES} ${svc}" + fi + done + + if [ -z "$BUILD_SERVICES" ]; then + echo "No services to build, skipping" exit 0 fi HARBOR="harbor.techbi.org" PROJECT="goodgo" + GITHUB_REPO="https://github.com/hongochai10/Microservices-Development.git" + BRANCH="${{ github.ref_name }}" + NS="staging" - echo "${{ secrets.HARBOR_PASSWORD }}" | docker login "${HARBOR}" -u "${{ secrets.HARBOR_USERNAME }}" --password-stdin + # Create Harbor docker config secret for Kaniko + kubectl create secret docker-registry kaniko-harbor-secret -n "${NS}" \ + --docker-server="${HARBOR}" \ + --docker-username="${{ secrets.HARBOR_USERNAME }}" \ + --docker-password="${{ secrets.HARBOR_PASSWORD }}" \ + --docker-email=admin@techbi.org \ + --dry-run=client -o yaml | kubectl apply -f - - build_service() { - local name="$1" - local context="$2" - local image="${HARBOR}/${PROJECT}/${name}-net" - - echo "=== Building ${name} ===" - docker build -t "${image}:${IMAGE_TAG}" -t "${image}:latest" "${context}" - docker push "${image}:${IMAGE_TAG}" - docker push "${image}:latest" - echo "=== ${name} pushed ===" + 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 } - for svc in $CHANGED_SERVICES; do - case "$svc" in - iam-service) build_service "iam-service" "./services/iam-service-net" ;; - merchant-service) build_service "merchant-service" "./services/merchant-service-net" ;; - order-service) build_service "order-service" "./services/order-service-net" ;; - fnb-engine) build_service "fnb-engine" "./services/fnb-engine-net" ;; - catalog-service) build_service "catalog-service" "./services/catalog-service-net" ;; - inventory-service) build_service "inventory-service" "./services/inventory-service-net" ;; - wallet-service) build_service "wallet-service" "./services/wallet-service-net" ;; - storage-service) build_service "storage-service" "./services/storage-service-net" ;; - booking-service) build_service "booking-service" "./services/booking-service-net" ;; - chat-service) build_service "chat-service" "./services/chat-service-net" ;; - social-service) build_service "social-service" "./services/social-service-net" ;; - promotion-service) build_service "promotion-service" "./services/promotion-service-net" ;; - membership-service) build_service "membership-service" "./services/membership-service-net" ;; - mining-service) build_service "mining-service" "./services/mining-service-net" ;; - mission-service) build_service "mission-service" "./services/mission-service-net" ;; - ads-manager-service) build_service "ads-manager-service" "./services/ads-manager-service-net" ;; - ads-serving-service) build_service "ads-serving-service" "./services/ads-serving-service-net" ;; - ads-billing-service) build_service "ads-billing-service" "./services/ads-billing-service-net" ;; - ads-tracking-service) build_service "ads-tracking-service" "./services/ads-tracking-service-net" ;; - ads-analytics-service) build_service "ads-analytics-service" "./services/ads-analytics-service-net" ;; - mkt-facebook-service) build_service "mkt-facebook-service" "./services/mkt-facebook-service-net" ;; - mkt-whatsapp-service) build_service "mkt-whatsapp-service" "./services/mkt-whatsapp-service-net" ;; - mkt-x-service) build_service "mkt-x-service" "./services/mkt-x-service-net" ;; - mkt-zalo-service) build_service "mkt-zalo-service" "./services/mkt-zalo-service-net" ;; - pos-web) build_service "web-client-tpos" "./apps/web-client-tpos-net" ;; - __k8s_config__) echo "K8s config changed, will apply manifests" ;; + get_image_name() { + case "$1" in + pos-web) echo "web-client-tpos-net" ;; + *) echo "${1}-net" ;; esac + } + + build_with_kaniko() { + local svc="$1" + local context=$(get_context "$svc") + local image_name=$(get_image_name "$svc") + local full_image="${HARBOR}/${PROJECT}/${image_name}" + local job_name="kaniko-build-$(echo ${svc} | tr '_' '-')-${IMAGE_TAG}" + + echo "=== Building ${svc} via Kaniko ===" + + # Create Kaniko Job + cat </dev/null + local result=$? + + if [ $result -ne 0 ]; then + echo "ERROR: Kaniko build failed for ${svc}" + kubectl logs job/${job_name} -n ${NS} --tail=30 2>/dev/null + return 1 + fi + + echo "=== ${svc} built and pushed ===" + } + + FAILED=0 + for svc in $BUILD_SERVICES; do + if ! build_with_kaniko "$svc"; then + FAILED=$((FAILED + 1)) + fi done + if [ $FAILED -gt 0 ]; then + echo "ERROR: ${FAILED} service(s) failed to build" + exit 1 + fi + - name: Deploy to K8s run: | if [ -z "$CHANGED_SERVICES" ]; then @@ -166,7 +254,7 @@ jobs: kubectl set image "deployment/${name}" "${name}=${image}" -n "${NS}" kubectl patch deployment "${name}" -n "${NS}" \ -p '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"harbor-pull-secret"}],"containers":[{"name":"'"${name}"'","imagePullPolicy":"Always"}]}}}}' - fi + } for svc in $CHANGED_SERVICES; do case "$svc" in @@ -202,11 +290,9 @@ jobs: FAILED=0 for svc in $CHANGED_SERVICES; do if [ "$svc" = "__k8s_config__" ]; then continue; fi - SVC_NAME="$svc" - if [ "$svc" = "pos-web" ]; then SVC_NAME="pos-web"; fi - echo "Waiting for ${SVC_NAME}..." - if ! kubectl rollout status "deployment/${SVC_NAME}" -n "${NS}" --timeout=180s 2>/dev/null; then - echo "WARNING: ${SVC_NAME} rollout did not complete" + echo "Waiting for ${svc}..." + if ! kubectl rollout status "deployment/${svc}" -n "${NS}" --timeout=180s 2>/dev/null; then + echo "WARNING: ${svc} rollout did not complete" FAILED=$((FAILED + 1)) fi done diff --git a/deployments/staging/kubernetes/act-runner-rbac.yaml b/deployments/staging/kubernetes/act-runner-rbac.yaml index 5ea4ad56..eed5882b 100644 --- a/deployments/staging/kubernetes/act-runner-rbac.yaml +++ b/deployments/staging/kubernetes/act-runner-rbac.yaml @@ -2,6 +2,7 @@ # VI: RBAC cho Gitea act_runner deploy vao namespace staging # # The act_runner ServiceAccount (in gitea namespace) needs permissions to: +# - Create Kaniko Jobs for building Docker images # - Apply manifests (deployments, services, configmaps, secrets, ingress, hpa, networkpolicies, pvc) # - Patch deployments (set image, rollout restart) # - Read pods/logs (rollout status) @@ -15,6 +16,9 @@ rules: - apiGroups: ["apps"] resources: ["deployments"] verbs: ["get", "list", "watch", "create", "update", "patch"] + - apiGroups: ["batch"] + resources: ["jobs"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] - apiGroups: [""] resources: ["services", "configmaps", "secrets", "persistentvolumeclaims"] verbs: ["get", "list", "watch", "create", "update", "patch"] diff --git a/deployments/staging/kubernetes/minio.yaml b/deployments/staging/kubernetes/minio.yaml index 52cfab90..0c163014 100644 --- a/deployments/staging/kubernetes/minio.yaml +++ b/deployments/staging/kubernetes/minio.yaml @@ -1,7 +1,11 @@ -# EN: MinIO - S3-compatible object storage for file uploads and media -# VI: MinIO - Luu tru doi tuong tuong thich S3 cho file upload va media -apiVersion: apps/v1 -kind: Deployment +# EN: MinIO ExternalName Service - Points to existing MinIO in minio namespace +# VI: MinIO ExternalName Service - Tro den MinIO hien tai trong namespace minio +# +# Existing MinIO: https://minio.techbi.org (namespace: minio) +# Console: https://minio-console.techbi.org +--- +apiVersion: v1 +kind: Service metadata: name: minio namespace: staging @@ -11,88 +15,8 @@ metadata: platform: goodgo tier: infrastructure spec: - replicas: 1 - selector: - matchLabels: - app: minio - template: - metadata: - labels: - app: minio - environment: staging - spec: - containers: - - name: minio - image: minio/minio:latest - command: - - server - - /data - - "--console-address" - - ":9001" - ports: - - containerPort: 9000 - protocol: TCP - - containerPort: 9001 - protocol: TCP - env: - - name: MINIO_ROOT_USER - valueFrom: - secretKeyRef: - name: goodgo-secrets - key: Storage__MinIO__AccessKey - - name: MINIO_ROOT_PASSWORD - valueFrom: - secretKeyRef: - name: goodgo-secrets - key: Storage__MinIO__SecretKey - resources: - requests: - memory: "256Mi" - cpu: "250m" - limits: - memory: "512Mi" - cpu: "500m" - livenessProbe: - httpGet: - path: /minio/health/live - port: 9000 - initialDelaySeconds: 15 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - readinessProbe: - httpGet: - path: /minio/health/ready - port: 9000 - initialDelaySeconds: 10 - periodSeconds: 5 - timeoutSeconds: 3 - failureThreshold: 3 - volumeMounts: - - name: minio-data - mountPath: /data - volumes: - - name: minio-data - persistentVolumeClaim: - claimName: minio-pvc ---- -apiVersion: v1 -kind: Service -metadata: - name: minio - namespace: staging - labels: - app: minio - environment: staging -spec: - selector: - app: minio - ports: - - name: minio - protocol: TCP - port: 9000 - targetPort: 9000 - type: ClusterIP + type: ExternalName + externalName: minio.minio.svc.cluster.local --- apiVersion: v1 kind: Service @@ -100,29 +24,10 @@ metadata: name: minio-console namespace: staging labels: - app: minio + app: minio-console environment: staging + platform: goodgo + tier: infrastructure spec: - selector: - app: minio - ports: - - name: console - protocol: TCP - port: 9001 - targetPort: 9001 - type: ClusterIP ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: minio-pvc - namespace: staging - labels: - app: minio - environment: staging -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi + type: ExternalName + externalName: minio-console.minio.svc.cluster.local