אוטומציה של קידום גרסאות והתקדמות בהשקה ב-Cloud Deploy

בדף הזה מוסבר איך להשתמש ב-Cloud Deploy כדי לקדם אוטומטית גרסת הפצה לסביבת יעד ולהעביר פריסה לשלב הבא שלה.

במדריך למתחילים הזה תבצעו את הפעולות הבאות:

  1. יוצרים שני אשכולות GKE או שני שירותים של Cloud Run.

  2. יוצרים הגדרת Skaffold ומניפסט של Kubernetes או הגדרת שירות של Cloud Run.

  3. הגדרת צינור עיבוד הנתונים לפריסה ויעדי הפריסה ב-Cloud Deploy.

    הצינור יופעל בשני יעדים: dev ו-staging. יעד staging משתמש באסטרטגיית פריסה של גרסה ראשונית (canary).

  4. מגדירים שני כללים לאוטומציה:

    • אוטומציה לקידום הגרסה אל יעד staging אחרי השקה מוצלחת אל dev.

    • אוטומציה להעברת ההשקה לשלב stable אחרי השלמה מוצלחת של שלב canary-25.

  5. יוצרים מהדורת תוכנה כדי ליצור מופע של צינור הפריסה, שייפרס אוטומטית אל dev היעד.

  6. אפשר לראות את צינור העברת התוכן ואת הגרסה במסוף Google Cloud .

    בגלל המבצע האוטומטי, הגרסה הזו מקודמת לstaging באופן אוטומטי.

    מכיוון שיעד staging משתמש באסטרטגיית פריסה של גרסה ראשונית (canary), וזו הפריסה הראשונה בסביבת זמן הריצה הזו, שלב canary-25 נדלג. כדי להבין למה שלב הקנרי נדלג בפעם הראשונה, אפשר לקרוא את המאמר למה לפעמים מדלגים על שלבים.

    בגלל ההתקדמות האוטומטית בשלבים, ההשקה עברה לשלב stable.

לפני שמתחילים

  1. נכנסים לחשבון Google Cloud . אם אתם משתמשים חדשים ב- Google Cloud, צרו חשבון כדי שתוכלו להעריך את הביצועים של המוצרים שלנו בתרחישים מהעולם האמיתי. לקוחות חדשים מקבלים בחינם גם קרדיט בשווי 300$ להרצה, לבדיקה ולפריסה של עומסי העבודה.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. Enable the Cloud Deploy, Cloud Build, GKE, Cloud Run, and Cloud Storage APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  5. התקינו את ה-CLI של Google Cloud.

  6. אם אתם משתמשים בספק זהויות חיצוני (IdP), קודם אתם צריכים להיכנס ל-CLI של gcloud באמצעות המאגר המאוחד לניהול זהויות.

  7. כדי לאתחל את ה-CLI של gcloud, הריצו את הפקודה הבאה:

    gcloud init
  8. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  9. Verify that billing is enabled for your Google Cloud project.

  10. Enable the Cloud Deploy, Cloud Build, GKE, Cloud Run, and Cloud Storage APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  11. התקינו את ה-CLI של Google Cloud.

  12. אם אתם משתמשים בספק זהויות חיצוני (IdP), קודם אתם צריכים להיכנס ל-CLI של gcloud באמצעות המאגר המאוחד לניהול זהויות.

  13. כדי לאתחל את ה-CLI של gcloud, הריצו את הפקודה הבאה:

    gcloud init
  14. אם ה-CLI כבר מותקן, צריך לוודא שאתם מריצים את הגרסה העדכנית:

    gcloud components update
    
  15. מוודאים שלחשבון השירות שמוגדר כברירת מחדל ב-Compute Engine יש הרשאות מספיקות.

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

    1. קודם מוסיפים את התפקיד clouddeploy.jobRunner:
      gcloud projects add-iam-policy-binding PROJECT_ID \
          --member=serviceAccount:$(gcloud projects describe PROJECT_ID \
          --format="value(projectNumber)")-compute@developer.gserviceaccount.com \
          --role="roles/clouddeploy.jobRunner"
      
    2. הוספת התפקיד clouddeploy.releaser:
      gcloud projects add-iam-policy-binding PROJECT_ID \
          --member=serviceAccount:$(gcloud projects describe PROJECT_ID \
          --format="value(projectNumber)")-compute@developer.gserviceaccount.com \
          --role="roles/clouddeploy.releaser"
      
    3. מוסיפים את תפקיד המפתח לזמן הריצה הספציפי.
      • ב-GKE:
        gcloud projects add-iam-policy-binding PROJECT_ID \
            --member=serviceAccount:$(gcloud projects describe PROJECT_ID \
            --format="value(projectNumber)")-compute@developer.gserviceaccount.com \
            --role="roles/container.developer"
        
      • ל-Cloud Run:
        gcloud projects add-iam-policy-binding PROJECT_ID \
            --member=serviceAccount:$(gcloud projects describe PROJECT_ID \
            --format="value(projectNumber)")-compute@developer.gserviceaccount.com \
            --role="roles/run.developer"
        
    4. מוסיפים את התפקיד iam.serviceAccountUser, שכולל את ההרשאה actAs לחשבון השירות שמוגדר כברירת מחדל, כדי לפרוס לסביבת זמן הריצה:
      gcloud iam service-accounts add-iam-policy-binding $(gcloud projects describe PROJECT_ID \
          --format="value(projectNumber)")-compute@developer.gserviceaccount.com \
          --member=serviceAccount:$(gcloud projects describe PROJECT_ID \
          --format="value(projectNumber)")-compute@developer.gserviceaccount.com \
          --role="roles/iam.serviceAccountUser" \
          --project=PROJECT_ID
      
    5. כדי להשתמש בחשבון השירות שמוגדר כברירת מחדל, צריך להוסיף לעצמכם את התפקיד iam.serviceAccountUser, כולל ההרשאה actAs:
      gcloud iam service-accounts add-iam-policy-binding $(gcloud projects describe PROJECT_ID \
          --format="value(projectNumber)")-compute@developer.gserviceaccount.com \
          --member=user:YOUR_EMAIL_ADDRESS \
          --role="roles/iam.serviceAccountUser" \
          --project=PROJECT_ID
      

      במקרה הזה, YOUR_EMAIL_ADDRESS היא כתובת האימייל שבה אתם משתמשים כדי לגשת ל-Google Cloud.

