דלגו לתוכן

תבניות pipeline

candidate: תג אחד לכל ה-pipeline (dotenv)

Section titled “candidate: תג אחד לכל ה-pipeline (dotenv)”

job אחד מחשב את הזהות פעם אחת. כל job מאוחר מקבל אותה דרך needs, ואף אחד לא מחשב מחדש.

file: pipelines/source.yml
candidate:
stage: test
script:
- echo "CANDIDATE=${CI_COMMIT_BRANCH}-$(date -u +%Y%m%d)-${CI_COMMIT_SHORT_SHA}" | tee candidate.env
artifacts:
reports: {dotenv: candidate.env}

פורמט: <BRANCH>-YYYYMMDD-<SHA קצר>, למשל dev-20261001-78e24670.

איך מוודאים: ב-log של candidate מופיעה השורה CANDIDATE=…; ב-job מאוחר echo "$CANDIDATE" מדפיס אותה.

file: pipelines/source.yml
build:
stage: build
needs: [candidate, test]
script:
- |
for svc in $SERVICES; do
docker build -t "$IMAGE_REPO/$svc:$CANDIDATE" -f "services/$svc/Dockerfile" services/
done
  • ה-context הוא services/, לא services/$svc: ה-Dockerfile מעתיק common/trident (תיקיית אחות משותפת). ראה docker/overview.
  • ה--t נותן את השם המלא כולל ה-tag.

איך מוודאים: ב-log כל service מסתיים ב-naming to …/<SERVICE>:<CANDIDATE>. ואחר כך על ה-VM: docker image ls --format '{{.Repository}}:{{.Tag}}'.

file: pipelines/source.yml
publish:
stage: publish
needs: [candidate, build]
script:
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
- |
for svc in $SERVICES; do
docker push "$IMAGE_REPO/$svc:$CANDIDATE"
done
  • --password-stdin: ה-token לא נכנס לשורת הפקודה.
  • docker push מקבל רק את שם ה-image; בלי -t, -f או context.
  • בלי docker login ה-push נכשל ב-denied: access forbidden.
  • לעולם לא latest, ולא retag.

איך מוודאים: Project → Deploy → Container registry מציג repository לכל service עם tag <CANDIDATE>. פרטים: gitlab/registry.

multi-line: - | מול כמה פריטים

Section titled “multi-line: - | מול כמה פריטים”
file: .gitlab-ci.yml
broken:
script:
- for s in $SERVICES; do
- echo "$s"
- done
works:
script:
- |
for s in $SERVICES; do
echo "$s"
done

איך מוודאים: Pipeline editor → Validate, והרצה: ה-job works מדפיס שורה לכל service.

פריט script עם : (נקודתיים+רווח) חייב מרכאות סביב כולו. הכללים והדוגמה: keywords.

.promote הוא תבנית אחת; שלושה jobs שונים רק ב-TARGET_ENV וב-rules.

file: pipelines/source.yml
.promote:
extends: .with-ci-scripts
stage: promote
needs: [candidate, publish]
script:
- bash .ci/scripts/promote.sh "$TARGET_ENV" "$CANDIDATE"
promote:dev:
extends: .promote
variables: {TARGET_ENV: dev}
rules: [{if: '$CI_COMMIT_BRANCH == "dev"'}]
promote:staging:
extends: .promote
variables: {TARGET_ENV: staging}
rules: [{if: '$CI_COMMIT_BRANCH == "main"'}]
  • ה-.with-ci-scripts עושה git clone של trident-ci ל-.ci עם oauth2:${TRIDENT_GIT_TOKEN} (include מביא YAML, לא קבצים).
  • promote:dev שמקבל 403: ה-variable ריק? ראה gitlab/variables (Protect ON ב-branch לא מוגן).
  • ה-CI כותב רק versions/<ENV>.yaml, ו-Argo מסנכרן. אין שום פקודת cluster ב-job.

שער ידני ל-prod: needs + environment + resource_group

Section titled “שער ידני ל-prod: needs + environment + resource_group”
file: pipelines/source.yml
promote:prod:
extends: .promote
variables: {TARGET_ENV: prod}
needs: [candidate, promote:staging]
rules: [{if: '$CI_COMMIT_BRANCH == "main"', when: manual}]
environment: {name: production}
resource_group: production
  • אותו promote.sh, אותו job-template; ההבדל הוא when: manual.
  • needs: [candidate, promote:staging]: prod מקבל את ה-candidate של ה-pipeline הזה, לא "מה שנמצא עכשיו ב-staging". לכן לא מחשבים $CANDIDATE מחדש.
  • כפתור ▶ ב-pipeline ישן מקדם את ה-candidate הישן. זה מכוון.
  • לא לוחצים על promote:prod לפני שבדקת ש-staging תקין (/info מחזיר version ו-environment נכונים).

promote:prod הוא job ידני של אותו pipeline של main (לא pipeline נפרד). הוא כותב versions/prod.yaml ב-gitops, ו-Argo מסנכרן.

GitLab UI
trident-source → Build → Pipelines → the main pipeline (the run whose candidate you validated)
→ stage promote → promote:prod → click ▶ (Run)
runs on: any shell
git -C <REPO> pull
git -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/prod.yaml

איך מוודאים: ה-job ירוק; ב-trident-gitops commit חדש (promote(prod): <CANDIDATE>) ב-versions/prod.yaml; ב-Argo האפליקציה של prod Synced + Healthy בלי למחוק כלום.

file: trident-source/.gitlab-ci.yml
include:
- project: "$TRIDENT_GROUP/trident-ci"
ref: main
file: pipelines/source.yml

ה-repo של הקוד מכיל רק את ה-include; הלוגיקה חיה ב-trident-ci. שינוי ב-pipeline = commit ל-trident-ci. TRIDENT_GROUP הוא group variable (path, ללא Mask).

repo ה-CI מוכיח שה-runner והקבצים עובדים:

file: trident-ci/.gitlab-ci.yml
stages: [check]
check:
stage: check
tags: [trident]
script:
- docker info --format '{{.ServerVersion}}'
- git --version
- for f in pipelines/*.yml; do python3 -c "import sys,yaml; yaml.safe_load(open('$f'))" && echo "ok $f"; done
- bash -n scripts/*.sh

איך מוודאים: כל הפקודות עוברות; bash -n הוא בדיקת syntax בלבד. אם ה-job נתקע ב-"no runner for tags trident": gitlab/runners (scope).

idempotent push (no-op כש-אין שינוי)

Section titled “idempotent push (no-op כש-אין שינוי)”

ה-push של promote חייב לעבור גם כשה-tag כבר כתוב: בלי שינוי אין commit.

runs on: CI job
git add <DIR>/<ENV>.yaml
# TRIDENT: git add apps/trident/versions/<ENV>.yaml
if ! git diff --cached --quiet; then
git commit -q -m "promote(<ENV>): <CANDIDATE>"
git push -q origin HEAD:<BRANCH>
fi
git rev-parse HEAD

git diff --cached --quiet יוצא 0 כשאין שינוי. פקודה בתנאי של if לא נחשבת ל-set -e, ולכן ה-script לא מת. ה-script המלא: bash/templates. הוסף [skip ci] להודעה אם ה-push מפעיל pipeline לולאתי ב-repo עם CI.