1. บทนำ
ยินดีต้อนรับสู่เวิร์กช็อป Rails 8 บน Google Cloud ใน Codelab แบบลงมือปฏิบัติจริงนี้ คุณจะได้แอปพลิเคชัน Rails 8 ที่ทันสมัยจากพื้นฐาน SQLite ในเครื่องแบบง่ายๆ ไปจนถึงสถาปัตยกรรมอ้างอิงระดับการใช้งานจริงที่พร้อมใช้งานในองค์กรบน Google Cloud
ในเวิร์กช็อปนี้ เราไม่ได้แค่ติดตั้งใช้งานแอป แต่เราจะดำเนินการการปรับระบบคลาวด์ให้ทันสมัยระดับโปรดักชันตามความคิดเห็น (การย้ายข้อมูลแบบปิดใช้แล้วย้ายข้อมูลที่ทำอย่างถูกต้อง)
คุณเริ่มต้นจากการตั้งค่าในเครื่องตามปกติที่"ทำงานในเครื่องของฉัน" (ดิสก์ชั่วคราว, SQLite แบบฝัง, งานในกระบวนการ) และค่อยๆ พัฒนาไปเป็นสถาปัตยกรรมระบบคลาวด์ระดับองค์กรที่เชื่อถือได้ใน Google Cloud
- 🐘 จาก SQLite ในเครื่อง → Cloud SQL (PostgreSQL): ไม่ต้องล้างข้อมูลในฐานข้อมูลเมื่อรีสตาร์ทอีกต่อไป เราย้ายไปใช้ PostgreSQL ที่มีการจัดการซึ่งเชื่อมต่ออย่างปลอดภัยผ่านพร็อกซีการตรวจสอบสิทธิ์ Cloud SQL (mTLS, ไม่มี IP สาธารณะ)
- 🪣 จากที่เก็บข้อมูลในเครื่องชั่วคราว → GCS แบบส่วนตัว: ดิสก์แบบ Serverless เป็นแบบชั่วคราว เราเชื่อมต่อ ActiveStorage กับ Google Cloud Storage แบบส่วนตัวโดยใช้ URL ที่ลงนามของ IAM (
iam: true) ซึ่งไม่มี Bucket สาธารณะและไม่มีการรั่วไหลของคีย์ - 🚀 จากงานในกระบวนการ → Cloud Run แบบหลายคอนเทนเนอร์: เราเชื่อมต่อ Monolith ของ Rails กับระบบคลาวด์แบบไร้เซิร์ฟเวอร์ เราใช้ Docker Compose มาตรฐานเพื่อเรียกใช้ Solid Queue เป็นคอนเทนเนอร์เวิร์กเกอร์เฉพาะควบคู่ไปกับ Puma ใน พ็อดแบบหลายคอนเทนเนอร์ของ Cloud Run ซึ่งไม่มีการขยายขนาดของ Microservice และไม่มีการขาดแคลนเทรด DHH คงจะภูมิใจ
🍌 และเนื่องจากเราอยู่ในปี 2026 เราจึงเสริมประสิทธิภาพทั้ง Stack ด้วย Google Antigravity เราไม่ได้เพิ่งมาคิดเรื่องนี้ แต่เรามีพรอมต์และ ทักษะที่จะช่วยให้คุณใช้ประโยชน์จากเวิร์กช็อปนี้ได้ดียิ่งขึ้น (และสนุกไปกับเวิร์กช็อป)
🏛️ สถาปัตยกรรมอ้างอิงเป้าหมาย (รูปแบบที่ 1: องค์กรเวกเตอร์แบบเรียบที่สะอาด)
นี่คือสถาปัตยกรรมอ้างอิงของ Google Cloud ที่คุณจะสร้างและติดตั้งใช้งาน (ตัวแปรที่ 1: เวกเตอร์แบบแบนที่สะอาดสำหรับองค์กร) ซึ่งแสดงบริการ Cloud Run แบบหลายคอนเทนเนอร์ที่ใช้งานจริงของเราซึ่งเชื่อมต่อกับบริการความคงทนและ AI ที่มีการจัดการทั้งหมดของ Google Cloud

🎞️ การพัฒนาสถาปัตยกรรม: จากศูนย์สู่การดำเนินการบนระบบคลาวด์
ดูการปรับปรุงสแต็กของเราอย่างต่อเนื่องจากพื้นฐานของเครื่องเดียวแบบชั่วคราวไปจนถึงพิมพ์เขียวของ Google Cloud ที่มีการจัดการเต็มรูปแบบในแต่ละเหตุการณ์สำคัญของเวิร์กช็อป

สิ่งที่คุณจะได้เรียนรู้
- วิธีจับคู่โปรแกรมกับ Google Antigravity เพื่อไขข้อสงสัยเกี่ยวกับ Rails 8 และ Google Cloud
- วิธีเรียกใช้การวินิจฉัยก่อนการบินอัตโนมัติ (
just workshop-test) - วิธีจัดสรรโครงสร้างพื้นฐานของระบบคลาวด์ของ Google Cloud แบบอะซิงโครนัสโดยใช้ Terraform ในขณะที่พัฒนาในเครื่องต่อไปโดยไม่บล็อกโดยใช้ผู้ให้บริการ
google - วิธีขจัดรูปแบบการรักษาความปลอดภัยที่ไม่ดี: ที่เก็บข้อมูล GCS แบบส่วนตัว (
iam: true) และอุโมงค์ mTLS ของพร็อกซีการตรวจสอบสิทธิ์ Cloud SQL แทนการเปิด0.0.0.0/0 - วิธีแทรกข้อมูลลับจาก Google Cloud Secret Manager โดยตรง
- วิธีจัดระเบียบงานพื้นหลัง GenAI แบบอะซิงโครนัส (เครื่องมือสร้างปก NanoBanana, การสังเคราะห์พอดแคสต์ 2 ภาษา) ผ่าน Solid Queue
มาเริ่มกันเลย
2. ขั้นตอนที่ 0: ข้อกำหนดเบื้องต้น การตั้งค่า Antigravity และการยืนยันการเรียกเก็บเงิน
💡 สถานการณ์: คุณและทีมกำลังสร้างแอปพลิเคชัน Rails 8 ที่มีความสำคัญต่อภารกิจ ก่อนที่จะแตะต้องโค้ดหรือเปิดใช้ทรัพยากรระบบคลาวด์ เราต้องสร้าง Toolchain เชื่อมต่อ Google Antigravity และยืนยันข้อมูลเข้าสู่ระบบ Google Cloud รวมถึงรากฐานการเรียกเก็บเงิน
1. รายการตรวจสอบข้อกำหนดเบื้องต้น
ก่อนเริ่มต้น โปรดตรวจสอบว่าคุณมีเครื่องมือต่อไปนี้ในสภาพแวดล้อมของคุณ
just(1.21 ขึ้นไป): (just --version) ตัวเรียกใช้งาน — ทุกคำสั่งในเวิร์กช็อปนี้คือjustสูตร (ขอให้ AI Harness ติดตั้งให้ หรือดูskills/rails8app-workshop)- Git (2.30 ขึ้นไป): (
git --version) สำหรับการควบคุมเวอร์ชัน การแยกสาขา และการโคลนที่เก็บ - Google Cloud SDK (
gcloudCLI): ติดตั้งและเป็นเวอร์ชันล่าสุด - CLI ของ Terraform (1.5 ขึ้นไป): สำหรับการจัดสรรโครงสร้างพื้นฐานแบบประกาศ
dockerและdocker-compose: ติดตั้งและเรียกใช้ในเครื่อง- Ruby
3.4.5: (ruby -v— ปักหมุดโดยblog/.ruby-version; ขอให้ AI Harness ติดตั้ง3.4.5หากไม่มี) ประกาศ Rails 8 ในGemfileและbundle installจะติดตั้งโดยอัตโนมัติ - Google Antigravity 2.0: ผู้ช่วยการเขียนโปรแกรมคู่ AI แบบอัตโนมัติ (ดาวน์โหลด Google Antigravity 2.0) คุณจะเข้าสู่ระบบด้วย Gmail ส่วนตัวโดยไม่ต้องใช้โทเค็น API
2. การตรวจสอบสิทธิ์ Google Cloud, การกำหนดค่าเฉพาะ และ ADC
เราขอแนะนำอย่างยิ่งให้สร้างการกำหนดค่าที่มีชื่อเฉพาะสำหรับเวิร์กช็อปนี้เพื่อป้องกันการทับซ้อนกับการตั้งค่า gcloud ขององค์กร ส่วนบุคคล หรือแบบหลายบัญชีที่มีอยู่
# 1. Create and activate dedicated workshop configuration (Fixes Issue #38)
gcloud config configurations create rails8-on-gcp-workshop --activate 2>/dev/null || \
gcloud config configurations activate rails8-on-gcp-workshop
# 2. Authenticate your account and Application Default Credentials (ADC)
gcloud auth login $GOOGLE_CLOUD_ACCOUNT
gcloud auth application-default login
# 3. Configure active project and region
gcloud config set project $GOOGLE_CLOUD_PROJECT
gcloud config set compute/region europe-west1
💡 เหตุใดจึงต้องมีการกำหนดค่าเฉพาะ การใช้ gcloud config configurations create rails8-on-gcp-workshop จะแยกการตั้งค่า CLI ทั้งหมด (บัญชี โปรเจ็กต์โควต้า ภูมิภาคเริ่มต้น) สำหรับเวิร์กช็อปนี้โดยเฉพาะ เมื่อเสร็จแล้ว คุณจะเปลี่ยนกลับไปใช้การตั้งค่าปกติได้ทุกเมื่อด้วย gcloud config configurations activate default

3. 🚨 การยืนยันการเรียกเก็บเงินของ GCP
⚠️ หมายเหตุ: การติดตั้งใช้งาน Google Cloud SQL และ Cloud Run ต้องใช้บัญชีสำหรับการเรียกเก็บเงินที่ลิงก์อยู่ซึ่งใช้งานได้ หรือเครดิตการศึกษาสำหรับเวิร์กช็อปที่ถูกต้อง มาตรวจสอบว่าการตั้งค่าถูกต้องกันเลย โดยให้เรียกใช้การตรวจสอบการยืนยันการเรียกเก็บเงิน
gcloud beta billing projects describe $GOOGLE_CLOUD_PROJECT
ตรวจสอบว่ามีการส่งคืน billingEnabled: true คุณยังแสดงบัญชีสำหรับการเรียกเก็บเงินทั้งหมดได้ด้วย โดยทำดังนี้
gcloud billing accounts list
โปรดตรวจสอบว่ามีอุปกรณ์ที่แสดง OPEN: True อย่างน้อย 1 เครื่อง หากไม่มีบัญชีใดที่ใช้งานอยู่ ให้ลิงก์บัญชีสำหรับการเรียกเก็บเงินหรือแลกสิทธิ์คูปองเครดิตเวิร์กช็อปในหน้าการเรียกเก็บเงินของคอนโซล Google Cloud

4. โคลนที่เก็บและจับคู่กับ Antigravity
โคลนที่เก็บและเข้าสู่ไดเรกทอรี โปรดทราบว่าเราจะใช้เฉพาะ main เท่านั้น
git clone https://github.com/palladius/rails8-app-on-gcp.git
cd rails8-app-on-gcp
เปิดไดเรกทอรีนี้ใน Google Antigravity Antigravity จะตรวจสอบที่เก็บข้อมูล อ่าน AGENTS.md และพร้อมเป็นโปรแกรมเมอร์คู่ของคุณโดยอัตโนมัติ
5. 🪫 หาก Antigravity ใช้เครดิตฟรีหมด
⚠️ เครดิต Cloud ที่คุณเพิ่งแลกรับสิทธิ์จะไม่ได้เติมเงินใน Antigravity โดยมีแพลตฟอร์มการเรียกเก็บเงิน 2 แพลตฟอร์มแยกกัน โควต้าของ Antigravity จะอยู่ในแพ็กเกจ Google AI (Google One) ส่วนบัตรกำนัลและเครดิต Cloud จะอยู่ในบัญชีสำหรับการเรียกเก็บเงินใน Cloud การลิงก์บัญชีสำหรับการเรียกเก็บเงินกับโปรเจ็กต์ GCP จะไม่ทำให้คุณได้รับพรอมต์ Antigravity เพิ่มอีก 1 รายการ
หาก Agent หยุดทำงานพร้อมข้อความโควต้า ให้ทำตามลำดับขั้นต่อไปนี้ โดย 2 ขั้นตอนแรกจะไม่มีค่าใช้จ่ายและดำเนินการได้ทันที
- เปลี่ยนกลุ่มโมเดล ระบบจะติดตามโควต้าต่อตระกูลโมเดล และ Antigravity จะแสดงพูล 2 รายการที่แยกกัน (โมเดล Gemini กับโมเดล Claude/GPT) โมเดล Claude และ GPT-OSS พร้อมให้บริการในรุ่นฟรี ดังนั้นพูล Gemini ที่หมดแล้วจึงมักจะไม่ได้ส่งผลกระทบต่อพูลอื่นๆ ใช้ตัวเลือกโมเดลใต้ช่องพรอมต์