יצירת סביבות זמן ריצה

אם אתם מבצעים פריסה ב-Cloud Run, אתם יכולים לדלג על הפקודה הזו.

ב-GKE, יוצרים שני אשכולות: automation-quickstart-cluster-dev ו-automation-quickstart-cluster-staging, עם הגדרות ברירת מחדל. נקודות הקצה של Kubernetes API באשכולות צריכות להיות נגישות ברשת מהאינטרנט הציבורי. אשכולות GKE נגישים חיצונית כברירת מחדל.

gcloud container clusters create-auto automation-quickstart-cluster-dev \
                 --project=PROJECT_ID \
                 --region=us-central1 \
                 && gcloud container clusters create-auto automation-quickstart-cluster-staging \
                 --project=PROJECT_ID \
                 --region=us-central1

מאתרים את מספר הפרויקט.

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

  1. מריצים את הפקודה הבאה כדי לקבל את מספר הפרויקט:

    gcloud projects describe PROJECT_ID --format="value(projectNumber)"
    
  2. מעתיקים את מספר הפרויקט מהפלט של שורת הפקודה ומדביקים אותו כאן.

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

    PROJECT_NUMBER
    

הכנת התצורה של Skaffold ומניפסט האפליקציה

‫Cloud Deploy משתמש ב-Skaffold כדי לספק את הפרטים לגבי מה לפרוס ואיך לפרוס אותו בצורה נכונה עבור יעדים נפרדים.

