סדר העבודה ותחנות
לפני התחנות: מיפוי הפרויקט ב-first-15-minutes ו-preflight ב-environment-setup. לפני כל תחנה קרא את הבלוק שלה ב-prevent-known-problems. כשמשהו אדום: when-stuck.
סיכום התחנות
Section titled “סיכום התחנות”| # | תחנה | ה-gate בשורה אחת | |
|---|---|---|---|
| 1 | repos, tokens, variables, runner | git ls-remote עובד וה-runner is valid | MUST |
| 2 | build ו-publish ל-GitLab Container Registry | docker manifest inspect <IMAGE>:<CANDIDATE> מצליח | MUST |
| 3 | promote | commit promote(<ENV>): <CANDIDATE> ב-gitops | MUST |
| 4 | values ו-render | helm template עובר, grep -c 'image: /' = 0 | MUST |
| 5 | bootstrap של Secrets | Secret בכל namespace + jwt מחזיר 200 | MUST |
| 6 | Argo Applications | Synced/Healthy ו-conditions ריק | MUST |
| 7 | כל environment מאומת | Pods 1/1 ו-/info נכון | MUST |
| 8 | observability | count by (namespace) (up) מציג כל env | MUST + SHOULD |
| 9 | verify, cleanup, idempotency | הרצף האידמפוטנטי עובר | MUST |
1. repos, tokens, variables, runner
Section titled “1. repos, tokens, variables, runner”MUST · מטרה: pipeline שיכול לרוץ ולכתוב ל-gitops, עם credential נכון לכל actor.
- group ו-projects, עם ה-path ולא ה-display name
- זהות ו-token לכל actor ואז role מול scope
- CI/CD variable: Mask ON, Protect OFF לכותב
- project runner: tag + scope
- לדחוף את כל ה-branches ואת ה-tags
Gate:
sudo gitlab-runner listsudo gitlab-runner verifygit ls-remote "https://oauth2:$(cat <TOKEN_FILE>)@<GITLAB_HOST>/<GROUP>/<REPO>.git"איך מוודאים: ה-runner ברשימה ו-is valid; git ls-remote מדפיס refs (לכל repo שה-token צריך). ב-UI: ה-self-test check של repo ה-CI ירוק. ls-remote מוכיח זהות וקריאה בלבד; כתיבה מוכחת רק בתחנה 3.
הכשל הסביר: job תקוע ב-pending (scope או tag של ה-runner), או include נכשל עם /trident-ci not found (TRIDENT_GROUP ריק).
בדיקה ראשונה: sudo gitlab-runner list מול Settings → CI/CD → Runners של ה-project: runners. ל-include: ה-variable כ-group variable רגיל (לא Masked): variables.
2. build ו-publish ל-GitLab Container Registry
Section titled “2. build ו-publish ל-GitLab Container Registry”MUST · מטרה: image לכל service ב-GitLab Container Registry של ה-repo של הקוד, עם tag = <CANDIDATE>, לא latest.
candidateב-dotenv- build loop, context =
services/ - publish loop: login עם
CI_REGISTRY_*ואז push - כרטיסי daemon.json (DNS ו-blob unknown) אם הסימפטומים אפשריים
Gate:
cat <TOKEN_FILE> | docker login -u <USER> --password-stdin <REGISTRY>docker manifest inspect <IMAGE>:<CANDIDATE>docker logout <REGISTRY># TRIDENT: <IMAGE> = registry.gitlab.com/trident-lab00/trident-source/ingest-apiאיך מוודאים: docker manifest inspect מדפיס manifest (ב-tag שלא קיים: no such manifest). ב-UI: Deploy → Container registry מציג repository לכל service עם tag <CANDIDATE>. ה-credential כאן הוא deploy token עם read_registry (registry).
הכשל הסביר: blob unknown to registry ב-push השני, Temporary failure in name resolution ב-build, או denied: access forbidden.
בדיקה ראשונה: docker info --format '{{.Driver}}' (מצופה overlay2): כרטיס 2. שגיאה בלי שינוי בקוד = סביבה, לא קוד.
3. promote
Section titled “3. promote”MUST · מטרה: ה-pipeline כותב versions/<ENV>.yaml ב-gitops ומסיים; ה-CI לא נוגע ב-cluster.
Gate:
git -C <REPO> pullgit -C <REPO> log origin/main -1 --format='%h %an %s' -- <FILE># TRIDENT: git -C trident-gitops log origin/main -1 --format='%h %an %s' -- apps/trident/versions/dev.yamlאיך מוודאים: שורה אחת עם ההודעה promote(<ENV>): <CANDIDATE> ועם ה-CANDIDATE של ה-pipeline שרצית (branch ותאריך). הרצה שנייה ללא שינוי: אין commit חדש.
הכשל הסביר: 403 ב-push של promote, אחרי ש-commit נוצר מקומית ב-job.
בדיקה ראשונה: האם ה-token ריק ב-job (Protect ON על branch לא מוגן): ה-job var-check מ-variables. אחר כך membership ו-scope: permissions.
4. values ו-render של ה-chart
Section titled “4. values ו-render של ה-chart”MUST · מטרה: לכל environment יש render מקומי תקין, עם tag אמיתי ובלי ערכים ריקים, לפני ש-push מגיע ל-Argo.
- render מקומי כמו ש-Argo מריץ
- לקרוא את ה-API של ה-chart ולעבור על כל מפתח שבהערת הקובץ
- גיליון
nxs-universal-chart, postgres, redis - חוזרים על התחנה לכל
<ENV>;versions/<ENV>.yamlריק עד promote: בידוד עםprobe
Gate:
helm template <RELEASE> <CHART_DIR> -n <NS> -f <FILE> -f <FILE> -f <FILE> > /tmp/render.yaml# TRIDENT: helm template trident charts/nxs-universal-chart -n trident-dev -f base.yaml -f dev.yaml -f versions/dev.yamlR=/tmp/render.yamlgrep -c 'image: /' "$R"grep -c 'image: .*:<CANDIDATE>' "$R"# TRIDENT, postgres render only: grep -c 'storageClassName: course-local-path' "$R"איך מוודאים: exit code 0; grep -c 'image: /' = 0; ספירת ה-images עם ה-tag = מספר ה-Deployments (3 ב-TRIDENT); בהרצת ה-postgres הספירה של storageClassName = 1.
הכשל הסביר: Error: open …: no such file or directory (שגיאת נתיב: -f בלע את ה-chart, או values לא בתיקייה הזאת), או YAML parse error … line N (defaultImageTag ריק).
בדיקה ראשונה: ls על כל נתיב ב--f ושה-chart הוא המילה הראשונה אחרי ה-release; ל-parse error: אותה פקודה עם --set defaultImageTag=probe. N הוא שורה ב-render, לא בקובץ שלך: שגיאות נפוצות.
5. bootstrap של Secrets
Section titled “5. bootstrap של Secrets”MUST · מטרה: לפני ש-Argo עושה sync, בכל namespace של environment יש Secret לכל מה שה-Pods צריכים, ול-Argo יש credential קריאה לכל repo.
- credential files: שמות, הרשאות
600, בלי newline - deploy token עם
read_registryובדיקה שהוא תקף (ה-gate) prepare-environment.shבלולאה על כל ה-environments- repo Secret לכל repo ש-Argo קורא
ה-Secret למשיכת images נוצר עם kubectl create secret docker-registry, ונשמר ב-type kubernetes.io/dockerconfigjson. אלה רק שמות של Kubernetes: ה-registry הוא עדיין ה-GitLab Container Registry, ו---docker-server=registry.gitlab.com (מארח בלבד): secrets.
Gate:
curl -s -o /dev/null -w '%{http_code}\n' -u "<USER>:$(cat <TOKEN_FILE>)" \ "https://<GITLAB_HOST>/jwt/auth?service=container_registry&scope=repository:<GROUP>/<REPO>:pull"kubectl get secret -A | grep <SECRET>kubectl -n <NS> get secret <SECRET> -o jsonpath='{.type}{"\n"}'kubectl -n argocd get secret -l argocd.argoproj.io/secret-type=repositoryאיך מוודאים: 200 (ב-401 ה-credential שגוי או פג); ה-Secret מופיע בכל namespace של environment; ה-type הוא kubernetes.io/dockerconfigjson; ב-argocd Secret לכל repo. ללא הדפסת ערכים.
הכשל הסביר: ImagePullBackOff ב-environment אחד ולא באחר (Secret קיים ב-namespace אחר).
בדיקה ראשונה: kubectl -n <NS> get secret <SECRET> ב-namespace שנכשל, ו-kubectl get secret -A | grep <SECRET> לראות איפה הוא כן: כלל ה-namespace. שגיאת credential file is not readable and non-empty: ls -l <FILE> ו-wc -c <FILE>.
6. Argo Applications
Section titled “6. Argo Applications”MUST · מטרה: root מוחל פעם אחת, וה-children הופכים Synced + Healthy, מתחילים מ-dev.
repoURLב-root וב-children,ref: values, tag מולmainsyncPolicyautomated + prune + selfHeal- root הוא האובייקט היחיד שמחילים ידנית
- אחרי כל תיקון:
git push, ולכשל במצב cluster: sync ידני
Gate:
grep -rn 'repoURL: ""' <FILE>kubectl -n argocd get applicationskubectl -n argocd get application <APP> -o jsonpath='{.status.sync.status}/{.status.health.status}{"\n"}'kubectl -n argocd get application <APP> -o jsonpath='{.status.conditions}{"\n"}'איך מוודאים: ה-grep לא מדפיס כלום; ברשימה root ואחריו ה-children; Synced/Healthy; conditions ריק. Healthy לצד Unknown = דגל אדום (operate).
הכשל הסביר: ComparisonError (השורה האחרונה היא הסיבה), או operationState.phase: Failed אחרי 5 ניסיונות.
בדיקה ראשונה: ה-conditions מלמטה למעלה: ComparisonError. ל-Failed: finishedAt מול date -u לפני שקוראים את ההודעה, ואז sync ידני; refresh=hard לא מתניע sync.
7. כל environment מאומת
Section titled “7. כל environment מאומת”MUST · מטרה: להוכיח התנהגות, לא רק סטטוס. dev ראשון; staging אחריו; ורק אז הכפתור הידני ל-prod.
- סולם האימות 3 עד 5
curl --resolveאל ה-NodePort/infoפעמיים, ו-quick-transitלהוכיח את ה-DBpromote:prodב-pipeline שלmain, רק אחרי ש-staging אומת
Gate:
kubectl get pods,svc,ingress,pvc,secret -n <NS>kubectl -n ingress-nginx get svccurl -k --resolve <HOST>:<PORT>:<VM_IP> https://<HOST>:<PORT>/info# TRIDENT: curl -k --resolve dev.trident.test:31651:192.168.242.130 https://dev.trident.test:31651/infoאיך מוודאים: Pods Running ו-1/1, PVC Bound; <PORT> = המספר אחרי 443:; ב-/info version = ה-candidate ו-environment = ה-env. accepted עולה בין שתי קריאות. detections = 0 צפוי בים שקט.
הכשל הסביר: Pod Pending (PVC בלי StorageClass), או CrashLoopBackOff עם StartError … read-only file system.
בדיקה ראשונה: kubectl -n <NS> describe pod <POD> ואז Events. לוג ריק = ה-container לא התחיל (kubernetes/overview). PVC: סולם האבחון.
8. observability
Section titled “8. observability”MUST (Prometheus ו-Grafana, אם החוזה כך) · SHOULD (Loki, Tempo, Alloy) · מטרה: כל סדרה נושאת namespace, וה-dashboard מבחין בין environments. מה MUST ומה SHOULD נקבע לפי החוזה שקיבלת.
relabel_configsשמשאיר אתnamespace- Grafana admin Secret ו-TLS
- ה-App אדום עד שה-namespace וה-Secrets קיימים, ואז sync ידני
- Loki, Tempo, Alloy, רק אחרי שה-MUST ירוקים
Gate:
# other terminal first: kubectl -n <NS> port-forward svc/prometheus 9090:9090curl -s 'http://localhost:9090/api/v1/query' --data-urlencode 'query=count by (namespace) (up)'איך מוודאים: data.result מכיל רשומה לכל namespace של environment, כל אחת עם ערך גדול מ-0. env חסר = לא נסרק.
הכשל הסביר: ה-App Failed או Missing כי ה-namespace או ה-Secrets לא היו קיימים כש-Argo ניסה.
בדיקה ראשונה: kubectl get ns <NS> ו-kubectl -n <NS> get secret <SECRET> -o jsonpath='{.data}' | jq 'keys' (שמות בלבד); אחרי ההכנה, sync ידני. bash -n על ה-script לפני הרצה.
9. verify, cleanup, idempotency
Section titled “9. verify, cleanup, idempotency”MUST · מטרה: לסיים כשה-cluster ניתן לאימות, וש-cleanup ו-verify-clean עוברים גם בהרצה שנייה.
- צ'קליסט MUST לפני הגשה
- סדר הניקוי: root קודם
- רצף האידמפוטנטיות
- העמוד המלא לסיום: last-20-minutes
Gate:
bash -n <FILE>grep -rnE 'TODO|repoURL: ""' <FILE>grep -nP ' +$' <FILE># script paths as in your project (bash/templates uses scripts/ and bootstrap/)bash verify.sh && bash cleanup.sh && bash verify-clean.sh && bash cleanup.sh && bash verify-clean.shאיך מוודאים: שלוש הבדיקות הראשונות לא מדפיסות שגיאה או התאמה; כל חוליה ברצף מסתיימת ב-exit 0, כולל cleanup.sh השני שרץ על cluster נקי.
הכשל הסביר: cleanup.sh שנכשל בהרצה שנייה כי exit 1 על "לא נמצא".
בדיקה ראשונה: bash cleanup.sh; echo "exit=$?" פעמיים. "כבר נעדר" הוא הצלחה: --ignore-not-found ובדיקת קיום לפני מחיקה: רצף האידמפוטנטיות.