รูปภาพรายวัน: ห้องปฏิบัติการ 6 - การเรียบเรียงด้วยเวิร์กโฟลว์

1. ภาพรวม

ในห้องทดลองก่อนหน้านี้ คุณได้สร้างแอป Pic-a-daily เวอร์ชันที่ขับเคลื่อนด้วยเหตุการณ์ ซึ่งใช้ Cloud Function ที่ทริกเกอร์ Cloud Function ของ Google Cloud สำหรับบริการวิเคราะห์รูปภาพ, GCS ที่เรียกใช้คอนเทนเนอร์ Cloud Run ผ่าน Pub/Sub สำหรับบริการภาพขนาดย่อ และ Eventarc เพื่อทริกเกอร์บริการ Image Garbage Collector บน Cloud Run นอกจากนี้ยังมี Cloud Scheduler เรียกใช้บริการภาพต่อกันด้วยดังนี้

d93345bfc235f81e.png

ในห้องทดลองนี้ คุณจะสร้างแอปเวอร์ชันที่มีการจัดการเป็นกลุ่ม คุณจะใช้เวิร์กโฟลว์เพื่อจัดการและเรียกบริการได้ดังนี้ แทนที่จะใช้เหตุการณ์ประเภทต่างๆ ที่ไหลผ่านระบบ

b763efcbf5589747.png

สิ่งที่คุณจะได้เรียนรู้

  • App Engine
  • Cloud Firestore
  • Cloud Functions
  • Cloud Run
  • เวิร์กโฟลว์

2. การตั้งค่าและข้อกำหนด

การตั้งค่าสภาพแวดล้อมตามเวลาที่สะดวก

  1. ลงชื่อเข้าใช้ Cloud Console และสร้างโปรเจ็กต์ใหม่หรือใช้โปรเจ็กต์ที่มีอยู่ซ้ำ (หากยังไม่มีบัญชี Gmail หรือ Google Workspace คุณต้องสร้างบัญชี)

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

โปรดจดจำรหัสโปรเจ็กต์ ซึ่งเป็นชื่อที่ไม่ซ้ำกันในโปรเจ็กต์ Google Cloud ทั้งหมด (ชื่อด้านบนมีคนใช้แล้ว และจะใช้ไม่ได้ ขออภัย) และจะมีการอ้างอิงใน Codelab ว่า PROJECT_ID ในภายหลัง

  1. ถัดไป คุณจะต้องเปิดใช้การเรียกเก็บเงินใน Cloud Console เพื่อใช้ทรัพยากร Google Cloud

การใช้งาน Codelab นี้น่าจะไม่มีค่าใช้จ่ายใดๆ หากมี ตรวจสอบว่าคุณได้ทำตามวิธีการใน "การล้างข้อมูล" ซึ่งจะแนะนำคุณเกี่ยวกับวิธีปิดทรัพยากรเพื่อไม่ให้มีการเรียกเก็บเงินนอกเหนือจากบทแนะนำนี้ ผู้ใช้ใหม่ของ Google Cloud จะมีสิทธิ์เข้าร่วมโปรแกรมทดลองใช้ฟรี$300 USD

เริ่มต้น Cloud Shell

แม้ว่าคุณจะดำเนินการ Google Cloud จากระยะไกลได้จากแล็ปท็อป แต่คุณจะใช้ Google Cloud Shell ซึ่งเป็นสภาพแวดล้อมแบบบรรทัดคำสั่งที่ทำงานในระบบคลาวด์ใน Codelab นี้

จากคอนโซล GCP ให้คลิกไอคอน Cloud Shell บนแถบเครื่องมือด้านขวาบนดังนี้

bce75f34b2c53987.png

การจัดสรรและเชื่อมต่อกับสภาพแวดล้อมนี้ควรใช้เวลาเพียงครู่เดียว เมื่อเสร็จแล้ว คุณจะเห็นข้อมูลต่อไปนี้

f6ef2b5f13479f3a.png

เครื่องเสมือนนี้เต็มไปด้วยเครื่องมือการพัฒนาทั้งหมดที่คุณต้องการ โดยมีไดเรกทอรีหลักขนาด 5 GB ที่ใช้งานได้ต่อเนื่องและทำงานบน Google Cloud ซึ่งช่วยเพิ่มประสิทธิภาพของเครือข่ายและการตรวจสอบสิทธิ์ได้อย่างมาก งานทั้งหมดใน Lab นี้สามารถทำได้โดยใช้เบราว์เซอร์

3. ข้อมูลเบื้องต้นเกี่ยวกับเวิร์กโฟลว์

90fcd42d556e310e.jpeg

คุณสามารถใช้เวิร์กโฟลว์เพื่อสร้างเวิร์กโฟลว์แบบ Serverless ที่จะลิงก์งานแบบ Serverless ต่างๆ เข้าด้วยกันตามลำดับที่คุณกำหนด คุณสามารถผสานรวมประสิทธิภาพของ API ของ Google Cloud, ผลิตภัณฑ์แบบ Serverless เช่น Cloud Functions และ Cloud Run และการเรียก API ภายนอกเพื่อสร้างแอปพลิเคชันแบบ Serverless ที่ยืดหยุ่นได้