במדריך למתחילים הזה יוצרים קובץ skaffold.yaml, שמזהה את מניפסט האפליקציה שבו יש להשתמש כדי לפרוס את האפליקציה לדוגמה.

  1. פותחים חלון טרמינל.

  2. יוצרים ספרייה חדשה ועוברים אליה.

    GKE

    mkdir deploy-automation-gke-quickstart
    cd deploy-automation-gke-quickstart
    

    Cloud Run

    mkdir deploy-automation-run-quickstart
    cd deploy-automation-run-quickstart
    
  3. יוצרים קובץ בשם skaffold.yaml עם התוכן הבא:

    GKE

    apiVersion: skaffold/v4beta7
    kind: Config
    metadata:
      name: gke-automation
    manifests:
      rawYaml:
      - k8s-deployment.yaml
    deploy:
      kubectl: {}
    

    Cloud Run

    apiVersion: skaffold/v4beta7
    kind: Config
    metadata:
      name: run-automation
    profiles:
    - name: dev
      manifests:
        rawYaml:
        - run-dev.yaml
    - name: staging
      manifests:
        rawYaml:
        - run-staging.yaml
    deploy:
      cloudrun: {}
    

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

    מידע נוסף על הקובץ הזה מופיע בskaffold.yamlמאמרי העזרה.

  4. יוצרים את ההגדרה של האפליקציה – זוג הגדרות שירות ל-Cloud Run או מניפסט של Kubernetes ל-GKE.

    GKE

    יוצרים קובץ בשם k8s-deployment.yaml עם התוכן הבא:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-deployment
      labels:
        app: my-app
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: my-app
      template:
        metadata:
          labels:
            app: my-app
        spec:
          containers:
          - name: nginx
            image: my-app-image
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: my-service
      namespace: default
    spec:
      selector:
        app: my-app
      ports:
        - protocol: TCP
          port: 80
    

    הקובץ הזה הוא מניפסט פשוט של Kubernetes, שמשמש לפריסת האפליקציה. קובץ האימג' של הקונטיינר לפריסה מוגדר כאן כפלייסהולדר, my-app-image, שמוחלף באימג' הספציפי כשיוצרים את הגרסה.

    Cloud Run

    1. יוצרים קובץ בשם run-dev.yaml עם התוכן הבא:

      apiVersion: serving.knative.dev/v1
      kind: Service
      metadata:
        name: my-automation-run-service-dev
      spec:
        template:
          spec:
            containers:
            - image: my-app-image
      
    2. יוצרים קובץ בשם run-staging.yaml עם התוכן הבא:

      apiVersion: serving.knative.dev/v1
      kind: Service
      metadata:
        name: my-automation-run-service-staging
      spec:
        template:
          spec:
            containers:
            - image: my-app-image
      

    הקובצים האלה הם הגדרות פשוטות של שירות Cloud Run, שמשמשות לפריסת האפליקציה. קובץ האימג' של הקונטיינר שרוצים לפרוס מוגדר כאן כפלייסהולדר, my-app-image, שמוחלף באימג' הספציפי כשיוצרים את הגרסה.

יצירת צינור העברת נתונים, יעדים ואוטומציה

