מדריך קלוד קוד בעברית

תיעוד 103

פריסת סביבות באירוח עצמי לייצור

הרצת רצים באירוח עצמי בסביבת ייצור: הקשחת אבטחה, בקרת תעבורה יוצאת ברשת, פרטי הזדהות של git, מתכוני Kubernetes ו-Compose, ופתרון תקלות.

הערה: סביבות באירוח עצמי נמצאות בבטא ציבורית בתוכניות Team ו-Enterprise; זמינות ומגבלות מכסה את מסלול ההפעלה. דף זה עוסק בהרצת צי הרצים בסביבת ייצור; עיין במדריך ההתחלה המהירה עבור הרץ וההפעלה הראשונים שלך.

סביבה באירוח עצמי מריצה הפעלות ענן של Claude Code על גבי רצים (runners) שאתה פורס בתוך הרשת שלך, ובסביבת ייצור הפעלות אלה מריצות קוד בהכוונת המודל בשם כל מי שיכול לשגר הפעלה לסביבה. דף זה מיועד למפעיל שמעביר סביבה עובדת לייצור. הוא עובר על הפריסה לפי הסדר: מה לנעול לפני חיבור מערכות אמיתיות, התעבורה היוצאת (egress) שהצי זקוק לה, כיצד הפעלות מזדהות מול מארח ה-git שלך, מתכוני הפריסה עצמם, ומה לבדוק כאשר הפעלות אינן מתנהגות כשורה.

#הקשחת הפריסה שלך

רץ באירוח עצמי מבצע קוד שרירותי בהכוונת המודל על גבי התשתית שלך בשם כל מי שיכול לשגר הפעלה לסביבה שלו. זהו כל חבר בארגון ה-Anthropic שלך, וכל מי שיכול להתחיל הפעלת ערוץ של Claude Tag בהיקף שבו בעלים (Owner) ניתב לסביבה. עבור על כל אחד מהסעיפים לפני שאתה מחבר סביבה למערכות ייצור:

  • קונטיינרים זמניים לכל הפעלה (Ephemeral, per-session containers): הרץ כל תהליך של רץ בקונטיינר או במכונה וירטואלית חדשים שמושמדים כאשר התהליך מסתיים, עם --capacity 1 וברירת המחדל של --drain-grace-sec 0, כך שכל קונטיינר משרת בדיוק הפעלה אחת. בקיבולת גבוהה יותר, או עם מרווח חסד לריקון (drain grace) חיובי, קונטיינר אחד משרת מספר הפעלות מאותו בעלים נעול; ראה מחזור חיי הרץ. אל תשתמש שוב במערכת קבצים בין הפעלות מחדש של רצים, למעט במערך המכוון של שליפה מוכנה מראש (pre-warmed checkout), ולעולם לא בין בעלים שונים.

  • ללא פרטי הזדהות רחבים ב-image: אל תכלול מפתחות SSH ארוכי טווח, פרטי הזדהות של ספק ענן, או אסימוני גישה אישיים המעניקים יותר ממה שהפעלה צריכה. הנפק פרטי הזדהות המשמשים במהלך הפעלה, כגון אסימוני push או API, לכל הפעלה בנפרד מתוך סקריפט המעטפת (wrapper script) שלך. עבור השכפול הראשוני (clone), שמתרחש לפני שסקריפט המעטפת רץ, השתמש בהוק מחזור חיים checkout או ב---use-anthropic-git-proxy; ראה הגדרת git.

  • שמור את סוד הסביבה מחוץ למארחים שמריצים הפעלות: סוד הסביבה יכול לרשום רצים ולקבל כל הפעלה שממתינה בתור בסביבה. בצי קבוע (fixed fleet) הוא נמצא בכל מארח של רץ, ושם קוד של כל הפעלה יכול לקרוא את קובץ הסוד. העדף רצים לפי דרישה (on-demand runners), שבהם הסוד נשאר במארח המתזמר (orchestrator), שלעולם אינו מריץ קוד משתמש, וכל רץ מקבל פקודת עבודה לשימוש חד פעמי שרושמת בדיוק רץ אחד. בצי קבוע, התייחס לקובץ סוד הסביבה כקריא לכל הפעלה, ובצע רוטציה לסוד לאחר כל חשד לפגיעה באבטחה של הפעלה כלשהי.

  • חסימת ברירת מחדל לתעבורה יוצאת (Default-deny network egress): הגבל תעבורה יוצאת של קונטיינר הרץ וההפעלה בגבול הרשת שלך בכל סביבה; הסעיף חסימת תעבורה יוצאת כברירת מחדל מכסה מה להתיר ומדוע.

  • IAM של המארח בהרשאה מינימלית (Least-privilege host IAM): זהות המחשוב המשויכת למארח הרץ, כגון instance profile או חשבון שירות של צומת, צריכה להעניק רק את מה שהרץ עצמו צריך. על הפעלות להשיג את פרטי ההזדהות שלהן דרך סקריפט המעטפת שלך במקום לרשת את אלה של המארח.

  • חסום את נקודת הקצה של מטא-דאטה בענן מפני הפעלות: מניעת גישה של הפעלות לזהות המארח מחייבת חסימת הגישה שלהן לנקודת הקצה של מטא-דאטה בענן, ומדיניות תעבורה יוצאת ברמת תת-רשת (subnet) אינה לוכדת תעבורת מטא-דאטה מסוג link-local, לכן חסום אותה בקונטיינר עצמו:

    • IMDSv2 עם מגבלת דילוגים (hop limit) של 1
    • GKE Workload Identity עם הסתרת מטא-דאטה (metadata concealment)
    • חסימה מפורשת עבור 169.254.169.254 במרחב שמות הרשת של קונטיינר ההפעלה

    החסימה חלה גם על סקריפט המעטפת ועל הוקי מחזור החיים שלך, מאחר שהם חולקים את אותו קונטיינר. בצע אימות לכל החלפת אסימונים מול JWT של ההפעלה מול שירות האסימונים שלך על גבי תעבורה יוצאת מורשית, או השתמש בזהות אינטרנט מבוססת קובץ כגון IAM Roles for Service Accounts (IRSA) ב-Amazon EKS.

  • בידוד מערכת קבצים לכל רץ: כל תהליך של רץ מקבל ספריית עבודה משלו שאף תהליך אחר במארח אינו יכול לקרוא או לכתוב אליה. הגדר את --hooks-dir, את סקריפט המעטפת ואת ~/.claude/ של המארח כקריאה בלבד עבור ההפעלה, בין אם הם מובנים בתוך ה-image ובין אם הם מותקנים כ-mount לקריאה בלבד.

  • לשיגור אין בקרת גישה לפי סביבה: כל חבר בארגון ה-Anthropic שלך יכול לשגר הפעלה לכל אחת מהסביבות שלו. אם בעלים (Owner) מנתב ערוצי Claude Tag לסביבה, כל מי שהגדרת הגישה של Claude Tag מתירה יכול להתחיל הפעלות ערוץ שרצות שם. כברירת מחדל, זהו כל מי שנמצא בסביבת העבודה של Slack המחוברת, עם או בלי חשבון Claude. התייחס לכל מארח של רץ כנגיש להרצת קוד על ידי כל מי שיכול לשגר אליו, והצב במארח הרץ רק נתונים ופרטי הזדהות שכל האנשים הללו מורשים לקרוא. הדגל --lock-to-account מגביל אילו הפעלות של איזה חשבון מארח מסוים מבצע, אך אינו מצמצם את מי שיכול לשגר לתוך הסביבה. כדי להפוך סביבות באירוח עצמי לאפשרות היחידה לבחירה, בעלים (Owner) יכול להסתיר סביבות באירוח Anthropic עבור הארגון כולו מתוך דף Cloud environments.

  • אכוף את משמר הגדרות המאגר (repo-settings guard): בחר את מצב המשמר באמצעות --confine-repo-settings. ברירת המחדל warn מתעדת הפרה ביומן ועדיין מייצרת את ההפעלה, enforce דוחה את ההפעלה, ו-off משבית את הסריקה. הרץ סורק את ההגדרות שנשמרו ב-commit בכל מאגר לאיתור:

    • הרשאה שנפתרת מחוץ לסביבת העבודה של אותה הפעלה: ערך ב-additionalDirectories, כלל Edit, Write או NotebookEdit ב-permissions.allow, או ערך ב-sandbox.filesystem.allowWrite או ב-allowRead
    • בלוק env שאינו ריק
    • עקיפת עמדת מפעיל כגון sandbox.enabled: false

    המשמר רץ ללא קשר ל---trust-workspace, ואינו מכסה הוקים של מאגר, .mcp.json או כללי Bash; עיין בסעיף הרשאות ואישור כלים כדי לראות היכן מקומן של הרשאות אלו.