ดังที่คุณอาจคาดหวังจากผู้จัดหลายๆ คน เวิร์กโฟลว์ช่วยคุณกำหนดโฟลว์ของตรรกะทางธุรกิจในภาษานิยามเวิร์กโฟลว์ตาม YAML/JSON และมี Workflows Execution API และ UI เวิร์กโฟลว์เพื่อทริกเกอร์ขั้นตอนเหล่านั้น

ซึ่งไม่ใช่แค่ผู้จัดที่มีฟีเจอร์ในตัวที่กำหนดค่าได้เหล่านี้

  • การลองซ้ำและจัดการข้อผิดพลาดระหว่างขั้นตอนต่างๆ ที่ยืดหยุ่นเพื่อให้ดำเนินการตามขั้นตอนต่างๆ ได้อย่างน่าเชื่อถือ
  • การแยกวิเคราะห์ JSON และการส่งตัวแปรระหว่างขั้นตอนเพื่อหลีกเลี่ยง Glue-code
  • สูตรนิพจน์สำหรับการตัดสินใจช่วยให้ดำเนินการตามขั้นตอนแบบมีเงื่อนไขได้
  • เวิร์กโฟลว์ย่อยสำหรับเวิร์กโฟลว์แบบโมดูลและนำมาใช้ซ้ำได้
  • การสนับสนุนบริการภายนอกช่วยให้จัดการบริการเป็นกลุ่มนอกเหนือจาก Google Cloud ได้
  • การรองรับการตรวจสอบสิทธิ์สำหรับ Google Cloud และบริการภายนอกเพื่อการดำเนินการตามขั้นตอนที่ปลอดภัย
  • เครื่องมือเชื่อมต่อกับบริการ Google Cloud เช่น Pub/Sub, Firestore, Tasks, Secret Manager เพื่อการผสานรวมที่ง่ายขึ้น

ยิ่งไปกว่านั้น Workflows เป็นผลิตภัณฑ์แบบ Serverless ที่มีการจัดการครบวงจร ไม่มีเซิร์ฟเวอร์ให้กำหนดค่าหรือปรับขนาด และคุณจะจ่ายเฉพาะที่ใช้ไปเท่านั้น

4. เปิดใช้ API

ในห้องทดลองนี้ คุณจะได้เชื่อมต่อ Cloud Functions และบริการ Cloud Run กับเวิร์กโฟลว์ นอกจากนี้ คุณจะใช้ App Engine, Cloud Build, Vision API และบริการอื่นๆ ด้วย

ใน Cloud Shell โปรดตรวจสอบว่าได้เปิดใช้บริการที่จำเป็นทั้งหมดแล้ว

gcloud services enable \
  appengine.googleapis.com \
  cloudbuild.googleapis.com \
  cloudfunctions.googleapis.com \
  compute.googleapis.com \
  firestore.googleapis.com \
  run.googleapis.com \
  vision.googleapis.com \
  workflows.googleapis.com \

หลังจากนั้นสักครู่ คุณควรเห็นว่าการดำเนินการเสร็จสิ้นเรียบร้อยแล้ว

Operation "operations/acf.5c5ef4f6-f734-455d-b2f0-ee70b5a17322" finished successfully.

5. รับโค้ด

รับโค้ด หากยังไม่ได้ทำใน Code Lab ก่อนหน้านี้:

git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop

คุณจะมีโครงสร้างโฟลเดอร์ต่อไปนี้ที่เกี่ยวข้องกับห้องทดลองนี้

frontend
 |
workflows
 |
 ├── functions
 ├── |── trigger-workflow
 ├── |── vision-data-transform
 ├── services
 ├── |── collage
 ├── |── thumbnails
 ├── workflows.yaml

โฟลเดอร์ที่เกี่ยวข้องมีดังต่อไปนี้

  • frontend มีฟรอนท์เอนด์ของ App Engine ที่เราจะนำมาใช้ซ้ำจาก Lab 4
  • functions มี Cloud Functions ที่สร้างขึ้นสำหรับเวิร์กโฟลว์
  • services มีบริการ Cloud Run ที่แก้ไขสำหรับเวิร์กโฟลว์
  • workflows.yaml คือไฟล์การกำหนดเวิร์กโฟลว์

6. สำรวจ YAML ของ Workflows

workflows.yaml จะกำหนดเวิร์กโฟลว์เป็นชุดขั้นตอน เราจะอธิบายเรื่องนี้เพื่อให้เข้าใจได้ดีขึ้น

ในช่วงเริ่มต้นเวิร์กโฟลว์จะมีพารามิเตอร์บางส่วนที่ส่งผ่านเข้ามา ซึ่งจะส่งผ่านไปโดย Cloud Functions 2 รายการที่ทริกเกอร์เวิร์กโฟลว์ เราจะไปที่ฟังก์ชันเหล่านี้ในภายหลัง แต่เวิร์กโฟลว์จะเริ่มต้นโดยทำดังนี้

d44a5e18aa9d4660.png

