תזמון של יצירת תמונות של מערכת הפעלה בהתאמה אישית

אתם יכולים לתזמן הפעלות חוזרות של Image Builder באמצעות Cloud Scheduler וטריגרים לפיתוח גרסת Build של Cloud Build. כשמתזמנים פיתוחים של קובצי אימג' בהתאמה אישית של מערכת ההפעלה, Cloud Build מעדכן באופן אוטומטי את קובצי האימג' הבסיסיים באמצעות תיקונים של מערכת ההפעלה ומדיניות האבטחה של הארגון, בלי צורך בהתערבות ידנית.

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

התפקידים הנדרשים

כדי לקבל את ההרשאות שדרושות ליצירת טריגרים ולתזמון של גרסאות build, בקשו מהאדמין להקצות לכם את תפקידי ה-IAM הבאים בפרויקט:

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

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

יצירת צינור עיבוד נתונים מתוזמן של גרסאות build

אפשר להגדיר יצירת קובצי אימג' חוזרים באמצעות ה-CLI של gcloud או ספריית הלקוח של Go:

gcloud

כדי לתזמן בנייה חוזרת של קובצי אימג' של מערכת ההפעלה באמצעות ה-CLI של gcloud:

  1. מריצים את הפקודה gcloud builds triggers create manual כדי ליצור טריגר לפיתוח גרסת Build ידני של Cloud Build שמציין את קובץ היעד cloudbuild.yaml. מכיוון ש-Cloud Scheduler מפעיל את הטריגר הזה באופן ידני ולא באירועים של מאגר, אל תציינו מסננים של בקשות דחיפה או משיכה:

    gcloud builds triggers create manual \
        --name="TRIGGER_NAME" \
        --region=REGION \
        --build-config=CLOUDBUILD_YAML_PATH \
        --project=PROJECT_ID
    
  2. מריצים את הפקודה gcloud builds triggers describe כדי לאחזר את המזהה הייחודי (trigger_id) שנוצר לטריגר החדש:

    gcloud builds triggers describe TRIGGER_NAME \
        --region=REGION \
        --format="value(id)" \
        --project=PROJECT_ID
    
  3. כדי ליצור משימה ב-Cloud Scheduler ששולחת בקשת HTTP POST ל-Cloud Build API (projects.locations.triggers.run) בהתאם ללוח הזמנים הנדרש של unix cron, למשל, מדי שבוע בימי שני בשעה 6:00 בבוקר באמצעות '0 6 * * 1', מריצים את הפקודה gcloud scheduler jobs create http:

    gcloud scheduler jobs create http JOB_NAME \
        --schedule="CRON_SCHEDULE" \
        --uri="https://cloudbuild.googleapis.com/v1/projects/PROJECT_ID/locations/REGION/triggers/TRIGGER_ID:run" \
        --message-body="{}" \
        --oauth-service-account-email="SERVICE_ACCOUNT_EMAIL" \
        --location=REGION \
        --project=PROJECT_ID
    

מחליפים את מה שכתוב בשדות הבאים:

  • ‫TRIGGER_NAME: השם של הטריגר הידני ל-Cloud Build, לדוגמה weekly-ubuntu-builder.
  • ‫REGION: האזור שבו יוצרים את הטריגר, לדוגמה us-central1.
  • ‫CLOUDBUILD_YAML_PATH: הנתיב לקובץ cloudbuild.yaml בספרייה המקומית, לדוגמה cloudbuild.yaml.
  • PROJECT_ID: מזהה הפרויקט.
  • ‫JOB_NAME: השם של משימת ה-cron ב-Cloud Scheduler, לדוגמה weekly-custom-os-patching.
  • ‫CRON_SCHEDULE: ביטוי התזמון של cron ב-Unix, לדוגמה '0 6 * * 1'.
  • ‫TRIGGER_ID: המזהה הייחודי (trigger_id) שנוצר לטריגר.
  • ‫SERVICE_ACCOUNT_EMAIL: כתובת האימייל של חשבון השירות שנותן ל-Cloud Scheduler הרשאה להפעיל את הטריגר. לחשבון השירות הזה נדרשות הרשאות roles/cloudbuild.builds.editor.