הערה: רשימת הכתובות המורשות (IP allowlist) של הארגון שלך אינה מכסה תעבורת רצים באירוח עצמי כברירת מחדל. אל תסתמך עליה כבקרת רשת עבור תעבורת רצים או הפעלות; החל במקום זאת חסימת ברירת מחדל לתעבורה יוצאת בגבול הרשת שלך, ופנה לצוות הלקוחות שלך ב-Anthropic אם ברצונך באכיפת רשימת כתובות IP מורשות עבור הארגון שלך.

#דרישות רשת

הרץ ותהליכי הבן של ההפעלה שהוא יוצר מבצעים חיבורים יוצאים למארחים שלהלן. הגבל את התעבורה היוצאת של קונטיינר ההפעלה למארחים אלה ולשירותים הפנימיים הספציפיים שהפעלות צריכות להגיע אליהם; הסעיף חסימת תעבורה יוצאת כברירת מחדל מכסה כיצד ומדוע.

מארחים אלה נדרשים תמיד:

HostPortUsed for
api.anthropic.com443, HTTPS; WSS עבור מחבר ה-SCM בלבדמישור הבקרה (control plane) של הרץ והזרמת הפעלות, הסקת מודל (model inference), דגלי תכונות (feature flags), אנליטיקת מוצר, שליפת מפתחות JWKS, חתימת commits, פרוקסי ה-git כאשר מוגדר --use-anthropic-git-proxy, ומנהרת מחבר ה-SCM של המתזמר כאשר מוגדר --scm-connector-host
מארח ה-git שלך, כגון github.com או מארח ה-GitHub Enterprise שלך443 או 22שכפול (cloning) ודחיפת (pushing) מאגרים. אינו נדרש אם הרץ משתמש ב---use-anthropic-git-proxy, המנתב תעבורת git דרך api.anthropic.com.

הצורך במארחים אלה תלוי בהגדרה שלך:

HostPortWhen required
downloads.claude.ai443בזמן ההתקנה, כאשר מתקינים או מעדכנים את Claude Code במארח באמצעות תוכנת ההתקנה המקורית; הסקריפט install.sh עצמו מוגש מ-claude.ai. בזמן ריצת ההפעלה, רק כאשר הפעלות מתקינות תוספים ממרקטפלייס התוספים הרשמי של Anthropic.
storage.googleapis.com443בזמן ריצת ההפעלה, עבור מספרי התקנות תוספים ומטא-דאטה המוצגים ב-/plugin.
code.claude.com ו-claude.com443חיפושי תיעוד על ידי הסוכן המובנה claude-code-guide ובקשות WebFetch שאושרו מראש במהלך הפעלות. חסימת מארחים אלה משפיעה רק על חיפושי תיעוד.
*.frame.claudeusercontent.com443רק כאשר כלי ה-Artifact זמין עבור הפעלות בארגון שלך; ברירות המחדל משתנות לפי תוכנית, בהתאם לטבלת הזמינות שם. הגדר CLAUDE_CODE_DISABLE_ARTIFACT=1 ברץ כדי להשאיר את הכלי מושבת ללא תלות בהגדרת הארגון.
registry.npmjs.org443כאשר הפעלה מתקינה תוסף, הן לצורך משיכת חבילות תוספים ממקור npm והן לצורך התקנת תלויות Node.js של התוסף, או כאשר רץ שרת MCP שהופעל באמצעות npx
http-intake.logs.us5.datadoghq.com443מדדים תפעוליים של Anthropic. רק כאשר מוגדר CLAUDE_CODE_BYOC_ENABLE_DATADOG=1; כבוי כברירת מחדל בסביבות באירוח עצמי.
browser-intake-us5-datadoghq.com443העלאות דוחות שגיאה של Anthropic, הנשלחות רק כאשר דיווח שגיאות מופעל עבור חשבון ההפעלה. מושתק באמצעות DISABLE_ERROR_REPORTING=1 או DISABLE_TELEMETRY=1.

הרץ אינו פונה אל statsig.anthropic.com, *.sentry.io, claude.ai, או platform.claude.com. מארחים אלה מופיעים בחלק מרשימות הבדיקה הישנות של רשתות ארגוניות, אך אין צורך להכניס אותם לרשימת המורשים עבור תעבורת רצים או הפעלות: שליפות של דגלי תכונות מגיעות אל api.anthropic.com, והרץ מזדהה באמצעות סוד הסביבה ולא באמצעות OAuth אינטראקטיבי. שני תהליכים בצד המארח כן פונים אל claude.ai, לכן הרץ אותם ממארח שהתעבורה היוצאת שלו מאפשרת זאת במקום להרחיב את התעבורה היוצאת של קונטיינר ההפעלה: תוכנת ההתקנה בשורת פקודה בודדת מושכת את install.sh מ-claude.ai בזמן ההתקנה, והפקודה האינטראקטיבית claude auth login, שבה משתמשים ההגדרה המודרכת, מצב מחובר של doctor, ו-שיגור מ-CI, מבצעת כניסה דרך claude.ai, claude.com, ו-platform.claude.com. גם mcp-proxy.anthropic.com אינו נדרש: הפעלות באירוח עצמי אינן משתמשות בו, והעברת מחברי claude.ai של הארגון שלך אל הפעלות, כאשר היא מופעלת עבור הארגון שלך, מנותבת דרך api.anthropic.com. ראה שרתי MCP.

#חסימת תעבורה יוצאת כברירת מחדל

פרוס קונטיינרים של רצים והפעלות במקטע רשת או במרחב שמות שתעבורתם היוצאת מוגבלת למארחים המופיעים בטבלת דרישות הרשת, למארח ה-git שלך, ולשירותים הפנימיים הספציפיים שהפעלות צריכות להגיע אליהם. המוצר אינו יכול לאמת או לאכוף זאת, לכן החל זאת בגבול הרשת שלך בכל סביבה. קוד הפעלה מונחה על ידי המודל ויכול לנסות לבצע חיבורים למארחים שרירותיים; חסימת ברירת מחדל לתעבורה יוצאת ברמת הרשת תוחמת את המקומות שאליהם ניסיונות אלה יכולים להגיע. הדבר חל ללא תלות במצב ההרשאות: ערכת הכלים המאושרת מראש כברירת מחדל כבר כוללת את Bash, כך שתעבורה יוצאת ממעטפת הפקודה (shell) רצה ללא בקשת אישור אפילו ללא מצב אוטומטי (auto mode).

לפרטים על הטלמטריה שכל הפעלה פולטת וכיצד לכבות אותה, עיין בסעיף טלמטריה.

#הזדהות מול פרוקסי יוצא (egress proxy)

חלק מפרוקסי התעבורה היוצאת הארגוניים דורשים כותרת Proxy-Authorization בכל חיבור. האסימון בכותרת זו לעיתים קרובות מתחלף מהר מכדי לכתוב אותו בתוך כתובת הפרוקסי שאתה מגדיר ב-HTTPS_PROXY. הגדר את HTTPS_PROXY או את HTTP_PROXY לכתובת הפרוקסי שלך כרגיל, ולאחר מכן הגדר את --proxy-authorization-command או את --proxy-authorization-file כדי להורות לרץ מאיפה לקרוא את ערך הכותרת. שני הדגלים דורשים את Claude Code בגרסה 2.1.238 ואילך.

#בחר מהיכן מגיע ערך ה-Proxy-Authorization

בחר את הדגל התואם לאופן שבו אתה מייצר את אסימון ה-Proxy-Authorization:

  • --proxy-authorization-command <command>: בחר באפשרות זו עבור אסימון שאתה מייצר לפי דרישה. הרץ מריץ את פקודת המעטפת ומשתמש ב-stdout המנוקה מרווחים (trimmed) שלה כערך הכותרת, לדוגמה Bearer <token>.
  • --proxy-authorization-file <path>: בחר באפשרות זו עבור אסימון שתהליך אחר מחליף במקום. הרץ קורא את הקובץ ומשתמש בתוכנו המנוקה מרווחים כערך הכותרת.

#תצורות שהרץ מסרב להתחיל איתן

לכל דגל יש גם צורה של משתנה סביבה, הרשומה לצידו במראי מקום לדגלי CLI של הרץ. לפני שהרץ יוצר קשר עם הפרוקסי שלך או עם מישור הבקרה, הוא בודק את הדגלים ואת המשתנים שלהם, ומסרב להתחיל בשלושה מקרים:

  • שני הדגלים מוגדרים: דגל אחד בתוספת משתנה הסביבה של הדגל השני נחשבים להגדרת שניהם.
  • אין כתובת פרוקסי: לא ב-HTTPS_PROXY ולא ב-HTTP_PROXY יש כתובת http:// או https://. הרץ קורא את שני המשתנים באותיות גדולות או קטנות, ואינו בודק את ALL_PROXY.
  • אחד הדגלים מועבר לפקודת המשנה של המתזמר: self-hosted-runner orchestrator אינו מקבל את הדגלים או את משתני הסביבה שלהם. העבר את הדגל לכל רץ שהמתזמר מפעיל במקום זאת.