ใน YAML คุณจะเห็นว่าพารามิเตอร์เหล่านี้ได้รับการกำหนดให้กับตัวแปรในขั้นตอน init เช่น ชื่อไฟล์และที่เก็บข้อมูลที่ทริกเกอร์เหตุการณ์ และ URL ของบริการ Cloud Functions และ Cloud Run บางส่วนที่เวิร์กโฟลว์จะเรียกใช้

main:
  params: [args]
  steps:
    - init:
        assign:
          - file: ${args.file}
          - bucket: ${args.bucket}
          - gsUri: ${"gs://" + bucket + "/" + file}
          - projectId: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
          - urls: ${args.urls}

ถัดไป เวิร์กโฟลว์จะตรวจสอบประเภทเหตุการณ์ มีเหตุการณ์ที่รองรับ 2 ประเภท ได้แก่ object.finalize (ส่งออกเมื่อบันทึกไฟล์ในที่เก็บข้อมูล Cloud Storage) และ object.delete (ส่งเมื่อลบไฟล์) สิ่งอื่นๆ จะยกข้อยกเว้นเหตุการณ์ที่ไม่รองรับ

dd1f450983655619.png

ต่อไปนี้คือขั้นตอนในคำจำกัดความของเวิร์กโฟลว์ YAML ที่เราจะตรวจสอบประเภทเหตุการณ์พื้นที่เก็บข้อมูลไฟล์

    - eventTypeSwitch:
        switch:
            - condition: ${args.eventType == "google.storage.object.finalize"}
              next: imageAnalysisCall
            - condition: ${args.eventType == "google.storage.object.delete"}
              next: pictureGarbageCollectionGCS
    - eventTypeNotSupported:
        raise: ${"eventType " + args.eventType + " is not supported"}
        next: end

โปรดสังเกตว่าเวิร์กโฟลว์รองรับคำสั่งสวิตช์และการจัดการข้อยกเว้น โดยมีคำสั่งสำหรับสวิตช์และเงื่อนไขต่างๆ และวิธีการเพิ่มข้อผิดพลาดเมื่อระบบไม่รู้จักเหตุการณ์นั้น

ต่อไป เราจะมาดู imageAnalysisCall กัน ชุดนี้เป็นการเรียกจากเวิร์กโฟลว์เพื่อเรียกใช้ Vision API เพื่อวิเคราะห์รูปภาพ แปลงข้อมูลการตอบสนองของ Vision API เพื่อจัดเรียงป้ายกำกับของสิ่งที่รู้จักในรูปภาพ เลือกสีที่โดดเด่น ตรวจสอบว่ารูปภาพนั้นแสดงได้หรือไม่ จากนั้นบันทึกข้อมูลเมตาลงใน Cloud Firestore

โปรดทราบว่าทุกอย่างเสร็จสิ้นในเวิร์กโฟลว์ ยกเว้น Vision Transform Cloud Functions (ซึ่งเราจะทำให้ใช้งานได้ในภายหลัง) ดังนี้

ca2ad16b9cbb436.png

นี่คือลักษณะของขั้นตอนใน YAML

    - imageAnalysisCall:
        call: http.post
        args:
          url: https://vision.googleapis.com/v1/images:annotate
          headers:
            Content-Type: application/json
          auth:
            type: OAuth2
          body:
            requests:
            - image:
                source:
                  gcsImageUri: ${gsUri}
              features:
              - type: LABEL_DETECTION
              - type: SAFE_SEARCH_DETECTION
              - type: IMAGE_PROPERTIES
        result: imageAnalysisResponse
    - transformImageAnalysisData:
        call: http.post
        args:
          url: ${urls.VISION_DATA_TRANSFORM_URL}
          auth:
            type: OIDC
          body: ${imageAnalysisResponse.body}
        result: imageMetadata
    - checkSafety:
        switch:
          - condition: ${imageMetadata.body.safe == true}
            next: storeMetadata
        next: end
    - storeMetadata:
        call: http.request
        args:
          url: ${"https://firestore.googleapis.com/v1/projects/" + projectId + "/databases/(default)/documents/pictures/" + file + "?updateMask.fieldPaths=color&updateMask.fieldPaths=labels&updateMask.fieldPaths=created"}
          auth:
            type: OAuth2
          method: PATCH
          body:
            name: ${"projects/" + projectId + "/databases/(default)/documents/pictures/" + file}
            fields:
              color:
                stringValue: ${imageMetadata.body.color}
              created:
                timestampValue: ${imageMetadata.body.created}
              labels:
                arrayValue:
                  values: ${imageMetadata.body.labels}
        result: storeMetadataResponse

เมื่อวิเคราะห์รูปภาพแล้ว 2 ขั้นตอนถัดไปคือการสร้างภาพขนาดย่อและภาพตัดปะของรูปภาพล่าสุด ซึ่งทำได้โดยการทำให้บริการ Cloud Run 2 รายการใช้งานได้และเรียกใช้บริการจาก thumbnailCall และ collageCall ขั้นตอน:

76f9179323c3144.png