- เลือกโมเดล Flash แทน Pro ขีดจำกัดของอัตราจะสัมพันธ์กับปริมาณงานที่ Agent ทำต่อคำขอ ดังนั้นโมเดลที่มีขนาดเล็กกว่าจะช่วยให้ใช้งานได้นานขึ้น
- ใช้ Antigravity CLI กับคีย์ Gemini API ของคุณเอง Antigravity IDE ไม่รองรับการใช้คีย์ของคุณเอง แต่มี CLI เป็นทางเลือกที่ระบุไว้ในเอกสาร สร้างคีย์ฟรีใน Google AI Studio (ต้องมีโปรเจ็กต์แต่ไม่มีบัญชีสำหรับการเรียกเก็บเงิน) จากนั้นดาวน์โหลดและกำหนดค่า Antigravity CLI
- รอหรืออัปเกรด โควต้าของระดับฟรีจะรีเฟรชทุกสัปดาห์ (ข้อความแสดงข้อผิดพลาดจะระบุวันที่รีเซ็ต) Google AI Pro/Ultra เป็นวิธีเดียวที่บันทึกไว้ในการเพิ่มพื้นฐานภายในแอปบนเดสก์ท็อป โดยแพ็กเกจเหล่านั้นจะรีเฟรชทุกๆ 5 ชั่วโมง และใช้เครดิต AI ที่ซื้อไปกับค่าบริการเกินโควต้าได้
- แม้ว่านี่จะเป็นเวิร์กช็อป Antigravity แต่สายรัดการเขียนโค้ด AI ส่วนใหญ่ก็ควรใช้งานได้เช่นกัน เพียงแค่ชี้ไปที่ไดเรกทอรี
AGENTS.mdและskills/ในที่เก็บ
6. การตรวจสอบขั้นตอนที่ 0 โดยอัตโนมัติ
ตรวจสอบว่าสภาพแวดล้อมในขั้นตอนที่ 0 เป็นไปตามชุดการประเมิน 100% ดังนี้
just workshop-eval 0
✨ ช่วงเวลาที่น่าประทับใจ: เครื่องมือประเมินเวิร์กช็อปและ Antigravity จะยืนยันเวอร์ชัน CLI, สภาพแวดล้อม Ruby และการตรวจสอบสิทธิ์ ADC ในเวลาไม่ถึง 2 วินาที
3. ขั้นตอนที่ 1: การเริ่มต้นใช้งานโครงสร้างพื้นฐานของ Terraform และการวินิจฉัยก่อนการใช้งาน
💡 กลยุทธ์: ฐานข้อมูลที่มีการจัดการ เช่น Google Cloud SQL PostgreSQL ใช้เวลาประมาณ 10-12 นาทีในการจัดสรร เราจึงเปิดตัวโครงสร้างพื้นฐานที่ไม่เปลี่ยนแปลงผ่าน Terraform ในเบื้องหลังตอนนี้ขณะที่เราพัฒนาในเครื่องแทนที่จะรอเฉยๆ ในภายหลัง
1. เรียกใช้ชุดการวินิจฉัยก่อนการนำส่งอัตโนมัติ
ก่อนเปิดตัวโครงสร้างพื้นฐานของระบบคลาวด์ ให้เรียกใช้ชุดโปรแกรมทดสอบก่อนเผยแพร่ที่ครอบคลุม
just workshop-test
สคริปต์นี้ (bin/workshop_diagnostics.rb)
- ยืนยัน
GOOGLE_CLOUD_ACCOUNTการกำหนดค่าข้อมูลประจำตัว - ยืนยันการเรียกเก็บเงินที่ใช้งานอยู่และการลิงก์โปรเจ็กต์
- ตรวจสอบข้อมูลรับรองเริ่มต้นของแอปพลิเคชัน (ADC) สำหรับ Vertex AI
- ยืนยันอิมเมจ Canary Seed ของ ActiveStorage (
blog/app/assets/images/gcs_dev_image.jpg)

หากไม่มี .env ให้คัดลอกจากเทมเพลตที่บันทึกไว้
cp .env.dist .env
# Edit .env and configure GOOGLE_CLOUD_ACCOUNT with your Google/Gmail account
💡 เคล็ดลับ: หาก just workshop-test รายงานว่ามีการปิดใช้ Billing API ในโปรเจ็กต์ของคุณ ให้เปิดใช้ API อย่างรวดเร็วโดยทำดังนี้
gcloud services enable cloudbilling.googleapis.com
2. ⏱️ เปิดใช้โครงสร้างพื้นฐานของ Terraform แบบไม่พร้อมกัน
เรียกใช้สูตร Terraform แบบขั้นตอนเดียว ซึ่งจะสร้างที่เก็บข้อมูลสถานะแบ็กเอนด์ระยะไกลและทริกเกอร์การติดตั้งใช้งานโครงสร้างพื้นฐาน
just terraform-apply

ทางเลือกด้วยตนเอง (หรือเรียกใช้ `iac/bin/terraform-apply.sh` โดยตรง)
# Fall back to active gcloud config if environment variables are unset
GOOGLE_CLOUD_PROJECT="${GOOGLE_CLOUD_PROJECT:-$(gcloud config get-value project)}"
GOOGLE_CLOUD_REGION="${GOOGLE_CLOUD_REGION:-europe-west1}"
# Create remote state bucket idempotently
gcloud storage buckets create "gs://${GOOGLE_CLOUD_PROJECT}-tfstate" --location="$GOOGLE_CLOUD_REGION" 2>/dev/null || \
gcloud storage buckets describe "gs://${GOOGLE_CLOUD_PROJECT}-tfstate" >/dev/null
cd iac
terraform init -backend-config="bucket=${GOOGLE_CLOUD_PROJECT}-tfstate"
terraform apply -auto-approve -var="project_id=${GOOGLE_CLOUD_PROJECT}" -var="region=${GOOGLE_CLOUD_REGION}"
cd ..
สิ่งที่ Terraform จัดสรร
- Bucket ของ Google Cloud Storage: สร้างขึ้นโดยมีการเข้าถึงแบบส่วนตัวและการลงนามในข้อมูลเข้าสู่ระบบ IAM (
iam: true) - รูปภาพทดสอบ Canary: อัปโหลด
gcs_dev_image.jpgไปยังที่เก็บข้อมูลเพื่อเปิดใช้การยืนยัน Blob จากต้นทางถึงปลายทาง - อินสแตนซ์ PostgreSQL ของ Google Cloud SQL: เริ่มการจัดสรรในเบื้องหลัง (~10-12 นาที)

💡 หมายเหตุ: คุณสามารถเพิกเฉยต่อคำเตือนเกี่ยวกับการสำรองข้อมูลอัตโนมัติที่ขาดหายไปได้อย่างปลอดภัย เนื่องจากเราไม่จำเป็นต้องใช้การสำรองข้อมูลดังกล่าวสำหรับฐานข้อมูลของเวิร์กช็อปนี้ (แม้ว่าการสำรองข้อมูลอัตโนมัติทุกวันจะเป็นแนวทางปฏิบัติแนะนำที่สำคัญสำหรับฐานข้อมูลการผลิตจริงก็ตาม)

