name: Deploy monie-backend (kaniko) on: push: branches: [ main ] pull_request: jobs: build-and-deploy: runs-on: [self-hosted, linux, k8s] env: CI_NS: ci APP_NS: prod # Kaniko job runs inside cluster pods and can reach registry via node IP. PUSH_REGISTRY: 192.168.1.250:32000 # Runtime pull should use the endpoint configured in MicroK8s containerd. DEPLOY_REGISTRY: localhost:32000 IMAGE: monie-backend DEPLOYMENT: monie-backend CONTAINER: monie-backend # repo без кредов (креды берём из secret внутри Kaniko Job) REPO_HOST: git.denjs.ru REPO_PATH: monie/monie-backend.git steps: - name: Skip deploy for pull requests if: github.event_name == 'pull_request' run: echo "Pull request check passed. Deploy runs only on push to main." - name: Build & push image with Kaniko (K8s Job) if: github.event_name == 'push' env: SHA: ${{ github.sha }} REF: ${{ github.ref_name }} run: | set -euo pipefail JOB="kaniko-${SHA}" DEST="${PUSH_REGISTRY}/${IMAGE}:${SHA}" kubectl -n "${CI_NS}" delete job "${JOB}" --ignore-not-found=true cat </dev/null || true)" FAILED="$(kubectl -n "${CI_NS}" get job "${JOB}" -o jsonpath='{.status.failed}' 2>/dev/null || true)" SUCCEEDED="${SUCCEEDED:-0}" FAILED="${FAILED:-0}" if [ "${SUCCEEDED}" -ge 1 ]; then OK=0 break fi if [ "${FAILED}" -ge 1 ]; then OK=1 break fi NOW_TS="$(date +%s)" if [ $((NOW_TS - START_TS)) -ge "${DEADLINE_SECONDS}" ]; then OK=2 break fi sleep 5 done echo "[ci] job status:" kubectl -n "${CI_NS}" get job "${JOB}" -o wide || true echo "[ci] job logs (tail):" kubectl -n "${CI_NS}" logs "job/${JOB}" --tail=300 || true if [ "${OK}" -ne 0 ]; then echo "[ci] job did not reach Complete; describing job/pods for debug" kubectl -n "${CI_NS}" describe job "${JOB}" || true kubectl -n "${CI_NS}" get pods -l job-name="${JOB}" -o wide || true kubectl -n "${CI_NS}" describe pod -l job-name="${JOB}" || true exit 1 fi - name: Deploy to prod if: github.event_name == 'push' env: SHA: ${{ github.sha }} run: | set -euo pipefail TARGET_IMAGE="${DEPLOY_REGISTRY}/${IMAGE}:${SHA}" kubectl -n "${APP_NS}" set image "deployment/${DEPLOYMENT}" \ "${CONTAINER}=${TARGET_IMAGE}" set +e kubectl -n "${APP_NS}" rollout status "deployment/${DEPLOYMENT}" --timeout=15m ROLLOUT_RC=$? set -e if [ "${ROLLOUT_RC}" -ne 0 ]; then echo "[deploy] rollout did not complete in time; collecting diagnostics" SELECTOR="$(kubectl -n "${APP_NS}" get deployment "${DEPLOYMENT}" \ -o jsonpath='{range $k,$v := .spec.selector.matchLabels}{$k}={$v},{end}' 2>/dev/null || true)" SELECTOR="${SELECTOR%,}" kubectl -n "${APP_NS}" get deployment "${DEPLOYMENT}" -o wide || true kubectl -n "${APP_NS}" describe deployment "${DEPLOYMENT}" || true if [ -n "${SELECTOR}" ]; then kubectl -n "${APP_NS}" get rs -l "${SELECTOR}" -o wide || true kubectl -n "${APP_NS}" get pods -l "${SELECTOR}" -o wide || true kubectl -n "${APP_NS}" describe pods -l "${SELECTOR}" || true fi kubectl -n "${APP_NS}" get events --sort-by=.lastTimestamp | tail -n 100 || true DESIRED="$(kubectl -n "${APP_NS}" get deployment "${DEPLOYMENT}" \ -o jsonpath='{.spec.replicas}' 2>/dev/null || true)" UPDATED="$(kubectl -n "${APP_NS}" get deployment "${DEPLOYMENT}" \ -o jsonpath='{.status.updatedReplicas}' 2>/dev/null || true)" AVAILABLE="$(kubectl -n "${APP_NS}" get deployment "${DEPLOYMENT}" \ -o jsonpath='{.status.availableReplicas}' 2>/dev/null || true)" DESIRED="${DESIRED:-0}" UPDATED="${UPDATED:-0}" AVAILABLE="${AVAILABLE:-0}" echo "[deploy] desired=${DESIRED} updated=${UPDATED} available=${AVAILABLE}" if [ "${UPDATED}" -ge "${DESIRED}" ] && [ "${AVAILABLE}" -ge "${DESIRED}" ]; then echo "[deploy] New replica is healthy; old replica termination is delayed. Continuing." exit 0 fi exit "${ROLLOUT_RC}" fi