ขั้นตอนใน YAML มีดังนี้

   - thumbnailCall:
        call: http.post
        args:
          url: ${urls.THUMBNAILS_URL}
          auth:
            type: OIDC
          body:
              gcsImageUri: ${gsUri}
        result: thumbnailResponse
    - collageCall:
        call: http.get
        args:
          url: ${urls.COLLAGE_URL}
          auth:
            type: OIDC
        result: collageResponse

สาขาของการดำเนินการนี้จะสิ้นสุดโดยการส่งคืนรหัสสถานะจากแต่ละบริการในขั้นตอน finalizeCompleted:

    - finalizeCompleted:
        return:
          imageAnalysis: ${imageAnalysisResponse.code}
          storeMetadata: ${storeMetadataResponse.code}
          thumbnail: ${thumbnailResponse.code}
          collage: ${collageResponse.code}

อีกสาขาหนึ่งของการดำเนินการคือเมื่อไฟล์ถูกลบออกจากที่เก็บข้อมูลของพื้นที่เก็บข้อมูลหลัก ซึ่งจะมีรูปภาพเวอร์ชันความละเอียดสูง ในสาขานี้ เราต้องการลบภาพขนาดย่อของรูปภาพ ในที่เก็บข้อมูลที่มีภาพขนาดย่อ และลบข้อมูลเมตาออกจาก Firestore โดยการดำเนินการทั้ง 2 อย่างนี้ทำได้ด้วยการเรียก HTTP จากเวิร์กโฟลว์

f172379274dcb3c2.png

ขั้นตอนใน YAML มีดังนี้

    - pictureGarbageCollectionGCS:
        try:
          call: http.request
          args:
            url: ${"https://storage.googleapis.com/storage/v1/b/thumbnails-" + projectId + "/o/" + file}
            auth:
              type: OAuth2
            method: DELETE
          result: gcsDeletionResult
        except:
          as: e
          steps:
              - dummyResultInOutVar:
                  assign:
                      - gcsDeletionResult:
                          code: 200
                          body: "Workaround for empty body response"
    - pictureGarbageCollectionFirestore:
        call: http.request
        args:
          url: ${"https://firestore.googleapis.com/v1/projects/" + projectId + "/databases/(default)/documents/pictures/" + file}
          auth:
            type: OAuth2
          method: DELETE
        result: firestoreDeletionResult

การลบ Branch จะสิ้นสุดด้วยการแสดงผลลัพธ์ / โค้ดจากแต่ละขั้นตอนดังนี้

    - deleteCompleted:
        return:
          gcsDeletion: ${gcsDeletionResult}
          firestoreDeletion: ${firestoreDeletionResult.code}

ในขั้นตอนต่อไปนี้ เราจะสร้างทรัพยากร Dependency ภายนอกทั้งหมดของเวิร์กโฟลว์ ซึ่งได้แก่ ที่เก็บข้อมูล, Cloud Functions, บริการ Cloud Run และฐานข้อมูล Firestore

7. สร้างที่เก็บข้อมูล

คุณต้องมีที่เก็บข้อมูล 2 ชุดสำหรับรูปภาพ โดย 1 ตัวเลือกสำหรับบันทึกรูปภาพต้นฉบับความละเอียดสูง และ 1 ตัวเลือกสำหรับบันทึกภาพขนาดย่อของรูปภาพ

สร้างที่เก็บข้อมูลระดับภูมิภาค (ในกรณีนี้คือยุโรป) แบบสาธารณะที่มีสิทธิ์เข้าถึงแบบเดียวกันเพื่อให้ผู้ใช้อัปโหลดรูปภาพได้โดยใช้เครื่องมือ gsutil ดังนี้

export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}
gsutil mb -l EU gs://${BUCKET_PICTURES}
gsutil uniformbucketlevelaccess set on gs://${BUCKET_PICTURES}
gsutil iam ch allUsers:objectViewer gs://${BUCKET_PICTURES}

สร้างที่เก็บข้อมูลระดับภูมิภาคสาธารณะอื่นสำหรับภาพขนาดย่อ

export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
gsutil mb -l EU gs://${BUCKET_THUMBNAILS}
gsutil uniformbucketlevelaccess set on gs://${BUCKET_THUMBNAILS}
gsutil iam ch allUsers:objectViewer gs://${BUCKET_THUMBNAILS}

คุณตรวจสอบอีกครั้งว่ามีการสร้างที่เก็บข้อมูลและเป็นแบบสาธารณะได้โดยไปที่ส่วน Cloud Storage ของ Cloud Console แล้วทำดังนี้

15063936edd72f06.png

8. การเปลี่ยนรูปแบบข้อมูล Vision (Cloud Function)

Workflows.yaml จะเริ่มต้นด้วย init, eventTypeSwitch และ eventTypeNotSupported ขั้นตอน ซึ่งจะช่วยให้ระบบกำหนดเส้นทางเหตุการณ์ที่มาจากที่เก็บข้อมูลไปยังขั้นตอนที่ถูกต้อง

สำหรับเหตุการณ์ object.finalize ขั้นตอน imageAnalysisCall จะเรียกใช้ Vision API เพื่อดึงข้อมูลเมตาของรูปภาพที่สร้างขึ้น ขั้นตอนทั้งหมดนี้ดำเนินการภายในเวิร์กโฟลว์