📝 จด URL ของ Cloud Run: การใช้ Terraform ควรสำเร็จและพิมพ์เอาต์พุตของโครงสร้างพื้นฐาน จดcloud_run_url (หรือคัดลอกไปยังคลิปบอร์ด) ไว้ เนื่องจากคุณจะต้องใช้ในขั้นตอนต่อๆ ไปเมื่อยืนยันบริการที่ใช้งานจริง
3. การตรวจสอบขั้นตอนที่ 1 โดยอัตโนมัติ (ไม่บังคับ)
ตรวจสอบว่าข้อกำหนดเบื้องต้นและการกำหนดค่าในขั้นตอนที่ 1 ผ่าน
just workshop-eval 1
⏱️ หมายเหตุ: การประเมินนี้จะตรวจสอบทรัพยากรระบบคลาวด์ที่ใช้งานจริงและอาจใช้เวลา 2-3 นาทีจึงจะเสร็จสิ้น ซึ่งเป็นขั้นตอนที่ไม่บังคับโดยสิ้นเชิง ในขณะที่คำสั่งทำงานในเทอร์มินัล คุณสามารถไปยังขั้นตอนถัดไปได้ทันทีโดยไม่ต้องรอ
4. ขั้นตอนที่ 2: การเริ่มต้นใช้งานในเครื่อง, Mailpit และการเริ่มต้นใช้งานของผู้ดูแลระบบ
จุดเริ่มต้นของเราคือแอปพลิเคชันบล็อก Rails 8 ที่สะอาดและทันสมัยซึ่งทำงานบน localhost ด้วย SQLite, การสกัดกั้นอีเมล Mailpit และ ActiveStorage ที่อิงตามดิสก์
1. บูตแอปในเครื่อง
📁 โปรดทราบเกี่ยวกับไดเรกทอรี ที่เก็บนี้มีแอป Rails ใน blog/ และ Terraform ใน iac/ ขั้นตอนที่ 1 ทำให้คุณอยู่ในรูทของที่เก็บ ดังนั้นทุกคำสั่งในขั้นตอนที่ 2 จะทำงานจาก
blog/ — Gemfile, bin/rails และ compose.yaml อาศัยอยู่ที่นั่น การเรียกใช้จากรูทจะล้มเหลวโดยมี no configuration file provided: not found หรือไม่มี Gemfile
ย้ายไปที่แอป Rails แล้วยืนยันว่าคุณใช้ Ruby ที่ปักหมุดไว้ จากนั้นติดตั้ง Gem และตั้งค่าฐานข้อมูลโดยทำดังนี้
cd blog
ruby -v # must print 3.4.5 — see Step 0 if it does not
bundle install
bin/rails db:setup
🧯 ข้อผิดพลาดเกี่ยวกับสิทธิ์ในการเขียนไปยัง
/var/lib/gems/
หรือ
ruby -v
แสดง Ruby ของระบบ (เช่น 3.3.x) หรือไม่ Ruby ในระบบ Linux แบบ Vanilla จะไม่สนใจไฟล์ .ruby-version และพยายามติดตั้ง Gem ทั่วทั้งระบบ ตรวจสอบว่าได้โหลด rbenv ในเชลล์เทอร์มินัลที่ใช้งานอยู่แล้ว
eval "$(rbenv init - bash)" # or: eval "$(rbenv init - zsh)"
ruby -v # confirm it now outputs 3.4.5!
หมายเหตุ: หากคุณข้ามการติดตั้ง 3.4.5 ในขั้นตอนที่ 0 ให้เรียกใช้ rbenv install 3.4.5 หรือเพียงใช้โหมด A (Docker Compose) ด้านล่าง (just compose-up) ซึ่งจะเรียกใช้สแต็ก Ruby ที่ปักหมุดไว้ภายในคอนเทนเนอร์โดยไม่ต้องแตะต้อง Gem ของโฮสต์
💡 ไม่ต้องการคิดถึงเรื่องนี้ใช่ไหม just install และ just compose-up จากรูทของที่เก็บจะทำ cd blog ให้คุณ
2. 🌱 การค้นหาอัตโนมัติของ Smart Seed และการเริ่มต้นระบบของผู้ดูแลระบบ (ปัญหา #21 และ #25)
ฐานข้อมูลเริ่มต้น (db/seeds.rb) มีการค้นหาสภาพแวดล้อมอัจฉริยะโดยอัตโนมัติ ดังนี้
- โดยจะตรวจสอบอแดปเตอร์ฐานข้อมูลที่ใช้งานอยู่ (SQLite กับ Postgres) และการกำหนดค่าพื้นที่เก็บข้อมูล
- โดยจะตรวจหาระยะที่ 0 (Localhost) และสร้างผู้ใช้ดูแลระบบเริ่มต้นโดยอัตโนมัติ รวมถึงโพสต์ด้านการสอนเริ่มต้น
[LOCAL BASELINE] Welcome to Rails 8 on Localhost!- ไฟล์แนบรูปภาพเศร้าในเครื่อง (
local_sad_image.png) ที่พร้อมใช้งานทันทีพร้อมลายน้ำที่แจ้งให้ทราบว่าพื้นที่เก็บข้อมูลในเครื่องเป็นแบบชั่วคราว
- ระบบจะทริกเกอร์อีเมลรีเซ็ตรหัสผ่านผ่าน ActionMailer โดยอัตโนมัติ
ยืนยันหรือเรียกใช้ Seed อีกครั้ง (ใช้ GOOGLE_CLOUD_ACCOUNT จาก .env โดยอัตโนมัติ):
bin/rails db:seed # or from repo root: just seed
บูตสแต็กการพัฒนาในเครื่องผ่าน Docker Compose โดยทำดังนี้
docker compose up -d # from blog/ — or `just compose-up` from the repo root

ตอนนี้แอปพลิเคชัน เซิร์ฟเวอร์ SMTP ของ Mailpit ในเครื่อง และโปรแกรมดูฐานข้อมูล Adminer ทำงานร่วมกันในคอนเทนเนอร์ที่แยกกันแล้ว
- แอป Rails: http://localhost:3000
- UI ของเว็บ Mailpit: http://localhost:8025
- UI ของฐานข้อมูล Adminer: http://localhost:8081
🧯 พอร์ต 3000 ขัดแย้งกันหรือ
server.pid
ข้อผิดพลาด หากก่อนหน้านี้คุณเริ่มเซิร์ฟเวอร์การพัฒนาแบบเนทีฟ (bin/dev) ให้หยุดด้วย Ctrl+C หาก Docker แจ้งว่าพอร์ต 3000 ถูกจัดสรรไปแล้วหรือพบ server.pid ที่เหลือ ให้ล้างข้อมูลด้วยคำสั่งต่อไปนี้
just compose-down
rm -f blog/tmp/pids/server.pid
just compose-up
3. ประสบการณ์การใช้งาน Mailpit และการเข้าสู่ระบบของผู้ดูแลระบบ
- ดูอีเมลขาออกด้วย Mailpit: เปิด
http://localhost:8025ในเบราว์เซอร์ ดูที่กล่องจดหมายในเครื่อง ในระหว่างdb:seedActionMailer ได้ส่งอีเมลเริ่มต้นใช้งานของผู้ดูแลระบบ ซึ่ง Mailpit จับภาพไว้ในเครื่องอย่างปลอดภัยโดยไม่ต้องแตะต้องเซิร์ฟเวอร์อีเมลหรือข้อมูลเข้าสู่ระบบภายนอก
2. เข้าสู่ระบบบล็อก: เปิด http://localhost:3000 ในเบราว์เซอร์
- คุณคลิกลิงก์รีเซ็ตรหัสผ่านในอีเมล Mailpit ได้โดยตรงเพื่อตั้งรหัสผ่าน
- หรือจะเข้าสู่ระบบโดยใช้อีเมลของบัญชี Google Cloud (จาก
.env) และรหัสผ่านเริ่มต้นที่กำหนดไว้ล่วงหน้าCh4ng3m3!!1ก็ได้
- สังเกตป้ายการวัดและส่งข้อมูลแบบภาพ:
- สังเกตแบนเนอร์และป้ายสภาพแวดล้อมสีเหลืองใน UI:
Notice: Ephemeral Database Active (POSTGRESQL)และ[EPHEMERAL DB / STORAGE] 💾 Local - สังเกตลายน้ำของโพสต์: ตราประทับ 🏠 (
nanobanana_stamp_local.pngที่มุมขวาล่างของภาพหน้าปก) ซึ่งจะช่วยให้คุณเห็นภาพยืนยันได้ทันทีว่าปัจจุบันชิ้นงานและฐานข้อมูลเชื่อมโยงกับพื้นที่เก็บข้อมูลในเครื่องแบบชั่วคราว
- สังเกตแบนเนอร์และป้ายสภาพแวดล้อมสีเหลืองใน UI:

💡 เคล็ดลับสำหรับมือโปร (ไม่บังคับ): การออกกำลังกายใน Rails Console คุณสงสัยไหมว่า Rails ทำงานร่วมกับข้อมูลที่สร้างขึ้นจาก CLI อย่างไร เข้าสู่คอนโซลแบบอินเทอร์แอกทีฟ
bin/rails console
ตรวจสอบผู้ใช้ผู้ดูแลระบบที่เริ่มต้นแบบไดนามิกโดยใช้ตัวแปรสภาพแวดล้อม
user = User.find_by(email_address: ENV.fetch("GOOGLE_CLOUD_ACCOUNT"))
# Or simply grab the first user:
user = User.first
puts "Admin email: #{user.email_address} (created via: #{user.created_via})"
exit
4. การตรวจสอบขั้นตอนที่ 2 โดยอัตโนมัติ
ยืนยันการตั้งค่าพื้นฐานในพื้นที่และการตั้งค่าผู้ดูแลระบบ
just workshop-eval 2

5. ข้อควรทราบ: คอนเทนเนอร์แบบไม่เก็บสถานะ
คอนเทนเนอร์ Cloud Run เป็นแบบไม่เก็บสถานะและมีอายุสั้น หากเราติดตั้งใช้งานฐานข้อมูล SQLite และไดเรกทอรี storage/ ในเครื่องโดยตรงกับ Cloud Run ระบบจะลบโพสต์และรูปภาพที่อัปโหลดทั้งหมดอย่างถาวรทุกครั้งที่คอนเทนเนอร์ปรับขนาดเป็น 0 หรือรีสตาร์ท
ในขั้นตอนถัดไป เราจะตั้งใจที่จะกำหนดค่าชั่วคราวนี้กับ Cloud Run เพื่อดูการเปลี่ยนแปลงแบบไม่เก็บสถานะด้วยตัวคุณเอง
5. ขั้นตอนที่ 3: การติดตั้งใช้งาน 1 - The Stateless Shock (WOW ในช่วงแรกๆ ใน 3 นาที!)
การพัฒนาแบบ Serverless สมัยใหม่เริ่มต้นด้วยชัยชนะตั้งแต่เนิ่นๆ นั่นคือการติดตั้งใช้งานแอปพลิเคชัน Rails แบบคอนเทนเนอร์เดียวโดยตรงใน Google Cloud Run ภายในเวลาไม่ถึง 3 นาที ซึ่งช่วยให้คุณไม่ต้องรอ 15-20 นาทีสำหรับฐานข้อมูลระบบคลาวด์ก่อนที่จะเห็นสิ่งใดก็ตามบนเว็บ
1. ย้อนความทรงจำด้วยไทม์แมชชีน
หากต้องการรับประกันว่าการกำหนดค่าเริ่มต้นของเราเป็นแบบชั่วคราว 100% (ฐานข้อมูล SQLite ในเครื่องและการจัดเก็บไฟล์ในดิสก์ในเครื่อง) ให้ใช้เครื่องมือไทม์แมชชีนแบบไม่มีสาขา
just workshop-rewind 1
💡 เกิดอะไรขึ้นworkshop-rewind 1 ได้ใช้การซ้อนทับการกำหนดค่า stage-1-stateless กับ blog/config/ โดยไม่ต้องออกจากสาขา main แอปของคุณได้รับการกำหนดค่าด้วย SQLite ในดิสก์คอนเทนเนอร์และ ActiveStorage ในระบบไฟล์ในเครื่อง
2. การติดตั้งใช้งาน Puma แบบคอนเทนเนอร์เดียวใน Cloud Run
ติดตั้งใช้งานจากซอร์สโค้ดไปยัง Cloud Run โดยตรง Rails 8 สมัยใหม่จะสร้าง Dockerfile อย่างเป็นทางการที่พร้อมใช้งานจริงโดยอัตโนมัติ (มาพร้อมการสร้างแบบหลายระดับ, jemalloc และการรักษาความปลอดภัยแบบไม่ใช่รูท) เมื่อคุณติดตั้งใช้งานจากโฟลเดอร์ blog/ Google Cloud Build จะตรวจพบ Dockerfile ดั้งเดิมนี้โดยตรงและจัดสรรบริการแบบ Serverless ที่มีการจัดการ
# Ensure you are inside the Rails application directory
cd blog
# Ensure default region is set
export GOOGLE_CLOUD_REGION="europe-west1"
# Deploy single-container service from source (with dummy key fallback if starting without credentials)
gcloud run deploy blog \
--source . \
--region $GOOGLE_CLOUD_REGION \
--allow-unauthenticated \
--set-env-vars GOOGLE_CLOUD_ACCOUNT=$GOOGLE_CLOUD_ACCOUNT,SECRET_KEY_BASE_DUMMY=1
คุณควรเห็นเอาต์พุตความคืบหน้าในลักษณะนี้

⏳ การดำเนินการนี้จะใช้เวลา 2-3 นาทีในขณะที่ Cloud Build จัดแพ็กเกจคอนเทนเนอร์และจัดสรรการแก้ไข Cloud Run
🧯 การแก้ปัญหาและข้อควรระวังที่พบบ่อย
PERMISSION_DENIED: Build failed because the default service account is missing required IAM permissions
? สาเหตุ 2 ประการที่แตกต่างกันทำให้เกิดข้อผิดพลาดเดียวกัน
- gcloud เพิ่งเปิดใช้ API ให้คุณ หากการติดตั้งใช้งานพิมพ์
The following APIs are not enabled ... cloudbuild.googleapis.comและคุณตอบYบิลด์อาจเริ่มก่อนที่สิทธิ์ใหม่จะเผยแพร่เสร็จสมบูรณ์ ซึ่งพรอมต์ของ gcloud เองจะเตือนว่า "การดำเนินการนี้จะใช้เวลา 2-3 นาที" รอสักครู่แล้วเรียกใช้คำสั่งเดิมอีกครั้ง โดยปกติแล้วจะสำเร็จ โดยปกติแล้วterraform applyในขั้นตอนที่ 1 จะเปิดใช้ API นี้ให้คุณ จึงไม่ควรเห็นข้อความแจ้งเลย - บัญชีบริการ Compute เริ่มต้นไม่มีบทบาทจริงๆ โปรเจ็กต์ GCP สมัยใหม่บังคับใช้สิทธิ์ขั้นต่ำที่สุด ซึ่งจะทำให้การติดตั้งใช้งานแหล่งที่มาหยุดทำงาน แก้ไขได้โดยทำดังนี้
just project-status # grants storage.admin, logging.logWriter, artifactregistry.writer, cloudbuild.builds.builderjust workshop-testยังรายงานปัญหานี้ด้วย ดังนั้นคุณควรเรียกใช้ซ้ำหากการติดตั้งใช้งานยังคงล้มเหลว
ในระหว่างการติดตั้งใช้งาน
- Cloud Run จะสร้างอิมเมจคอนเทนเนอร์ Rails
- โดยจะกำหนดโดเมน TLS ที่ปลอดภัยและเป็นแบบสาธารณะ:
https://blog-[hash]-[region].a.run.app - การรับส่งข้อมูลจะเริ่มกำหนดเส้นทางไปยัง Puma ในพอร์ต 8080
3. ✨ ช่วงเวลาที่น่าประทับใจในช่วงแรก
เปิด URL ของ Cloud Run ที่สร้างขึ้นในเบราว์เซอร์
- แอปพลิเคชัน Rails 8 ที่ทันสมัยของคุณพร้อมใช้งานใน Google Cloud แล้ว
- เข้าสู่ระบบด้วยข้อมูลเข้าสู่ระบบของผู้ดูแลระบบ (
GOOGLE_CLOUD_ACCOUNTและAPP_ADMIN_PASSWORD) หากไม่พบปุ่มเข้าสู่ระบบ ให้คลิก "โพสต์ใหม่" แล้วระบบจะแจ้งให้ป้อนชื่อผู้ใช้และรหัสผ่านก่อน
- คลิก "โพสต์ใหม่" เขียนบทความชื่อ "โพสต์แรกของฉันใน Cloud Run" แนบรูปภาพ แล้วคลิกสร้างโพสต์
- ระบบจะเผยแพร่โพสต์ของคุณโดยมีการจัดรูปแบบทั้งหมด และแสดงรูปภาพ
- โปรดสังเกตการตรวจวัดระยะไกลด้วยภาพต่อไปนี้
- ป้ายส่วนหัว:
[EPHEMERAL DB / STORAGE] 💾 Local - ลายน้ำที่เป็นรูปภาพ: ตราประทับ 🏠 (
127.0.0.1ป้ายดิสก์ชั่วคราวที่มุมขวาล่าง)
- ป้ายส่วนหัว:
🐝 เข้าร่วมลีดเดอร์บอร์ดของเวิร์กช็อปสด Hive หากคุณออนไลน์อยู่และผู้คุมสอบแสดงลีดเดอร์บอร์ด และคุณต้องการเข้าร่วม ให้เพิ่ม URL ของ Cloud Run ที่นี่ 👉 ลงทะเบียน Cloud Run ในลีดเดอร์บอร์ด

4. 💥 ข้อควรระวัง: Stateless Shock และกับดัก "Puma Workaround"
Cloud Run เป็นแพลตฟอร์มแบบไม่เก็บสถานะและแบบ Serverless เมื่อการเข้าชมเว็บลดลงเหลือ 0 Cloud Run จะลดขนาดลงเหลือ 0 อินสแตนซ์คอนเทนเนอร์เพื่อประหยัดค่าใช้จ่าย เมื่อมีคำขอ HTTP ใหม่เข้ามาหรือมีการติดตั้งใช้งานรีวิชันคอนเทนเนอร์ใหม่ Cloud Run จะเริ่มอิมเมจคอนเทนเนอร์ใหม่ที่สะอาด
แบนเนอร์งานที่ค้างอยู่
เมื่อคุณสร้างโพสต์หรือแนบรูปภาพในการติดตั้งใช้งานคอนเทนเนอร์เดียว Rails จะจัดคิวงาน ActiveJob (เช่น การวิเคราะห์ขนาดรูปภาพหรือการจัดทำดัชนีข้อมูลเมตา) แต่เนื่องจากไม่มีใครเรียกใช้ Worker ในเบื้องหลัง คุณจึงจะเห็นแบนเนอร์คำเตือน

การแก้ไขที่น่าสนใจ: การเรียกใช้คิวที่เสถียรภายใน Puma
นักพัฒนาซอฟต์แวร์ที่ฉลาดอาจพูดว่า "เดี๋ยวก่อน Rails 8 ช่วยให้เราเรียกใช้ Solid Queue ภายในกระบวนการเว็บเซิร์ฟเวอร์ Puma ได้โดยตรงด้วยการเปิดใช้
SOLID_QUEUE_IN_PUMA=true
ตัวแปรสภาพแวดล้อม"
มาทดสอบวิธีแก้ปัญหานี้ใน Cloud Run กัน
# Force a revision update to enable Solid Queue inside Puma
gcloud run services update blog \
--region $GOOGLE_CLOUD_REGION \
--update-env-vars SOLID_QUEUE_IN_PUMA=true
ตอนนี้ให้กลับไปที่เบราว์เซอร์แล้วรีเฟรชหน้าเว็บ
💥 The Stateless Shock:
- ข่าวดี: ตอนนี้ Worker ของ Solid Queue ทำงานอยู่ภายใน Puma แล้ว ระบบจะระบายงานใหม่ทันที
- The Cold Shower (The Catch!):
- เนื่องจาก Cloud Run ได้ติดตั้งใช้งานรีวิชันใหม่ ระบบจึงแทนที่อินสแตนซ์คอนเทนเนอร์ก่อนหน้า
- บทความที่คุณเขียนและไฟล์ฐานข้อมูล SQLite ในดิสก์ถูกลบออกทั้งหมด
- บทเรียนด้านสถาปัตยกรรม: การเรียกใช้ Worker ที่ทำงานอยู่เบื้องหลังภายใน Puma จะใช้ CPU/RAM ของเธรดเว็บที่มีค่า และยังไม่แก้ปัญหาความคงทน
5. การตรวจสอบขั้นตอนที่ 3 โดยอัตโนมัติ
ยืนยันการติดตั้งใช้งาน Cloud Run และการจัดการการแจ้งเตือน
just workshop-eval 3
✨ บทเรียน: วิธีแก้ปัญหาแบบคอนเทนเนอร์เดียว เช่น SOLID_QUEUE_IN_PUMA มีประโยชน์สำหรับการพัฒนาในเครื่อง แต่ในสถาปัตยกรรมระบบคลาวด์สมัยใหม่
- ไฟล์สื่อต้องใช้ Google Cloud Storage (GCS) (ขั้นตอนที่ 4)
- ข้อมูลเชิงสัมพันธ์และคิวงานต้องใช้ Google Cloud SQL ที่มีการจัดการ (ขั้นตอนที่ 5)
- ส่วน Worker ที่ทำงานหนักในเบื้องหลังควรอยู่ในคอนเทนเนอร์ Sidecar โดยเฉพาะ (ขั้นตอนที่ 6)
6. ขั้นตอนที่ 4: Deploy 3 - GCS Persistent Storage & POLA Warning
ในขั้นตอนนี้ เราจะแยกพื้นที่เก็บข้อมูลสื่อและไฟล์ออกจากดิสก์คอนเทนเนอร์โดยเปลี่ยน ActiveStorage เป็น Google Cloud Storage (GCS) โดยใช้ URL ที่ลงชื่อซึ่งมีอายุสั้นผ่าน IAM Credentials API (iam: true)
ก่อนที่จะแตะต้องไฟล์กำหนดค่าใดๆ โปรดทำความเข้าใจ 3 สิ่งที่ Rails ต้องใช้ในการสื่อสารกับ GCS
① รหัสโปรเจ็กต์ + ชื่อ Bucket — Rails ต้องทราบตำแหน่งที่จะจัดเก็บ Blob แอปจะอ่าน GOOGLE_CLOUD_PROJECT จากสภาพแวดล้อมและกำหนดชื่อที่เก็บข้อมูลเป็น ${GOOGLE_CLOUD_PROJECT}-activestorage-prod Terraform จากขั้นตอนที่ 1 ได้สร้างที่เก็บข้อมูลนี้แล้ว คุณจึงไม่ต้องดำเนินการใดๆ เพิ่มเติม
② บัญชีบริการที่มีสิทธิ์ที่เหมาะสม - Cloud Run ทำงานในฐานะบัญชีบริการเริ่มต้นของ Compute Engine (PROJECT_NUMBER-compute@developer.gserviceaccount.com) SA นี้ต้องมีบทบาท IAM 2 บทบาทใน Bucket ดังนี้
roles/storage.objectAdmin- เพื่ออัปโหลดและแสดง Blobroles/iam.serviceAccountTokenCreatorใน ตัวมันเอง - เพื่อเรียกใช้ IAM CredentialssignBlobAPI และสร้าง URL ที่ลงชื่อซึ่งมีอายุสั้น
⚠️ ทางลัดที่น่าสนใจ -
public: true วิธีที่เร็วที่สุดในการทำให้ GCS ทำงานได้คือการตั้งค่า public: true ใน storage.yml และให้สิทธิ์ allUsers:objectViewer ในที่เก็บข้อมูล รูปภาพจะโหลดทันทีโดยไม่ต้องลงชื่อเข้าใช้ อย่าทำเช่นนี้ ถังข้อมูลสาธารณะจะทำให้สื่อของผู้ใช้ที่อัปโหลดทั้งหมดรั่วไหลไปยังอินเทอร์เน็ตแบบเปิดตลอดไป พิมพ์เขียวของเราใช้ iam: true เพื่อให้ที่เก็บข้อมูลเป็นแบบส่วนตัว 100% โดย URL ของรูปภาพทุกรายการจะเป็นโทเค็นที่ลงนามแล้วซึ่งจะหมดอายุและสร้างขึ้นทันทีโดย IAM Credentials API
③
ACTIVE_STORAGE_SERVICE=google - ตัวแปรสภาพแวดล้อมเดียวที่เปลี่ยน Rails จากดิสก์ในเครื่องเป็น GCS ในรันไทม์ ไม่ต้องเปลี่ยนแปลงโค้ด ไม่ต้องติดตั้งตรรกะของแอปพลิเคชันใหม่ เพียงแค่สลับตัวแปรสภาพแวดล้อม
1. ย้อนความทรงจำด้วยไทม์แมชชีน
ย้อนเวลาไปที่ขั้นตอนที่ 2
just workshop-rewind 2
ตรวจสอบ blog/config/storage.yml — คุณจะเห็นว่าแอปกำหนดสภาพแวดล้อม GCS ที่มีชื่อ 3 รายการ (dev / test / prod) ซึ่งทั้งหมดใช้รูปแบบที่ปลอดภัยเดียวกัน
<% gcp_project = ENV.fetch("GOOGLE_CLOUD_PROJECT") { Rails.application.credentials.dig(:gcs, :project) } %>
<% gcs_signer_sa = ENV.fetch("GCS_SIGNER_SA_EMAIL") { "rails-cloudrun-sa@#{gcp_project}.iam.gserviceaccount.com" } %>
google_prod: &google_prod
service: GCS
project: <%= gcp_project %>
bucket: <%= gcp_project %>-activestorage-prod # ← derived from project ID, no extra env var!
iam: true # Sign URLs via IAM Credentials signBlob API (no private key JSON required!)
gsa_email: <%= gcs_signer_sa %>
# Convenience alias — ACTIVE_STORAGE_SERVICE=google points here
google:
<<: *google_prod

2. การให้สิทธิ์การจัดเก็บข้อมูลและการลงนามของ IAM
ตรวจสอบว่าบัญชีบริการรันไทม์ของ Cloud Run มีสิทธิ์ลงนามใน URL และอัปโหลดออบเจ็กต์
export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
export RUN_SA="${PROJECT_NUMBER}-compute@developer.gserviceaccount.com"
export GCS_BUCKET="${GOOGLE_CLOUD_PROJECT}-activestorage-prod"
# Grant Storage Object Admin
gcloud storage buckets add-iam-policy-binding gs://$GCS_BUCKET \
--member="serviceAccount:$RUN_SA" \
--role="roles/storage.objectAdmin"
# Grant Service Account Token Creator (required for IAM signed URLs)
gcloud iam service-accounts add-iam-policy-binding $RUN_SA \
--member="serviceAccount:$RUN_SA" \
--role="roles/iam.serviceAccountTokenCreator"
3. การติดตั้งใช้งานครั้งที่ 3 ไปยัง Cloud Run โดยแนบ GCS
ติดตั้งใหม่โดยเปิดใช้ GCS ตรวจสอบว่าคุณอยู่ในโฟลเดอร์ blog/ (มิฉะนั้น Cloud Run จะพยายามสร้างโดยใช้ Buildpacks แทน Dockerfile ของ Rails 8 ซึ่งจะทำให้การสร้างล้มเหลว)
ใช้ --update-env-vars (ไม่ใช่ --set-env-vars) เพื่อเก็บตัวแปรสภาพแวดล้อมที่มีอยู่ (คีย์หลัก, การกำหนดค่า IAP ฯลฯ) ไว้
cd blog
gcloud run deploy blog \
--source . \
--region $GOOGLE_CLOUD_REGION \
--update-env-vars ACTIVE_STORAGE_SERVICE=google
💡 เคล็ดลับ: หากการติดตั้งใช้งานล้มเหลว ให้คลิกลิงก์บันทึกของ Cloud Build ที่แสดงอย่างสะดวกในเอาต์พุตของเทอร์มินัล (ดังที่แสดงในรูปภาพด้านล่าง) นอกจากนี้ คุณยังขอความช่วยเหลือจาก Antigravity ในการถอดรหัสและแก้ไขข้อผิดพลาดได้ด้วย

4. ✨ ภาพที่รอดชีวิตและแสตมป์บนคลาวด์
- รีเฟรช URL ของบล็อก
- สร้างบล็อกโพสต์ใหม่ชื่อ "การเอาตัวรอดในระบบคลาวด์" แล้วอัปโหลดรูปภาพ
- ดูที่มุมขวาล่างของรูปภาพ
- แสตมป์ 🏠 หายไปแล้ว
- โดยจะแทนที่ด้วยแสตมป์ GCS บนคลาวด์ (
nanobanana_stamp_cloud.png) ที่มีสีสัน
- บังคับให้รีสตาร์ทคอนเทนเนอร์อีกครั้ง (ซึ่งควรจะทริกเกอร์การแก้ไขครั้งที่ 4)
gcloud run services update blog --region $GOOGLE_CLOUD_REGION --update-env-vars RESTART_TRIGGER=$(date +%s) - รีเฟรชหน้าเว็บ: ขณะที่รีเซ็ตฐานข้อมูล SQLite ไบนารีของรูปภาพจะปลอดภัยใน Google Cloud Storage ยืนยันผ่าน CLI
gcloud storage ls -l -r gs://$GCS_BUCKET/
ต่อไปนี้คือรายการ Blob และออบเจ็กต์สื่อที่อัปโหลดซึ่งคุณอาจเห็นในคอนโซลเบราว์เซอร์ของ Google Cloud Storage ใน Bucket การผลิต (gs://$GCS_BUCKET)

5. ⚠️ ข้อควรระวัง: แบนเนอร์คำเตือนเกี่ยวกับงานที่ค้างอยู่
เมื่อคุณอัปโหลดรูปภาพ ActiveStorage จะจัดคิวงานวิเคราะห์ (ActiveStorage::AnalyzeJob) เพื่อดึงมิติข้อมูลและข้อมูลเมตา
อย่างไรก็ตาม ปัจจุบัน Cloud Run เรียกใช้ได้เพียงคอนเทนเนอร์ฝั่งเว็บเดียว (puma) ใน Rails 8 Solid Queue จะจัดเก็บงานที่ทำงานอยู่เบื้องหลังในฐานข้อมูล แต่ไม่มีใครเรียกใช้ bundle exec rails solid_queue:start
ดูที่ด้านบนของหน้าบล็อก คุณจะเห็นแบนเนอร์คำเตือนสีสดที่แสดงโดย blog/app/views/layouts/_check_stuck_jobs.html.erb
เราจะแก้ปัญหานี้อย่างเหมาะสมในขั้นตอนที่ 6 เมื่อเราเปลี่ยนไปใช้สถาปัตยกรรม Sidecar แบบหลายคอนเทนเนอร์ระดับเวอร์ชันที่ใช้งานจริงพร้อมคอนเทนเนอร์ worker เฉพาะที่เรียกใช้ Solid Queue แยกจากการเข้าชมเว็บ
6. การตรวจสอบขั้นตอนที่ 4 โดยอัตโนมัติ
ยืนยันการกำหนดค่า GCS และการวัดระยะของงานที่ค้างอยู่
just workshop-eval 4
7. ขั้นตอนที่ 5: รายการตรวจสอบก่อนเปิดตัว: Cloud SQL, Secrets และการเชื่อมต่อ DB
ในขณะที่คุณเชี่ยวชาญเรื่องคอนเทนเนอร์แบบไม่เก็บสถานะและ Google Cloud Storage ในขั้นตอนที่ 3 และ 4 Terraform ก็ได้สร้างแบ็กเอนด์เวอร์ชันที่ใช้งานจริงให้คุณเสร็จสมบูรณ์แล้ว
ก่อนที่จะติดตั้งใช้งานสถาปัตยกรรมไซด์คาร์แบบ 3 คอนเทนเนอร์เต็มรูปแบบสำหรับการใช้งานจริง (ติดตั้งใช้งาน 4 ในขั้นตอนที่ 6) ขั้นตอนนี้จะทำหน้าที่เป็นการตรวจสอบก่อนการบินอย่างรวดเร็วเพื่อยืนยันสถานะการทำงาน การเชื่อมต่อ และการเข้าถึงลับของฐานข้อมูล
0. ตัวแปรสภาพแวดล้อมของ Bootstrap
ส่งออกตัวแปรเชลล์ที่จำเป็นทั้งหมดจากเอาต์พุต Terraform โดยตรง
# Core project variables (should already be set from Step 0)
export GOOGLE_CLOUD_REGION="${GOOGLE_CLOUD_REGION:-europe-west1}"
# Compute runtime service account
export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
export RUN_SA="${PROJECT_NUMBER}-compute@developer.gserviceaccount.com"
# Cloud SQL instance name (from Terraform output, NOT hardcoded)
export SQL_INSTANCE_NAME=$(cd iac && terraform output -raw sql_instance_name 2>/dev/null || gcloud sql instances list --format='value(name)' --limit=1)
# Database password (from Terraform output)
export DB_PASSWORD=$(cd iac && terraform output -raw db_password 2>/dev/null || echo "CHANGE_ME")
# GCS bucket names
export GCS_BUCKET="${GOOGLE_CLOUD_PROJECT}-activestorage-prod"
echo "✅ Pre-flight environment variables ready:"
echo " RUN_SA=$RUN_SA"
echo " SQL_INSTANCE_NAME=$SQL_INSTANCE_NAME"
echo " GCS_BUCKET=$GCS_BUCKET"
1. การตรวจสอบสถานะของ Cloud SQL
ตรวจสอบว่าอินสแตนซ์ PostgreSQL ที่มีการจัดการได้จัดสรรเริ่มต้นเสร็จสมบูรณ์และทำงานได้ปกติโดยทำดังนี้
echo "Checking instance: $SQL_INSTANCE_NAME"
gcloud sql instances describe $SQL_INSTANCE_NAME --format="value(state)"
เอาต์พุตต้องเป็น RUNNABLE
2. (ไม่บังคับ) การทดสอบการเชื่อมต่อฐานข้อมูลจากแล็ปท็อป
ในสภาพแวดล้อมการใช้งานจริง คอนเทนเนอร์ Cloud Run จะเชื่อมต่อกับ Cloud SQL อย่างปลอดภัยผ่านพร็อกซีแบบ Sidecar ที่เข้ารหัส (127.0.0.1:5432) โดยไม่ต้องเปิดเผยฐานข้อมูลต่ออินเทอร์เน็ตสาธารณะ (0.0.0.0/0)
ℹ️ หมายเหตุ: ขั้นตอนนี้เป็นแบบไม่บังคับ ใน Cloud Run คอนเทนเนอร์ Sidecar ของพร็อกซีการตรวจสอบสิทธิ์ Cloud SQL อย่างเป็นทางการจะจัดการการเชื่อมต่อ mTLS โดยอัตโนมัติ คุณไม่จำเป็นต้องติดตั้งอะไรในเครื่องเพื่อเข้าร่วมเวิร์กช็อปให้เสร็จสมบูรณ์
หากคุณติดตั้ง cloud-sql-proxy และ psql ในเครื่องและต้องการยืนยันการเชื่อมต่อโดยตรงจากแล็ปท็อป ให้ทำดังนี้
# Optional: test connectivity via Google-managed mTLS proxy
gcloud sql connect $SQL_INSTANCE_NAME --user=rails_user --database=rails_production
(หากระบบแจ้งให้ป้อนรหัสผ่าน ให้ป้อน
$DB_PASSWORD
ไม่เช่นนั้น คุณสามารถข้ามไปยังขั้นตอนที่ 3 ด้านล่างได้เลย)
3. การตรวจสอบข้อมูลลับที่จัดสรรโดย Terraform
ห้ามจัดเก็บรหัสผ่านฐานข้อมูล, คีย์ API หรือคีย์หลักของ Rails ในรูปแบบข้อความธรรมดาใน Git หรือในตัวแปรสภาพแวดล้อมของคอนเทนเนอร์ ในสถาปัตยกรรมระบบคลาวด์ที่ทันสมัย เราใช้ Google Cloud Secret Manager สำหรับการแทรกรันไทม์แบบ Zero Trust
ℹ️ Terraform จัดการให้คุณในขั้นตอนที่ 1:
rails-master-key— สำหรับการถอดรหัสข้อมูลเข้าสู่ระบบของ Rails ในขณะรันไทม์rails-db-password- รหัสผ่านแบบสุ่มที่ปลอดภัยด้วยการเข้ารหัสลับซึ่งตรงกับผู้ใช้ Cloud SQLrails-admin-password- รหัสผ่านที่ปลอดภัยสำหรับผู้ใช้ที่เป็นผู้ดูแลระบบเริ่มต้น
ตรวจสอบว่ามีและเปิดใช้ข้อมูลลับใน Secret Manager ดังนี้
gcloud secrets list --filter="name:rails-"

🔑 การซิงค์ master.key กับแล็ปท็อป (การซิงค์ในเครื่อง)
เนื่องจาก blog/config/master.key ถูกละเว้นใน git เพื่อความปลอดภัย โคลนในเครื่องของคุณจึงอาจยังไม่มี เรียกใช้ข้อมูลโค้ดการซ่อมแซมตัวเองที่เป็นมิตรนี้เพื่อดึงข้อมูลจาก Secret Manager เพื่อให้เครื่องมือ Rails ในเครื่องถอดรหัสข้อมูลเข้าสู่ระบบได้
if [ ! -f blog/config/master.key ]; then
echo "📥 Pulling rails-master-key from Secret Manager to local blog/config/master.key..."
gcloud secrets versions access latest --secret=rails-master-key > blog/config/master.key
echo "🔑 Created local blog/config/master.key! 🎉"
else
echo "✅ Local blog/config/master.key already exists! 🚀"
fi
🧪 Playground: หากต้องการสร้างข้อมูลลับที่กำหนดเองเพื่อดูว่าทำได้ง่ายเพียงใด Secret Manager ไม่ได้มีไว้สำหรับ Rails เท่านั้น คุณสร้างข้อมูลลับได้ทุกอย่างด้วยคำสั่ง CLI ง่ายๆ เพียงคำสั่งเดียว
echo -n "MySuperSecretValue123!" | gcloud secrets create workshop-fun-secret --data-file=-
echo "✨ Created workshop-fun-secret in Secret Manager! 🪄"
4. การยืนยันสิทธิ์ของผู้เข้าถึงข้อมูลลับ
เพื่อให้คอนเทนเนอร์ Cloud Run ติดตั้งข้อมูลลับเหล่านี้เป็นตัวแปรสภาพแวดล้อมหรือการติดตั้งโวลุ่มเมื่อบูต บัญชีบริการรันไทม์ ($RUN_SA) ต้องมีบทบาท roles/secretmanager.secretAccessor ในข้อมูลลับแต่ละรายการ
Terraform ได้ให้สิทธิ์นี้แล้วในขั้นตอนที่ 1 ยืนยันการเชื่อมโยงนโยบาย IAM ใน rails-master-key:
# Verify that Cloud Run runtime SA has Secret Accessor role
gcloud secrets get-iam-policy rails-master-key \
--flatten="bindings[].members" \
--format="table(bindings.role,bindings.members)" \
--filter="bindings.members:$RUN_SA"
คุณควรเห็นข้อมูลต่อไปนี้
ROLE MEMBERS
roles/secretmanager.secretAccessor serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com

5. การตรวจสอบก่อนส่งอัตโนมัติ
เรียกใช้ชุดโปรแกรมทดสอบขั้นตอนที่ 5 โดยอัตโนมัติเพื่อยืนยันว่าฐานข้อมูลเรียกใช้ได้ ข้อมูลลับไม่ว่างเปล่า และสิทธิ์ IAM เป็นสีเขียว
just workshop-eval 5
8. ขั้นตอนที่ 6: Deploy 4 - Enterprise Multi-Container Sidecars (The Gold Standard)
ตอนนี้เราจะประกอบสถาปัตยกรรมอ้างอิงขั้นสุดยอด นั่นคือ Multi-Container Cloud Run!
1. การฟื้นฟูมาตรฐานทองคำ
กู้คืนการกำหนดค่าที่เก็บไปยังสถานะ main ที่เป็นมาตรฐาน
just workshop-restore-gold
2. การตรวจสอบพิมพ์เขียวการผลิตแบบ 3 คอนเทนเนอร์
เปิด blog/compose.prod.yaml แล้วตรวจสอบสถาปัตยกรรม

graph LR
Client[Internet / HTTPS Client] -->|Port 8080| Web[Web Container: Puma]
Web -->|Localhost:5432| Proxy[Sidecar: Cloud SQL Auth Proxy]
Worker[Worker Container: Solid Queue] -->|Localhost:5432| Proxy
Proxy -->|IAM mTLS Tunnel| CloudSQL[(Google Cloud SQL PostgreSQL)]
การทำให้ใช้งานจริงในเวอร์ชันที่ใช้งานจริงจะเรียกใช้คอนเทนเนอร์ที่ประสานงาน 3 รายการซึ่งใช้เครือข่ายในพื้นที่เดียวกัน
web: แสดงการรับส่งข้อมูล HTTP ในพอร์ต 8080 ผ่าน Pumaworker: คอนเทนเนอร์การประมวลผลเบื้องหลังเฉพาะที่เรียกใช้bundle exec rails solid_queue:startcloudsql-proxy: Sidecar พร็อกซีการตรวจสอบสิทธิ์ Google Cloud SQL อย่างเป็นทางการ (gcr.io/cloud-sql-connectors/cloud-sql-proxy:2) ที่เชื่อมโยงกับ127.0.0.1:5432
3. การเรียกใช้การย้ายข้อมูลฐานข้อมูลผ่าน Cloud Run Job
ก่อนที่จะกำหนดเส้นทางการเข้าชมเว็บไปยังการติดตั้งใช้งานใหม่ เราต้องเรียกใช้การย้ายฐานข้อมูลและการเริ่มต้นใช้งานกับ Cloud SQL
⚖️ วิธีเรียกใช้การย้ายข้อมูลในคอนเทนเนอร์: 2 กลยุทธ์
ในสภาพแวดล้อมระบบคลาวด์แบบคอนเทนเนอร์ มีแนวทางทั่วไป 2 วิธีในการดำเนินการย้ายฐานข้อมูล ดังนี้
- ตัวเลือก ก: อัตโนมัติภายใน Docker Entrypoint (
entrypoint.shเรียกใช้db:migrateเมื่อบูตคอนเทนเนอร์)- ข้อดี: ทำงานอัตโนมัติทั้งหมด นักพัฒนาแอปไม่ต้องจดจำคำสั่งเพื่อเรียกใช้
- ข้อเสีย: เป็นอันตรายในการปรับขนาดอัตโนมัติแบบไร้เซิร์ฟเวอร์ เมื่อ Cloud Run ปรับขนาดเป็น 10 อินสแตนซ์พร้อมกันภายใต้การเข้าชมสูง คอนเทนเนอร์ 10 รายการจะแข่งขันกันเพื่อเรียกใช้การย้ายข้อมูลพร้อมกัน ซึ่งทำให้เกิดการล็อกฐานข้อมูล เงื่อนไขการแข่งขันของสคีมา หรือการหมดเวลาการบูต
- ตัวเลือก B: ระบุอย่างชัดเจนผ่าน Cloud Run Job (ตัวเลือกสถาปัตยกรรมของเรา)
- ข้อดี: ควบคุมได้อย่างสมบูรณ์ ปลอดภัยในการทำธุรกรรม และไม่มีการแข่งขัน ทำงานเป็นงานคอนเทนเนอร์แบบครั้งเดียวที่แยกออกจากทราฟิกเว็บที่ให้บริการอย่างสมบูรณ์ หากการย้ายข้อมูลไม่สำเร็จ การแสดงโฆษณาบนเว็บจะไม่ได้รับผลกระทบ
- ข้อเสีย: ต้องทริกเกอร์งาน CLI หรือขั้นตอน CI/CD ก่อนการติดตั้งใช้งาน
เราเลือกตัวเลือก B เพื่อความน่าเชื่อถือในการผลิตสูงสุด
⚠️ สำคัญ: DATABASE_URL รูปแบบและความเข้มงวดของ Ruby 3.4.5 RFC 3986
งาน Cloud Run จะเชื่อมต่อกับ Cloud SQL โดยใช้พร็อกซีซ็อกเก็ต Unix แบบเนทีฟ (/cloudsql/PROJECT:REGION:INSTANCE) โดย DATABASE_URL ต้องใช้รูปแบบทริปเปิลสแลช
postgresql:///rails_production?user=rails_user&password=PASS&host=/cloudsql/PROJECT:REGION:INSTANCE
# Core environment variables for database migration & initial admin seed
export GOOGLE_CLOUD_ACCOUNT="${GOOGLE_CLOUD_ACCOUNT:-$(gcloud config get-value account)}"
echo "Admin user will be seeded for: $GOOGLE_CLOUD_ACCOUNT"
# Get the latest blog image from Cloud Run (jobs don't support --source)
export BLOG_IMAGE=$(gcloud run services describe blog --region=$GOOGLE_CLOUD_REGION --format='value(spec.template.spec.containers[0].image)')
# Build the DATABASE_URL in triple-slash format (required for Unix socket proxy)
export DB_PASSWORD=$(gcloud secrets versions access latest --secret=rails-db-password)
export CLOUDSQL_CONNECTION="${GOOGLE_CLOUD_PROJECT}:${GOOGLE_CLOUD_REGION}:${SQL_INSTANCE_NAME}"
export DB_URL="postgresql:///rails_production?user=rails_user&password=${DB_PASSWORD}&host=/cloudsql/${CLOUDSQL_CONNECTION}"
# Create migration job — note ALL 4 database URL env vars and GOOGLE_CLOUD_ACCOUNT for seed user creation
gcloud run jobs create rails-migrate \
--image=$BLOG_IMAGE \
--command "bin/rails" \
--args "db:prepare" \
--set-env-vars="DATABASE_URL=${DB_URL},DATABASE_QUEUE_URL=${DB_URL},DATABASE_CACHE_URL=${DB_URL},DATABASE_CABLE_URL=${DB_URL},GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT},GOOGLE_CLOUD_ACCOUNT=${GOOGLE_CLOUD_ACCOUNT}" \
--set-secrets="RAILS_MASTER_KEY=rails-master-key:latest" \
--set-cloudsql-instances="${CLOUDSQL_CONNECTION}" \
--service-account=$RUN_SA \
--region $GOOGLE_CLOUD_REGION 2>/dev/null || true
# Execute migration job
gcloud run jobs execute rails-migrate --region $GOOGLE_CLOUD_REGION --wait
💡 ฐานข้อมูลหลายรายการของ Rails 8: แอปใช้ฐานข้อมูล 4 รายการ (หลัก คิว แคช เคเบิล) ต่อ database.yml ตัวแปรสภาพแวดล้อม 4 DATABASE_*_URL ทั้งหมดต้องชี้ไปยังอินสแตนซ์ Cloud SQL เดียวกัน มิฉะนั้นระบบจะไม่สร้างตาราง Solid Queue/Cache/Cable
หลังจาก db:prepare ให้โหลดสคีมา Solid Queue/Cache/Cable ดังนี้
# Schema load for queue, cache, and cable databases (creates solid_queue_jobs, etc.)
gcloud run jobs update rails-migrate \
--command "bash" \
--args "-c,DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bin/rails db:schema:load:queue db:schema:load:cache db:schema:load:cable" \
--region $GOOGLE_CLOUD_REGION
gcloud run jobs execute rails-migrate --region $GOOGLE_CLOUD_REGION --wait
ในรูปภาพด้านบน คุณจะเห็นเอาต์พุตที่เป็นไปได้ของ
gcloud run jobs executions describe $JOBNAME
คอนโซลงานใน Google Cloud Run แสดง
rails-migrate
ดำเนินการสำเร็จ
4. การติดตั้งใช้งานครั้งที่ 4: การติดตั้งใช้งาน Cloud Run แบบหลายคอนเทนเนอร์ผ่าน Docker Compose
ตอนนี้คุณสามารถติดตั้งใช้งานสแต็กการผลิตแบบ 3 คอนเทนเนอร์ของแท้ (web, worker, cloudsql-proxy) ได้โดยตรงจาก compose.prod.yaml
# 1. Self-healing environment exports (guarantees no missing master key or DB password)
export RAILS_MASTER_KEY="${RAILS_MASTER_KEY:-$(cat config/master.key 2>/dev/null || gcloud secrets versions access latest --secret=rails-master-key)}"
export DB_PASSWORD=$(gcloud secrets versions access latest --secret=rails-db-password)
export CLOUDSQL_INSTANCE_CONNECTION_NAME="${GOOGLE_CLOUD_PROJECT}:${GOOGLE_CLOUD_REGION}:${SQL_INSTANCE_NAME}"
# 2. Database credentials & GCS attachments
export DB_USER="rails_user"
export DB_NAME="rails_production"
export GCS_BUCKET="${GCS_BUCKET}"
export ACTIVE_STORAGE_SERVICE="google"
export GOOGLE_CLOUD_ACCOUNT="${GOOGLE_CLOUD_ACCOUNT:-$(gcloud config get-value account)}"
export GEMINI_API_KEY="${GEMINI_API_KEY:-dummy-key}"
# 3. Deploy the full multi-container sidecar architecture to Cloud Run
gcloud run compose up compose.prod.yaml \
--region=$GOOGLE_CLOUD_REGION \
--allow-unauthenticated
คอนโซล Google Cloud Run: แท็บ "คอนเทนเนอร์" ที่แสดงคอนเทนเนอร์ Sidecar ทั้ง 3 รายการ (
cloudsql-proxy
,
web
,
worker
)
💡 ความผิดปกติของ UI / ข้อบกพร่องของคอนโซล: ในเมนูแบบเลื่อนลงของคอนโซล คุณอาจเห็นว่า Cloud Run ติดป้ายกำกับรายการแรกเป็น Ingress container: cloudsql-proxy ไม่ต้องกังวล นี่เป็นเพียงข้อบกพร่องด้านภาพใน UI ของคอนโซล Google Cloud (ติดตามใน #149) ซึ่งเกิดจากการจัดลำดับการขึ้นต่อกันของคอนเทนเนอร์ ในความเป็นจริง web เป็นคอนเทนเนอร์เดียวที่รับฟังพอร์ต HTTP 8080 และจัดการการรับส่งข้อมูลเว็บขาเข้า 100% ขณะที่ cloudsql-proxy จะให้บริการการรับส่งข้อมูล PostgreSQL ส่วนตัวบนพอร์ต 5432 อย่างเคร่งครัด
5. ✨ ช่วงเวลาที่น่าทึ่ง: ไม่มีคำเตือนและข้อมูลในระบบคลาวด์ยังคงอยู่ครบถ้วน
สูดลมหายใจลึกๆ แล้วมองที่หน้าจอ แบนเนอร์คำเตือนทั้งหมดหายไปแล้ว 🪄
บล็อก Rails 8 เวอร์ชันที่ใช้งานจริง: UI ที่สมบูรณ์ แบนเนอร์คำเตือนเป็น 0 และสถานะ Cloud SQL ที่คงอยู่
ตอนนี้แอปพลิเคชันเป็น Production-Grade & Cloud-Native อย่างเป็นทางการแล้ว
- ทำงานบน Google Cloud SQL (PostgreSQL) ที่มีการจัดการผ่านการเชื่อมต่อ mTLS ที่ปลอดภัย
- จัดเก็บสื่ออย่างปลอดภัยใน Google Cloud Storage ส่วนตัวด้วยการลงนาม Blob ของ IAM
- ไม่มีคำเตือนเกี่ยวกับพื้นที่เก็บข้อมูลชั่วคราวและไม่มีการแจ้งเตือนเกี่ยวกับงานที่ค้างอยู่
เปิด URL ของ Cloud Run โดยทำดังนี้
- ดูป้ายการวัดและส่งข้อมูล:
[CLOUD PERSISTENT 🐘 ☁️]ได้รับการยืนยันใน Seed ฐานข้อมูลแล้ว- ทั้งป้าย Google Cloud Run และ GCS ในส่วนท้ายจะส่องแสงเป็นสีเขียว
- แบนเนอร์คำเตือนเกี่ยวกับงานที่ค้างหายไปแล้ว
- สร้างบล็อกโพสต์และความคิดเห็น
- รีสตาร์ทหรือติดตั้งใช้งานใหม่ได้หลายครั้งตามต้องการ ข้อมูล โพสต์ ความคิดเห็น และชิ้นงานจะคงอยู่ตลอดไปใน Cloud SQL และ GCS
6. การตรวจสอบขั้นตอนที่ 6 โดยอัตโนมัติ
ตรวจสอบการกำหนดค่าแบบหลายคอนเทนเนอร์
just workshop-eval 6
9. ขั้นตอนที่ 7: ไปป์ไลน์ Generative AI, Podcastifier และการล่าขุมทรัพย์ใน GCS 🏴☠️
เมื่อ Solid Queue ทำงานในคอนเทนเนอร์เฉพาะและ Google Cloud Storage ทำงานอยู่ เราจะสามารถปลดปล่อย Generative AI แบบอะซิงโครนัสได้
1. โปรแกรมสร้างปกย้อนยุค NanoBanana (ไปป์ไลน์ GenAI ที่พร้อมใช้งาน)

ข่าวดีคือ ฟังก์ชันนี้ได้นำไปใช้ในโค้ดเบสอย่างเต็มรูปแบบแล้ว คุณไม่จำเป็นต้องเขียนโค้ดใดๆ งานของคุณที่นี่คือการเรียกใช้และสังเกตไปป์ไลน์ GenAI บนระบบคลาวด์แบบไม่พร้อมกันที่ทำงานอยู่
🧠 วิธีการทำงานเบื้องหลัง
- การตรวจสอบสิทธิ์: ไม่ต้องใช้คีย์ API โดยจะใช้ข้อมูลรับรองเริ่มต้นของแอปพลิเคชัน (
roles/aiplatform.userใน Vertex AI) โดยอัตโนมัติผ่านบัญชีบริการรันไทม์ของ Cloud Run (หรือหากระบุGEMINI_API_KEYไว้ ระบบจะเรียกใช้ Gemini API โดยตรง) - ไปป์ไลน์: เมื่อสร้างบทความโดยไม่มีภาพหน้าปก
after_commitจะเรียกกลับเพื่อจัดคิวGenerateCoverImageJobลงใน Solid Queue - โมเดล: พรอมต์โมเดลมัลติโมดัลของ Google (Gemini 2.5 Flash Image / Imagen ใน Vertex AI) เพื่อสร้างโปสเตอร์ภาพยนตร์อิตาลีปี 1960 ที่ดูสมจริง ("Locandina di un film 1960") พร้อมด้วยกล้วยที่รับเชิญและทับทิม "8" ที่ส่องประกาย
- ลายน้ำที่มาแบบไดนามิก: ใช้
libvipsเพื่อประทับตราภาพแบบไดนามิกที่มุม (ตราเมฆสีบน GCS) - การสลับฮอตสปอตของ Turbo Stream: เมื่อแนบรูปภาพแล้ว
Turbo::StreamsChannel.broadcast_refresh_to(post)จะอัปเดตเบราว์เซอร์ของผู้อ่านแบบเรียลไทม์โดยไม่ต้องโหลดหน้าเว็บซ้ำด้วยตนเอง

📐 ดูแหล่งที่มาของไดอะแกรมลำดับ Mermaid
sequenceDiagram
autonumber
actor User as 👤 Reader / Author
participant Web as 🌐 Web (Puma)
participant DB as 🐘 Cloud SQL (Solid Queue)
participant Worker as ⚙️ Worker (Solid Queue)
participant Vertex as 🧠 Vertex AI (Gemini Flash / Imagen)
participant GCS as ☁️ Google Cloud Storage
User->>Web: POST /posts (Title & Body, No Cover)
Web->>DB: 1. Save Post & Enqueue GenerateCoverImageJob
Web-->>User: Redirect to Post (turbo_stream subscribed)
Worker->>DB: 2. Dequeue GenerateCoverImageJob
Worker->>Vertex: 3. Prompt for 1960s Italian Poster (ADC auth)
Vertex-->>Worker: 4. Raw Image Buffer
Worker->>Worker: 5. Stamp Provenance Watermark (libvips)
Worker->>GCS: 6. Attach Blob via ActiveStorage (IAM signBlob)
Worker->>Web: 7. Turbo::StreamsChannel.broadcast_refresh_to(post)
Web-->>User: ⚡ Live UI Hot-Swap: Poster magically appears!
🧪 ลองใช้แบบเรียลไทม์
คุณเรียกใช้ฟีเจอร์นี้ได้ 2 วิธี ดังนี้
- ตัวเลือก A (UI บนเว็บ): คลิกโพสต์ใหม่ ป้อนชื่อ เช่น "สถาปัตยกรรมแบบ Serverless ด้วย Ruby on Rails 8" เขียนเนื้อหา และปล่อยให้ช่องป้อนไฟล์ภาพหน้าปกว่าง คลิกสร้างโพสต์
- ตัวเลือก ข (CLI Runner): เรียกใช้จากเทอร์มินัล
bin/rails runner 'Post.create!(title: "Serverless Architecture with Ruby on Rails 8", body: "Exploring asynchronous AI pipelines with Solid Queue and NanoBanana!")'
รอประมาณ 15-30 วินาที: ดูบันทึกของ Worker ในคิวที่เชื่อถือได้ใน Cloud Run โปสเตอร์ย้อนยุคจะปรากฏในโพสต์โดยตรง
📸 TODO(riccardo): add screenshot of a blog post with an AI-generated vintage 1960s Italian movie poster featuring a cameo banana and ruby 8
2. ภารกิจ Bilingual Podcastifier (แบบฝึกหัดการเขียนโค้ดแบบแอนตี้กราวิตี้)
⚠️ ประกาศสำคัญ: ฟีเจอร์นี้ยังไม่พร้อมใช้งาน ซึ่งแตกต่างจากเครื่องมือสร้างปกด้านบน
หากเปิด blog/app/jobs/podcastifier_job.rb คุณจะเห็น Stub โครงร่างที่ว่างเปล่า
class PodcastifierJob < ApplicationJob
queue_as :default
def perform(post_id)
# TODO(student): COMPLETE_ME — Pair program with Google Antigravity to implement
# Italian TTS podcast generation using voice 'it-IT-Wavenet-A' via Cloud TTS / ADC!
end
end
ภารกิจของคุณในการฝึกปฏิบัติครั้งนี้คือการจับคู่โปรแกรมกับ Google Antigravity เพื่อทําฟีเจอร์นี้ให้เสร็จสมบูรณ์
- พรอมต์ Antigravity:"ช่วยฉันติดตั้งใช้งาน PodcastifierJob ใน
app/jobs/podcastifier_job.rbโดยควรดึงข้อมูลโพสต์ แปล หรือสังเคราะห์ภาพรวมเสียงภาษาอิตาลีโดยใช้ Cloud Text-to-Speech ของ Google (เสียง "it-IT-Wavenet-A" ที่มีรหัสภาษา "it-IT" ผ่านข้อมูลเข้าสู่ระบบ ADC) และแนบไฟล์เสียงไปกับpost.podcast_audio_itโดยใช้ ActiveStorage" - เพิ่มเพลเยอร์เพื่อดู: ใน
app/views/posts/show.html.erbให้เพิ่มเพลเยอร์HTML5 เมื่อ@post.podcast_audio_it.attached? - ทริกเกอร์การสังเคราะห์: เมื่อบันทึกแล้ว Solid Queue จะเรียกใช้การอ่านออกเสียงข้อความแบบอะซิงโครนัสในพื้นหลัง

🎧 ตัวอย่างผลลัพธ์ของ Podcastifier:
💡 หากต้องการความช่วยเหลือหรือพบปัญหา โซลูชันอ้างอิงที่สมบูรณ์และผ่านการทดสอบแล้วพร้อมใช้งานใน Branch solutions/podcastifier คุณตรวจสอบได้ทุกเมื่อด้วย git diff solutions/podcastifier
3. [ไม่บังคับ] 🏴☠️ กิจกรรมล่าสมบัติใน GCS (การกู้คืน Blob ในคอนโซล)
ℹ️ การตรวจสอบข้อกำหนดเบื้องต้น: Local
cloud-sql-proxy
ต้องใช้ CLI แบบฝึกหัดที่ไม่บังคับนี้จะเชื่อมต่อแล็ปท็อปในเครื่องกับ Google Cloud SQL โดยตรงผ่านอุโมงค์ mTLS ที่เข้ารหัส ตรวจสอบว่าคุณได้ติดตั้งพร็อกซี CLI แล้วหรือไม่
which cloud-sql-proxy
- หากติดตั้งแล้ว ให้ดำเนินการต่อด้านล่าง
- หากยังไม่ได้ติดตั้งและต้องการทำภารกิจนี้ ให้ติดตั้งโดยใช้คำสั่งต่อไปนี้
# Linux (x86_64) curl -o /tmp/cloud-sql-proxy https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.14.0/cloud-sql-proxy.linux.amd64 chmod +x /tmp/cloud-sql-proxy && sudo mv /tmp/cloud-sql-proxy /usr/local/bin/cloud-sql-proxy # macOS (Homebrew) brew install cloud-sql-proxy - ไม่เช่นนั้น: คุณสามารถข้ามไปยังการตรวจสอบอัตโนมัติในขั้นตอนที่ 7 ได้
คุณจำรูปภาพที่อัปโหลดในขั้นตอนที่ 4 ก่อนที่การรีสตาร์ทคอนเทนเนอร์จะล้างฐานข้อมูล SQLite ชั่วคราวได้ไหม ไฟล์รูปภาพนั้นยังคงอยู่ใน Bucket ของ GCS ส่วนตัวของคุณอย่างปลอดภัยในรูปแบบ "Blob ที่ไม่มีเจ้าของ"
มาใช้คอนโซล Rails เพื่อกู้คืนและแนบไปกับโพสต์ Cloud SQL กัน
# Connect to your production database via Rails console and Cloud SQL Proxy
cloud-sql-proxy --port 5432 ${GOOGLE_CLOUD_PROJECT}:${GOOGLE_CLOUD_REGION}:${SQL_INSTANCE_NAME} &
DATABASE_URL=postgresql://rails_user:${DB_PASSWORD}@127.0.0.1:5432/rails_production bin/rails c
ในคอนโซล Rails ให้ทำดังนี้
# 1. Search for orphaned GCS blobs in ActiveStorage
orphan_blobs = ActiveStorage::Blob.where.missing(:attachments)
puts "🏴☠️ Found #{orphan_blobs.count} orphaned GCS blobs!"
# 2. Attach the surviving blob to your latest post
if orphan_blobs.any?
post = Post.last
post.cover_image.attach(orphan_blobs.first)
post.save!
puts "🎉 Rescued blob #{orphan_blobs.first.filename} attached to '#{post.title}'!"
end
exit
📸 TODO(riccardo): add screenshot of the interactive Rails console executing the GCS Treasure Hunt snippet and rescuing orphaned ActiveStorage blobs
รีเฟรชบล็อก: รูปภาพที่อัปโหลดในระหว่าง Stateless Shock ของขั้นตอนที่ 4 จะกลับมาและแนบไปกับโพสต์ Cloud SQL อย่างถาวร
4. การตรวจสอบขั้นตอนที่ 7 โดยอัตโนมัติ
ยืนยันงานและชิ้นงาน GenAI
just workshop-eval 7
10. ขั้นตอนที่ 8: เลือกการผจญภัยของคุณเอง / ภารกิจขั้นสูง 🏆
ตอนนี้คุณได้เชี่ยวชาญสถาปัตยกรรมอ้างอิงที่แน่นอนแล้ว ให้เลือกภารกิจจบการศึกษา
🛡️ ภารกิจที่ 1: Google IAP (Identity-Aware Proxy) แบบ Zero Trust
- ความยาก: ปานกลาง (Enterprise Security)
- เป้าหมาย: ล็อกแอปพลิเคชัน Cloud Run เพื่อให้เฉพาะบัญชี Google / Gmail ที่ยืนยันแล้วเท่านั้นที่เข้าถึงได้ ซึ่งจะช่วยกำจัดการเข้าสู่ระบบด้วยรหัสผ่านไปโดยสิ้นเชิง
- วิธีการทำงาน
- ตัวจัดสรรภาระงานแอปพลิเคชัน HTTPS ภายนอกจะสิ้นสุด Google OAuth และยืนยันตัวตนก่อนที่การรับส่งข้อมูลจะไปถึง Cloud Run
- Google จะส่งต่อส่วนหัวของข้อมูลประจำตัวที่ยืนยันแล้ว (
X-Goog-Authenticated-User-Email) - Rails จะเข้าสู่ระบบโดยใช้ข้อมูลประจำตัว Google ที่ยืนยันแล้วโดยอัตโนมัติผ่าน
blog/app/controllers/concerns/iap_authenticatable.rbดังนี้module IapAuthenticatable extend ActiveSupport::Concern included { before_action :authenticate_via_iap } private def authenticate_via_iap return unless (raw = request.headers["X-Goog-Authenticated-User-Email"]).present? email = raw.sub(/^accounts\.google\.com:/, "") user = User.find_or_create_by!(email_address: email) { |u| u.password = SecureRandom.hex(16) } start_new_session_for(user) unless authenticated? end end - เปิดใช้โมดูล Terraform ใน
iac/iap.tfด้วยenable_iap = trueและระบุบัญชี Google ที่อนุญาตiap_allowed_users = [var.google_cloud_account]

📊 Quest 2: การส่งข้อมูลทางไกลของ SRE ในการผลิตและ Cloud Logging
- ความยาก: ปานกลาง (ความสามารถในการสังเกต)
- เป้าหมาย: สตรีมบันทึกแอปพลิเคชัน JSON ที่มีโครงสร้างพร้อมรหัสความสัมพันธ์ของการติดตามไปยัง Google Cloud Logging โดยตรง และตรวจหาข้อยกเว้นในเวอร์ชันที่ใช้งานจริงแบบเรียลไทม์ด้วย Cloud Error Reporting
- วิธีการทำงาน
- กำหนดค่า
blog/config/environments/production.rbเพื่อส่งบันทึก JSON ที่มีโครงสร้างพร้อมป้ายกำกับการติดตามของ GCP - เรียกใช้ข้อยกเว้นการทดสอบโดยเจตนา แล้วดู Google Cloud Error Reporting จัดกลุ่มและแจ้งให้คุณทราบทันที
- กำหนดค่า
📸 TODO(riccardo): add screenshot of Google Cloud Error Reporting showing grouped production exceptions and Cloud Logging structured JSON payload with trace labels
🧠 Quest 3: pgvector การค้นหาเชิงความหมายและ RAG ของ Gemini
- ความยาก: ยาก (โครงงาน GenAI)
- เป้าหมาย: ค้นหาบทความตามแนวคิดโดยใช้ Vector Embeddings ที่จัดเก็บไว้ใน PostgreSQL บน Cloud SQL
- วิธีการทำงาน
- เปิดใช้ส่วนขยาย
vectorในอินสแตนซ์ Cloud SQL PostgreSQL โดยทำดังนี้CREATE EXTENSION IF NOT EXISTS vector; - เพิ่ม
neighborgem ไปยังblog/Gemfileแล้วสร้างการฝังข้อความด้วย Gemini (text-embedding-004) ในPost#after_save - ทำการค้นหาตามระยะทางโคไซน์ (
<=>) เพื่อขับเคลื่อนแถบค้นหาเชิงความหมายด้วย Turbo Streams
- เปิดใช้ส่วนขยาย
📸 TODO(riccardo): add screenshot of the live blog semantic search bar returning conceptual matches with cosine similarity scores
⚡ เควสที่ 4: ผู้ช่วยด้านการตรวจสอบ SEO และประสิทธิภาพ
- ความยาก: ง่าย / สนุก (ประสบการณ์ของนักพัฒนาแอป)
- เป้าหมาย: ตรวจสอบ Core Web Vitals, Largest Contentful Paint (LCP) และดัชนีความสามารถในการอ่าน Flesch-Kincaid / Fog โดยใช้เครื่องมือ Antigravity และ Speedgrapher
📸 TODO(riccardo): add screenshot of Speedgrapher / Lighthouse SEO and Core Web Vitals audit summary
🤔 Curiosity Box: การรับคอนโซล Rails แบบสดใน Cloud Run
💡 คำถาม: ในแพลตฟอร์ม PaaS แบบ VM แบบเดิมหรือแบบ Heroku นักพัฒนาซอฟต์แวร์มักจะใช้ SSH เพื่อเข้าถึงอินสแตนซ์ที่ทำงานอยู่ หรือใช้ heroku run rails console เพื่อตรวจสอบหรือแก้ไขข้อมูลการผลิตแบบเรียลไทม์ สิ่งที่เทียบเท่ากับ Cloud Run ดั้งเดิมคืออะไร และคุณจะเพิ่มความปลอดภัยได้อย่างไร
เหตุผล
gcloud run exec
ไม่มีสำหรับบริการ Cloud Run
Cloud Run เป็นแพลตฟอร์มแบบไม่มีเซิร์ฟเวอร์ ซึ่งคอนเทนเนอร์ของคุณอาจทำงานเป็นอินสแตนซ์ที่เหมือนกัน 0, 1 หรือหลายร้อยอินสแตนซ์ โดยไม่มีตัวตนที่เสถียรหรือเชลล์ที่ระบุได้ ซึ่งแตกต่างจาก Kubernetes (kubectl exec) โดยพื้นฐาน ซึ่งพ็อดที่เฉพาะเจาะจงจะมีซ็อกเก็ตที่มีชื่อที่คุณเชื่อมต่อได้
# ❌ This does NOT exist for Cloud Run Services:
gcloud run services exec blog --region europe-west1 -- rails console
# ✅ This exists for Cloud Run JOBS (non-interactive, one-shot tasks):
gcloud run jobs execute my-job --region europe-west1 --wait
รูปแบบดั้งเดิมของ GCP ทั้ง 4 รูปแบบ
รูปแบบ | คำสั่ง | แบบอินเทอร์แอกทีฟ | ความปลอดภัย |
1. พร็อกซีในเครื่อง + ฐานข้อมูลระยะไกล |
| ✅ เต็ม | 🔒 mTLS ของพร็อกซีการตรวจสอบสิทธิ์ Cloud SQL |
2. งานใน Cloud Run (แบบครั้งเดียว) |
| ❌ สคริปต์เท่านั้น | 🔒 ต้องมีบทบาท IAM |
3. อัญมณีของเว็บคอนโซล + IAP | เบราว์เซอร์ → | ✅ เต็ม | 🛡️ Zero Trust ของ IAP |
4. Cloud Shell + Proxy | Cloud Shell → | ✅ เต็ม | 🔒 ตัวตน Google |
รูปแบบที่ 1 (แนะนำสำหรับการตรวจสอบข้อมูล): เรียกใช้คอนโซล Rails ในเครื่องที่สื่อสารกับ Cloud SQL PostgreSQL โดยตรงผ่านพร็อกซีการตรวจสอบสิทธิ์ Cloud SQL
# In one terminal: start the auth proxy
cloud-sql-proxy rails8-fl-20260907b-xm8ko4:europe-west1:your-instance
# In another terminal: open a read-write or sandbox console
DATABASE_URL=postgresql://rails_user:${DB_PASSWORD}@127.0.0.1:5432/rails_production \
bin/rails console --sandbox
คุณจะได้รับความสามารถในการโต้ตอบ IRB อย่างเต็มรูปแบบโดยไม่มีการเปิดเผยเครือข่าย เนื่องจาก Cloud SQL Proxy ใช้ mTLS ผ่านซ็อกเก็ตโดเมน Unix หรือ Loopback
รูปแบบที่ 3 (Web Console + IAP Zero-Trust, เส้นทางเบราว์เซอร์ที่เพิ่มความปลอดภัย):
web-console gem มีเซสชัน IRB ที่ทำงานในเบราว์เซอร์ หากไม่มีการป้องกัน ก็จะเป็นช่องโหว่ด้านความปลอดภัยที่ร้ายแรง ดังนั้นอย่าเปิดเผยต่อสาธารณะ แต่เมื่อใช้ร่วมกับ IAP ของ Google (Quest 1) พื้นผิวการโจมตีจะลดลง โดยมีเพียงข้อมูลระบุตัวตนของ Google ที่ยืนยันแล้วในรายการที่อนุญาตเท่านั้นที่เข้าถึงปลายทาง /rails/console ได้
# Gemfile — only load in development/staging, never production without IAP!
gem "web-console", group: :development
# config/environments/production.rb — if IAP is enabled:
config.web_console.allowed_ips = ["0.0.0.0/0"] # IAP terminates auth before us
⚠️ รูปแบบที่ 3 ต้องเปิดใช้ Quest 1 (IAP) ก่อน หากไม่มี /rails/console ใน URL สาธารณะก็เหมือนกับการปล่อยให้ห้องเซิร์ฟเวอร์ของคุณไม่ได้ล็อก IAP จึงกลายเป็นเครื่องมือที่ทรงพลังสำหรับผู้ปฏิบัติงานซึ่งได้รับการเสริมความแข็งแกร่งด้วย Zero Trust ระดับ Google
ถาม Antigravity: "แสดงวิธีเรียกใช้
rails console --sandbox
กับฐานข้อมูลการผลิต Cloud SQL ของฉันอย่างปลอดภัยโดยใช้พร็อกซีการตรวจสอบสิทธิ์ Cloud SQL"
🏆 การจบการศึกษาใน The Hive: หลักฐานการทำงานที่ผ่านการตรวจสอบโดยผู้คุมสอบ
เมื่อทำภารกิจที่เลือกเสร็จแล้ว ให้รับถ้วยรางวัลจบหลักสูตรขั้นที่ 8 🏆 ในลีดเดอร์บอร์ดของ The Hive โดยทำดังนี้
- ส่งเควสต์ใน GitHub:
- เปิดปัญหาใหม่ในที่เก็บอย่างเป็นทางการ: github.com/palladius/rails8-app-on-gcp/issues/new
- รูปแบบชื่อ:
🎓 [Step 8 Completed]: - ในเนื้อหา ให้ใส่คำอธิบายสั้นๆ เกี่ยวกับสิ่งที่คุณทำสำเร็จและลิงก์ไปยังการติดตั้งใช้งาน Cloud Run ที่ใช้งานจริง
- เชื่อมต่อแอป Cloud Run กับปัญหา
- จดหมายเลขปัญหา (เช่น
88หรือ URL แบบเต็มhttps://github.com/palladius/rails8-app-on-gcp/issues/88) - แทรกตัวแปรสภาพแวดล้อม
STEP_8_GHIลงในบริการ Cloud Run โดยทำดังนี้gcloud run services update blog \ --region europe-west1 \ --update-env-vars STEP_8_GHI=<YOUR_ISSUE_NUMBER> - ตรวจสอบว่า
/status.jsonปลายทางรายงานภารกิจของคุณแล้ว คุณควรเห็นข้อมูลต่อไปนี้curl -s https://<YOUR_APP>.run.app/status.json | jq .quest{ "step_8_completed": true, "ghi_issue": 88, "ghi_url": "https://github.com/palladius/rails8-app-on-gcp/issues/88" }
- จดหมายเลขปัญหา (เช่น
- รับการตรวจสอบจากผู้คุมสอบและปลดล็อกถ้วยรางวัลทองคำ:
- ตรวจสอบลีดเดอร์บอร์ดของ The Hive: แถวของคุณจะแสดงป้ายสีเหลืองอำพัน
⏳ GHI #XX review pending - ขอให้ผู้คุมสอบของเวิร์กช็อป (@palladius, @emilianodellacasa หรือ @ricc) ตรวจสอบการติดตั้งใช้งาน
- ทันทีที่ผู้คุมสอบแสดงความคิดเห็นเกี่ยวกับปัญหา
LGTMThe Hive จะยกระดับความคืบหน้าของคุณเป็น 8/8 🏆 โดยอัตโนมัติพร้อมป้ายสีทอง/ม่วงเรืองแสงและถ้วยรางวัลถาวรที่ลิงก์ไปยังปัญหา Capstone ของคุณโดยตรง
- ตรวจสอบลีดเดอร์บอร์ดของ The Hive: แถวของคุณจะแสดงป้ายสีเหลืองอำพัน
11. บทสรุปและการล้างข้อมูล 🎓
ยินดีด้วย 🎉
คุณได้สร้างและติดตั้งใช้งานแอปพลิเคชัน Rails 8 ระดับการใช้งานจริงที่พร้อมใช้งานในองค์กรบน Google Cloud Platform แล้ว
- การเปลี่ยนผ่านแบบไม่มีสาขา: เชี่ยวชาญเวิร์กโฟลว์ที่ทันสมัยด้วยการซ้อนทับไทม์แมชชีนใน
main - Cloud Storage: ที่เก็บข้อมูลออบเจ็กต์ส่วนตัวที่ปรับขนาดได้พร้อมการลงนาม Blob ของ IAM (
iam: true) - Cloud SQL: PostgreSQL ที่มีการจัดการซึ่งรักษาความปลอดภัยด้วยอุโมงค์ mTLS ของพร็อกซีการตรวจสอบสิทธิ์ Cloud SQL
- Secret Manager: ไม่มีข้อมูลเข้าสู่ระบบแบบข้อความธรรมดาหรือการรั่วไหลของไฟล์
.env - Cloud Run แบบหลายคอนเทนเนอร์: เว็บ Puma, Worker ของ Solid Queue และ Sidecar ของพร็อกซีที่แยกกัน
- Generative AI: การสร้างโปสเตอร์ย้อนยุคแบบไม่พร้อมกันและการสังเคราะห์พอดแคสต์ TTS ด้วย Vertex AI
- ภารกิจ: IAP แบบ Zero Trust, ความสามารถในการสังเกตของ SRE และการฝัง pgvector
🧹 การล้างข้อมูลทรัพยากร
โปรดล้างข้อมูลทรัพยากร Google Cloud เพื่อหลีกเลี่ยงการเรียกเก็บเงินอย่างต่อเนื่องหลังจากเวิร์กช็อปเสร็จสิ้น เลือกแนวทางที่เหมาะกับสภาพแวดล้อมของคุณมากที่สุด
ตัวเลือกที่ 1: การลบ Terraform (แนะนำ / ค่าเริ่มต้น 🟢)
ใช้ตัวเลือกนี้หากคุณใช้โปรเจ็กต์ที่อยู่ในระบบคลาวด์ของ Google ที่มีอยู่หรือแชร์ซึ่งมีทรัพยากรหรือข้อมูลอื่นๆ โดยจะทำลายเฉพาะทรัพยากรที่จัดสรรไว้ในเวิร์กช็อปนี้ (Cloud Run, Cloud SQL, Secret Manager, บัคเก็ต GCS) เท่านั้น และจะไม่แตะต้องส่วนอื่นๆ ของโปรเจ็กต์
cd iac
terraform destroy -auto-approve
ตัวเลือกที่ 2: การลบโปรเจ็กต์ทั้งหมด (ไม่ทิ้งร่องรอย 🌪️)
ใช้ตัวเลือกนี้หากคุณสร้างโปรเจ็กต์เวิร์กช็อปเฉพาะ (เช่น ใช้เครดิตเวิร์กช็อปหรือแซนด์บ็อกซ์) และต้องการรับประกันว่าจะไม่มีร่องรอยใดๆ หลงเหลืออยู่ ซึ่งรวมถึงบันทึก เมตาดาต้า บัญชีบริการ และลิงก์การเรียกเก็บเงิน
gcloud projects delete $GOOGLE_CLOUD_PROJECT --quiet