אפשר להגדיר את צינור העברת הנתונים ואת יעדי ההעברה בקובץ אחד או בקבצים נפרדים. אפשר גם להגדיר פעולת אוטומציה בקובץ נפרד. במדריך הזה לשימוש מהיר, נעשה שימוש בקובץ אחד לצינור, ליעדים ולאוטומציה.

  1. יוצרים את צינור ההפצה, הגדרות היעד ופעולת האוטומציה:

    GKE

    בספרייה deploy-automation-gke-quickstart, יוצרים קובץ חדש: clouddeploy.yaml, עם התוכן הבא:

    apiVersion: deploy.cloud.google.com/v1
    kind: DeliveryPipeline
    metadata:
      name: my-automation-demo-app-1
    description: Automation demonstration pipeline
    serialPipeline:
      stages:
      - targetId: automation-quickstart-dev
      - targetId: automation-quickstart-staging
        profiles: []
        strategy:
          canary:
            runtimeConfig:
              kubernetes:
                serviceNetworking:
                  service: "my-service"
                  deployment: "my-deployment"
            canaryDeployment:
              percentages: [25]
              verify: false
    ---
    
    apiVersion: deploy.cloud.google.com/v1
    kind: Target
    metadata:
      name: automation-quickstart-dev
    description: Dev cluster to demonstrate deploy automation
    gke:
      cluster: projects/PROJECT_ID/locations/us-central1/clusters/automation-quickstart-cluster-dev
    ---
    
    apiVersion: deploy.cloud.google.com/v1
    kind: Target
    metadata:
      name: automation-quickstart-staging
    description: Staging cluster to demonstrate deploy automation
    gke:
      cluster: projects/PROJECT_ID/locations/us-central1/clusters/automation-quickstart-cluster-staging
    ---
    
    apiVersion: deploy.cloud.google.com/v1
    kind: Automation
    metadata:
      name: my-automation-demo-app-1/promote
    description: promotes a release
    suspended: false
    serviceAccount: PROJECT_NUMBER-compute@developer.gserviceaccount.com
    selector:
      targets:
      - id: automation-quickstart-dev
    rules:
    - promoteReleaseRule:
        id: "promote-release"
        wait: 1m
        destinationTargetId: "@next"
    ---
    
    apiVersion: deploy.cloud.google.com/v1
    kind: Automation
    metadata:
      name: my-automation-demo-app-1/advance
    description: advances a rollout
    suspended: false
    serviceAccount: PROJECT_NUMBER-compute@developer.gserviceaccount.com
    selector:
      targets:
      - id: automation-quickstart-staging
    rules:
    - advanceRolloutRule:
        id: "advance-rollout"
        sourcePhases: ["canary-25"]
        wait: 1m
    

    Cloud Run

    בספרייה deploy-automation-run-quickstart, יוצרים קובץ חדש: clouddeploy.yaml, עם התוכן הבא:

    apiVersion: deploy.cloud.google.com/v1
    kind: DeliveryPipeline
    metadata:
      name: my-automation-demo-app-1
    description: Automation demonstration pipeline
    serialPipeline:
      stages:
      - targetId: automation-quickstart-dev
        profiles: [dev]
      - targetId: automation-quickstart-staging
        profiles: [staging]
        strategy:
          canary:
            runtimeConfig:
              cloudRun:
                automaticTrafficControl: true
            canaryDeployment:
              percentages: [25]
              verify: false
    ---
    
    apiVersion: deploy.cloud.google.com/v1
    kind: Target
    metadata:
      name: automation-quickstart-dev
    description: Dev cluster to demonstrate deploy automation
    run:
      location: projects/PROJECT_ID/locations/us-central1
    ---
    
    apiVersion: deploy.cloud.google.com/v1
    kind: Target
    metadata:
      name: automation-quickstart-staging
    description: Staging cluster to demonstrate deploy automation
    run:
      location: projects/PROJECT_ID/locations/us-central1
    ---
    
    apiVersion: deploy.cloud.google.com/v1
    kind: Automation
    metadata:
      name: my-automation-demo-app-1/promote
    description: Promotes a release to the next target
    suspended: false
    serviceAccount: PROJECT_NUMBER-compute@developer.gserviceaccount.com
    selector:
      targets:
      - id: automation-quickstart-dev
    rules:
    - promoteReleaseRule:
        id: "promote-release"
        wait: 1m
        destinationTargetId: "@next"
    ---
    
    apiVersion: deploy.cloud.google.com/v1
    kind: Automation
    metadata:
      name: my-automation-demo-app-1/advance
    description: advances a rollout
    suspended: false
    serviceAccount: PROJECT_NUMBER-compute@developer.gserviceaccount.com
    selector:
      targets:
      - id: automation-quickstart-staging
    rules:
    - advanceRolloutRule:
        id: "advance-rollout"
        sourcePhases: ["canary-25"]
        wait: 1m
    
  2. רושמים את צינור עיבוד הנתונים ואת היעדים בשירות Cloud Deploy:

    gcloud deploy apply --file=clouddeploy.yaml --region=us-central1 --project=PROJECT_ID
    

    עכשיו יש לכם צינור עיבוד נתונים עם יעד מרובה אחד שכולל שני יעדים של GKE או Cloud Run, והוא מוכן לפריסת האפליקציה.

  3. מאשרים את הצנרת ואת היעדים:

    במסוף Google Cloud , נכנסים לדף Delivery pipelines של Cloud Deploy כדי לראות רשימה של צינורות העברת הנתונים שזמינים לכם.

    פתיחת הדף Delivery pipelines

    צינור ההפצה שיצרתם מוצג עם שני יעדים שמופיעים בעמודה יעדים.

    הדמיה של צינור עיבוד נתונים למסירה במסוף Google Cloud

  4. לוחצים על שם צינור הנתונים כדי לפתוח את ההדמיה והפרטים של צינור העברת הנתונים.

  5. בקטע פרטים על צינור ההפצה, לוחצים על הכרטיסייה פעולות אוטומטיות.

    שתי הפעולות האוטומטיות שיצרתם מוצגות.

    הדמיה של צינור העברת נתונים במסוף Google Cloud

יצירת גרסה

הפצה היא המשאב המרכזי ב-Cloud Deploy שמייצג את השינויים שנפרסים. צינור העברת התוכן מגדיר את מחזור החיים של הגרסה הזו. פרטים על מחזור החיים הזה מופיעים במאמר ארכיטקטורת שירות Cloud Deploy.

GKE

מריצים את הפקודה הבאה מהספרייה deploy-automation-gke-quickstart כדי ליצור משאב release שמייצג את קובץ האימג' של הקונטיינר לפריסה:

 gcloud deploy releases create test-release-001 \
   --project=PROJECT_ID \
   --region=us-central1 \
   --delivery-pipeline=my-automation-demo-app-1 \
   --images=my-app-image=gcr.io/google-containers/nginx@sha256:f49a843c290594dcf4d193535d1f4ba8af7d56cea2cf79d1e9554f077f1e7aaa