daaed43a22d2b0d3.png

ต่อไป เราต้องเปลี่ยนรูปแบบข้อมูลที่แสดงผลจาก Vision API ก่อนที่จะบันทึกลงใน Firestore กล่าวอย่างเจาะจงก็คือ เราจำเป็นต้อง

  • ระบุป้ายกำกับที่แสดงผลสำหรับรูปภาพ
  • แสดงสีที่โดดเด่นของรูปภาพ
  • ตรวจสอบว่าภาพดังกล่าวปลอดภัยหรือไม่

ซึ่งทำในโค้ดในฟังก์ชันระบบคลาวด์และเวิร์กโฟลว์จะเรียกใช้ฟังก์ชันนี้เท่านั้น

5e120e70c67779cd.png

สำรวจโค้ด

โดย Cloud Function จะเรียกว่า vision-data-transform คุณสามารถตรวจสอบโค้ดแบบเต็มใน index.js อย่างที่เห็น จุดประสงค์ของฟังก์ชันนี้เพียงอย่างเดียวคือการแปลง JSON เป็น JSON เพื่อจัดเก็บข้อมูลเมตาของรูปภาพอย่างสะดวกใน Firestore

ทำให้ใช้งานได้กับ Cloud Functions

ไปที่โฟลเดอร์โดยใช้วิธีต่อไปนี้

cd workflows/functions/vision-data-transform/nodejs

ตั้งค่าภูมิภาคที่ต้องการ ดังนี้

export REGION=europe-west1
gcloud config set functions/region ${REGION}

ทำให้ฟังก์ชันใช้งานได้ด้วย

export SERVICE_NAME=vision-data-transform
gcloud functions deploy ${SERVICE_NAME} \
  --source=. \
  --runtime nodejs10 \
  --entry-point=vision_data_transform \
  --trigger-http \
  --allow-unauthenticated

เมื่อทำให้ฟังก์ชันใช้งานได้แล้ว ขั้นตอน transformImageAnalysisData ของเวิร์กโฟลว์จะเรียกใช้ฟังก์ชันนี้เพื่อเปลี่ยนรูปแบบข้อมูล Vision API ได้

9. เตรียมฐานข้อมูล

ขั้นตอนถัดไปในเวิร์กโฟลว์คือการตรวจสอบความปลอดภัยของรูปภาพจากข้อมูลรูปภาพ แล้วจัดเก็บข้อมูลเกี่ยวกับรูปภาพที่ Vision API แสดงไว้ในฐานข้อมูล Cloud Firestore ซึ่งเป็นฐานข้อมูลเอกสาร NoSQL แบบ Serverless ที่ดำเนินการบนระบบคลาวด์อย่างรวดเร็ว มีการจัดการครบวงจรดังนี้

6624c616bc7cd97f.png

โดยการดำเนินการทั้ง 2 อย่างนี้จะทำได้ในเวิร์กโฟลว์ แต่คุณต้องสร้างฐานข้อมูล Firestore เพื่อให้พื้นที่เก็บข้อมูลเมตาทำงานได้

ขั้นแรก ให้สร้างแอป App Engine ในภูมิภาคที่คุณต้องการฐานข้อมูล Firestore (ข้อกำหนดของ Firestore) ดังนี้

export REGION_FIRESTORE=europe-west2
gcloud app create --region=${REGION_FIRESTORE}

จากนั้นให้สร้างฐานข้อมูล Firestore ในภูมิภาคเดียวกันโดยทำดังนี้

gcloud firestore databases create --region=${REGION_FIRESTORE}

โดยเอกสารจะสร้างขึ้นแบบเป็นโปรแกรมในคอลเล็กชันของเราและประกอบด้วย 4 ฟิลด์ ดังนี้

  • name (สตริง): ชื่อไฟล์ของรูปภาพที่อัปโหลด ซึ่งเป็นคีย์ของเอกสาร
  • labels (อาร์เรย์ของสตริง): ป้ายกำกับของรายการที่รู้จักโดย Vision API
  • color (สตริง): รหัสสีเลขฐาน 16 ของสีหลัก (เช่น #ab12ef)
  • สร้าง (วันที่): การประทับเวลาที่เก็บข้อมูลเมตาของรูปภาพนี้
  • ภาพขนาดย่อ (บูลีน): ช่องที่ไม่บังคับซึ่งจะแสดงและเป็น "จริง" หากมีการสร้างภาพขนาดย่อสำหรับรูปภาพนี้

เนื่องจากเราจะค้นหาใน Firestore เพื่อค้นหารูปภาพที่มีภาพขนาดย่อ และจัดเรียงตามวันที่สร้าง เราจะต้องสร้างดัชนีการค้นหา คุณสร้างดัชนีได้ด้วยคำสั่งต่อไปนี้

gcloud firestore indexes composite create --collection-group=pictures \
  --field-config field-path=thumbnail,order=descending \
  --field-config field-path=created,order=descending

โปรดทราบว่าการสร้างดัชนีอาจใช้เวลาถึง 10 นาทีโดยประมาณ

เมื่อสร้างดัชนีแล้ว คุณจะดูดัชนีได้ใน Cloud Console โดยทำดังนี้

43af1f5103bf423.png

ขั้นตอน storeMetadata ของเวิร์กโฟลว์จะจัดเก็บข้อมูลเมตาของรูปภาพไปยัง Firestore ได้แล้ว

10. บริการภาพขนาดย่อ (Cloud Run)

ลำดับต่อไปคือการสร้างภาพขนาดย่อของรูปภาพ ซึ่งทำในโค้ดในบริการ Cloud Run และเวิร์กโฟลว์จะเรียกใช้บริการนี้ในขั้นตอน thumbnailCall:

84d987647f082b53.png

สำรวจโค้ด

บริการ Cloud Run มีชื่อว่า thumbnails คุณสามารถตรวจสอบโค้ดแบบเต็มใน index.js

สร้างและนำอิมเมจคอนเทนเนอร์ไปใช้จริง

Cloud Run เรียกใช้คอนเทนเนอร์ แต่คุณต้องสร้างอิมเมจคอนเทนเนอร์ก่อน (ตามที่กำหนดไว้ใน Dockerfile) คุณใช้ Google Cloud Build เพื่อสร้างอิมเมจคอนเทนเนอร์แล้วโฮสต์กับ Google Container Registry ได้

ไปที่โฟลเดอร์โดยใช้วิธีต่อไปนี้

cd workflows/services/thumbnails/nodejs

รุ่น:

export SERVICE_SRC=thumbnails
export SERVICE_NAME=${SERVICE_SRC}-service
gcloud builds submit \
  . \
  --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}