#מה הרץ משנה בזמן שדגל proxy-authorization מוגדר

כאשר אחד הדגלים מוגדר, הרץ מפעיל מאזין (listener) משלו ושולח תעבורת פרוקסי מעצמו, מהוקי מחזור החיים שלו ומההפעלות שלו דרך אותו מאזין. המאזין מוסיף את כותרת ה-Proxy-Authorization בדרך אל הפרוקסי שלך.

  • מאזין (Listener): המאזין הוא forward proxy בכתובת 127.0.0.1. הרץ מפעיל את המאזין לפני ההרשמה מול מישור הבקרה, ומסיים את פעולתו בהפעלה אם לא ניתן להפעיל את המאזין.
  • משתני פרוקסי: הרץ משכתב את המשתנה מבין HTTPS_PROXY ו-HTTP_PROXY שהגדרת, כך שיצביע על המאזין. הערך המשוכתב הזה מגיע אל הרץ עצמו, אל הוקי מחזור החיים שלו ואל כל הפעלה שהוא מריץ.
  • רוטציית אסימונים: אסימון שהוחלף נכנס לתוקף ללא הפעלה מחדש. עבור כל חיבור שהמאזין פותח מול הפרוקסי שלך, הרץ מריץ שוב את הפקודה שלך או קורא שוב את הקובץ שלך ומוסיף את התוצאה ככותרת.
  • סביבת ההפעלה: הפעלה מגיעה אל הפרוקסי שלך אך ורק דרך המאזין. בסביבה של כל הפעלה הרץ מסיר את ALL_PROXY, מסיר כל איות של HTTPS_PROXY או HTTP_PROXY שלא הגדרת, ומקבע את NO_PROXY לערך של הרץ עצמו.
  • יומנים (Logs): הרץ לעולם אינו מתעד את ערך הכותרת ביומן.

#הגדרת git

הרץ מנהל את שליפות המאגרים (repository checkouts) אך אינו מגדיר זהות או פרטי הזדהות של git כברירת מחדל. אתה שולט ב-image של הרץ ובסביבת התהליך, ולכן אתה שולט בהגדרות git. בחר באחת משתי גישות:

  • אפשר לרץ להגדיר את git: הפעל את הרץ עם --configure-git כדי שהוא יכתוב את אותה הגדרת זהות וחתימת commits שבה משתמשות הפעלות באירוח Anthropic
  • ספק את הגדרת git בתוך ה-image שלך: הגדר זהות ופרטי הזדהות ל-push בעצמך, לדוגמה כדי לבצע commit תחת זהות בוט משלך

רף גרסאות מינימלי עבור Git במארח הרץ: חתימת commits של SSH באמצעות --configure-git דורשת את Git 2.34 ואילך, --use-anthropic-git-proxy דורש 2.32 ואילך, וחידוש הפעלות מענפים שנדחפו על ידי --push-outcome-on-release דורש 2.29 ואילך. Git 2.24 מספיק אם אתה משמיט את שלושתם ומנהל את זהות ה-git בעצמך.

#אפשר לרץ להגדיר את git

הפעל את הרץ עם --configure-git, או הגדר את SELF_HOSTED_RUNNER_CONFIGURE_GIT=1, כדי שיכתוב הגדרת git גלובלית בעת ההפעלה:

  • user.name = Claude ו-user.email = [email protected], בהתאמה להפעלות באירוח Anthropic
  • חתימת commits ותגיות בתבנית SSH, המנותבת דרך shim בניהול הרץ שחותם על כל commit דרך שירות החתימה של Anthropic באמצעות פרטי ההזדהות של ההפעלה עצמה. החתימות ניתנות לאימות ב-GitHub מול מפתח חתימת ה-SSH שפורסם על ידי Anthropic.

חתימת commits דורשת את git 2.34 ואילך; הרץ בודק זאת בעת ההפעלה ויוצא עם שגיאה אם ה-git שלך ישן יותר. דגל זה אינו מגדיר פרטי הזדהות ל-push, אותם אתה עדיין מספק ב-image.

#ספק את הגדרת git בתוך ה-image שלך

זהות git נדרשת עבור כל commit. הגדר אותה ברמת המערכת כולה ב-Dockerfile שלך, כך שההגדרה תחול ללא תלות במשתמש שתחתיו רץ תהליך הרץ:

RUN git config --system user.name "Claude" && \
    git config --system user.email "[email protected]"

ללא זהות, הפקודה git commit נכשלת עם Please tell me who you are והפעלות אינן יכולות להתקדם. באפשרותך להשתמש בזהות בוט משלך במקום זאת; הרץ אינו דורס ערכים אלה.

אל תצרוב פרטי הזדהות ארוכי טווח או בעלי היקף רחב לדחיפה בתוך image משותף של רץ: פרט הזדהות ב-image זמין לכל הפעלה שה-image מריץ, ללא תלות במי שהתחיל אותה. במקום זאת, הנפק אסימון קצר מועד ובעל הרשאות מינימליות לכל הפעלה מתוך סקריפט המעטפת (wrapper script) שלך, תוך שימוש בזהות יוצר ההפעלה שפוענחה מתוך ה-JWT של ההפעלה. שלב זאת עם קונטיינר זמני לכל הפעלה, הדורש --capacity 1, כך שאף פרט הזדהות לא יחיה מעבר להפעלה שהנפיקה אותו; עיין בסעיף ההקשחה.

אם אתה מוכרח להגדיר פרטי הזדהות לדחיפה ברמת ה-image, למשל עבור מפתח פריסה (deploy key) לקריאה בלבד, הגבל את ההיקף שלהם בצורה ההדוקה ביותר שמארח ה-git שלך מאפשר:

  • מפתח פריסה של SSH המוגבל למאגר יחיד עם שכתוב url.<base>.insteadOf
  • הליפר פרטי הזדהות (credential.helper) שמחזיר אסימון בעל היקף מינימלי
  • משתנה GIT_SSH_COMMAND המצביע על מפתח בעל היקף מצומצם

כל מנגנון שתגדיר חייב לפעול ללא בקשת אישור (prompt), מכיוון שה-clone וה-fetch המובנים של הרץ משביתים את הבקשות ש-git, SSH ו-Git Credential Manager היו מציגים אחרת:

  • הרץ מגדיר GIT_TERMINAL_PROMPT=0, כך ש-git אינו מבקש שם משתמש או סיסמה.
  • הרץ מריץ SSH עם BatchMode=yes, שמתווסף אל ה-GIT_SSH_COMMAND שלך אם הגדרת כזה, כך ש-SSH אינו מבקש ביטוי סיסמה (passphrase) או אישור מארח.
  • הרץ מגדיר GCM_INTERACTIVE=never, כך ש-Git Credential Manager אינו פותח תיבת דו-שיח לכניסה.
  • הרץ מנקה את core.askPass, כך שאם אתה משתמש ב-askpass helper, הגדר אותו דרך משתנה הסביבה GIT_ASKPASS במקום זאת.

אם מארח ה-git שלך דוחה את פרטי ההזדהות, או שלא הגדרת כאלה, הרץ מנסה שוב מספר פעמים ולאחר מכן מכשיל את הכנת המאגר. הרץ אינו מעביר הגדרות אלה אל סביבת ההפעלה.

אם ספריות השליפה נמצאות בבעלות uid שונה מזה של תהליך הרץ, git יסרב לפעול עליהן; הוסף את safe.directory:

RUN git config --system --add safe.directory '*'

#שימוש בפרוקסי ה-git של Anthropic

הפעל את הרץ עם --use-anthropic-git-proxy, או הגדר את CLAUDE_RUNNER_USE_GIT_PROXY=1, כדי שיבצע clone דרך פרוקסי ה-git של Anthropic, כשהוא מאומת באמצעות האסימון קצר המועד של ההפעלה עצמה. עבור הפעלות משתמש רגילות, הפרוקסי משתמש באסימון ה-OAuth של GitHub או GitHub Enterprise שנשמר עבור יוצר ההפעלה; עבור הפעלות של בוטים וסוכנים, הוא משתמש באסימון ההתקנה של GitHub App של הארגון שלך. בכל מקרה, ה-image של הרץ אינו זקוק לשום פרטי הזדהות של git: ללא מפתחות SSH, ללא מסייע הזדהות (credential helper), וללא קובץ .netrc. זהו אותו נתיב אימות שבו משתמשות סביבות באירוח Anthropic.