שימו לב לדגל --images=, שמשמש להחלפת ה-placeholder‏ (my-app-image) במניפסט בתמונה ספציפית עם חתימת SHA. ‫Google ממליצה ליצור תבניות למניפסטים בדרך הזו, ולהשתמש בשמות תמונות שעומדים בדרישות של SHA כשיוצרים גרסת הפצה.

Cloud Run

מריצים את הפקודה הבאה מהספרייה deploy-automation-run-quickstart כדי ליצור משאב release שמייצג את קובץ האימג' של הקונטיינר לפריסה:

 gcloud deploy releases create test-release-001 \
   --project=PROJECT_ID \
   --region=us-central1 \
   --delivery-pipeline=my-automation-demo-app-1 \
   --images=my-app-image=us-docker.pkg.dev/cloudrun/container/hello@sha256:95ade4b17adcd07623b0a0c68359e344fe54e65d0cb01b989e24c39f2fcd296a

שימו לב לדגל --images=, שבו משתמשים כדי להחליף את ה-placeholder ‏ (my-app-image) בהגדרת השירות בתמונה הספציפית שמוגדרת באמצעות SHA. ‫Google ממליצה ליצור תבניות להגדרות של השירותים והמשימות בדרך הזו, ולהשתמש בשמות תמונות שעומדים בדרישות של SHA כשיוצרים מהדורות.

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

במדריך למתחילים הזה יש שני תהליכי אוטומציה, ולכן קורים שני דברים באופן אוטומטי:

  • אחרי פריסה מוצלחת ביעד הראשון, הגרסה מקודמת אוטומטית ליעד השני.

    יש זמן המתנה של דקה אחת לקידום האוטומטי.

  • ביעד השני, שבו מוגדרת בדיקת Canary בשיעור של 25%, האוטומציה השנייה מקדמת את ההשקה מ-canary-25 ל-stable.

    בגרסה הראשונה הזו, שלב canary-25 נדלג, כי אין גרסה קיימת של האפליקציה שאפשר להשוות אליה. ההשקה תתקדם אוטומטית לשיעור של stable.

    יש עיכוב של דקה אחת באוטומציה המתקדמת.

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

אם רוצים לקבל מידע נוסף על הפעלת שיטת פריסה של גרסה ראשונית (canary), אפשר לנסות את המדריך למתחילים עם גרסה ראשונית (canary).

צפייה בתוצאות במסוף Google Cloud

אפשר לראות את התוצאות, כולל ההרצות של האוטומציה, בGoogle Cloud מסוף.

  1. עוברים לדף צינורות העברת נתונים ב-Cloud Deploy כדי לראות את צינור העברת הנתונים.

    פתיחת הדף Delivery pipelines

  2. לוחצים על השם של צינור העברת הנתונים 'my-automation-demo-app-1'.

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

    תצוגה חזותית של צינור העברת נתונים במסוף Google Cloud

    פריט התוכן יופיע בכרטיסייה פריטי תוכן בקטע פרטים על צינור ההפצה.

  3. לוחצים על הכרטיסייה הפעלות של אוטומציה.

    יש שתי רשומות, אחת לכל אחת משתי הפעולות האוטומטיות שיצרתם. אפשר ללחוץ על כל אחת מהן כדי לראות את פרטי ההפעלה של האוטומציה.

    פרטי הפעלת אוטומציה שמוצגים במסוף Google Cloud

הסרת המשאבים

כדי לא לצבור חיובים לחשבון Google Cloud על המשאבים שבהם השתמשתם בדף הזה, פועלים לפי השלבים הבאים:

  1. מחיקה של אשכולות GKE או שירותי Cloud Run:

    GKE

    gcloud container clusters delete automation-quickstart-cluster-dev --region=us-central1 --project=PROJECT_ID \
    && gcloud container clusters delete automation-quickstart-cluster-staging --region=us-west1 --project=PROJECT_ID
    

    Cloud Run

    gcloud run services delete my-automation-run-service-dev --region=us-central1 --project=PROJECT_ID \
    && gcloud run services delete my-automation-run-service-staging --region=us-central1 --project=PROJECT_ID
    
  2. מחיקת צינור העברת התוכן, יעדים, פעולות אוטומטיות, גרסה והשקות:

    gcloud deploy delete --file=clouddeploy.yaml --force --region=us-central1 --project=PROJECT_ID
    
  3. מוחקים את הקטגוריות של Cloud Storage שנוצרו על ידי Cloud Deploy.

    אחד מסתיים ב-_clouddeploy והשני הוא [region].deploy-artifacts.[project].appspot.com.

    פתיחת הדף Cloud Storage browser

סיימתם את המדריך למתחילים!

המאמרים הבאים