หลังจากผ่านไป 1-2 นาที บิลด์ควรสำเร็จและคอนเทนเนอร์จะใช้งานได้กับ Google Container Registry

ทำให้ใช้งานได้กับ Cloud Run

ตั้งค่าตัวแปรและการกำหนดค่าที่จำเป็น

export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
gcloud config set run/region ${REGION}
gcloud config set run/platform managed

ทำให้ใช้งานได้ด้วยคำสั่งต่อไปนี้

gcloud run deploy ${SERVICE_NAME} \
    --image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \
    --no-allow-unauthenticated \
    --memory=1Gi \
    --update-env-vars BUCKET_THUMBNAILS=${BUCKET_THUMBNAILS}

เมื่อทำให้บริการใช้งานได้แล้ว ขั้นตอน thumbnailCall ของเวิร์กโฟลว์จะสามารถเรียกใช้บริการนี้ได้

11. บริการภาพต่อกัน (Cloud Run)

ขั้นตอนต่อไปในการสร้างภาพคอลลาจจากรูปภาพล่าสุด ซึ่งทำในโค้ดในบริการ Cloud Run และเวิร์กโฟลว์จะเรียกใช้บริการนี้ในขั้นตอน collageCall:

591e36149066e1ba.png

สำรวจโค้ด

บริการ Cloud Run มีชื่อว่า collage คุณสามารถตรวจสอบโค้ดแบบเต็มใน index.js

สร้างและนำอิมเมจคอนเทนเนอร์ไปใช้จริง

Cloud Run เรียกใช้คอนเทนเนอร์ แต่คุณต้องสร้างอิมเมจคอนเทนเนอร์ก่อน (ตามที่กำหนดไว้ใน Dockerfile) คุณใช้ Google Cloud Build เพื่อสร้างอิมเมจคอนเทนเนอร์แล้วโฮสต์กับ Google Container Registry ได้

ไปที่โฟลเดอร์โดยใช้วิธีต่อไปนี้

cd services/collage/nodejs

รุ่น:

export SERVICE_SRC=collage
export SERVICE_NAME=${SERVICE_SRC}-service
gcloud builds submit \
  . \
  --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}

หลังจากผ่านไป 1-2 นาที บิลด์ควรสำเร็จและคอนเทนเนอร์จะใช้งานได้กับ Google Container Registry

ทำให้ใช้งานได้กับ Cloud Run

ตั้งค่าตัวแปรและการกำหนดค่าที่จำเป็น

export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
gcloud config set run/region ${REGION}
gcloud config set run/platform managed

ทำให้ใช้งานได้:

gcloud run deploy ${SERVICE_NAME} \
    --image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \
    --no-allow-unauthenticated \
    --memory=1Gi \
    --update-env-vars BUCKET_THUMBNAILS=${BUCKET_THUMBNAILS}

เมื่อทำให้บริการใช้งานได้แล้ว คุณสามารถตรวจสอบได้ว่าทั้ง 2 บริการทำงานอยู่ในส่วน Cloud Run ของ Cloud Console และเวิร์กโฟลว์ collageCall จะสามารถเรียกใช้บริการนี้ได้

3ae9873f4cbbf423.png

12. การทำให้เวิร์กโฟลว์ใช้งานได้

เราทำให้ทรัพยากร Dependency ภายนอกทั้งหมดของเวิร์กโฟลว์ใช้งานได้แล้ว ขั้นตอนที่เหลือทั้งหมด (finalizeCompleted, pictureGarbageCollectionGCS, pictureGarbageCollectionFirestore, deleteCompleted) สามารถทำได้โดยเวิร์กโฟลว์เอง

