Managed Airflow (דור 3) | Managed Airflow (דור 2) | Managed Airflow (דור 1 מדור קודם)
בדף הזה מוסבר איך להשתמש בפונקציות של Cloud Run כדי להפעיל DAG של Managed Service for Apache Airflow בתגובה לאירועים.
Apache Airflow מיועד להרצת DAGs בלוח זמנים קבוע, אבל אפשר גם להפעיל DAGs בתגובה לאירועים. אחת הדרכים לעשות את זה היא להשתמש בפונקציות Cloud Run כדי להפעיל DAGs מנוהלים של Airflow כשמתרחש אירוע ספציפי.
בדוגמה שבמדריך הזה, DAG מופעל בכל פעם שמתרחש שינוי בקטגוריה של Cloud Storage. שינויים באובייקט כלשהו בקטגוריה מפעילים פונקציה. הפונקציה הזו שולחת בקשה ל-Airflow REST API של סביבת Airflow המנוהלת שלכם. מערכת Airflow מעבדת את הבקשה ומריצה DAG. ה-DAG מוציא מידע על השינוי.
לפני שמתחילים
בקטע הזה מפורטים שלבי ההכנה.
בדיקת הגדרות הרשת בסביבה
הפתרון הזה לא פועל בהגדרות של כתובות IP פרטיות ו-VPC Service Controls, כי אי אפשר להגדיר קישוריות מפונקציות של Cloud Run לשרת האינטרנט של Airflow בהגדרות האלה.
ב-Managed Airflow (דור 2), אפשר להשתמש בגישה אחרת: הפעלת DAG באמצעות פונקציות Cloud Run והודעות Pub/Sub
הפעלת ממשקי API בפרויקט
המסוף
מפעילים את ממשקי ה-API של Managed Airflow ושל פונקציות Cloud Run.
תפקידים שנדרשים להפעלת ממשקי API
כדי להפעיל ממשקי API, נדרשת ההרשאה serviceusage.services.enable. אם יצרתם את הפרויקט, סביר להניח שכבר יש לכם את ההרשאה הזו דרך התפקיד 'בעלים' (roles/owner). אחרת, תוכלו לקבל את ההרשאה הזו דרך התפקיד 'אדמין בממשק 'שימוש בשירות'' (roles/serviceusage.serviceUsageAdmin). איך מקצים תפקידים
gcloud
מפעילים את ממשקי ה-API של פונקציות Managed Airflow ו-Cloud Run:
תפקידים שנדרשים להפעלת ממשקי API
כדי להפעיל ממשקי API, נדרשת ההרשאה serviceusage.services.enable. אם יצרתם את הפרויקט, סביר להניח שכבר יש לכם את ההרשאה הזו דרך התפקיד 'בעלים' (roles/owner). אחרת, תוכלו לקבל את ההרשאה הזו דרך התפקיד 'אדמין של Service Usage' (roles/serviceusage.serviceUsageAdmin). איך מקצים תפקידים
gcloud services enable cloudfunctions.googleapis.comcomposer.googleapis.com
הפעלת Airflow API בארכיטקטורת REST
ב-Airflow 2, ממשק ה-API היציב ל-REST כבר מופעל כברירת מחדל. אם ה-API היציב מושבת בסביבה שלכם, צריך להפעיל את ה-API היציב ל-REST.
התרת קריאות API ל-Airflow API בארכיטקטורת REST באמצעות בקרת גישה של שרת האינטרנט
פונקציות Cloud Run יכולות לפנות אל Airflow API בארכיטקטורת REST באמצעות כתובת IPv4 או IPv6.
אם אתם לא בטוחים מה יהיה טווח כתובות ה-IP של הקריאה, כדאי להשתמש באפשרות ברירת המחדל להגדרה בWebserver Access Control, שהיא All IP addresses have access (default), כדי שלא תחסמו בטעות את הפונקציות של Cloud Run. תמיד אפשר להגדיר גישה לרשת של שרת האינטרנט מאוחר יותר.
יצירת קטגוריה של Cloud Storage
בדוגמה הזו, מופעל DAG בתגובה לשינויים בקטגוריה של Cloud Storage. יוצרים קטגוריה חדשה כדי להשתמש בה בדוגמה הזו.
קבלת כתובת ה-URL של שרת האינטרנט של Airflow
בדוגמה הזו מתבצעות בקשות ל-API בארכיטקטורת REST לנקודת הקצה של שרת האינטרנט של Airflow. משתמשים בכתובת ה-URL של שרת האינטרנט של Airflow בקוד של Cloud Functions.
המסוף
נכנסים לדף Environments במסוף Google Cloud .
לוחצים על שם הסביבה.
בדף Environment details, עוברים לכרטיסייה Environment configuration.
כתובת ה-URL של שרת האינטרנט של Airflow מופיעה בפריט Airflow web UI.
gcloud
מריצים את הפקודה הבאה:
gcloud composer environments describe ENVIRONMENT_NAME \
--location LOCATION \
--format='value(config.airflowUri)'
מחליפים את:
-
ENVIRONMENT_NAMEבשם הסביבה. -
LOCATIONעם האזור שבו הסביבה נמצאת.
העלאת DAG לסביבה
העלאת DAG לסביבה הפלט של ה-DAG הבא הוא הגדרת ההרצה של ה-DAG שהתקבלה. אפשר להפעיל את ה-DAG הזה מפונקציה שיוצרים בהמשך המדריך הזה.
פריסת פונקציה של Cloud Functions שמפעילה את ה-DAG
אפשר לפרוס פונקציה של Cloud Functions באמצעות השפה המועדפת שנתמכת על ידי פונקציות Cloud Run או Cloud Run. במדריך הזה נסביר על Cloud Function שהוטמעה ב-Python וב-Java.
ציון פרמטרים להגדרת Cloud Functions
סביבה. בוחרים באפשרות דור ראשון.
Trigger. בדוגמה הזו, בוחרים טריגר שפועל כשנוצר אובייקט חדש בקטגוריה, או כשמתבצע שכתוב של אובייקט קיים.
סוג הטריגר. Cloud Storage.
סוג האירוע. סיום / יצירה.
Bucket. בוחרים קטגוריה שתפעיל את הפונקציה הזו.
ניסיון חוזר במקרה של כשל. לצורך הדוגמה הזו, מומלץ להשבית את האפשרות הזו. אם אתם משתמשים בפונקציה משלכם בסביבת ייצור, כדאי להפעיל את האפשרות הזו כדי לטפל בשגיאות זמניות.
חשבון שירות של זמן ריצה, בקטע הגדרות של זמן ריצה, build, חיבורים ואבטחה. אפשר לבחור באחת מהאפשרויות הבאות, בהתאם להעדפות שלכם:
בוחרים באפשרות חשבון השירות של Compute Engine שמוגדר כברירת מחדל. עם הרשאות IAM שמוגדרות כברירת מחדל, החשבון הזה יכול להריץ פונקציות שיש להן גישה לסביבות מנוהלות של Airflow.
יוצרים חשבון שירות בהתאמה אישית עם התפקיד Composer User ומציינים אותו כחשבון שירות של זמן הריצה של הפונקציה. האפשרות הזו מבוססת על העיקרון של הרשאות מינימליות.
Runtime and entry point (זמן ריצה ונקודת כניסה), בשלב Code (קוד):
(Python) כשמוסיפים קוד לדוגמה הזו, בוחרים את זמן הריצה Python 3.7 או גרסה מאוחרת יותר ומציינים את
trigger_dag_gcfכנקודת הכניסה.(Java) כשמוסיפים קוד לדוגמה הזו, בוחרים את זמן הריצה Java 17 ומציינים את
com.example.Exampleכנקודת הכניסה.
הוספת דרישות
Python
מציינים את יחסי התלות בקובץ requirements.txt:
Java
מוסיפים את יחסי התלות הבאים לקטע dependencies ב-pom.xml שנוצר על ידי ממשק המשתמש של Google Cloud Functions.
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-docs</artifactId>
<version>v1-rev20210707-1.32.1</version>
</dependency>
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>1.32.1</version>
</dependency>
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-credentials</artifactId>
<version>1.14.0</version>
</dependency>
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-oauth2-http</artifactId>
<version>1.14.0</version>
</dependency>
הוספת קוד פונקציה
Python
מוסיפים את הקוד להפעלת DAG באמצעות API בארכיטקטורת REST של Airflow. יוצרים קובץ בשם composer2_airflow_rest_api.py ומכניסים לתוכו את הקוד ליצירת קריאות ל-Airflow REST API.
אל תשנו אף משתנה. הפונקציה Cloud Function מייבאת את הקובץ הזה מהקובץ main.py.
מוסיפים את הקוד הבא לקובץ main.py. מחליפים את הערך של המשתנה web_server_url בכתובת של שרת האינטרנט של Airflow שקיבלתם קודם.
# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Trigger a DAG in a Cloud Composer 2 environment in response to an event,
using Cloud Functions.
"""
from typing import Any
import composer2_airflow_rest_api
def trigger_dag_gcf(data, context=None):
"""
Trigger a DAG and pass event data.
Args:
data: A dictionary containing the data for the event. Its format depends
on the event.
context: The context object for the event.
For more information about the arguments, see:
https://cloud.google.com/functions/docs/writing/background#function_parameters
"""
# TODO(developer): replace with your values
# Replace web_server_url with the Airflow web server address. To obtain this
# URL, run the following command for your environment:
# gcloud composer environments describe example-environment \
# --location=your-composer-region \
# --format="value(config.airflowUri)"
web_server_url = (
"https://example-airflow-ui-url-dot-us-central1.composer.googleusercontent.com"
)
# Replace with the ID of the DAG that you want to run.
dag_id = 'composer_sample_trigger_response_dag'
composer2_airflow_rest_api.trigger_dag(web_server_url, dag_id, data)
Java
מוסיפים את הקוד הבא לקובץ Example.java. מחליפים את הערך של המשתנה webServerUrl בכתובת של שרת האינטרנט של Airflow שקיבלתם קודם.
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.example;
import com.example.Example.GcsEvent;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpContent;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpResponseException;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.http.json.JsonHttpContent;
import com.google.api.client.json.gson.GsonFactory;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.cloud.functions.BackgroundFunction;
import com.google.cloud.functions.Context;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
/**
* Cloud Function that triggers an Airflow DAG in response to an event (in
* this case a Cloud Storage event).
*/
public class Example implements BackgroundFunction<GcsEvent> {
private static final Logger logger = Logger.getLogger(Example.class.getName());
// TODO(developer): replace with your values
// Replace webServerUrl with the Airflow web server address. To obtain this
// URL, run the following command for your environment:
// gcloud composer environments describe example-environment \
// --location=your-composer-region \
// --format="value(config.airflowUri)"
@Override
public void accept(GcsEvent event, Context context) throws Exception {
String webServerUrl = "https://example-airflow-ui-url-dot-us-central1.composer.googleusercontent.com";
String dagName = "composer_sample_trigger_response_dag";
String url = String.format("%s/api/v1/dags/%s/dagRuns", webServerUrl, dagName);
logger.info(String.format("Triggering DAG %s as a result of an event on the object %s.",
dagName, event.name));
logger.info(String.format("Triggering DAG via the following URL: %s", url));
GoogleCredentials googleCredentials = GoogleCredentials.getApplicationDefault()
.createScoped("https://www.googleapis.com/auth/cloud-platform");
HttpCredentialsAdapter credentialsAdapter = new HttpCredentialsAdapter(googleCredentials);
HttpRequestFactory requestFactory =
new NetHttpTransport().createRequestFactory(credentialsAdapter);
Map<String, Map<String, String>> json = new HashMap<String, Map<String, String>>();
Map<String, String> conf = new HashMap<String, String>();
conf.put("bucket", event.bucket);
conf.put("name", event.name);
conf.put("generation", event.generation);
conf.put("operation", context.eventType());
json.put("conf", conf);
HttpContent content = new JsonHttpContent(new GsonFactory(), json);
HttpRequest request = requestFactory.buildPostRequest(new GenericUrl(url), content);
request.getHeaders().setContentType("application/json");
HttpResponse response;
try {
response = request.execute();
int statusCode = response.getStatusCode();
logger.info("Response code: " + statusCode);
logger.info(response.parseAsString());
} catch (HttpResponseException e) {
// https://cloud.google.com/java/docs/reference/google-http-client/latest/com.google.api.client.http.HttpResponseException
logger.info("Received HTTP exception");
logger.info(e.getLocalizedMessage());
logger.info("- 400 error: wrong arguments passed to Airflow API");
logger.info("- 401 error: check if service account has Composer User role");
logger.info("- 403 error: check Airflow RBAC roles assigned to service account");
logger.info("- 404 error: check Web Server URL");
} catch (Exception e) {
logger.info("Received exception");
logger.info(e.getLocalizedMessage());
}
}
/** Details of the storage event. */
public static class GcsEvent {
/** Bucket name. */
String bucket;
/** Object name. */
String name;
/** Object version. */
String generation;
}
}
בדיקת הפונקציה
כדי לוודא שהפונקציה ו-DAG פועלים כמצופה:
- מחכים עד שהפונקציה תופעל.
- מעלים קובץ לקטגוריה של Cloud Storage. לחלופין, אפשר להפעיל את הפונקציה באופן ידני על ידי בחירת הפעולה Test the function (בדיקת הפונקציה) עבורה במסוף Google Cloud .
- בודקים את דף ה-DAG בממשק האינטרנט של Airflow. ל-DAG צריך להיות הפעלה אחת פעילה או שכבר הסתיימה.
- בממשק המשתמש של Airflow, בודקים את יומני המשימות של ההרצה הזו. אפשר לראות שהנתונים שהתקבלו מהפונקציה מופיעים ביומנים של המשימה
print_gcs_info:
Python
[2021-04-04 18:25:44,778] {bash_operator.py:154} INFO - Output:
[2021-04-04 18:25:44,781] {bash_operator.py:158} INFO - Triggered from GCF:
{bucket: example-storage-for-gcf-triggers, contentType: text/plain,
crc32c: dldNmg==, etag: COW+26Sb5e8CEAE=, generation: 1617560727904101,
... }
[2021-04-04 18:25:44,781] {bash_operator.py:162} INFO - Command exited with
return code 0h
Java
[2023-02-08, 08:00:09 UTC] {subprocess.py:86} INFO - Output:
[2023-02-08, 08:00:09 UTC] {subprocess.py:93} INFO - {bucket: example-storage-for-gcf-triggers, generation: 1675843189006715, name: file.txt, operation: google.storage.object.create}
[2023-02-08, 08:00:09 UTC] {subprocess.py:97} INFO - Command exited with return code 0
המאמרים הבאים
- גישה לממשק המשתמש של Airflow
- גישה ל-Airflow API בארכיטקטורת REST
- כתיבת תרשימי DAG
- כתיבה של פונקציות Cloud Run
- טריגרים של Cloud Storage