המשך

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

לפני שמריצים את הקוד לדוגמה, צריך לבצע את הפעולות הבאות:

  • מעלים את קובץ התצורה imagebuilder.yaml לקטגוריה של Cloud Storage, לדוגמה gs://STAGING_BUCKET/imagebuilder.yaml.
  • נותנים לחשבון השירות של התזמון (cloud-build-trigger-scheduler@PROJECT_ID.iam.gserviceaccount.com) את התפקיד "עריכה ב-Cloud Build" (roles/cloudbuild.builds.editor) בפרויקט, ואת התפקיד "משתמש בחשבון שירות" (roles/iam.serviceAccountUser) בחשבון השירות שמריץ את ה-build. מידע נוסף זמין במאמר תזמון גרסאות build במסמכי התיעוד של Cloud Build.
import (
	"context"
	"fmt"
	"io"

	scheduler "cloud.google.com/go/scheduler/apiv1"
	"cloud.google.com/go/scheduler/apiv1/schedulerpb"
	"google.golang.org/api/cloudbuild/v1"
)

// scheduleBuild creates a manual Cloud Build trigger that runs an Image
// Builder pipeline, and a Cloud Scheduler job that runs the trigger every day.
//
// Before you run this sample, upload your imagebuilder.yaml configuration file
// to Cloud Storage, create a generic Artifact Registry repository, and create a
// service account to run the build.
//
// The job runs the trigger as the default scheduling service account,
// cloud-build-trigger-scheduler@PROJECT_ID.iam.gserviceaccount.com. Grant that
// service account the Cloud Build Editor role, and the Service Account User
// role on the service account that runs the build. For details, see
// https://cloud.google.com/build/docs/schedule-builds.
func scheduleBuild(w io.Writer, projectID, gcsWorkdir, configPath, serviceAccount string) error {
	// projectID := "my-project-id"
	region := "us-central1"
	// gcsWorkdir := "gs://my-bucket/workdir/"
	// configPath := "gs://my-bucket/imagebuilder.yaml"
	repository := "vm-images"
	packageName := "custom-os-images"
	// serviceAccount := "image-builder@my-project-id.iam.gserviceaccount.com"
	triggerName := "scheduled-image-builder"
	jobName := "scheduled-image-builder-job"
	schedule := "0 9 * * *"

	ctx := context.Background()
	cbService, err := cloudbuild.NewService(ctx)
	if err != nil {
		return fmt.Errorf("cloudbuild.NewService: %w", err)
	}
	schedulerClient, err := scheduler.NewCloudSchedulerClient(ctx)
	if err != nil {
		return fmt.Errorf("scheduler.NewCloudSchedulerClient: %w", err)
	}
	defer schedulerClient.Close()

	parent := fmt.Sprintf("projects/%s/locations/%s", projectID, region)
	sa := fmt.Sprintf("projects/%s/serviceAccounts/%s", projectID, serviceAccount)

	trigger := &cloudbuild.BuildTrigger{
		Name:        triggerName,
		Description: "Manual trigger for scheduled VM image builds",
		EventType:   "MANUAL",
		Build: &cloudbuild.Build{
			ServiceAccount: sa,
			// AutomapSubstitutions exposes these substitutions to every step as
			// environment variables. See
			// https://cloud.google.com/build/docs/configuring-builds/substitute-variable-values#mapping_substitutions_to_environment_variables
			Substitutions: map[string]string{
				"_GCS_WORKDIR":               gcsWorkdir,
				"_SERVICE_ACCOUNT":           sa,
				"_IMAGE_OUTPUT_PATH":         "image-builder/binaryOut",
				"_IMAGE_BUILDER_CONFIG_PATH": configPath,
				"_ARTIFACT_REGISTRY_RESOURCE_URI": fmt.Sprintf(
					"projects/%s/locations/%s/repositories/%s/packages/%s/versions/v${BUILD_ID}",
					projectID, region, repository, packageName,
				),
			},
			Steps: []*cloudbuild.BuildStep{
				{
					Id:     "imagebuilder-customize",
					Name:   "us-docker.pkg.dev/image-builder-official/release/builder:stable",
					Script: "#!/usr/bin/env bash\n/build",
					Results: []*cloudbuild.StepResult{
						{
							Name:            "base_image",
							AttestationType: "https://cloudbuild.googleapis.com/attestations/build_content_restrictions",
						},
						{Name: "image_builder_telemetry_metrics"},
					},
				},
				{
					Id:      "imagebuilder-validate",
					Name:    "us-docker.pkg.dev/image-builder-official/release/validator:stable",
					Script:  "#!/usr/bin/env bash\n/validate",
					Results: []*cloudbuild.StepResult{{Name: "image_builder_telemetry_metrics"}},
				},
				{
					Id:      "imagebuilder-publish",
					Name:    "us-docker.pkg.dev/image-builder-official/release/builder:stable",
					Script:  "#!/usr/bin/env bash\n/publish",
					Results: []*cloudbuild.StepResult{{Name: "image_builder_telemetry_metrics"}},
				},
			},
			Options: &cloudbuild.BuildOptions{
				AutomapSubstitutions:  true,
				DynamicSubstitutions:  true,
				RequestedVerifyOption: "VERIFIED",
				SubstitutionOption:    "ALLOW_LOOSE",
				// Builds that run as a user-specified service account must set a
				// logging option.
				Logging: "CLOUD_LOGGING_ONLY",
			},
			Artifacts: &cloudbuild.Artifacts{
				GenericArtifacts: []*cloudbuild.GenericArtifact{
					{
						Folder:       "${_IMAGE_OUTPUT_PATH}",
						RegistryPath: "${_ARTIFACT_REGISTRY_RESOURCE_URI}",
					},
				},
			},
			Timeout: "3600s",
		},
	}
	createdTrigger, err := cbService.Projects.Locations.Triggers.Create(parent, trigger).
		Context(ctx).Do()
	if err != nil {
		return fmt.Errorf("Triggers.Create: %w", err)
	}
	fmt.Fprintf(w, "Created trigger %s (ID: %s)\n", createdTrigger.Name, createdTrigger.Id)

	schedulerSA := fmt.Sprintf(
		"cloud-build-trigger-scheduler@%s.iam.gserviceaccount.com", projectID,
	)
	job := &schedulerpb.Job{
		Name:        fmt.Sprintf("%s/jobs/%s", parent, jobName),
		Description: "Runs the Image Builder trigger on a schedule",
		Schedule:    schedule,
		Target: &schedulerpb.Job_HttpTarget{
			HttpTarget: &schedulerpb.HttpTarget{
				Uri: fmt.Sprintf(
					"https://cloudbuild.googleapis.com/v1/projects/%s/locations/%s/triggers/%s:run",
					projectID, region, createdTrigger.Id,
				),
				HttpMethod: schedulerpb.HttpMethod_POST,
				AuthorizationHeader: &schedulerpb.HttpTarget_OauthToken{
					OauthToken: &schedulerpb.OAuthToken{
						ServiceAccountEmail: schedulerSA,
					},
				},
			},
		},
	}
	req := &schedulerpb.CreateJobRequest{Parent: parent, Job: job}
	createdJob, err := schedulerClient.CreateJob(ctx, req)
	if err != nil {
		return fmt.Errorf("CreateJob: %w", err)
	}
	fmt.Fprintf(w, "Created job %s with schedule %q\n", createdJob.Name, createdJob.Schedule)
	return nil
}

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