ได้เวลาทำให้เวิร์กโฟลว์ใช้งานได้แล้ว

ไปที่โฟลเดอร์ที่มีไฟล์ workflows.yaml และทำให้ใช้งานได้ด้วย:

export WORKFLOW_REGION=europe-west4
export WORKFLOW_NAME=picadaily-workflows
gcloud workflows deploy ${WORKFLOW_NAME} \
  --source=workflows.yaml \
  --location=${WORKFLOW_REGION}

เวิร์กโฟลว์จะทำให้ใช้งานได้ภายในไม่กี่วินาที และคุณจะเห็นได้ในส่วนเวิร์กโฟลว์ของ Cloud Console

94a720149e5df9c5.png

คุณสามารถคลิกที่เวิร์กโฟลว์และแก้ไขได้หากต้องการ ระหว่างการแก้ไข คุณจะเห็นภาพแทนเวิร์กโฟลว์ที่ดี:

55441b158f6027f3.png

นอกจากนี้คุณยังเรียกใช้เวิร์กโฟลว์จาก Cloud Console ด้วยตนเองโดยใช้พารามิเตอร์ที่ถูกต้องได้ด้วย แต่เราจะเรียกใช้เครื่องมือดังกล่าวโดยอัตโนมัติเพื่อตอบกลับเหตุการณ์ของ Cloud Storage ในขั้นตอนถัดไป

13. ทริกเกอร์เวิร์กโฟลว์ (Cloud Functions)

ทำให้เวิร์กโฟลว์ใช้งานได้และพร้อมทำงานแล้ว ตอนนี้เราจำเป็นต้องทริกเกอร์เวิร์กโฟลว์เมื่อมีการสร้างไฟล์หรือลบไฟล์ในที่เก็บข้อมูล Cloud Storage เหตุการณ์เหล่านี้คือ storage.object.finalize และ storage.object.delete ตามลำดับ

เวิร์กโฟลว์มี API และไลบรารีของไคลเอ็นต์สำหรับการสร้าง จัดการ และเรียกใช้เวิร์กโฟลว์ที่คุณใช้งานได้ ในกรณีนี้ คุณจะใช้ Workflows Execution API โดยเฉพาะอย่างยิ่งไลบรารีของไคลเอ็นต์ Node.js เพื่อทริกเกอร์เวิร์กโฟลว์

คุณจะทริกเกอร์เวิร์กโฟลว์จาก Cloud Function เพื่อฟังเหตุการณ์ของ Cloud Storage เนื่องจาก Cloud Function จะฟังเหตุการณ์ได้เพียงประเภทเดียว ดังนั้นคุณจะทำให้ Cloud Functions ใช้งานได้ 2 รายการเพื่อฟังทั้งเหตุการณ์สร้างและลบกิจกรรม

c4d79646de729e4.png

สำรวจโค้ด

โดย Cloud Function จะเรียกว่า trigger-workflow คุณสามารถตรวจสอบโค้ดแบบเต็มใน index.js

ทำให้ใช้งานได้กับ Cloud Functions

ไปที่โฟลเดอร์โดยใช้วิธีต่อไปนี้

cd workflows/functions/trigger-workflow/nodejs

ตั้งค่าตัวแปรและการกำหนดค่าที่จำเป็น

export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
export WORKFLOW_NAME=picadaily-workflows
export WORKFLOW_REGION=europe-west4
export COLLAGE_URL=$(gcloud run services describe collage-service --format 'value(status.url)')
export THUMBNAILS_URL=$(gcloud run services describe thumbnails-service --format 'value(status.url)')
export VISION_DATA_TRANSFORM_URL=$(gcloud functions describe vision-data-transform --format 'value(httpsTrigger.url)')
gcloud config set functions/region ${REGION}

ทำให้ฟังก์ชันที่ตอบสนองใช้งานได้เพื่อสรุปเหตุการณ์

export SERVICE_NAME=trigger-workflow-on-finalize
gcloud functions deploy ${SERVICE_NAME} \
  --source=. \
  --runtime nodejs10 \
  --entry-point=trigger_workflow \
  --trigger-resource=${BUCKET_PICTURES} \
  --trigger-event=google.storage.object.finalize \
  --allow-unauthenticated \
  --set-env-vars GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT},WORKFLOW_REGION=${WORKFLOW_REGION},WORKFLOW_NAME=${WORKFLOW_NAME},THUMBNAILS_URL=${THUMBNAILS_URL},COLLAGE_URL=${COLLAGE_URL},VISION_DATA_TRANSFORM_URL=${VISION_DATA_TRANSFORM_URL}

ใช้ฟังก์ชันที่ 2 เพื่อตอบกลับการลบเหตุการณ์ ดังนี้

export SERVICE_NAME=trigger-workflow-on-delete
gcloud functions deploy ${SERVICE_NAME} \
  --source=. \
  --runtime nodejs10 \
  --entry-point=trigger_workflow \
  --trigger-resource=${BUCKET_PICTURES} \
  --trigger-event=google.storage.object.delete \
  --allow-unauthenticated \
  --set-env-vars GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT},WORKFLOW_REGION=${WORKFLOW_REGION},WORKFLOW_NAME=${WORKFLOW_NAME},THUMBNAILS_URL=${THUMBNAILS_URL},COLLAGE_URL=${COLLAGE_URL},VISION_DATA_TRANSFORM_URL=${VISION_DATA_TRANSFORM_URL}