הפרוקסי דורש --capacity 1 מכיוון שכתובת הפרוקסי היא לכל הפעלה, וכן git 2.32 ואילך מכיוון שגרסאות git ישנות יותר מתעלמות ממנגנון התצורה שהפרוקסי משתמש בו כדי לבודד הפעלות זו מזו. הרץ מסרב להתחיל אם אחת מהדרישות אינה מתקיימת. מכיוון שהפרוקסי מבצע fetch מהצד של Anthropic, מארח ה-git שלך חייב להיות נגיש מתשתית Anthropic, אותה דרישה שקיימת עבור הפעלות באירוח Anthropic; עבור מארח git שניתוב אליו מתאפשר רק בתוך הרשת שלך, השתמש בהוק מחזור חיים checkout במקום זאת. כל תהליך רץ מטפל בהפעלה אחת בכל פעם, לכן הפעל יותר רפליקות (replicas) לצורך מקביליות. כאשר הפרוקסי מופעל, לדגלים --git-host-rewrite ו---git-ssh-rewrite אין השפעה: כתובת הפרוקסי מצביעה על api.anthropic.com, ולא על מארח ה-git שלך.

#שכתוב כתובות git עבור רשתות פרטיות

כתובות URL של מאגרים מגיעות ממישור הבקרה כ-HTTPS, עם שם המארח של מארח ה-git שלך; עבור GitHub Enterprise, זהו שם המארח שהגדרת עבור אינטגרציית GitHub Enterprise בהגדרות הניהול של Claude Code ב-claude.ai. שני דגלים שניתן לחזור עליהם משכתבים כתובות אלה לפני ה-clone:

  • --git-host-rewrite <from>=<to>: עבור DNS מסוג split-horizon, שבו Anthropic מגיעה אל מארח ה-git שלך דרך שם מארח חיצוני אך הרצים חייבים להשתמש בשם פנימי
  • --git-ssh-rewrite <host>: עבור מארחי git שמקבלים רק SSH, דבר המשכתב את https://<host>/owner/repo אל git@<host>:owner/repo

שכתוב מארח רץ תחילה, לכן ציין את שם המארח הפנימי ב---git-ssh-rewrite אם אתה זקוק לשניהם. לשליטה מלאה על השליפה, השתמש בהוק מחזור חיים checkout.

#בניית ה-image של הרץ

Anthropic אינה מפרסמת image מוכן מראש לרץ. בנה בעצמך סביב הקובץ הבינארי claude, תוך הוספת שרשרת הכלים (toolchain) שהמאגרים שלך צריכים בשכבות: סביבות ריצה לשפות (runtimes), מהדרים (compilers), מנהלי חבילות ורכיבי צד (sidecars) של MCP.

המתכונים שלהלן משתמשים ב---capacity 4, כך שקונטיינר יחיד משרת עד ארבע הפעלות במקביל מאותו בעלים נעול. הדבר אינו מספק את בידוד הקונטיינר לכל הפעלה המתואר בסעיף ההקשחה: לפני חיבור סביבה למערכות ייצור, הפעל את המתכונים עם --capacity 1 עם קונטיינר אחד לכל הפעלה, או השתמש ברצים לפי דרישה, אשר שומרים בנוסף את סוד הסביבה מחוץ למארחים המריצים הפעלות.

קובץ Dockerfile זה הוא נקודת התחלה מינימלית:

FROM debian:bookworm-slim
ARG CLAUDE_CODE_VERSION
RUN apt-get update && apt-get install -y --no-install-recommends git curl ca-certificates openssh-client \
 && rm -rf /var/lib/apt/lists/*
RUN curl -fsSL "https://downloads.claude.ai/claude-code-releases/${CLAUDE_CODE_VERSION:?set with --build-arg CLAUDE_CODE_VERSION}/linux-x64/claude" \
      -o /usr/local/bin/claude && chmod +x /usr/local/bin/claude
RUN git config --system user.name "Claude" \
 && git config --system user.email "[email protected]" \
 && git config --system --add safe.directory '*'
ENTRYPOINT ["claude"]

החלף את linux-x64 ב-linux-arm64 אם הצמתים שלך הם ARM, או ב-linux-x64-musl או linux-arm64-musl ב-image מבוסס musl כגון Alpine; ראה התקנת Alpine Linux עבור החבילות הנוספות ש-images מבוססי musl זקוקים להן. הכתובת היא מיקום ההפצה הסטנדרטי של Claude Code, כך שתוכל לאמת את הקובץ הבינארי שהורד מול המניפסט החתום של ההפצה כפי שמתואר בסעיף שלמות בינארית וחתימת קוד. בנה את ה-image עם Claude Code בגרסה 2.1.224 ואילך, דחוף אותו אל ה-registry שלך והפנה אליו במתכונים שלהלן:

docker build --build-arg CLAUDE_CODE_VERSION=2.1.224 -t <your-registry>/claude-runner:latest .

#קביעת גודל CPU וזיכרון עבור הפעלות

קבע את גודל הקונטיינר או המארח של הרץ לפי ההפעלות שהוא מריץ ולא לפי תהליך הרץ עצמו. הרץ עצמו דוגם (polls) עבודה, מכין את השליפה של כל הפעלה, מריץ את הוקי מחזור החיים שלך, ומפעיל ומפקח על תהליכי ההפעלה. העומס מגיע מההפעלות: כל אחת מהן היא תהליך של Claude Code בתוספת כל מה שהוא מפעיל, כגון בניות (builds), סוויטות בדיקות, התקנות חבילות, ושרתי MCP.

עבור הפעלה בודדת, התחל עם הערכים הבאים, המוגדרים כ-requests ו-limits ב-Kubernetes או המקבילה בפלטפורמה שלך, והתייחס אליהם כנקודת התחלה ולא כדרישה קשיחה:

  • זיכרון: בקשה (request) ומגבלה (limit) של 4 GiB כל אחת, העונות על המינימום של 4 GB בדרישות המערכת של Claude Code. שמור על שניהם שווים כדי שהמתזמן יקצה את מלוא הזיכרון של הקונטיינר. כאשר הקונטיינר מגיע למגבלת הזיכרון שלו, הליבה (kernel) הורגת תהליכים בתוכו, מה שעלול לסיים הפעלה באמצע משימה.
  • CPU: בקשה של 2 מעבדים (CPUs) ומגבלה של 4 מעבדים, כך שהפעלה תוכל לפרוץ (burst) מעל הבקשה במהלך בניות. הליבה מאטה (throttles) קונטיינר במגבלת ה-CPU שלו במקום להרוג תהליכים בתוכו, כך שהפעלות במגבלה רצות לאט יותר אך ממשיכות לרוץ.

במפרט קונטיינר של Kubernetes, הגדר את ערכי ההתחלה האלה באמצעות בלוק ה-resources הבא:

resources:
  requests:
    cpu: "2"
    memory: 4Gi
  limits:
    cpu: "4"
    memory: 4Gi

בניות ובדיקות הן בדרך כלל החלק הגדול והמשתנה ביותר בעומס של הפעלה, לכן הרץ בנייה מייצגת של המאגר שלך, מדוד את שיא ה-CPU והזיכרון שלה, והעלה כל ערך התחלתי שאינו משאיר מקום לתהליך של Claude Code מעבר לאותו שיא.

הרץ משתמש ב---capacity כדי להגביל כמה הפעלות הוא מריץ בבת אחת. הוא אינו מחלק את ה-CPU או הזיכרון ביניהן, כך שההפעלות על רץ חולקות את ה-CPU והזיכרון של הקונטיינר. כדי להגביל את חלקה של הפעלה בודדת, החל מגבלות מתוך סקריפט המעטפת שלך. מה שיש לתת לקונטיינר יחיד תלוי אפוא בכמה הפעלות הוא משרת בו זמנית:

  • הפעלה אחת לכל רץ: תן לכל קונטיינר את הערכים של הפעלה אחת. השתמש בגודל זה ב---capacity 1, עליו ממליץ סעיף ההקשחה, ועבור רצים לפי דרישה, שבהם אתה מגדיר את הערכים בעומס העבודה שה-הוק spawn-runner שלך שולח, כגון pod template של Kubernetes Job.
  • מספר הפעלות לכל רץ: ב---capacity מעל אחת, הכפל את הערכים של הפעלה אחת בקיבולת, מכיוון שעד מספר זה של הפעלות יכולות לרוץ בקונטיינר באותו זמן. המתכונים של Kubernetes ו-Docker Compose רצים עם --capacity 4 ללא מגבלות CPU או זיכרון, לכן הוסף מגבלות המותאמות לגודל הקיבולת שאתה מריץ.

#Kubernetes

הרץ משרת GET /healthz ביציאה 8080 כברירת מחדל, הניתנת להגדרה באמצעות --health-port, כך שבדיקות (probes) של Kubernetes פועלות ללא הגדרה נוספת. נקודת הקצה מחזירה 200 בכל עת שהתהליך חי, כך שהבדיקות שלהלן מזהות תהליך מת, ולא תהליך תקוע; כדי לתפוס רץ שהפסיק לדגום, הגדר התראה על סדרת last_poll_age_seconds מתוך /metrics. ה-Deployment שלהלן מתקין (mounts) את סוד הסביבה מתוך Kubernetes Secret, מכוון את בדיקות ה-liveness וה-readiness אל /healthz, וקובע תקופת חסד לסיום (termination grace period) של 90 שניות. עיין בסעיף תזמון כיבוי כדי להבין מדוע תקופת החסד חשובה.

המניפסט אינו מגדיר resources של CPU או זיכרון בקונטיינר של הרץ. הוסף בלוק המותאם לגודל הקיבולת שאתה מריץ, כפי שמתואר בסעיף קביעת גודל CPU וזיכרון עבור הפעלות.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: claude-runner
  namespace: claude-runners
spec:
  replicas: 3
  selector:
    matchLabels:
      app: claude-runner
  template:
    metadata:
      labels:
        app: claude-runner
        app.kubernetes.io/part-of: claude-code-self-hosted-runner
    spec:
      terminationGracePeriodSeconds: 90
      containers:
        - name: runner
          image: <your-registry>/claude-runner:latest
          args:
            - self-hosted-runner
            - --environment-secret-file
            - /etc/claude/environment-secret
            - --capacity
            - "4"
          volumeMounts:
            - name: environment-secret
              mountPath: /etc/claude
              readOnly: true
          ports:
            - name: health
              containerPort: 8080
          readinessProbe:
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10
          livenessProbe:
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 30
            periodSeconds: 30
      volumes:
        - name: environment-secret
          secret:
            secretName: claude-runner-environment-secret

ה-Deployment שלמעלה שוכן במרחב שמות claude-runners. צור תחילה את מרחב השמות:

kubectl create namespace claude-runners

צור את ה-Secret המגבה מתוך קובץ מקומי המכיל את הערך שהעתקת בשלב Copy environment key בממשק הניהול, כך שהסוד לעולם לא יופיע בהיסטוריית ה-shell שלך. הרץ (umask 077 && cat > ./environment-secret), הדבק את הסוד, לחץ Enter, ולאחר מכן Ctrl-D. לאחר מכן צור את ה-Secret ומחק את הקובץ:

kubectl create secret generic claude-runner-environment-secret -n claude-runners --from-file=environment-secret=./environment-secret

#Docker Compose

שירות ה-Compose שלהלן מפעיל מחדש את הרץ בכל פעם שהוא יוצא, מה שמכסה הן קריסות והן יציאה רגילה לאחר ריקון (draining). מדיניות הפעלה מחדש של Docker מפעילה מחדש את אותו קונטיינר כששכבת הכתיבה שלו שלמה, כך שהרץ חוזר על גבי מערכת קבצים שעושים בה שימוש חוזר במקום מערכת חדשה כפי שממליצה עמדת ההקשחה; השתמש במתכון זה לצורך הערכה, ועבור סביבת ייצור צור מחדש את הקונטיינר בכל הרצה או השתמש במתזמר שעושה זאת.

services:
  claude-runner:
    image: <your-registry>/claude-runner:latest
    command:
      - self-hosted-runner
      - --environment-secret-file
      - /run/secrets/environment-secret
      - --capacity
      - "4"
    secrets:
      - environment-secret
    restart: always
    stop_grace_period: 90s

secrets:
  environment-secret:
    file: ./environment-secret

#תזמון כיבוי

בעת קבלת SIGTERM, הרץ מפסיק לקבל עבודה חדשה, ולמעט אם הגדרת את --defer-shutdown-max-min, הוא ממתין עד --drain-wait-sec, אפס כברירת מחדל, לסיום תורות שנמצאים בעיצומם, מסיים את עץ התהליכים של כל הפעלה, ומריץ את הוק מחזור החיים post-session. עץ תהליכים זה כולל פקודות ש-Claude עדיין הריץ בהפעלה.

מסלול הריקון המלא זקוק לעד --session-stop-grace-sec + --drain-wait-sec + --post-session-hook-timeout-sec, בתוספת 15 שניות של תקורה קבועה עבור ניקוי תהליכים, ובתוספת 30 שניות נוספות כאשר מוגדר --push-outcome-on-release. זהו סך של 80 שניות בברירות המחדל, והרץ מתעד את הסך הכולל ביומן בעת ההפעלה. הפעלות מתרוקנות במקביל תחת תקציב יחיד זה, כך שהסך הכולל אינו גדל עם --capacity.

בברירת המחדל --drain-wait-sec 0, הפעלה מחדש מדורגת קוטעת תורות בעיצומם; כל הפעלה מתחדשת ברץ אחר, ומאבדת עבודה שלא נדחפה כפי שמתואר תחת מגבלות נוספות. הגדר את --drain-wait-sec, והעלה את תקופת החסד בהתאמה, כדי לאפשר לתורות להסתיים תחילה.

לאורך כל המסלול הזה, הרץ ממשיך לשלוח פעימות לב (heartbeating) למישור הבקרה בקיבולת אפס, כדי שחכירת ההפעלה (session lease) לא תפוג ותועבר מחדש לרץ אחר בזמן שהוק ה-post-session עדיין כותב עבודה שטרם נשמרה ב-commit. פעימות הלב נפסקות ממש לפני שהרץ מבטל את רישומו.

תן לרץ לפחות את הסך הכולל שהוא מתעד ביומן בעת ההפעלה לפני שהמארח עוצר אותו. המקום שבו אתה מגדיר זאת תלוי באופן שבו המארחים שלך עוצרים:

  • עם תקופת חסד עבור SIGTERM: הגדר את terminationGracePeriodSeconds ב-Kubernetes, את stop_grace_period ב-Docker Compose, או את המקבילה במתזמר שלך, לפחות לסך הכולל הזה. ברירת המחדל של Kubernetes שהיא 30 שניות קצרה ממסלול הריקון של הרץ, כך ש-Kubernetes יעצור את ה-pod לפני שהרץ יסיים להתרוקן.
  • עם --retire-at: קבע את המרווח בין מועד הפרישה לבין מועד עצירת המארח כך שיכסה תורות טיפוסיים, בתוספת השהיית משימות הרקע המתוארת במחזור חיי הרץ, ובתוספת אותו סך כולל. חשב את מועד הפרישה בכל הפעלה, לדוגמה date +%s בתוספת משך החיים המיועד של הרץ.
  • עם --defer-shutdown-max-min: הוסף שני חלקים נוספים לסך הכולל של מסלול הריקון. הראשון הוא הדקות שאתה מגדיר. השני הוא חסד שלאחר השחרור (post-release grace) שמתואר בסעיף דחיית הריקון מעבר לאות הראשון, 75 שניות בברירות המחדל. כאשר הדגל מוגדר, הרץ מדפיס גם את המספר המשולב בעת ההפעלה, לאחר הסך הכולל של מסלול הריקון.

#דחיית הריקון מעבר לאות הראשון

הגדר את --defer-shutdown-max-min <n> אם ברצונך שרץ שאתה מפעיל מחדש ימשיך לשרת את ההפעלות שהוא מחזיק עד n דקות, במקום לרוקן אותן באות הראשון. באות SIGTERM או SIGINT הראשון, הרץ מפסיק לקבל עבודה חדשה וממשיך לשרת את ההפעלות שהוא מחזיק. הוא ממשיך לדגום כך שמישור הבקרה לא יציב את ההפעלות הללו בתור מחדש. דורש את Claude Code בגרסה 2.1.238 ואילך.

#מה קורה להפעלות שהרץ מחזיק לאחר האות הראשון

בשני השלבים הראשונים שלאחר האות, הרץ משחרר הפעלות, והפעלה ששוחררה מתחדשת ברץ חדש כאשר המשתמש שלה שולח את ההודעה הבאה שלו. בספירה מהאות הראשון, הרץ עובר דרך שלושה שלבים:

  1. במהלך n הדקות הראשונות: הרץ משרת את ההפעלות שלו כרגיל וממשיך לאכוף את --startup-timeout-min ואת --kill-session-after-min. אם הגדרת בנוסף את --release-idle-session-min, הרץ משחרר כל הפעלה שהמשתמש שלה לא היה פעיל במשך פרק זמן זה; בלעדיו, הרץ אינו משחרר אף הפעלה מוקדם, מלבד עקב פסק זמן להפעלה (startup timeout).
  2. כאשר n הדקות מסתיימות: הרץ משחרר כל הפעלה שהוא עדיין מחזיק, בין אם היא במצב סרק ובין אם לא. הרץ ממתין לסיום התור של הפעלה שנמצאת באמצע תור, ועד 60 שניות נוספות עבור משימות רקע של תור, לפני שחרור אותה הפעלה.
  3. כאשר חסד שלאחר השחרור מסתיים: הרץ מרוקן את כל ההפעלות שהוא עדיין מחזיק, ומישור הבקרה מציב כל הפעלה שהתרוקנה מיד בתור לרץ אחר. חסד שלאחר השחרור מתחיל כאשר n הדקות מסתיימות, ומשכו 75 שניות בברירות המחדל. אם הגדרת את --drain-wait-sec מעל 60 שניות, חסד שלאחר השחרור הוא --drain-wait-sec בתוספת 15 שניות במקום זאת.

בכל שלב, הרץ יוצא בקוד 0 ברגע שהוא אינו מחזיק עוד בהפעלות. אות שני מקצר את השלבים: הרץ מתרוקן מיד, כפי שהוא עושה באות הראשון ללא --defer-shutdown-max-min. ברגע שריקון כבר מתבצע, האות הבא מביא ליציאה כפויה של הרץ. הדבר תקף בין אם אות שני התחיל את הריקון ובין אם סיום חסד שלאחר השחרור התחיל אותו.

#קביעת גודל פסק הזמן לעצירה

הגדר את פסק הזמן לעצירה במארח שלך לפחות כסכום של שלושה חלקים: n הדקות שאתה מגדיר, חסד שלאחר השחרור, ומסלול הריקון המלא המתואר בסעיף תזמון כיבוי. בהגדרות ברירת מחדל חסד שלאחר השחרור הוא 75 שניות ומסלול הריקון הוא 80 שניות, לכן אפשר n דקות בתוספת 155 שניות. הרץ מדפיס סכום זה בעת ההפעלה בכל פעם ש---defer-shutdown-max-min מוגדר.

אם פסק הזמן לעצירה מסתיים לפני שהרץ מסיים, המארח הורג את הרץ. ההפעלות שהוא עדיין מחזיק אינן מקבלות הוק post-session. הרץ אינו מבטל את רישומו, ומישור הבקרה מציב את ההפעלות בתור מחדש כדקה לאחר מכן. אם אינך יכול לתת לפסק הזמן לעצירה סכום זה, השאר את --defer-shutdown-max-min ללא הגדרה כדי שהרץ יתרוקן באות הראשון במקום זאת.

#מה מגיע להוק post-session שרץ

הוק ה-post-session ותהליך הבן של הפעלת Claude רצים כל אחד בקבוצת תהליכי POSIX משלו, בנפרד מזו של הרץ, כך שמנגנוני עצירה מגיעים אליהם בצורה שונה:

  • SIGTERM בזמן שהרץ כבר מתרוקן: מביא ליציאה כפויה של הרץ מיד, תוך דילוג על מה שנותר ממסלול הריקון. ללא --defer-shutdown-max-min, זהו ה-SIGTERM השני שהרץ מקבל. שום דבר אינו מאותת להוק post-session שרץ באמצע, כך שבמארח bare-metal שבו תהליך init מאמץ תהליכים יתומים (orphans), הוא מסיים בעצמו, אך ללא פיקוח: תקציב פסק הזמן שלו אינו חל עוד, וכתיבה לצינור יומן סגור עלולה להרוג אותו עם SIGPIPE, לכן הוק שצריך לשרוד יציאה כפויה שם צריך לנתב מחדש את הפלט שלו לקובץ. במתכוני הקונטיינר בדף זה הרץ הוא PID 1 של הקונטיינר והיציאה שלו מסיימת את הקונטיינר, ותחת ברירת המחדל של systemd שהיא KillMode=control-group, ההריגה ברמת ה-cgroup כולו מגיעה גם להוק, כפי שמתואר בסעיף הריגות ברמת ה-cgroup כולו; בשני המקרים, התייחס ליציאה כפויה כקטלנית עבור ההוק והסתמך על תקופת החסד במקום זאת.
  • אותות ברמת קבוצת התהליכים כולה, כגון kill -- -<pid> בסקריפט מעטפת, בקרת משימות במעטפת (shell job control), או כלב שמירה ברמת הקבוצה כולה: מגיעים אל הרץ ואל תהליך בן של הוק checkout שבאמצע ריצה, אשר נשאר מקושר לקבוצה באופן מכוון, אך לא להוק post-session שבאמצע ריצה או לתהליך הבן של ההפעלה.
  • הריגות ברמת ה-cgroup כולו, כגון ברירת המחדל KillMode=control-group של systemd או ה-SIGKILL ש-Kubernetes מעביר לקונטיינר כולו כאשר terminationGracePeriodSeconds פוקע: מגיעות להכול, כולל להוק. בידוד ברמת קבוצת תהליכים אינו מגן מפני אלה, וזו הסיבה שתקופת החסד חייבת לכסות את מלוא מסלול הריקון.
  • פסק הזמן של ההוק עצמו: כאשר הוק חורג מ---post-session-hook-timeout-sec, הרץ שולח SIGTERM לכל קבוצת התהליכים של ההוק, ולאחר מכן SIGKILL שתי שניות מאוחר יותר, כך שפועל שההוק פיצל (forked), כגון tar, rsync או git, מסתיים יחד עם מעטפת המעטפת במקום לשרוד כיתום. הפיקוח של הרץ מסתיים ברגע ש-stdio של ההוק נסגר: פועל שניתב מחדש את הפלט שלו לקובץ ושורד מעבר לשלב ה-SIGTERM נמצא מעבר להישג ידו של הרץ.

כאשר הריקון מתחיל, ושוב בעת יציאה כפויה, הרץ מתעד ביומן כמה הוקי post-session עדיין רצים, כדי שתוכל להבדיל בין ריקון שקט לבין ריקון שנמצא באמצע יצירת תמונת מצב (snapshot).

#שמירה על ספריית בסיס וקיבולת זהות בכל הרצים

אם רץ מת באמצע הפעלה, השרת מציב את ההפעלה בתור מחדש ורץ אחר בסביבה אוסף אותה. אותו רץ גוזר את נתיב השליפה מה---base-dir ומה---capacity שלו עצמו: --capacity 1 שולף ישירות תחת --base-dir, ו---capacity מעל 1 משתמש במקום זאת ב-worktrees לכל הפעלה. כאשר רצים באותה סביבה משתמשים בערכים שונים עבור אחד משני הדגלים, ספריית העבודה של ההפעלה המחודשת משתנה, ונתיבים מוחלטים שהסוכן רשם קודם לכן, בעריכות, בקריאות לכלים או בהערות שלו עצמו, מצביעים על מיקום שאינו קיים עוד.

השתמש באותו --base-dir ובאותה --capacity בכל רץ בסביבה, ואל תשתמש בערך ייחודי למארח כגון מזהה מופע (instance ID) או שם מארח.

ספריית הבסיס מוגדרת כברירת מחדל ל-/workspace, למעט החריג המתועד בשורת המראי מקום עבור --base-dir. הרץ זקוק להרשאת כתיבה אליה. בעת ההפעלה, לפני הרישום, הרץ יוצר את הספרייה ומוודא שהוא יכול לכתוב אליה, ויוצא עם cannot create or write to base directory כאשר הוא אינו יכול. רץ המופעל כ-root יוצר את /workspace של ברירת המחדל בעצמו. עבור רץ שאינו root, צור את הספרייה והענק בעלות למשתמש של הרץ לפני הפעלת הרץ, או כוון את --base-dir לספרייה שאותו משתמש כבר מחזיק בבעלות עליה.

#שימוש חוזר בשליפה מוכנה מראש (pre-warmed checkout)

עבור מאגרים גדולים, פעולת ה-clone יכולה לתפוס את עיקר זמן ההפעלה של ההפעלה. ב---capacity 1 ללא הוק checkout, הרץ שומר clone קנוני יחיד לכל מאגר בנתיב <base-dir>/<repo-owner>/<repo> ומשתמש בו שוב בין הפעלות: הוא מושך את ה-ref המבוקש, מנתק את HEAD, ומבצע אליו reset hard, פעולה שהיא כמעט מיידית כאשר מעט השתנה. כדי לדלג על ה-clone הקר, ספק את ה-clone באחת משתי דרכים:

  • Clone בתוך ה-image: בנה את ה-clone לתוך ה-image של הרץ שלך באותו נתיב. כל קונטיינר חדש יתחיל אז עם ה-clone המוכן מבלי לעשות שימוש חוזר בדיסק.
  • Clone בכונן קבוע (persistent volume): ברצים שאתה נועל מראש לחשבון של משתמש יחיד באמצעות --lock-to-account, כוון את --base-dir לכונן קבוע, כך שהדיסק ישרת תמיד רק את אותו חשבון. רץ שננעל מראש לעולם אינו מקבל הפעלות ערוץ של Claude Tag, לכן אפשרות זו אינה חלה על רצים המשרתים אותן.

מה שנתיב השימוש החוזר מבטיח ומה שאינו מבטיח:

  • כל מבנה של clone עובד: clone מלא, רדוד (shallow) או של ענף בודד בנתיב משמש כמות שהוא. הרץ לעולם אינו מעביר --depth בעת ביצוע fetch לתוך clone קיים, כך שהכנה מראש מלאה שומרת על ההיסטוריה המלאה שלה והכנה רדודה נשארת רדודה. משתנה הסביבה CLAUDE_RUNNER_FETCH_DEPTH (full, 0, או מספר; ברירת מחדל 50) שולט רק ב-clone הקר שהרץ מבצע כאשר עדיין לא קיים clone.
  • שינויים במעקב מתאפסים, קבצים שאינם במעקב נשארים: כל הפעלה מתחילה מאיפוס קשיח (hard reset) שמוחק את השינויים במעקב מההפעלה הקודמת, אך הרץ לעולם אינו מריץ git clean, כך שקבצים שאינם במעקב מהפעלות קודמות של הבעלים הנעול נשארים בעץ.
  • עם פרוקסי ה-git, האיפוס הופך ל-checkout: עם --use-anthropic-git-proxy, הרץ מנקה ומחטא את .git/ של ה-clone לפני כל הפעלה, כשהוא שומר על מאגר האובייקטים, ה-refs ומצב ה-shallow אך מוחק את ה-index, כך שכל הפעלה משלמת עלות של checkout מלא של עץ העבודה במקום איפוס כמעט מיידי; הוא עדיין לעולם אינו משכפל מחדש. הכנה מראש של תתי מודולים (submodules) אינה נתמכת תחת הפרוקסי.
  • פעולות clone ארוכות אינן דורשות מעקף: הרץ תוחם כל פעולת git באמצעות מנגנון watchdog ללא התקדמות של 120 שניות ומגבלה קשיחה של 30 דקות, ולא פסק זמן קבוע ושטוח, כך ש-clone קר ואיטי שממשיך לדווח על התקדמות יושלם בהצלחה.

#קיבוע הגרסה

תהליך הבן של Claude Code בכל הפעלה מריץ את הקובץ הבינארי של הרץ עצמו, והרץ מכבה עדכון אוטומטי בתוך ההפעלות שהוא מפעיל, כך שכל הפעלה מריצה את הגרסה שהתקנת במארח או בנית לתוך ה-image. עדכון ברמת המארח נכנס לתוקף בפעם הבאה שהרץ מופעל.

  • כדי להחזיק צי על גרסה אחת: בנה את ה-image עם גרסה מקובעת, או במארח bare-metal התקן גרסה ספציפית והשבת עדכונים אוטומטיים
  • כדי לשדרג: התקן את הגרסה החדשה יותר או בנה מחדש את ה-image, ולאחר מכן הפעל מחדש את הרצים
  • תוספים (Plugins): מרקטפלייסים של תוספים אינם מתעדכנים אוטומטית גם כן; הגדר FORCE_AUTOUPDATE_PLUGINS=1 בסביבת הרץ כדי לאפשר לתוספים להתעדכן אוטומטית בעוד שהקובץ הבינארי נשאר מקובע

#שינוי גודל הצי

המתזמר שלך מחליט מתי להוסיף או להסיר רצים. בגלל נעילת בעלים יחיד לכל רץ, מספר הרפליקות המינימלי הוא מספר המשתמשים וסוכני Claude Tag שאתה צופה שיהיו פעילים בו זמנית; הדגל --capacity שולט במקביליות בתוך ההפעלות של אותו בעלים, ולא בין בעלים שונים.

קיימות שתי גישות לשינוי גודל:

  • צי קבוע (Fixed fleet): הפעל קבוצה סטטית של רפליקות רצים ובצע שינוי גודל על פי מדדי Prometheus שכל רץ מגיש
  • רצים לפי דרישה (On-demand runners): הרץ את פקודת המשנה claude self-hosted-runner orchestrator, אשר דוגמת מ-Anthropic הפעלות שנמצאות בתור ללא רץ זמין ומפעילה את הוק ה-spawn-runner שלך כדי לאתחל רץ אחד לכל הפעלה. ראה רצים לפי דרישה.

#בעיות ומגבלות ידועות

להלן המגבלות במהדורה זו, בצירוף מעקפים במקומות שבהם קיים מעקף.

#תעבורת מחברים (connectors) יוצאת מהרשת שלך

Anthropic קוראת לכלי מחברים, כגון GitHub, Slack, Linear ומחברי claude.ai האחרים, מתוך התשתית שלה ולא מתוך הרץ שלך, כך שכאשר Claude משתמש במחבר בהפעלה באירוח עצמי, אותה תעבורה עוברת דרך api.anthropic.com ולא נובעת מתוך גבול הרשת שלך. כדי למנוע ממחבר לפעול בהפעלות באירוח עצמי, סנן אותו כמו כל שרת MCP אחר באמצעות הגדרות המדיניות allowedMcpServers ו-deniedMcpServers. Claude Code מחיל הגדרות אלה הן על המחברים ש-Anthropic מספקת והן על השרתים שאתה מגדיר, כך שאם אתה פורס רשימת מורשים (allowlist) עבור שרתים אחרים, Claude Code חוסם גם מחברים שסופקו. כדי להשאיר מחברים זמינים לצד רשימת מורשים מבוססת כתובות URL, הוסף רשומות התואמות לנתיבי הפרוקסי של Anthropic עבור מחברים שסופקו:

  • https://api.anthropic.com/v2/ccr-sessions/*
  • https://api.anthropic.com/v1/code/sessions/*
  • https://api.anthropic.com/v1/code/mcp/*

אם תעבורת הכלים חייבת להישאר בתוך הרשת שלך, הפעל את הכלים המקבילים כשרתי MCP מקומיים ב-image של הרץ במקום זאת. ראה שרתי MCP.

#חלק מההפעלות אינן נחשבות כאיטיות או במצב סרק (idle)

הפעלה שמחזיקה משימת רקע שלעולם אינה מסתיימת אינה נחשבת כאינה פעילה (idle), ולכן --release-idle-session-min לא ישחרר את המשבצת (slot) של אותה הפעלה. הפעלה שממתינה לאישור שהתבקש מתוך קריאה לכלי שרץ גם כן אינה נחשבת כאינה פעילה. הגדר תמיד את --kill-session-after-min לצידו כמעצור חירום קשיח כדי שאף הפעלה לא תוכל להחזיק במשבצת ללא הגבלת זמן.

הדגל --kill-session-after-min הוא מעצור חירום עבור הפעלות שיצאו משליטה. הרץ מסיים כל הפעלה שמגיעה למגבלה, אפילו כזו שמישהו עדיין משתמש בה, לכן הגדר את הדגל בערך הגבוה בהרבה מההפעלה הארוכה ביותר שאתה מצפה לה, כגון --kill-session-after-min 480 עבור 8 שעות. כדי לפנות משבצות משיחות שעוברות למצב סרק, השתמש ב---release-idle-session-min במקום זאת.

#מגבלות נוספות

  • הפעלות שחודשו מאבדות עבודה שלא נדחפה: כאשר הפעלה משוחררת, בעקבות פסק זמן לחוסר פעילות או בעת הפעלה מחדש של רץ, והמשתמש שולח הודעה נוספת, ההפעלה מתחדשת ברץ חדש שמשכפל את המאגר מחדש מענף ההתחלה שלו, כך שעבודה שההפעלה לא דחפה אובדת. הגדר את --push-outcome-on-release כדי שהרץ יבצע מאמץ מרבי לדחוף את ענפי התוצאה של ההפעלה לפני שהוא משחרר אותה, כך שההפעלה המחודשת תתחיל מאותם commits במקום זאת; הדבר שומר על עבודה שנשמרה ב-commit, ולא על עץ עבודה עם שינויים שלא נשמרו (dirty working tree). לפני הפעלתו, הגבל את מי שיכול לדחוף ל-refs של claude/* ב-remote המקור, למשל באמצעות ערכת כללי ענפים (branch ruleset): בעת חידוש, הרץ מושך את הענף שנדחף קודם לכן מבלי לאמת מי דחף אותו, כך שכל מי שיש לו הרשאת דחיפה לאותם refs יכול להציב תוכן בתוך סביבת העבודה המחודשת. הרץ גם משליך הגדרות ברמת ההפעלה בעת חידוש, כלומר את ספריית הגדרות Claude של ההפעלה וכל מצב מעטפת שההפעלה כתבה; הדגל --push-outcome-on-release אינו מכסה דברים אלה.
  • לא ניתן להוסיף מאגרים פרטיים באמצע הפעלה: מאגר שנוסף להפעלה לאחר שהיא כבר התחילה אינו משוכפל עם פרטי הזדהות ברץ באירוח עצמי, ולכן פעולת ההוספה נכשלת. בחר את כל המאגרים שההפעלה זקוקה להם בעת יצירתה.
  • חלק מהמחברים אינם מופיעים בהפעלות באירוח עצמי: מחבר שעדיין לא חיברת בהגדרות claude.ai אינו מופיע ברשימה בהפעלה באירוח עצמי, וההפעלה לא תנחה אותך לחבר אותו. חבר אותו תחילה בהגדרות, ולאחר מכן התחל הפעלה חדשה. הוספת מחבר להפעלה שכבר רצה אינה הופכת את כליו לזמינים עבור Claude; התחל הפעלה חדשה כדי לקלוט מחבר שנוסף לאחרונה.

#דיווח על בעיה

במקרה של בעיות בסביבות באירוח עצמי, פנה לצוות הלקוחות שלך ב-Anthropic.

#פתרון תקלות

לאבחון מודרך, הרץ את תת הפקודה doctor במארח הרץ. תת הפקודה doctor מתחילה הפעלת Claude Code אינטראקטיבית שאליה מצורפים היומנים והמצב של הרץ. היכנס תחילה באמצעות claude auth login באותו מארח כדי שההפעלה תוכל לתשאל את הסביבה שלך, את הרצים שלה ואת ההפעלות שממתינות בתור. ללא כניסה זו, למשל כאשר המארח מזדהה באמצעות מפתח API, היא מוגבלת לנקודת קצה של בריאות מקומית, למדדים וליומן של הרץ, והיא קוראת את היומן רק אם הפעלת את הרץ עם --log-file.

claude self-hosted-runner doctor

בעיות נפוצות:

  • הרץ אינו מופיע בסביבה: ודא שהמארח יכול להגיע אל api.anthropic.com באמצעות HTTPS, שסוד הסביבה עדכני, וששעון המארח מתואם בטווח של חמש דקות מהזמן האמיתי; סטייה גדולה יותר גורמת לאימות להיכשל. הרץ מתעד [runner:fatal] עם סיבת הדחייה במקרה של כשל באימות.
  • הרץ יוצא בעת ההפעלה עם cannot create or write to base directory: הרץ אינו יכול ליצור את --base-dir או לכתוב אליה, שמוגדרת כברירת מחדל ל-/workspace. תקן את הבעלות על הספרייה או כוון את --base-dir לנתיב שניתן לכתוב אליו, כפי שמתואר בסעיף שמירה על ספריית בסיס וקיבולת זהות בכל הרצים. אם הרץ מתעד במקום זאת [runner:fatal] המציין שפסק הזמן לבדיקת ספריית הבסיס פקע, הספרייה נמצאת על גבי התקנת NFS או CSI תקועה. בדוק את תקינות ההתקנה ולא את ההרשאות. הרץ מדפיס את שני כשלי ההפעלה הללו ל-stderr לפני שהוא פותח את --log-file, לכן חפש אותם במסוף או ביומני הקונטיינר של הפלטפורמה שלך ולא בקובץ היומן. לפני גרסה 2.1.225, הרץ לא בדק את ספריית הבסיס בעת ההפעלה, והגדרה שגויה זו הכשילה הפעלות לאחר איסופן במקום זאת.
  • הפעלות נשארות בתור: ייתכן שכל רץ מקוון נעול לבעלים אחר. בדוק את המדד claude_code_self_hosted_runner_locked_account של כל רץ או את השדה locked_account בשורת היומן [runner:health] שלו כדי לראות מי מחזיק בו. שניהם מציגים את כתובת האימייל של הבעלים רק לאחר שהונפק לרץ אסימון הפעלה הנושא תביעת act.email, דבר שהפעלות של סוכן Claude Tag לעולם אינן עושות. ללא התביעה, הרץ אינו פולט סדרת locked_account ומתעד locked_account=yes, מה שאומר לך שהרץ נעול אך לא לאיזה בעלים. הוסף רפליקות, או המתן שרץ קיים יתרוקן ויופעל מחדש. אם הסביבה משתמשת ברצים לפי דרישה, בדוק את המתזמר במקום זאת; ראה רצים לפי דרישה.
  • הפעלות נכשלות מיד לאחר האיסוף: פתח את ההפעלה ב-claude.ai/code כדי לראות את השגיאה. הסיבות הנפוצות ביותר הן היעדר פרטי הזדהות של git ב-image של הרץ וכלי בנייה שאינם מותקנים. ספריית בסיס שאינה ניתנת לכתיבה עוצרת את הרץ בעת ההפעלה במקום להכשיל הפעלות. עיין בסעיף הרץ יוצא בעת ההפעלה עם cannot create or write to base directory ברשימה זו.
  • הפעלות אינן יכולות להגיע לרשת דרך פרוקסי יוצא המבצע אימות: כאשר המקור שהגדרת באמצעות --proxy-authorization-command או --proxy-authorization-file נכשל, מגיע לפסק זמן לאחר 30 שניות, או מחזיר ערך ריק, הרץ משיב לחיבור זה ב-502 Bad Gateway ומתעד את הסיבה ביומן. הרץ מצנזר את ה-stderr של הפקודה באותו יומן ולעולם אינו מתעד את ערך הכותרת. עם --proxy-authorization-command, הרץ את הפקודה בעצמך במארח כדי לוודא שהיא מדפיסה את ערך הכותרת המלא ב-stdout. אם הרץ יוצא במקום זאת בעת ההפעלה עם could not start the proxy-authorization listener, הוא לא הצליח לפתוח את מאזין ה-loopback שלו.
  • הרץ מתעד שורות Poll failed המכילות rejecting the malformed poll response: הרץ קיבל תגובת דגימת עבודה שתוכנה אינו ה-JSON הצפוי של התור, לרוב מכיוון שגורם כלשהו בין הרץ ל-api.anthropic.com, כגון פרוקסי מיירט או פורטל שבוי (captive portal), ענה בדף משלו. הרץ דוחה את התגובה, סופר אותה תחת סוג ה-transport של המדד claude_code_self_hosted_runner_poll_errors_total, ומנסה שוב על פי לוח הזמנים של דגימה שנכשלה המתואר במחזור חיי הפעלה. הרץ ממשיך לשרת את ההפעלות החיות שלו. הגדר את הפרוקסי להעביר תגובות מ-api.anthropic.com ללא שינוי. לפני גרסה 2.1.246, הרץ קרא תגובה כזו כתור עבודה ריק, מה שיכול היה לסיים את ההפעלות החיות שלו או לגרום לו לצאת.
  • הענף של הפעלה אינו קיים עוד ב-remote: עבור מקור git שההפעלה רק קוראת ממנו, הרץ מדלג על אותו מקור וממשיך עם היתר. עבור המקור שההפעלה דוחפת אליו תוצאות, ענף שנמחק, בדרך כלל מכיוון שהוא מוזג ונמחק אוטומטית, מכשיל את ההפעלה עם שגיאה המציינת את שם המאגר והענף ומבקשת ממך לשחזר את הענף ולנסות שוב. הרץ מכשיל את ההפעלה עם אותה שגיאה כאשר דילוג היה משאיר אותה ללא מאגר כלל. לפני גרסה 2.1.228, הפעלה כזו הייתה מתחילה בספרייה ריקה.
  • להפעלות לוקח מספר דקות להתחיל: ה-clone הראשוני תופס בדרך כלל את רוב הזמן. עקוב אחר המדד claude_code_self_hosted_runner_session_init_duration_seconds כדי לוודא זאת, וקצר את ה-clone באמצעות שליפה מוכנה מראש (pre-warmed checkout) או ערך קטן יותר של CLAUDE_RUNNER_FETCH_DEPTH.
  • ה-Pod נהרג באמצע ריקון: הגדל את terminationGracePeriodSeconds לפחות לערך שהרץ מתעד ביומן בעת ההפעלה. ראה תזמון כיבוי.

ברגע שהרישום ליומן מאותחל, הרץ כותב את יומן מחזור החיים שלו, כולל שורות [runner:fatal], ל-stdout, ואת פלט הדיבוג ל-stderr, כולם כשורות טקסט פשוט ולא כ-JSON. כשלי ההפעלה המתוארים בסעיפי פתרון התקלות לעיל מודפסים ל-stderr לפני אותה נקודה. ניתן ללכוד את שני הזרמים באמצעות --log-file, מה שמאפשר גם ל-self-hosted-runner doctor לעקוב אחריהם, או באמצעות איסוף היומנים של הפלטפורמה שלך. תהליך הבן של כל הפעלה כותב יומן דיבוג נפרד. בעת כשל, הרץ שומר על היומן, מדפיס את נתיב היומן ביומן הרץ, ומציג את סוף היומן לצד ההפעלה ב-claude.ai/code.

#מה הלאה