เมื่อการทำให้ใช้งานได้เสร็จสมบูรณ์ คุณจะเห็นทั้ง 2 ฟังก์ชันใน Cloud Console ดังนี้

7d60c8b7851f39f5.png

14. ฟรอนท์เอนด์ (App Engine)

ในขั้นตอนนี้ คุณจะสร้างฟรอนท์เอนด์ของเว็บบน Google App Engine จาก Pic-a-daily: Lab 4 - สร้างฟรอนท์เอนด์ของเว็บ ซึ่งจะอนุญาตให้ผู้ใช้อัปโหลดรูปภาพจากเว็บแอปพลิเคชัน ตลอดจนเรียกดูรูปภาพที่อัปโหลดและภาพขนาดย่อได้

223fb2281614d053.png

คุณสามารถดูข้อมูลเพิ่มเติมเกี่ยวกับ App Engine และอ่านคำอธิบายโค้ดได้ใน Pic-a-daily: Lab 4 - สร้างฟรอนท์เอนด์ของเว็บ

สำรวจโค้ด

แอป App Engine มีชื่อว่า frontend คุณสามารถตรวจสอบโค้ดแบบเต็มใน index.js

ทำให้ใช้งานได้กับ App Engine

ไปที่โฟลเดอร์โดยใช้วิธีต่อไปนี้

cd frontend

ตั้งค่าภูมิภาคที่ต้องการและแทนที่ GOOGLE_CLOUD_PROJECT ใน app.yaml ด้วยรหัสโปรเจ็กต์จริงดังนี้

export REGION=europe-west1
gcloud config set compute/region ${REGION}
sed -i -e "s/GOOGLE_CLOUD_PROJECT/${GOOGLE_CLOUD_PROJECT}/" app.yaml

ทำให้ใช้งานได้:

gcloud app deploy app.yaml -q

หลังจากผ่านไป 1-2 นาที ระบบจะแจ้งให้ทราบว่าแอปพลิเคชันกำลังให้บริการรับส่งข้อมูล ดังนี้

Beginning deployment of service [default]...
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 8 files to Google Cloud Storage                ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...done.
Setting traffic split for service [default]...done.
Deployed service [default] to [https://GOOGLE_CLOUD_PROJECT.appspot.com]
You can stream logs from the command line by running:
  $ gcloud app logs tail -s default
To view your application in the web browser run:
  $ gcloud app browse

นอกจากนี้ คุณยังไปที่ส่วน App Engine ของ Cloud Console เพื่อดูว่าแอปใช้งานได้หรือไม่ และสำรวจฟีเจอร์ของ App Engine เช่น การกำหนดเวอร์ชันและการแยกการรับส่งข้อมูล ดังนี้

f4bd5f4de028bd83.png

15. ทดสอบเวิร์กโฟลว์

หากต้องการทดสอบ ให้ไปที่ URL เริ่มต้นของ App Engine สำหรับแอป (https://<YOUR_PROJECT_ID>.appspot.com/) และคุณควรจะเห็น UI ฟรอนท์เอนด์พร้อมทำงาน

1649ac060441099.png

อัปโหลดรูปภาพ การดำเนินการนี้จะทริกเกอร์เวิร์กโฟลว์และคุณจะเห็นการดำเนินการเวิร์กโฟลว์ในสถานะ Active ใน Cloud Console:

b5a2a3d7a2bc094.png

เมื่อเวิร์กโฟลว์เสร็จเรียบร้อยแล้ว คุณสามารถคลิกรหัสการดำเนินการและดูผลลัพธ์จากบริการต่างๆ ดังนี้

8959df5098c21548.png

อัปโหลดรูปภาพอีก 3 รูป นอกจากนี้ คุณควรจะเห็นภาพขนาดย่อและภาพต่อกันของรูปภาพในที่เก็บข้อมูล Cloud Storage และฟรอนท์เอนด์ของ App Engine ด้วย

d90c786ff664a5dc.png

16. ล้างข้อมูล (ไม่บังคับ)

หากไม่ต้องการใช้แอปนี้ต่อ คุณสามารถล้างทรัพยากรเพื่อประหยัดค่าใช้จ่ายและเป็นพลเมืองระบบคลาวด์ที่ดีโดยรวมโดยการลบโปรเจ็กต์ทั้งหมด โดยทำดังนี้

gcloud projects delete ${GOOGLE_CLOUD_PROJECT} 

17. ยินดีด้วย

คุณสร้างแอปเวอร์ชันที่มีการจัดการโดยใช้เวิร์กโฟลว์เพื่อจัดการเป็นกลุ่มและโทรหาบริการ

หัวข้อที่ครอบคลุม

  • App Engine
  • Cloud Firestore
  • Cloud Functions
  • Cloud Run
  • เวิร์กโฟลว์